Merge "Remove store_aggregation_counters argument from profile merging" am: 56701ba879 am: 554e0296cb am: 4b10f282a6
am: 07ebc75790
Change-Id: I4b24488b21afa7b02e7acf79fb56c4df443065ea
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0d20b64
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/cmds/dumpstate/README.md b/cmds/dumpstate/README.md
index c818c05..26dabbb 100644
--- a/cmds/dumpstate/README.md
+++ b/cmds/dumpstate/README.md
@@ -92,6 +92,12 @@
adb shell setprop dumpstate.version default
```
+## To set Bugreport API workflow for bugreport
+
+```
+adb shell setprop settings_call_bugreport_api true
+```
+
## Code style and formatting
Use the style defined at the
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4674d2a..0a91a07 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2048,12 +2048,12 @@
}
if (ds.options_->do_fb) {
- ds.screenshot_path_ = ds.GetPath(".png");
+ ds.screenshot_path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
}
ds.tmp_path_ = ds.GetPath(".tmp");
ds.log_path_ = ds.GetPath("-dumpstate_log-" + std::to_string(ds.pid_) + ".txt");
- std::string destination = ds.options_->bugreport_fd.get() != -1
+ std::string destination = ds.CalledByApi()
? StringPrintf("[fd:%d]", ds.options_->bugreport_fd.get())
: ds.bugreport_internal_dir_.c_str();
MYLOGD(
@@ -2067,7 +2067,7 @@
ds.tmp_path_.c_str(), ds.screenshot_path_.c_str());
if (ds.options_->do_zip_file) {
- ds.path_ = ds.GetPath(".zip");
+ ds.path_ = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
MYLOGD("Creating initial .zip file (%s)\n", ds.path_.c_str());
create_parent_dirs(ds.path_.c_str());
ds.zip_file.reset(fopen(ds.path_.c_str(), "wb"));
@@ -2102,7 +2102,7 @@
MYLOGI("changing suffix from %s to %s\n", ds.name_.c_str(), name.c_str());
ds.name_ = name;
if (!ds.screenshot_path_.empty()) {
- std::string new_screenshot_path = ds.GetPath(".png");
+ std::string new_screenshot_path = ds.GetPath(ds.CalledByApi() ? "-tmp.png" : ".png");
if (rename(ds.screenshot_path_.c_str(), new_screenshot_path.c_str())) {
MYLOGE("rename(%s, %s): %s\n", ds.screenshot_path_.c_str(),
new_screenshot_path.c_str(), strerror(errno));
@@ -2120,7 +2120,7 @@
} else {
do_text_file = false;
// If the user has changed the suffix, we need to change the zip file name.
- std::string new_path = ds.GetPath(".zip");
+ std::string new_path = ds.GetPath(ds.CalledByApi() ? "-tmp.zip" : ".zip");
if (ds.path_ != new_path) {
MYLOGD("Renaming zip file from %s to %s\n", ds.path_.c_str(), new_path.c_str());
if (rename(ds.path_.c_str(), new_path.c_str())) {
@@ -2354,9 +2354,6 @@
// clang-format off
case 'd': do_add_date = true; break;
case 'z': do_zip_file = true; break;
- // o=use_outfile not supported anymore.
- // TODO(b/111441001): Remove when all callers have migrated.
- case 'o': break;
case 's': use_socket = true; break;
case 'S': use_control_socket = true; break;
case 'v': show_header_only = true; break;
@@ -2728,7 +2725,7 @@
}
/* tell activity manager we're done */
- if (options_->do_broadcast) {
+ if (options_->do_broadcast && !CalledByApi()) {
SendBugreportFinishedBroadcast();
// Note that listener_ is notified in Run();
}
@@ -2775,6 +2772,10 @@
ds.consent_callback_->getResult() == UserConsentResult::DENIED;
}
+bool Dumpstate::CalledByApi() const {
+ return ds.options_->bugreport_fd.get() != -1 ? true : false;
+}
+
void Dumpstate::CleanupFiles() {
android::os::UnlinkAndLogOnError(tmp_path_);
android::os::UnlinkAndLogOnError(screenshot_path_);
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 82bf821..5ba84ca 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -344,6 +344,11 @@
bool IsUserConsentDenied() const;
/*
+ * Returns true if dumpstate is called by bugreporting API
+ */
+ bool CalledByApi() const;
+
+ /*
* Structure to hold options that determine the behavior of dumpstate.
*/
struct DumpOptions {
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 14937b8..e491a4b 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -11,8 +11,7 @@
# dumpstatez generates a zipped bugreport but also uses a socket to print the file location once
# it is finished.
-service dumpstatez /system/bin/dumpstate -S -d -z \
- -o /data/user_de/0/com.android.shell/files/bugreports/bugreport
+service dumpstatez /system/bin/dumpstate -S -d -z
socket dumpstate stream 0660 shell log
class main
disabled
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 181046a..dbbcdff 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -201,9 +201,7 @@
(char*)"dumpstate",
(char*)"-d",
(char*)"-z",
- (char*)"-B",
- (char*)"-o",
- (char*)dirname(android::base::GetExecutablePath().c_str())
+ (char*)"-B"
};
// clang-format on
sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 26e9984..d99bcc8 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -127,4 +127,6 @@
const int FLAG_USE_QUOTA = 0x1000;
const int FLAG_FORCE = 0x2000;
+
+ const int FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES = 0x20000;
}
diff --git a/cmds/surfacereplayer/proto/src/trace.proto b/cmds/surfacereplayer/proto/src/trace.proto
index c70bc3e..792ff91 100644
--- a/cmds/surfacereplayer/proto/src/trace.proto
+++ b/cmds/surfacereplayer/proto/src/trace.proto
@@ -1,5 +1,6 @@
syntax = "proto2";
option optimize_for = LITE_RUNTIME;
+package android.surfaceflinger;
message Trace {
repeated Increment increment = 1;
@@ -46,6 +47,10 @@
SecureFlagChange secure_flag = 14;
DeferredTransactionChange deferred_transaction = 15;
CornerRadiusChange corner_radius = 16;
+ ReparentChange reparent = 17;
+ RelativeParentChange relative_parent = 18;
+ DetachChildrenChange detach_children = 19;
+ ReparentChildrenChange reparent_children = 20;
}
}
@@ -177,3 +182,20 @@
required int32 id = 1;
required int32 mode = 2;
}
+
+message ReparentChange {
+ required int32 parent_id = 1;
+}
+
+message ReparentChildrenChange {
+ required int32 parent_id = 1;
+}
+
+message RelativeParentChange {
+ required int32 relative_parent_id = 1;
+ required int32 z = 2;
+}
+
+message DetachChildrenChange {
+ required bool detach_children = 1;
+}
diff --git a/cmds/surfacereplayer/replayer/Event.cpp b/cmds/surfacereplayer/replayer/Event.cpp
index 390d398..64db5f0 100644
--- a/cmds/surfacereplayer/replayer/Event.cpp
+++ b/cmds/surfacereplayer/replayer/Event.cpp
@@ -17,6 +17,7 @@
#include "Event.h"
using namespace android;
+using Increment = surfaceflinger::Increment;
Event::Event(Increment::IncrementCase type) : mIncrementType(type) {}
diff --git a/cmds/surfacereplayer/replayer/Event.h b/cmds/surfacereplayer/replayer/Event.h
index 44b60f5..09a7c24 100644
--- a/cmds/surfacereplayer/replayer/Event.h
+++ b/cmds/surfacereplayer/replayer/Event.h
@@ -24,6 +24,8 @@
namespace android {
+using Increment = surfaceflinger::Increment;
+
class Event {
public:
Event(Increment::IncrementCase);
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 34886a9..a4a9b6a 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -412,6 +412,18 @@
setDeferredTransaction(transaction, change.id(),
change.deferred_transaction());
break;
+ case SurfaceChange::SurfaceChangeCase::kReparent:
+ setReparentChange(transaction, change.id(), change.reparent());
+ break;
+ case SurfaceChange::SurfaceChangeCase::kReparentChildren:
+ setReparentChildrenChange(transaction, change.id(), change.reparent_children());
+ break;
+ case SurfaceChange::SurfaceChangeCase::kRelativeParent:
+ setRelativeParentChange(transaction, change.id(), change.relative_parent());
+ break;
+ case SurfaceChange::SurfaceChangeCase::kDetachChildren:
+ setDetachChildrenChange(transaction, change.id(), change.detach_children());
+ break;
default:
status = 1;
break;
@@ -680,3 +692,35 @@
mComposerClient = new SurfaceComposerClient;
return mComposerClient->initCheck();
}
+
+void Replayer::setReparentChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const ReparentChange& c) {
+ sp<IBinder> newParentHandle = nullptr;
+ if (mLayers.count(c.parent_id()) != 0 && mLayers[c.parent_id()] != nullptr) {
+ newParentHandle = mLayers[c.parent_id()]->getHandle();
+ }
+ t.reparent(mLayers[id], newParentHandle);
+}
+
+void Replayer::setRelativeParentChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const RelativeParentChange& c) {
+ if (mLayers.count(c.relative_parent_id()) == 0 || mLayers[c.relative_parent_id()] == nullptr) {
+ ALOGE("Layer %d not found in set relative parent transaction", c.relative_parent_id());
+ return;
+ }
+ t.setRelativeLayer(mLayers[id], mLayers[c.relative_parent_id()]->getHandle(), c.z());
+}
+
+void Replayer::setDetachChildrenChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const DetachChildrenChange& c) {
+ t.detachChildren(mLayers[id]);
+}
+
+void Replayer::setReparentChildrenChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const ReparentChildrenChange& c) {
+ if (mLayers.count(c.parent_id()) == 0 || mLayers[c.parent_id()] == nullptr) {
+ ALOGE("Layer %d not found in reparent children transaction", c.parent_id());
+ return;
+ }
+ t.reparentChildren(mLayers[id], mLayers[c.parent_id()]->getHandle());
+}
diff --git a/cmds/surfacereplayer/replayer/Replayer.h b/cmds/surfacereplayer/replayer/Replayer.h
index ad807ee..3b94618 100644
--- a/cmds/surfacereplayer/replayer/Replayer.h
+++ b/cmds/surfacereplayer/replayer/Replayer.h
@@ -38,6 +38,8 @@
#include <unordered_map>
#include <utility>
+using namespace android::surfaceflinger;
+
namespace android {
const auto DEFAULT_PATH = "/data/local/tmp/SurfaceTrace.dat";
@@ -108,6 +110,14 @@
layer_id id, const SecureFlagChange& sfc);
void setDeferredTransaction(SurfaceComposerClient::Transaction& t,
layer_id id, const DeferredTransactionChange& dtc);
+ void setReparentChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const ReparentChange& c);
+ void setRelativeParentChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const RelativeParentChange& c);
+ void setDetachChildrenChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const DetachChildrenChange& c);
+ void setReparentChildrenChange(SurfaceComposerClient::Transaction& t,
+ layer_id id, const ReparentChildrenChange& c);
void setDisplaySurface(SurfaceComposerClient::Transaction& t,
display_id id, const DispSurfaceChange& dsc);
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 2def64d..01cf2f8 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -60,6 +60,22 @@
ANDROID_BITMAP_FORMAT_RGBA_4444 = 7,
/** Alpha: 8 bits. */
ANDROID_BITMAP_FORMAT_A_8 = 8,
+ /** Each component is stored as a half float. **/
+ ANDROID_BITMAP_FORMAT_RGBA_F16 = 9,
+};
+
+/** Bitmap alpha format */
+enum {
+ /** Pixel components are premultiplied by alpha. */
+ ANDROID_BITMAP_FLAGS_ALPHA_PREMUL = 0,
+ /** Pixels are opaque. */
+ ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE = 1,
+ /** Pixel components are independent of alpha. */
+ ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL = 2,
+ /** Bit mask for AndroidBitmapFormat.flags to isolate the alpha. */
+ ANDROID_BITMAP_FLAGS_ALPHA_MASK = 0x3,
+ /** Shift for AndroidBitmapFormat.flags to isolate the alpha. */
+ ANDROID_BITMAP_FLAGS_ALPHA_SHIFT = 0,
};
/** Bitmap info, see AndroidBitmap_getInfo(). */
@@ -72,8 +88,9 @@
uint32_t stride;
/** The bitmap pixel format. See {@link AndroidBitmapFormat} */
int32_t format;
- /** Unused. */
- uint32_t flags; // 0 for now
+ /** Two bits are used to encode alpha. Use ANDROID_BITMAP_FLAGS_ALPHA_MASK
+ * and ANDROID_BITMAP_FLAGS_ALPHA_SHIFT to retrieve them. */
+ uint32_t flags;
} AndroidBitmapInfo;
/**
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 44883cc..1b589bc 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -83,7 +83,7 @@
* Power a callback to be run on the next frame. The data pointer provided will
* be passed to the callback function when it's called.
*/
-void AChoreographer_postFrameCallback64(AChoreographer* chroreographer,
+void AChoreographer_postFrameCallback64(AChoreographer* choreographer,
AChoreographer_frameCallback64 callback, void* data) __INTRODUCED_IN(29);
/**
diff --git a/include/android/surface_control.h b/include/android/surface_control.h
index ef2ad99..abb8368 100644
--- a/include/android/surface_control.h
+++ b/include/android/surface_control.h
@@ -130,7 +130,7 @@
/**
* Returns a sync fence that signals when the transaction has been presented.
* The recipient of the callback takes ownership of the fence and is responsible for closing
- * it.
+ * it. If a device does not support present fences, a -1 will be returned.
*/
int ASurfaceTransactionStats_getPresentFenceFd(ASurfaceTransactionStats* surface_transaction_stats)
__INTRODUCED_IN(29);
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 4365a3c..d23e3b7 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -37,7 +37,6 @@
virtual void setInputWindows(const std::vector<InputWindowInfo>& inputHandles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) = 0;
- virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) = 0;
virtual void registerInputChannel(const sp<InputChannel>& channel) = 0;
virtual void unregisterInputChannel(const sp<InputChannel>& channel) = 0;
};
@@ -51,8 +50,7 @@
enum {
SET_INPUT_WINDOWS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
REGISTER_INPUT_CHANNEL_TRANSACTION,
- UNREGISTER_INPUT_CHANNEL_TRANSACTION,
- TRANSFER_TOUCH_FOCUS
+ UNREGISTER_INPUT_CHANNEL_TRANSACTION
};
virtual status_t onTransact(uint32_t code, const Parcel& data,
diff --git a/include/input/Input.h b/include/input/Input.h
index 805957a..cbd1a41 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -24,12 +24,15 @@
*/
#include <android/input.h>
+#include <math.h>
+#include <stdint.h>
#include <utils/BitSet.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
#include <utils/Vector.h>
-#include <stdint.h>
+
+#include <limits>
/*
* Additional private constants not defined in ndk/ui/input.h.
@@ -246,6 +249,13 @@
*/
const char* motionClassificationToString(MotionClassification classification);
+/**
+ * Invalid value for cursor position. Used for non-mouse events, tests and injected events. Don't
+ * use it for direct comparison with any other value, because NaN isn't equal to itself according to
+ * IEEE 754. Use isnan() instead to check if a cursor position is valid.
+ */
+constexpr float AMOTION_EVENT_INVALID_CURSOR_POSITION = std::numeric_limits<float>::quiet_NaN();
+
/*
* Pointer coordinate data.
*/
@@ -459,6 +469,18 @@
inline float getYPrecision() const { return mYPrecision; }
+ inline float getRawXCursorPosition() const { return mRawXCursorPosition; }
+
+ float getXCursorPosition() const;
+
+ inline float getRawYCursorPosition() const { return mRawYCursorPosition; }
+
+ float getYCursorPosition() const;
+
+ void setCursorPosition(float x, float y);
+
+ static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
+
inline nsecs_t getDownTime() const { return mDownTime; }
inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; }
@@ -600,26 +622,13 @@
ssize_t findPointerIndex(int32_t pointerId) const;
- void initialize(
- int32_t deviceId,
- int32_t source,
- int32_t displayId,
- int32_t action,
- int32_t actionButton,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- MotionClassification classification,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords);
+ void initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
+ int32_t buttonState, MotionClassification classification, float xOffset,
+ float yOffset, float xPrecision, float yPrecision, float rawXCursorPosition,
+ float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ size_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords);
void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -669,6 +678,8 @@
float mYOffset;
float mXPrecision;
float mYPrecision;
+ float mRawXCursorPosition;
+ float mRawYCursorPosition;
nsecs_t mDownTime;
Vector<PointerProperties> mPointerProperties;
Vector<nsecs_t> mSampleEventTimes;
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 59d16d1..eaa562b 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -359,6 +359,9 @@
DEFINE_AXIS(BRAKE),
DEFINE_AXIS(DISTANCE),
DEFINE_AXIS(TILT),
+ DEFINE_AXIS(SCROLL),
+ DEFINE_AXIS(RELATIVE_X),
+ DEFINE_AXIS(RELATIVE_Y),
DEFINE_AXIS(GENERIC_1),
DEFINE_AXIS(GENERIC_2),
DEFINE_AXIS(GENERIC_3),
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 63606e5..c056c97 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -31,13 +31,17 @@
#include <string>
+#include <android-base/chrono_utils.h>
+
#include <binder/IBinder.h>
#include <input/Input.h>
-#include <utils/Errors.h>
-#include <utils/Timers.h>
-#include <utils/RefBase.h>
-#include <utils/Vector.h>
#include <utils/BitSet.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+#include <android-base/unique_fd.h>
namespace android {
class Parcel;
@@ -113,6 +117,8 @@
float yOffset;
float xPrecision;
float yPrecision;
+ float xCursorPosition;
+ float yCursorPosition;
uint32_t pointerCount;
uint32_t empty3;
// Note that PointerCoords requires 8 byte alignment.
@@ -161,8 +167,7 @@
virtual ~InputChannel();
public:
- InputChannel() = default;
- InputChannel(const std::string& name, int fd);
+ static sp<InputChannel> create(const std::string& name, android::base::unique_fd fd);
/* Creates a pair of input channels.
*
@@ -172,7 +177,7 @@
sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
inline std::string getName() const { return mName; }
- inline int getFd() const { return mFd; }
+ inline int getFd() const { return mFd.get(); }
/* Sends a message to the other endpoint.
*
@@ -203,16 +208,15 @@
sp<InputChannel> dup() const;
status_t write(Parcel& out) const;
- status_t read(const Parcel& from);
+ static sp<InputChannel> read(const Parcel& from);
sp<IBinder> getToken() const;
void setToken(const sp<IBinder>& token);
private:
- void setFd(int fd);
-
+ InputChannel(const std::string& name, android::base::unique_fd fd);
std::string mName;
- int mFd = -1;
+ android::base::unique_fd mFd;
sp<IBinder> mToken = nullptr;
};
@@ -261,27 +265,14 @@
* Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS.
* Other errors probably indicate that the channel is broken.
*/
- status_t publishMotionEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t displayId,
- int32_t action,
- int32_t actionButton,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- MotionClassification classification,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- uint32_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords);
+ status_t publishMotionEvent(uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId,
+ int32_t action, int32_t actionButton, int32_t flags,
+ int32_t edgeFlags, int32_t metaState, int32_t buttonState,
+ MotionClassification classification, float xOffset, float yOffset,
+ float xPrecision, float yPrecision, float xCursorPosition,
+ float yCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords);
/* Receives the finished signal from the consumer in reply to the original dispatch signal.
* If a signal was received, returns the message sequence number,
@@ -297,6 +288,7 @@
status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
private:
+
sp<InputChannel> mChannel;
};
diff --git a/include/input/LatencyStatistics.h b/include/input/LatencyStatistics.h
new file mode 100644
index 0000000..bd86266
--- /dev/null
+++ b/include/input/LatencyStatistics.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _UI_INPUT_STATISTICS_H
+#define _UI_INPUT_STATISTICS_H
+
+#include <android-base/chrono_utils.h>
+
+#include <stddef.h>
+
+namespace android {
+
+class LatencyStatistics {
+private:
+ /* Minimum sample recorded */
+ float mMin;
+ /* Maximum sample recorded */
+ float mMax;
+ /* Sum of all samples recorded */
+ float mSum;
+ /* Sum of all the squares of samples recorded */
+ float mSum2;
+ /* Count of all samples recorded */
+ size_t mCount;
+ /* The last time statistics were reported */
+ std::chrono::steady_clock::time_point mLastReportTime;
+ /* Statistics Report Frequency */
+ const std::chrono::seconds mReportPeriod;
+
+public:
+ LatencyStatistics(std::chrono::seconds period);
+
+ void addValue(float);
+ void reset();
+ bool shouldReport();
+
+ float getMean();
+ float getMin();
+ float getMax();
+ float getStDev();
+ size_t getCount();
+};
+
+} // namespace android
+
+#endif // _UI_INPUT_STATISTICS_H
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 0a6685e..9da9c13 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -21,6 +21,13 @@
#include <utils/SystemClock.h>
+#include <sys/types.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AppOpsManager"
+
namespace android {
namespace {
@@ -49,6 +56,12 @@
return gToken;
}
+thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
+thread_local int32_t uidOfThisBinderTransaction = -1;
+
+// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
+uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
+
AppOpsManager::AppOpsManager()
{
}
@@ -102,18 +115,41 @@
}
int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
+ return noteOp(op, uid, callingPackage, String16("noteOp from native code"));
+}
+
+int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+ const String16& message) {
sp<IAppOpsService> service = getService();
- return service != nullptr
+ int32_t mode = service != nullptr
? service->noteOperation(op, uid, callingPackage)
: APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+ if (mode == AppOpsManager::MODE_ALLOWED) {
+ markAppOpNoted(uid, callingPackage, op, message);
+ }
+
+ return mode;
}
int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault) {
+ return startOpNoThrow(op, uid, callingPackage, startIfModeDefault,
+ String16("startOpNoThrow from native code"));
+}
+
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+ bool startIfModeDefault, const String16& message) {
sp<IAppOpsService> service = getService();
- return service != nullptr
+ int32_t mode = service != nullptr
? service->startOperation(getToken(service), op, uid, callingPackage,
startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+ if (mode == AppOpsManager::MODE_ALLOWED) {
+ markAppOpNoted(uid, callingPackage, op, message);
+ }
+
+ return mode;
}
void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -146,5 +182,45 @@
return -1;
}
+void AppOpsManager::setCameraAudioRestriction(int32_t mode) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ service->setCameraAudioRestriction(mode);
+ }
+}
+
+bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ return service->shouldCollectNotes(opcode);
+ }
+ return false;
+}
+
+void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+ const String16& message) {
+ // check it the appops needs to be collected and cache result
+ if (appOpsToNote[opCode] == 0) {
+ if (shouldCollectNotes(opCode)) {
+ appOpsToNote[opCode] = 2;
+ } else {
+ appOpsToNote[opCode] = 1;
+ }
+ }
+
+ if (appOpsToNote[opCode] != 2) {
+ return;
+ }
+
+ noteAsyncOp(String16(), uid, packageName, opCode, message);
+}
+
+void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ }
+}
} // namespace android
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index b2bd9e5..6c16c2d 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -111,7 +111,6 @@
return reply.readStrongBinder();
}
-
virtual int32_t permissionToOpCode(const String16& permission) {
Parcel data, reply;
data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -137,6 +136,51 @@
}
return reply.readInt32();
}
+
+ virtual void setCameraAudioRestriction(int32_t mode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(mode);
+ remote()->transact(SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION, data, &reply);
+ }
+
+ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+
+ // Convert empty callingPackage into null string
+ if (callingPackageName.size() != 0) {
+ data.writeString16(callingPackageName);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
+ data.writeInt32(uid);
+
+ // Convert empty packageName into null string
+ if (packageName.size() != 0) {
+ data.writeString16(packageName);
+ } else {
+ data.writeString16(nullptr, 0);
+ }
+
+ data.writeInt32(opCode);
+ data.writeString16(message);
+ remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
+ }
+
+ virtual bool shouldCollectNotes(int32_t opCode) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(opCode);
+ remote()->transact(SHOULD_COLLECT_NOTES_TRANSACTION, data, &reply);
+ // fail on exception
+ if (reply.readExceptionCode() != 0) {
+ return false;
+ }
+ return reply.readBool();
+ }
};
IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -234,6 +278,32 @@
reply->writeInt32(res);
return NO_ERROR;
} break;
+ case SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ const int32_t mode = data.readInt32();
+ setCameraAudioRestriction(mode);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case NOTE_ASYNC_OP_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ String16 callingPackageName = data.readString16();
+ int32_t uid = data.readInt32();
+ String16 packageName = data.readString16();
+ int32_t opCode = data.readInt32();
+ String16 message = data.readString16();
+ noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+ reply->writeNoException();
+ return NO_ERROR;
+ } break;
+ case SHOULD_COLLECT_NOTES_TRANSACTION: {
+ CHECK_INTERFACE(IAppOpsService, data, reply);
+ int32_t opCode = data.readInt32();
+ bool shouldCollect = shouldCollectNotes(opCode);
+ reply->writeNoException();
+ reply->writeBool(shouldCollect);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/binder/IMemory.cpp b/libs/binder/IMemory.cpp
index 094f89f..c2bb811 100644
--- a/libs/binder/IMemory.cpp
+++ b/libs/binder/IMemory.cpp
@@ -149,7 +149,7 @@
return static_cast<char*>(base) + offset;
}
-void* IMemory::pointer() const {
+void* IMemory::unsecurePointer() const {
ssize_t offset;
sp<IMemoryHeap> heap = getMemory(&offset);
void* const base = heap!=nullptr ? heap->base() : MAP_FAILED;
@@ -158,6 +158,8 @@
return static_cast<char*>(base) + offset;
}
+void* IMemory::pointer() const { return unsecurePointer(); }
+
size_t IMemory::size() const {
size_t size;
getMemory(nullptr, &size);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index e5c7d74..573a038 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2354,6 +2354,22 @@
mObjectsSize = 0;
break;
}
+ const flat_binder_object* flat
+ = reinterpret_cast<const flat_binder_object*>(mData + offset);
+ uint32_t type = flat->hdr.type;
+ if (!(type == BINDER_TYPE_BINDER || type == BINDER_TYPE_HANDLE ||
+ type == BINDER_TYPE_FD)) {
+ // We should never receive other types (eg BINDER_TYPE_FDA) as long as we don't support
+ // them in libbinder. If we do receive them, it probably means a kernel bug; try to
+ // recover gracefully by clearing out the objects, and releasing the objects we do
+ // know about.
+ android_errorWriteLog(0x534e4554, "135930648");
+ ALOGE("%s: unsupported type object (%" PRIu32 ") at offset %" PRIu64 "\n",
+ __func__, type, (uint64_t)offset);
+ releaseObjects();
+ mObjectsSize = 0;
+ break;
+ }
minOffset = offset + sizeof(flat_binder_object);
}
scanForFds();
diff --git a/libs/binder/fuzzer/Android.bp b/libs/binder/fuzzer/Android.bp
new file mode 100644
index 0000000..f3e4229
--- /dev/null
+++ b/libs/binder/fuzzer/Android.bp
@@ -0,0 +1,31 @@
+cc_fuzz {
+ name: "binder_parcel_fuzzer",
+ host_supported: true,
+ srcs: [
+ "binder.cpp",
+ "hwbinder.cpp",
+ "main.cpp",
+ "util.cpp",
+ ],
+ static_libs: [
+ "libbase",
+ "libbinderthreadstate",
+ "libcgrouprc",
+ "libcgrouprc_format",
+ "libcutils",
+ "libhidlbase",
+ "liblog",
+ "libprocessgroup",
+ "libjsoncpp",
+ "libutils",
+ ],
+
+ target: {
+ android: {
+ shared_libs: ["libbinder"],
+ },
+ host: {
+ static_libs: ["libbinder"],
+ },
+ },
+}
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
new file mode 100644
index 0000000..86264db
--- /dev/null
+++ b/libs/binder/fuzzer/binder.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define FUZZ_LOG_TAG "binder"
+
+#include "binder.h"
+#include "util.h"
+
+#include <android/os/IServiceManager.h>
+
+using ::android::status_t;
+
+class ExampleParcelable : public android::Parcelable {
+public:
+ status_t writeToParcel(android::Parcel* /*parcel*/) const override {
+ FUZZ_LOG() << "should not reach";
+ abort();
+ }
+ status_t readFromParcel(const android::Parcel* parcel) override {
+ mExampleExtraField++;
+ return parcel->readInt64(&(this->mExampleUsedData));
+ }
+private:
+ int64_t mExampleExtraField = 0;
+ int64_t mExampleUsedData = 0;
+};
+
+struct ExampleFlattenable : public android::Flattenable<ExampleFlattenable> {
+public:
+ size_t getFlattenedSize() const { return sizeof(mValue); }
+ size_t getFdCount() const { return 0; }
+ status_t flatten(void*& /*buffer*/, size_t& /*size*/, int*& /*fds*/, size_t& /*count*/) const {
+ FUZZ_LOG() << "should not reach";
+ abort();
+ }
+ status_t unflatten(void const*& buffer, size_t& size, int const*& /*fds*/, size_t& /*count*/) {
+ if (size < sizeof(mValue)) {
+ return android::NO_MEMORY;
+ }
+ android::FlattenableUtils::read(buffer, size, mValue);
+ return android::OK;
+ }
+private:
+ int32_t mValue = 0xFEEDBEEF;
+};
+
+struct ExampleLightFlattenable : public android::LightFlattenablePod<ExampleLightFlattenable> {
+ int32_t mValue = 0;
+};
+
+#define PARCEL_READ_WITH_STATUS(T, FUN) \
+ [] (const ::android::Parcel& p, uint8_t /*data*/) {\
+ FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
+ T t{};\
+ status_t status = p.FUN(&t);\
+ FUZZ_LOG() << #T " status: " << status /* << " value: " << t*/;\
+ }
+
+#define PARCEL_READ_NO_STATUS(T, FUN) \
+ [] (const ::android::Parcel& p, uint8_t /*data*/) {\
+ FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
+ T t = p.FUN();\
+ (void) t;\
+ FUZZ_LOG() << #T " done " /* << " value: " << t*/;\
+ }
+
+#define PARCEL_READ_OPT_STATUS(T, FUN) \
+ PARCEL_READ_WITH_STATUS(T, FUN), \
+ PARCEL_READ_NO_STATUS(T, FUN)
+
+std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS {
+ PARCEL_READ_NO_STATUS(size_t, dataSize),
+ PARCEL_READ_NO_STATUS(size_t, dataAvail),
+ PARCEL_READ_NO_STATUS(size_t, dataPosition),
+ PARCEL_READ_NO_STATUS(size_t, dataCapacity),
+ [] (const ::android::Parcel& p, uint8_t pos) {
+ FUZZ_LOG() << "about to setDataPosition: " << pos;
+ p.setDataPosition(pos);
+ FUZZ_LOG() << "setDataPosition done";
+ },
+ PARCEL_READ_NO_STATUS(size_t, allowFds),
+ PARCEL_READ_NO_STATUS(size_t, hasFileDescriptors),
+ [] (const ::android::Parcel& p, uint8_t len) {
+#ifdef __ANDROID__
+ std::string interface(len, 'a');
+ FUZZ_LOG() << "about to enforceInterface: " << interface;
+ bool b = p.enforceInterface(::android::String16(interface.c_str()));
+ FUZZ_LOG() << "enforced interface: " << b;
+#else
+ FUZZ_LOG() << "skipping enforceInterface";
+ (void)p;
+ (void)len;
+#endif // __ANDROID__
+ },
+ [] (const ::android::Parcel& p, uint8_t /*len*/) {
+#ifdef __ANDROID__
+ FUZZ_LOG() << "about to checkInterface";
+ bool b = p.checkInterface(new android::BBinder());
+ FUZZ_LOG() << "checked interface: " << b;
+#else
+ FUZZ_LOG() << "skipping checkInterface";
+ (void)p;
+#endif // __ANDROID__
+ },
+ PARCEL_READ_NO_STATUS(size_t, objectsCount),
+ PARCEL_READ_NO_STATUS(status_t, errorCheck),
+ [] (const ::android::Parcel& p, uint8_t len) {
+ FUZZ_LOG() << "about to read void*";
+ std::vector<uint8_t> data(len);
+ status_t status = p.read(data.data(), len);
+ FUZZ_LOG() << "read status: " << status;
+ },
+ [] (const ::android::Parcel& p, uint8_t len) {
+ FUZZ_LOG() << "about to readInplace";
+ const void* r = p.readInplace(len);
+ FUZZ_LOG() << "readInplace done. pointer: " << r << " bytes: " << hexString(r, len);
+ },
+ PARCEL_READ_OPT_STATUS(int32_t, readInt32),
+ PARCEL_READ_OPT_STATUS(uint32_t, readUint32),
+ PARCEL_READ_OPT_STATUS(int64_t, readInt64),
+ PARCEL_READ_OPT_STATUS(uint64_t, readUint64),
+ PARCEL_READ_OPT_STATUS(float, readFloat),
+ PARCEL_READ_OPT_STATUS(double, readDouble),
+ PARCEL_READ_OPT_STATUS(intptr_t, readIntPtr),
+ PARCEL_READ_OPT_STATUS(bool, readBool),
+ PARCEL_READ_OPT_STATUS(char16_t, readChar),
+ PARCEL_READ_OPT_STATUS(int8_t, readByte),
+
+ PARCEL_READ_WITH_STATUS(std::string, readUtf8FromUtf16),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<std::string>, readUtf8FromUtf16),
+ [] (const ::android::Parcel& p, uint8_t /*data*/) {
+ FUZZ_LOG() << "about to read c-str";
+ const char* str = p.readCString();
+ FUZZ_LOG() << "read c-str: " << (str ? str : "<empty string>");
+ },
+ PARCEL_READ_OPT_STATUS(android::String8, readString8),
+ PARCEL_READ_OPT_STATUS(android::String16, readString16),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<android::String16>, readString16),
+ [] (const ::android::Parcel& p, uint8_t /*data*/) {
+ FUZZ_LOG() << "about to readString16Inplace";
+ size_t outLen = 0;
+ const char16_t* str = p.readString16Inplace(&outLen);
+ FUZZ_LOG() << "readString16Inplace: " << hexString(str, sizeof(char16_t) * outLen)
+ << " size: " << outLen;
+ },
+ PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readStrongBinder),
+ PARCEL_READ_WITH_STATUS(android::sp<android::IBinder>, readNullableStrongBinder),
+
+ // only reading one parcelable type for now
+ // TODO(b/131868573): can force read of arbitrarily sized vector
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<ExampleParcelable>>>, readParcelableVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<ExampleParcelable>, readParcelableVector),
+ PARCEL_READ_WITH_STATUS(ExampleParcelable, readParcelable),
+ PARCEL_READ_WITH_STATUS(std::unique_ptr<ExampleParcelable>, readParcelable),
+
+ // only reading one binder type for now
+ PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readStrongBinder),
+ PARCEL_READ_WITH_STATUS(android::sp<android::os::IServiceManager>, readNullableStrongBinder),
+
+ // TODO(b/131868573): can force read of arbitrarily sized vector
+ // PARCEL_READ_WITH_STATUS(::std::unique_ptr<std::vector<android::sp<android::IBinder>>>, readStrongBinderVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<android::sp<android::IBinder>>, readStrongBinderVector),
+
+ // TODO(b/131868573): can force read of arbitrarily sized vector
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int8_t>>, readByteVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<int8_t>, readByteVector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint8_t>>, readByteVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<uint8_t>, readByteVector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int32_t>>, readInt32Vector),
+ // PARCEL_READ_WITH_STATUS(std::vector<int32_t>, readInt32Vector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<int64_t>>, readInt64Vector),
+ // PARCEL_READ_WITH_STATUS(std::vector<int64_t>, readInt64Vector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<uint64_t>>, readUint64Vector),
+ // PARCEL_READ_WITH_STATUS(std::vector<uint64_t>, readUint64Vector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<float>>, readFloatVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<float>, readFloatVector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<double>>, readDoubleVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<double>, readDoubleVector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<bool>>, readBoolVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<bool>, readBoolVector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<char16_t>>, readCharVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<char16_t>, readCharVector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<android::String16>>>, readString16Vector),
+ // PARCEL_READ_WITH_STATUS(std::vector<android::String16>, readString16Vector),
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<std::unique_ptr<std::string>>>, readUtf8VectorFromUtf16Vector),
+ // PARCEL_READ_WITH_STATUS(std::vector<std::string>, readUtf8VectorFromUtf16Vector),
+
+ [] (const android::Parcel& p, uint8_t /*len*/) {
+ FUZZ_LOG() << "about to read flattenable";
+ ExampleFlattenable f;
+ status_t status = p.read(f);
+ FUZZ_LOG() << "read flattenable: " << status;
+ },
+ [] (const android::Parcel& p, uint8_t /*len*/) {
+ FUZZ_LOG() << "about to read lite flattenable";
+ ExampleLightFlattenable f;
+ status_t status = p.read(f);
+ FUZZ_LOG() << "read lite flattenable: " << status;
+ },
+
+ // TODO(b/131868573): can force read of arbitrarily sized vector
+ // TODO: resizeOutVector
+
+ PARCEL_READ_NO_STATUS(int32_t, readExceptionCode),
+ [] (const android::Parcel& p, uint8_t /*len*/) {
+ FUZZ_LOG() << "about to readNativeHandle";
+ native_handle_t* t = p.readNativeHandle();
+ FUZZ_LOG() << "readNativeHandle: " << t;
+ if (t != nullptr) {
+ FUZZ_LOG() << "about to free readNativeHandle";
+ native_handle_close(t);
+ native_handle_delete(t);
+ FUZZ_LOG() << "readNativeHandle freed";
+ }
+ },
+ PARCEL_READ_NO_STATUS(int, readFileDescriptor),
+ PARCEL_READ_NO_STATUS(int, readParcelFileDescriptor),
+ PARCEL_READ_WITH_STATUS(android::base::unique_fd, readUniqueFileDescriptor),
+
+ // TODO(b/131868573): can force read of arbitrarily sized vector
+ // PARCEL_READ_WITH_STATUS(std::unique_ptr<std::vector<android::base::unique_fd>>, readUniqueFileDescriptorVector),
+ // PARCEL_READ_WITH_STATUS(std::vector<android::base::unique_fd>, readUniqueFileDescriptorVector),
+
+ [] (const android::Parcel& p, uint8_t len) {
+ FUZZ_LOG() << "about to readBlob";
+ ::android::Parcel::ReadableBlob blob;
+ status_t status = p.readBlob(len, &blob);
+ FUZZ_LOG() << "readBlob status: " << status;
+ },
+ [] (const android::Parcel& p, uint8_t options) {
+ FUZZ_LOG() << "about to readObject";
+ bool nullMetaData = options & 0x1;
+ const void* obj = static_cast<const void*>(p.readObject(nullMetaData));
+ FUZZ_LOG() << "readObject: " << obj;
+ },
+ PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
+ PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
+ PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
+};
diff --git a/libs/binder/fuzzer/binder.h b/libs/binder/fuzzer/binder.h
new file mode 100644
index 0000000..32dcc79
--- /dev/null
+++ b/libs/binder/fuzzer/binder.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Parcel.h>
+#include <vector>
+
+#include "parcel.h"
+
+extern std::vector<ParcelRead<::android::Parcel>> BINDER_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/hwbinder.cpp b/libs/binder/fuzzer/hwbinder.cpp
new file mode 100644
index 0000000..b8cce72
--- /dev/null
+++ b/libs/binder/fuzzer/hwbinder.cpp
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define FUZZ_LOG_TAG "hwbinder"
+
+#include "hwbinder.h"
+#include "util.h"
+
+#include <android-base/logging.h>
+#include <hwbinder/Parcel.h>
+
+using ::android::status_t;
+
+// TODO: support scatter-gather types
+
+std::ostream& operator<<(std::ostream& os, const ::android::sp<::android::hardware::IBinder>& binder) {
+ os << binder.get();
+ return os;
+}
+
+#define PARCEL_READ_NO_STATUS(T, FUN) \
+ [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
+ FUZZ_LOG() << "about to read " #T " using " #FUN " with no status";\
+ T t = p.FUN();\
+ FUZZ_LOG() << #T " value: " << t;\
+ }
+
+#define PARCEL_READ_WITH_STATUS(T, FUN) \
+ [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {\
+ FUZZ_LOG() << "about to read " #T " using " #FUN " with status";\
+ T t;\
+ status_t status = p.FUN(&t);\
+ FUZZ_LOG() << #T " status: " << status << " value: " << t;\
+ }
+
+std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTIONS {
+ PARCEL_READ_NO_STATUS(size_t, dataSize),
+ PARCEL_READ_NO_STATUS(size_t, dataAvail),
+ PARCEL_READ_NO_STATUS(size_t, dataPosition),
+ PARCEL_READ_NO_STATUS(size_t, dataCapacity),
+ [] (const ::android::hardware::Parcel& p, uint8_t pos) {
+ FUZZ_LOG() << "about to setDataPosition: " << pos;
+ p.setDataPosition(pos);
+ FUZZ_LOG() << "setDataPosition done";
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t length) {
+ FUZZ_LOG() << "about to enforceInterface";
+ std::string interfaceName(length, 'a');
+ bool okay = p.enforceInterface(interfaceName.c_str());
+ FUZZ_LOG() << "enforceInterface status: " << okay;
+ },
+ PARCEL_READ_NO_STATUS(size_t, objectsCount),
+ PARCEL_READ_WITH_STATUS(int8_t, readInt8),
+ PARCEL_READ_WITH_STATUS(uint8_t, readUint8),
+ PARCEL_READ_WITH_STATUS(int16_t, readInt16),
+ PARCEL_READ_WITH_STATUS(uint16_t, readUint16),
+ PARCEL_READ_WITH_STATUS(int32_t, readInt32),
+ PARCEL_READ_WITH_STATUS(uint32_t, readUint32),
+ PARCEL_READ_WITH_STATUS(int64_t, readInt64),
+ PARCEL_READ_WITH_STATUS(uint64_t, readUint64),
+ PARCEL_READ_WITH_STATUS(float, readFloat),
+ PARCEL_READ_WITH_STATUS(double, readDouble),
+ PARCEL_READ_WITH_STATUS(bool, readBool),
+ PARCEL_READ_WITH_STATUS(::android::String16, readString16),
+ PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readStrongBinder),
+ PARCEL_READ_WITH_STATUS(::android::sp<::android::hardware::IBinder>, readNullableStrongBinder),
+ [] (const ::android::hardware::Parcel& p, uint8_t amount) {
+ FUZZ_LOG() << "about to readInPlace " << amount;
+ const uint8_t* data = (const uint8_t*)p.readInplace(amount);
+ if (data) {
+ std::vector<uint8_t> vdata(data, data + amount);
+ FUZZ_LOG() << "readInPlace " << amount << " data: " << hexString(vdata);
+ } else {
+ FUZZ_LOG() << "readInPlace " << amount << " no data";
+ }
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t size) {
+ FUZZ_LOG() << "about to readBuffer";
+ size_t handle = 0;
+ const void* data = nullptr;
+ status_t status = p.readBuffer(size, &handle, &data);
+ FUZZ_LOG() << "readBuffer status: " << status << " handle: " << handle << " data: " << data;
+
+ // should be null since we don't create any IPC objects
+ CHECK(data == nullptr) << data;
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t size) {
+ FUZZ_LOG() << "about to readNullableBuffer";
+ size_t handle = 0;
+ const void* data = nullptr;
+ status_t status = p.readNullableBuffer(size, &handle, &data);
+ FUZZ_LOG() << "readNullableBuffer status: " << status << " handle: " << handle << " data: " << data;
+
+ // should be null since we don't create any IPC objects
+ CHECK(data == nullptr) << data;
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t size) {
+ FUZZ_LOG() << "about to readEmbeddedBuffer";
+ size_t handle = 0;
+ size_t parent_buffer_handle = 0;
+ size_t parent_offset = 3;
+ const void* data = nullptr;
+ status_t status = p.readEmbeddedBuffer(size, &handle, parent_buffer_handle, parent_offset, &data);
+ FUZZ_LOG() << "readEmbeddedBuffer status: " << status << " handle: " << handle << " data: " << data;
+
+ // should be null since we don't create any IPC objects
+ CHECK(data == nullptr) << data;
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t size) {
+ FUZZ_LOG() << "about to readNullableEmbeddedBuffer";
+ size_t handle = 0;
+ size_t parent_buffer_handle = 0;
+ size_t parent_offset = 3;
+ const void* data = nullptr;
+ status_t status = p.readNullableEmbeddedBuffer(size, &handle, parent_buffer_handle, parent_offset, &data);
+ FUZZ_LOG() << "readNullableEmbeddedBuffer status: " << status << " handle: " << handle << " data: " << data;
+
+ // should be null since we don't create any IPC objects
+ CHECK(data == nullptr) << data;
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+ FUZZ_LOG() << "about to readNativeHandleNoDup";
+ const native_handle_t* handle = nullptr;
+ status_t status = p.readNativeHandleNoDup(&handle);
+ FUZZ_LOG() << "readNativeHandleNoDup status: " << status << " handle: " << handle;
+
+ // should be null since we don't create any IPC objects
+ CHECK(handle == nullptr) << handle;
+ CHECK(status != ::android::OK);
+ },
+ [] (const ::android::hardware::Parcel& p, uint8_t /*data*/) {
+ FUZZ_LOG() << "about to readNullableNativeHandleNoDup";
+ const native_handle_t* handle = nullptr;
+ status_t status = p.readNullableNativeHandleNoDup(&handle);
+ FUZZ_LOG() << "readNullableNativeHandleNoDup status: " << status << " handle: " << handle;
+
+ // should be null since we don't create any IPC objects
+ CHECK(handle == nullptr) << handle;
+ },
+};
diff --git a/libs/binder/fuzzer/hwbinder.h b/libs/binder/fuzzer/hwbinder.h
new file mode 100644
index 0000000..03ab510
--- /dev/null
+++ b/libs/binder/fuzzer/hwbinder.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <hwbinder/Parcel.h>
+#include <vector>
+
+#include "parcel.h"
+
+extern std::vector<ParcelRead<::android::hardware::Parcel>> HWBINDER_PARCEL_READ_FUNCTIONS;
diff --git a/libs/binder/fuzzer/main.cpp b/libs/binder/fuzzer/main.cpp
new file mode 100644
index 0000000..03fde3a
--- /dev/null
+++ b/libs/binder/fuzzer/main.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define FUZZ_LOG_TAG "main"
+
+#include "binder.h"
+#include "hwbinder.h"
+#include "util.h"
+
+#include <android-base/logging.h>
+
+#include <cstdlib>
+#include <ctime>
+
+template <typename P>
+void doFuzz(
+ const std::vector<ParcelRead<P>>& reads,
+ const std::vector<uint8_t>& input,
+ const std::vector<uint8_t>& instructions) {
+
+ P p;
+ p.setData(input.data(), input.size());
+
+ for (size_t i = 0; i < instructions.size() - 1; i += 2) {
+ uint8_t a = instructions[i];
+ uint8_t b = instructions[i + 1];
+
+ FUZZ_LOG() << "size: " << p.dataSize() << " avail: " << p.dataAvail()
+ << " pos: " << p.dataPosition() << " cap: " << p.dataCapacity();
+
+ reads[a % reads.size()](p, b);
+ }
+}
+
+void fuzz(uint8_t options, const std::vector<uint8_t>& input, const std::vector<uint8_t>& instructions) {
+ (void) options;
+
+ // although they will do completely different things, might as well fuzz both
+ doFuzz<::android::hardware::Parcel>(HWBINDER_PARCEL_READ_FUNCTIONS, input, instructions);
+ doFuzz<::android::Parcel>(BINDER_PARCEL_READ_FUNCTIONS, input, instructions);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ if (size <= 1) return 0; // no use
+ uint8_t options = *data;
+ data++;
+ size--;
+
+ // TODO: generate 'objects' data
+
+ // data to fill out parcel
+ size_t inputLen = size / 2;
+ std::vector<uint8_t> input(data, data + inputLen);
+ data += inputLen;
+ size -= inputLen;
+
+ // data to use to determine what to do
+ size_t instructionLen = size;
+ std::vector<uint8_t> instructions(data, data + instructionLen);
+ data += instructionLen;
+ size -= instructionLen;
+
+ CHECK(size == 0) << "size: " << size;
+
+ FUZZ_LOG() << "options: " << (int)options << " inputLen: " << inputLen << " instructionLen: " << instructionLen;
+ FUZZ_LOG() << "input: " << hexString(input);
+ FUZZ_LOG() << "instructions: " << hexString(instructions);
+
+ fuzz(options, input, instructions);
+ return 0;
+}
diff --git a/libs/binder/fuzzer/parcel.h b/libs/binder/fuzzer/parcel.h
new file mode 100644
index 0000000..5f05335
--- /dev/null
+++ b/libs/binder/fuzzer/parcel.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+template <typename P>
+using ParcelRead = std::function<void(const P& p, uint8_t data)>;
+
+
diff --git a/libs/binder/fuzzer/util.cpp b/libs/binder/fuzzer/util.cpp
new file mode 100644
index 0000000..b1213e9
--- /dev/null
+++ b/libs/binder/fuzzer/util.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define FUZZ_LOG_TAG "util"
+#include "util.h"
+
+#include <android-base/logging.h>
+
+#include <iomanip>
+#include <sstream>
+
+std::string hexString(const void* bytes, size_t len) {
+ if (bytes == nullptr) return "<null>";
+
+ std::ostringstream s;
+ s << std::hex << std::setfill('0');
+ for (size_t i = 0; i < len; i++) {
+ s << std::setw(2) << static_cast<int>(
+ static_cast<const uint8_t*>(bytes)[i]);
+ }
+ return s.str();
+}
+std::string hexString(const std::vector<uint8_t>& bytes) {
+ return hexString(bytes.data(), bytes.size());
+}
diff --git a/libs/binder/fuzzer/util.h b/libs/binder/fuzzer/util.h
new file mode 100644
index 0000000..416c3a7
--- /dev/null
+++ b/libs/binder/fuzzer/util.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#ifndef FUZZ_LOG_TAG
+#error "Must define FUZZ_LOG_TAG"
+#endif
+
+#define ENABLE_LOG_FUZZ 1
+#define FUZZ_LOG() FuzzLog(FUZZ_LOG_TAG, ENABLE_LOG_FUZZ).log()
+
+class FuzzLog {
+public:
+ FuzzLog(const std::string& tag, bool log) : mTag(tag), mLog(log) {}
+ ~FuzzLog() {
+ if (mLog) {
+ std::cout << mTag << ": " << mOs.str() << std::endl;
+ }
+ }
+
+ std::stringstream& log() {
+ return mOs;
+ }
+
+private:
+ std::string mTag;
+ bool mLog;
+ std::stringstream mOs;
+};
+
+std::string hexString(const void* bytes, size_t len);
+std::string hexString(const std::vector<uint8_t>& bytes);
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index b19cde7..0ab40b8 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -17,12 +17,14 @@
#ifndef ANDROID_APP_OPS_MANAGER_H
#define ANDROID_APP_OPS_MANAGER_H
-#ifndef __ANDROID_VNDK__
-
#include <binder/IAppOpsService.h>
#include <utils/threads.h>
+#ifdef __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif
+
// ---------------------------------------------------------------------------
namespace android {
@@ -109,6 +111,18 @@
OP_START_FOREGROUND = 76,
OP_BLUETOOTH_SCAN = 77,
OP_USE_BIOMETRIC = 78,
+ OP_ACTIVITY_RECOGNITION = 79,
+ OP_SMS_FINANCIAL_TRANSACTIONS = 80,
+ OP_READ_MEDIA_AUDIO = 81,
+ OP_WRITE_MEDIA_AUDIO = 82,
+ OP_READ_MEDIA_VIDEO = 83,
+ OP_WRITE_MEDIA_VIDEO = 84,
+ OP_READ_MEDIA_IMAGES = 85,
+ OP_WRITE_MEDIA_IMAGES = 86,
+ OP_LEGACY_STORAGE = 87,
+ OP_ACCESS_ACCESSIBILITY = 88,
+ OP_READ_DEVICE_IDENTIFIERS = 89,
+ _NUM_OP = 90
};
AppOpsManager();
@@ -116,27 +130,38 @@
int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
const String16& callingPackage);
+ // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead
int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
+ int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+ const String16& message);
+ // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&)
+ // instead
int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
bool startIfModeDefault);
+ int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+ bool startIfModeDefault, const String16& message);
void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
int32_t permissionToOpCode(const String16& permission);
+ void setCameraAudioRestriction(int32_t mode);
+ void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName,
+ int32_t opCode, const String16& message);
private:
Mutex mLock;
sp<IAppOpsService> mService;
sp<IAppOpsService> getService();
+ void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+ const String16& message);
+ bool shouldCollectNotes(int32_t opCode);
};
} // namespace android
+
// ---------------------------------------------------------------------------
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
#endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index b74c623..8b8a3c2 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -18,11 +18,13 @@
#ifndef ANDROID_IAPP_OPS_SERVICE_H
#define ANDROID_IAPP_OPS_SERVICE_H
-#ifndef __ANDROID_VNDK__
-
#include <binder/IAppOpsCallback.h>
#include <binder/IInterface.h>
+#ifdef __ANDROID_VNDK__
+#error "This header is not visible to vendors"
+#endif
+
namespace android {
// ----------------------------------------------------------------------
@@ -45,6 +47,10 @@
virtual int32_t permissionToOpCode(const String16& permission) = 0;
virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
const String16& packageName) = 0;
+ virtual void setCameraAudioRestriction(int32_t mode) = 0;
+ virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+ const String16& packageName, int32_t opCode, const String16& message) = 0;
+ virtual bool shouldCollectNotes(int32_t opCode) = 0;
enum {
CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -56,6 +62,9 @@
GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
+ NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
+ SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
+ SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+11,
};
enum {
@@ -81,8 +90,4 @@
} // namespace android
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
-
#endif // ANDROID_IAPP_OPS_SERVICE_H
diff --git a/libs/binder/include/binder/IMemory.h b/libs/binder/include/binder/IMemory.h
index 3728029..1a36eb0 100644
--- a/libs/binder/include/binder/IMemory.h
+++ b/libs/binder/include/binder/IMemory.h
@@ -77,10 +77,33 @@
virtual sp<IMemoryHeap> getMemory(ssize_t* offset=nullptr, size_t* size=nullptr) const = 0;
// helpers
- void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
- void* pointer() const;
+
+ // Accessing the underlying pointer must be done with caution, as there are
+ // some inherent security risks associated with it. When receiving an
+ // IMemory from an untrusted process, there is currently no way to guarantee
+ // that this process would't change the content after the fact. This may
+ // lead to TOC/TOU class of security bugs. In most cases, when performance
+ // is not an issue, the recommended practice is to immediately copy the
+ // buffer upon reception, then work with the copy, e.g.:
+ //
+ // std::string private_copy(mem.size(), '\0');
+ // memcpy(private_copy.data(), mem.unsecurePointer(), mem.size());
+ //
+ // In cases where performance is an issue, this matter must be addressed on
+ // an ad-hoc basis.
+ void* unsecurePointer() const;
+
size_t size() const;
ssize_t offset() const;
+
+private:
+ // These are now deprecated and are left here for backward-compatibility
+ // with prebuilts that may reference these symbol at runtime.
+ // Instead, new code should use unsecurePointer()/unsecureFastPointer(),
+ // which do the same thing, but make it more obvious that there are some
+ // security-related pitfalls associated with them.
+ void* pointer() const;
+ void* fastPointer(const sp<IBinder>& heap, ssize_t offset) const;
};
class BnMemory : public BnInterface<IMemory>
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 5e0574a..db4a36b 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -73,6 +73,7 @@
BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
BINDER_LIB_TEST_ECHO_VECTOR,
+ BINDER_LIB_TEST_REJECT_BUF,
};
pid_t start_server_process(int arg2, bool usePoll = false)
@@ -1025,6 +1026,34 @@
EXPECT_EQ(readValue, testValue);
}
+TEST_F(BinderLibTest, BufRejected) {
+ Parcel data, reply;
+ uint32_t buf;
+ sp<IBinder> server = addServer();
+ ASSERT_TRUE(server != nullptr);
+
+ binder_buffer_object obj {
+ .hdr = { .type = BINDER_TYPE_PTR },
+ .buffer = reinterpret_cast<binder_uintptr_t>((void*)&buf),
+ .length = 4,
+ .flags = 0,
+ };
+ data.setDataCapacity(1024);
+ // Write a bogus object at offset 0 to get an entry in the offset table
+ data.writeFileDescriptor(0);
+ EXPECT_EQ(data.objectsCount(), 1);
+ uint8_t *parcelData = const_cast<uint8_t*>(data.data());
+ // And now, overwrite it with the buffer object
+ memcpy(parcelData, &obj, sizeof(obj));
+ data.setDataSize(sizeof(obj));
+
+ status_t ret = server->transact(BINDER_LIB_TEST_REJECT_BUF, data, &reply);
+ // Either the kernel should reject this transaction (if it's correct), but
+ // if it's not, the server implementation should return an error if it
+ // finds an object in the received Parcel.
+ EXPECT_NE(NO_ERROR, ret);
+}
+
class BinderLibTestService : public BBinder
{
public:
@@ -1307,6 +1336,9 @@
reply->writeUint64Vector(vector);
return NO_ERROR;
}
+ case BINDER_LIB_TEST_REJECT_BUF: {
+ return data.objectsCount() == 0 ? BAD_VALUE : NO_ERROR;
+ }
default:
return UNKNOWN_TRANSACTION;
};
@@ -1338,6 +1370,9 @@
*/
testService->setExtension(new BBinder());
+ // Required for test "BufRejected'
+ testService->setRequestingSid(true);
+
/*
* We need this below, but can't hold a sp<> because it prevents the
* node from being cleaned up automatically. It's safe in this case
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index 28cb138..9080ce1 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -19,7 +19,11 @@
name: "libtimeinstate_test",
srcs: ["testtimeinstate.cpp"],
shared_libs: [
+ "libbase",
+ "libbpf",
+ "libbpf_android",
"libtimeinstate",
+ "libnetdutils",
],
cflags: [
"-Werror",
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 5fd4a95..f255512 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -17,12 +17,16 @@
#define LOG_TAG "libtimeinstate"
#include "cputimeinstate.h"
+#include "timeinstate.h"
#include <dirent.h>
#include <errno.h>
#include <inttypes.h>
+#include <sys/sysinfo.h>
#include <mutex>
+#include <numeric>
+#include <optional>
#include <set>
#include <string>
#include <unordered_map>
@@ -37,44 +41,36 @@
#include <libbpf.h>
#include <log/log.h>
-#define BPF_FS_PATH "/sys/fs/bpf/"
-
using android::base::StringPrintf;
using android::base::unique_fd;
namespace android {
namespace bpf {
-struct time_key_t {
- uint32_t uid;
- uint32_t freq;
-};
-
-struct val_t {
- uint64_t ar[100];
-};
-
static std::mutex gInitializedMutex;
static bool gInitialized = false;
static uint32_t gNPolicies = 0;
+static uint32_t gNCpus = 0;
static std::vector<std::vector<uint32_t>> gPolicyFreqs;
static std::vector<std::vector<uint32_t>> gPolicyCpus;
static std::set<uint32_t> gAllFreqs;
-static unique_fd gMapFd;
+static unique_fd gTisMapFd;
+static unique_fd gConcurrentMapFd;
-static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
+static std::optional<std::vector<uint32_t>> readNumbersFromFile(const std::string &path) {
std::string data;
- if (!android::base::ReadFileToString(path, &data)) return false;
+ if (!android::base::ReadFileToString(path, &data)) return {};
auto strings = android::base::Split(data, " \n");
+ std::vector<uint32_t> ret;
for (const auto &s : strings) {
if (s.empty()) continue;
uint32_t n;
- if (!android::base::ParseUint(s, &n)) return false;
- out->emplace_back(n);
+ if (!android::base::ParseUint(s, &n)) return {};
+ ret.emplace_back(n);
}
- return true;
+ return ret;
}
static int isPolicyFile(const struct dirent *d) {
@@ -93,6 +89,8 @@
std::lock_guard<std::mutex> guard(gInitializedMutex);
if (gInitialized) return true;
+ gNCpus = get_nprocs_conf();
+
struct dirent **dirlist;
const char basepath[] = "/sys/devices/system/cpu/cpufreq";
int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
@@ -111,21 +109,27 @@
for (const auto &name : {"available", "boost"}) {
std::string path =
StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
- if (!readNumbersFromFile(path, &freqs)) return false;
+ auto nums = readNumbersFromFile(path);
+ if (!nums) return false;
+ freqs.insert(freqs.end(), nums->begin(), nums->end());
}
std::sort(freqs.begin(), freqs.end());
gPolicyFreqs.emplace_back(freqs);
for (auto freq : freqs) gAllFreqs.insert(freq);
- std::vector<uint32_t> cpus;
std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
- if (!readNumbersFromFile(path, &cpus)) return false;
- gPolicyCpus.emplace_back(cpus);
+ auto cpus = readNumbersFromFile(path);
+ if (!cpus) return false;
+ gPolicyCpus.emplace_back(*cpus);
}
- gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
- if (gMapFd < 0) return false;
+ gTisMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+ if (gTisMapFd < 0) return false;
+
+ gConcurrentMapFd =
+ unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+ if (gConcurrentMapFd < 0) return false;
gInitialized = true;
return true;
@@ -145,97 +149,259 @@
// process dies then it must be called again to resume tracking.
// This function should *not* be called while tracking is already active; doing so is unnecessary
// and can lead to accounting errors.
-bool startTrackingUidCpuFreqTimes() {
+bool startTrackingUidTimes() {
+ if (!initGlobals()) return false;
+
+ unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+ if (fd < 0) return false;
+
+ for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
+ for (auto &cpu : gPolicyCpus[i]) {
+ if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+ }
+ }
+
+ unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+ if (fd2 < 0) return false;
+ freq_idx_key_t key;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ key.policy = i;
+ for (uint32_t j = 0; j < gPolicyFreqs[i].size(); ++j) {
+ key.freq = gPolicyFreqs[i][j];
+ // Start indexes at 1 so that uninitialized state is distinguishable from lowest freq.
+ // The uid_times map still uses 0-based indexes, and the sched_switch program handles
+ // conversion between them, so this does not affect our map reading code.
+ uint32_t idx = j + 1;
+ if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+ }
+ }
+
return attachTracepointProgram("sched", "sched_switch") &&
attachTracepointProgram("power", "cpu_frequency");
}
-// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
-// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
-// using the format:
+// Retrieve the times in ns that uid spent running at each CPU frequency.
+// Return contains no value on error, otherwise it contains a vector of vectors using the format:
// [[t0_0, t0_1, ...],
// [t1_0, t1_1, ...], ...]
// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
-bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
- if (!gInitialized && !initGlobals()) return false;
- time_key_t key = {.uid = uid, .freq = 0};
+std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid) {
+ if (!gInitialized && !initGlobals()) return {};
- freqTimes->clear();
- freqTimes->resize(gNPolicies);
- std::vector<uint32_t> idxs(gNPolicies, 0);
+ std::vector<std::vector<uint64_t>> out;
+ uint32_t maxFreqCount = 0;
+ for (const auto &freqList : gPolicyFreqs) {
+ if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+ out.emplace_back(freqList.size(), 0);
+ }
- val_t value;
- for (uint32_t freq : gAllFreqs) {
- key.freq = freq;
- int ret = findMapEntry(gMapFd, &key, &value);
- if (ret) {
- if (errno == ENOENT)
- memset(&value.ar, 0, sizeof(value.ar));
- else
- return false;
+ std::vector<tis_val_t> vals(gNCpus);
+ time_key_t key = {.uid = uid};
+ for (uint32_t i = 0; i <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++i) {
+ key.bucket = i;
+ if (findMapEntry(gTisMapFd, &key, vals.data())) {
+ if (errno != ENOENT) return {};
+ continue;
}
- for (uint32_t i = 0; i < gNPolicies; ++i) {
- if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
- uint64_t time = 0;
- for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
- idxs[i] += 1;
- (*freqTimes)[i].emplace_back(time);
+
+ auto offset = i * FREQS_PER_ENTRY;
+ auto nextOffset = (i + 1) * FREQS_PER_ENTRY;
+ for (uint32_t j = 0; j < gNPolicies; ++j) {
+ if (offset >= gPolicyFreqs[j].size()) continue;
+ auto begin = out[j].begin() + offset;
+ auto end = nextOffset < gPolicyFreqs[j].size() ? begin + FREQS_PER_ENTRY : out[j].end();
+
+ for (const auto &cpu : gPolicyCpus[j]) {
+ std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
+ }
}
}
- return true;
+ return out;
}
-// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
-// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
-// vectors of vectors using the format:
+// Retrieve the times in ns that each uid spent running at each CPU freq.
+// Return contains no value on error, otherwise it contains a map from uids to vectors of vectors
+// using the format:
// { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
// uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
-bool getUidsCpuFreqTimes(
- std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
- if (!gInitialized && !initGlobals()) return false;
-
- int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
- if (fd < 0) return false;
- BpfMap<time_key_t, val_t> m(fd);
-
- std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
- for (uint32_t i = 0; i < gNPolicies; ++i) {
- std::unordered_map<uint32_t, uint32_t> freqIdxs;
- for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
- policyFreqIdxs.emplace_back(freqIdxs);
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+getUidsCpuFreqTimes() {
+ if (!gInitialized && !initGlobals()) return {};
+ time_key_t key, prevKey;
+ std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> map;
+ if (getFirstMapKey(gTisMapFd, &key)) {
+ if (errno == ENOENT) return map;
+ return std::nullopt;
}
- auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
- const BpfMap<time_key_t, val_t> &) {
- if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
- (*freqTimeMap)[key.uid].resize(gNPolicies);
- for (uint32_t i = 0; i < gNPolicies; ++i) {
- (*freqTimeMap)[key.uid][i].resize(gPolicyFreqs[i].size(), 0);
+ std::vector<std::vector<uint64_t>> mapFormat;
+ for (const auto &freqList : gPolicyFreqs) mapFormat.emplace_back(freqList.size(), 0);
+
+ std::vector<tis_val_t> vals(gNCpus);
+ do {
+ if (findMapEntry(gTisMapFd, &key, vals.data())) return {};
+ if (map.find(key.uid) == map.end()) map.emplace(key.uid, mapFormat);
+
+ auto offset = key.bucket * FREQS_PER_ENTRY;
+ auto nextOffset = (key.bucket + 1) * FREQS_PER_ENTRY;
+ for (uint32_t i = 0; i < gNPolicies; ++i) {
+ if (offset >= gPolicyFreqs[i].size()) continue;
+ auto begin = map[key.uid][i].begin() + offset;
+ auto end = nextOffset < gPolicyFreqs[i].size() ? begin + FREQS_PER_ENTRY :
+ map[key.uid][i].end();
+ for (const auto &cpu : gPolicyCpus[i]) {
+ std::transform(begin, end, std::begin(vals[cpu].ar), begin, std::plus<uint64_t>());
}
}
+ prevKey = key;
+ } while (!getNextMapKey(gTisMapFd, &prevKey, &key));
+ if (errno != ENOENT) return {};
+ return map;
+}
+
+static bool verifyConcurrentTimes(const concurrent_time_t &ct) {
+ uint64_t activeSum = std::accumulate(ct.active.begin(), ct.active.end(), (uint64_t)0);
+ uint64_t policySum = 0;
+ for (const auto &vec : ct.policy) {
+ policySum += std::accumulate(vec.begin(), vec.end(), (uint64_t)0);
+ }
+ return activeSum == policySum;
+}
+
+// Retrieve the times in ns that uid spent running concurrently with each possible number of other
+// tasks on each cluster (policy times) and overall (active times).
+// Return contains no value on error, otherwise it contains a concurrent_time_t with the format:
+// {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...]}
+// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
+// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster
+std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry) {
+ if (!gInitialized && !initGlobals()) return {};
+ concurrent_time_t ret = {.active = std::vector<uint64_t>(gNCpus, 0)};
+ for (const auto &cpuList : gPolicyCpus) ret.policy.emplace_back(cpuList.size(), 0);
+ std::vector<concurrent_val_t> vals(gNCpus);
+ time_key_t key = {.uid = uid};
+ for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+ if (findMapEntry(gConcurrentMapFd, &key, vals.data())) {
+ if (errno != ENOENT) return {};
+ continue;
+ }
+ auto offset = key.bucket * CPUS_PER_ENTRY;
+ auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY;
+
+ auto activeBegin = ret.active.begin() + offset;
+ auto activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret.active.end();
+
+ for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) {
+ std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin,
+ std::plus<uint64_t>());
+ }
- for (size_t policy = 0; policy < gNPolicies; ++policy) {
+ for (uint32_t policy = 0; policy < gNPolicies; ++policy) {
+ if (offset >= gPolicyCpus[policy].size()) continue;
+ auto policyBegin = ret.policy[policy].begin() + offset;
+ auto policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY
+ : ret.policy[policy].end();
+
for (const auto &cpu : gPolicyCpus[policy]) {
- auto freqIdx = policyFreqIdxs[policy][key.freq];
- (*freqTimeMap)[key.uid][policy][freqIdx] += val.ar[cpu];
+ std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin,
+ std::plus<uint64_t>());
}
}
- return android::netdutils::status::ok;
- };
- return isOk(m.iterateWithValue(fn));
+ }
+ if (!verifyConcurrentTimes(ret) && retry) return getUidConcurrentTimes(uid, false);
+ return ret;
+}
+
+// Retrieve the times in ns that each uid spent running concurrently with each possible number of
+// other tasks on each cluster (policy times) and overall (active times).
+// Return contains no value on error, otherwise it contains a map from uids to concurrent_time_t's
+// using the format:
+// { uid0 -> {.active = [a0, a1, ...], .policy = [[p0_0, p0_1, ...], [p1_0, p1_1, ...], ...] }, ...}
+// where ai is the ns spent running concurrently with tasks on i other cpus and pi_j is the ns spent
+// running on the ith cluster, concurrently with tasks on j other cpus in the same cluster.
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes() {
+ if (!gInitialized && !initGlobals()) return {};
+ time_key_t key, prevKey;
+ std::unordered_map<uint32_t, concurrent_time_t> ret;
+ if (getFirstMapKey(gConcurrentMapFd, &key)) {
+ if (errno == ENOENT) return ret;
+ return {};
+ }
+
+ concurrent_time_t retFormat = {.active = std::vector<uint64_t>(gNCpus, 0)};
+ for (const auto &cpuList : gPolicyCpus) retFormat.policy.emplace_back(cpuList.size(), 0);
+
+ std::vector<concurrent_val_t> vals(gNCpus);
+ std::vector<uint64_t>::iterator activeBegin, activeEnd, policyBegin, policyEnd;
+
+ do {
+ if (findMapEntry(gConcurrentMapFd, &key, vals.data())) return {};
+ if (ret.find(key.uid) == ret.end()) ret.emplace(key.uid, retFormat);
+
+ auto offset = key.bucket * CPUS_PER_ENTRY;
+ auto nextOffset = (key.bucket + 1) * CPUS_PER_ENTRY;
+
+ activeBegin = ret[key.uid].active.begin();
+ activeEnd = nextOffset < gNCpus ? activeBegin + CPUS_PER_ENTRY : ret[key.uid].active.end();
+
+ for (uint32_t cpu = 0; cpu < gNCpus; ++cpu) {
+ std::transform(activeBegin, activeEnd, std::begin(vals[cpu].active), activeBegin,
+ std::plus<uint64_t>());
+ }
+
+ for (uint32_t policy = 0; policy < gNPolicies; ++policy) {
+ if (offset >= gPolicyCpus[policy].size()) continue;
+ policyBegin = ret[key.uid].policy[policy].begin() + offset;
+ policyEnd = nextOffset < gPolicyCpus[policy].size() ? policyBegin + CPUS_PER_ENTRY
+ : ret[key.uid].policy[policy].end();
+
+ for (const auto &cpu : gPolicyCpus[policy]) {
+ std::transform(policyBegin, policyEnd, std::begin(vals[cpu].policy), policyBegin,
+ std::plus<uint64_t>());
+ }
+ }
+ prevKey = key;
+ } while (!getNextMapKey(gConcurrentMapFd, &prevKey, &key));
+ if (errno != ENOENT) return {};
+ for (const auto &[key, value] : ret) {
+ if (!verifyConcurrentTimes(value)) {
+ auto val = getUidConcurrentTimes(key, false);
+ if (val.has_value()) ret[key] = val.value();
+ }
+ }
+ return ret;
}
// Clear all time in state data for a given uid. Returns false on error, true otherwise.
-bool clearUidCpuFreqTimes(uint32_t uid) {
+// This is only suitable for clearing data when an app is uninstalled; if called on a UID with
+// running tasks it will cause time in state vs. concurrent time totals to be inconsistent for that
+// UID.
+bool clearUidTimes(uint32_t uid) {
if (!gInitialized && !initGlobals()) return false;
- time_key_t key = {.uid = uid, .freq = 0};
- std::vector<uint32_t> idxs(gNPolicies, 0);
- for (auto freq : gAllFreqs) {
- key.freq = freq;
- if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
+ time_key_t key = {.uid = uid};
+
+ uint32_t maxFreqCount = 0;
+ for (const auto &freqList : gPolicyFreqs) {
+ if (freqList.size() > maxFreqCount) maxFreqCount = freqList.size();
+ }
+
+ tis_val_t zeros = {0};
+ std::vector<tis_val_t> vals(gNCpus, zeros);
+ for (key.bucket = 0; key.bucket <= (maxFreqCount - 1) / FREQS_PER_ENTRY; ++key.bucket) {
+ if (writeToMapEntry(gTisMapFd, &key, vals.data(), BPF_EXIST) && errno != ENOENT)
+ return false;
+ if (deleteMapEntry(gTisMapFd, &key) && errno != ENOENT) return false;
+ }
+
+ concurrent_val_t czeros = {.policy = {0}, .active = {0}};
+ std::vector<concurrent_val_t> cvals(gNCpus, czeros);
+ for (key.bucket = 0; key.bucket <= (gNCpus - 1) / CPUS_PER_ENTRY; ++key.bucket) {
+ if (writeToMapEntry(gConcurrentMapFd, &key, cvals.data(), BPF_EXIST) && errno != ENOENT)
+ return false;
+ if (deleteMapEntry(gConcurrentMapFd, &key) && errno != ENOENT) return false;
}
return true;
}
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index 9f6103e..f620715 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -22,10 +22,19 @@
namespace android {
namespace bpf {
-bool startTrackingUidCpuFreqTimes();
-bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
-bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
-bool clearUidCpuFreqTimes(unsigned int uid);
+bool startTrackingUidTimes();
+std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
+std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
+ getUidsCpuFreqTimes();
+
+struct concurrent_time_t {
+ std::vector<uint64_t> active;
+ std::vector<std::vector<uint64_t>> policy;
+};
+
+std::optional<concurrent_time_t> getUidConcurrentTimes(uint32_t uid, bool retry = true);
+std::optional<std::unordered_map<uint32_t, concurrent_time_t>> getUidsConcurrentTimes();
+bool clearUidTimes(unsigned int uid);
} // namespace bpf
} // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index 9837865..15f6214 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,57 +1,354 @@
+#include "timeinstate.h"
+
+#include <sys/sysinfo.h>
+
+#include <numeric>
#include <unordered_map>
#include <vector>
#include <gtest/gtest.h>
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
#include <cputimeinstate.h>
+#include <libbpf.h>
namespace android {
namespace bpf {
+static constexpr uint64_t NSEC_PER_SEC = 1000000000;
+static constexpr uint64_t NSEC_PER_YEAR = NSEC_PER_SEC * 60 * 60 * 24 * 365;
+
using std::vector;
-TEST(TimeInStateTest, SingleUid) {
- vector<vector<uint64_t>> times;
- ASSERT_TRUE(getUidCpuFreqTimes(0, ×));
- EXPECT_FALSE(times.empty());
+TEST(TimeInStateTest, SingleUidTimeInState) {
+ auto times = getUidCpuFreqTimes(0);
+ ASSERT_TRUE(times.has_value());
+ EXPECT_FALSE(times->empty());
}
-TEST(TimeInStateTest, AllUid) {
+TEST(TimeInStateTest, SingleUidConcurrentTimes) {
+ auto concurrentTimes = getUidConcurrentTimes(0);
+ ASSERT_TRUE(concurrentTimes.has_value());
+ ASSERT_FALSE(concurrentTimes->active.empty());
+ ASSERT_FALSE(concurrentTimes->policy.empty());
+
+ uint64_t policyEntries = 0;
+ for (const auto &policyTimeVec : concurrentTimes->policy) policyEntries += policyTimeVec.size();
+ ASSERT_EQ(concurrentTimes->active.size(), policyEntries);
+}
+
+static void TestConcurrentTimesConsistent(const struct concurrent_time_t &concurrentTime) {
+ size_t maxPolicyCpus = 0;
+ for (const auto &vec : concurrentTime.policy) {
+ maxPolicyCpus = std::max(maxPolicyCpus, vec.size());
+ }
+ uint64_t policySum = 0;
+ for (size_t i = 0; i < maxPolicyCpus; ++i) {
+ for (const auto &vec : concurrentTime.policy) {
+ if (i < vec.size()) policySum += vec[i];
+ }
+ ASSERT_LE(concurrentTime.active[i], policySum);
+ policySum -= concurrentTime.active[i];
+ }
+ policySum = 0;
+ for (size_t i = 0; i < concurrentTime.active.size(); ++i) {
+ for (const auto &vec : concurrentTime.policy) {
+ if (i < vec.size()) policySum += vec[vec.size() - 1 - i];
+ }
+ auto activeSum = concurrentTime.active[concurrentTime.active.size() - 1 - i];
+ // This check is slightly flaky because we may read a map entry in the middle of an update
+ // when active times have been updated but policy times have not. This happens infrequently
+ // and can be distinguished from more serious bugs by re-running the test: if the underlying
+ // data itself is inconsistent, the test will fail every time.
+ ASSERT_LE(activeSum, policySum);
+ policySum -= activeSum;
+ }
+}
+
+static void TestUidTimesConsistent(const std::vector<std::vector<uint64_t>> &timeInState,
+ const struct concurrent_time_t &concurrentTime) {
+ ASSERT_NO_FATAL_FAILURE(TestConcurrentTimesConsistent(concurrentTime));
+ ASSERT_EQ(timeInState.size(), concurrentTime.policy.size());
+ uint64_t policySum = 0;
+ for (uint32_t i = 0; i < timeInState.size(); ++i) {
+ uint64_t tisSum =
+ std::accumulate(timeInState[i].begin(), timeInState[i].end(), (uint64_t)0);
+ uint64_t concurrentSum = std::accumulate(concurrentTime.policy[i].begin(),
+ concurrentTime.policy[i].end(), (uint64_t)0);
+ if (tisSum < concurrentSum)
+ ASSERT_LE(concurrentSum - tisSum, NSEC_PER_SEC);
+ else
+ ASSERT_LE(tisSum - concurrentSum, NSEC_PER_SEC);
+ policySum += concurrentSum;
+ }
+ uint64_t activeSum = std::accumulate(concurrentTime.active.begin(), concurrentTime.active.end(),
+ (uint64_t)0);
+ EXPECT_EQ(activeSum, policySum);
+}
+
+TEST(TimeInStateTest, SingleUidTimesConsistent) {
+ auto times = getUidCpuFreqTimes(0);
+ ASSERT_TRUE(times.has_value());
+
+ auto concurrentTimes = getUidConcurrentTimes(0);
+ ASSERT_TRUE(concurrentTimes.has_value());
+
+ ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(*times, *concurrentTimes));
+}
+
+TEST(TimeInStateTest, AllUidTimeInState) {
vector<size_t> sizes;
- std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
- ASSERT_TRUE(getUidsCpuFreqTimes(&map));
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
- ASSERT_FALSE(map.empty());
+ ASSERT_FALSE(map->empty());
- auto firstEntry = map.begin()->second;
+ auto firstEntry = map->begin()->second;
for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
- for (const auto &vec : map) {
+ for (const auto &vec : *map) {
ASSERT_EQ(vec.second.size(), sizes.size());
for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
}
}
+TEST(TimeInStateTest, SingleAndAllUidTimeInStateConsistent) {
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
+
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidCpuFreqTimes(uid);
+ ASSERT_TRUE(times2.has_value());
+
+ ASSERT_EQ(times1.size(), times2->size());
+ for (uint32_t i = 0; i < times1.size(); ++i) {
+ ASSERT_EQ(times1[i].size(), (*times2)[i].size());
+ for (uint32_t j = 0; j < times1[i].size(); ++j) {
+ ASSERT_LE((*times2)[i][j] - times1[i][j], NSEC_PER_SEC);
+ }
+ }
+ }
+}
+
+TEST(TimeInStateTest, AllUidConcurrentTimes) {
+ auto map = getUidsConcurrentTimes();
+ ASSERT_TRUE(map.has_value());
+ ASSERT_FALSE(map->empty());
+
+ auto firstEntry = map->begin()->second;
+ for (const auto &kv : *map) {
+ ASSERT_EQ(kv.second.active.size(), firstEntry.active.size());
+ ASSERT_EQ(kv.second.policy.size(), firstEntry.policy.size());
+ for (size_t i = 0; i < kv.second.policy.size(); ++i) {
+ ASSERT_EQ(kv.second.policy[i].size(), firstEntry.policy[i].size());
+ }
+ }
+}
+
+TEST(TimeInStateTest, SingleAndAllUidConcurrentTimesConsistent) {
+ auto map = getUidsConcurrentTimes();
+ ASSERT_TRUE(map.has_value());
+ for (const auto &kv : *map) {
+ uint32_t uid = kv.first;
+ auto times1 = kv.second;
+ auto times2 = getUidConcurrentTimes(uid);
+ ASSERT_TRUE(times2.has_value());
+ for (uint32_t i = 0; i < times1.active.size(); ++i) {
+ ASSERT_LE(times2->active[i] - times1.active[i], NSEC_PER_SEC);
+ }
+ for (uint32_t i = 0; i < times1.policy.size(); ++i) {
+ for (uint32_t j = 0; j < times1.policy[i].size(); ++j) {
+ ASSERT_LE(times2->policy[i][j] - times1.policy[i][j], NSEC_PER_SEC);
+ }
+ }
+ }
+}
+
+void TestCheckDelta(uint64_t before, uint64_t after) {
+ // Times should never decrease
+ ASSERT_LE(before, after);
+ // UID can't have run for more than ~1s on each CPU
+ ASSERT_LE(after - before, NSEC_PER_SEC * 2 * get_nprocs_conf());
+}
+
+TEST(TimeInStateTest, AllUidTimeInStateMonotonic) {
+ auto map1 = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map1.has_value());
+ sleep(1);
+ auto map2 = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map2.has_value());
+
+ for (const auto &kv : *map1) {
+ uint32_t uid = kv.first;
+ auto times = kv.second;
+ ASSERT_NE(map2->find(uid), map2->end());
+ for (uint32_t policy = 0; policy < times.size(); ++policy) {
+ for (uint32_t freqIdx = 0; freqIdx < times[policy].size(); ++freqIdx) {
+ auto before = times[policy][freqIdx];
+ auto after = (*map2)[uid][policy][freqIdx];
+ ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+ }
+ }
+ }
+}
+
+TEST(TimeInStateTest, AllUidConcurrentTimesMonotonic) {
+ auto map1 = getUidsConcurrentTimes();
+ ASSERT_TRUE(map1.has_value());
+ ASSERT_FALSE(map1->empty());
+ sleep(1);
+ auto map2 = getUidsConcurrentTimes();
+ ASSERT_TRUE(map2.has_value());
+ ASSERT_FALSE(map2->empty());
+
+ for (const auto &kv : *map1) {
+ uint32_t uid = kv.first;
+ auto times = kv.second;
+ ASSERT_NE(map2->find(uid), map2->end());
+ for (uint32_t i = 0; i < times.active.size(); ++i) {
+ auto before = times.active[i];
+ auto after = (*map2)[uid].active[i];
+ ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+ }
+ for (uint32_t policy = 0; policy < times.policy.size(); ++policy) {
+ for (uint32_t idx = 0; idx < times.policy[policy].size(); ++idx) {
+ auto before = times.policy[policy][idx];
+ auto after = (*map2)[uid].policy[policy][idx];
+ ASSERT_NO_FATAL_FAILURE(TestCheckDelta(before, after));
+ }
+ }
+ }
+}
+
+TEST(TimeInStateTest, AllUidTimeInStateSanityCheck) {
+ auto map = getUidsCpuFreqTimes();
+ ASSERT_TRUE(map.has_value());
+
+ bool foundLargeValue = false;
+ for (const auto &kv : *map) {
+ for (const auto &timeVec : kv.second) {
+ for (const auto &time : timeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) foundLargeValue = true;
+ }
+ }
+ }
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(foundLargeValue);
+}
+
+TEST(TimeInStateTest, AllUidConcurrentTimesSanityCheck) {
+ auto concurrentMap = getUidsConcurrentTimes();
+ ASSERT_TRUE(concurrentMap);
+
+ bool activeFoundLargeValue = false;
+ bool policyFoundLargeValue = false;
+ for (const auto &kv : *concurrentMap) {
+ for (const auto &time : kv.second.active) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) activeFoundLargeValue = true;
+ }
+ for (const auto &policyTimeVec : kv.second.policy) {
+ for (const auto &time : policyTimeVec) {
+ ASSERT_LE(time, NSEC_PER_YEAR);
+ if (time > UINT32_MAX) policyFoundLargeValue = true;
+ }
+ }
+ }
+ // UINT32_MAX nanoseconds is less than 5 seconds, so if every part of our pipeline is using
+ // uint64_t as expected, we should have some times higher than that.
+ ASSERT_TRUE(activeFoundLargeValue);
+ ASSERT_TRUE(policyFoundLargeValue);
+}
+
+TEST(TimeInStateTest, AllUidTimesConsistent) {
+ auto tisMap = getUidsCpuFreqTimes();
+ ASSERT_TRUE(tisMap.has_value());
+
+ auto concurrentMap = getUidsConcurrentTimes();
+ ASSERT_TRUE(concurrentMap.has_value());
+
+ ASSERT_EQ(tisMap->size(), concurrentMap->size());
+ for (const auto &kv : *tisMap) {
+ uint32_t uid = kv.first;
+ auto times = kv.second;
+ ASSERT_NE(concurrentMap->find(uid), concurrentMap->end());
+
+ auto concurrentTimes = (*concurrentMap)[uid];
+ ASSERT_NO_FATAL_FAILURE(TestUidTimesConsistent(times, concurrentTimes));
+ }
+}
+
TEST(TimeInStateTest, RemoveUid) {
- vector<vector<uint64_t>> times, times2;
- ASSERT_TRUE(getUidCpuFreqTimes(0, ×));
- ASSERT_FALSE(times.empty());
+ uint32_t uid = 0;
+ {
+ // Find an unused UID
+ auto times = getUidsCpuFreqTimes();
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+ for (const auto &kv : *times) uid = std::max(uid, kv.first);
+ ++uid;
+ }
+ {
+ // Add a map entry for our fake UID by copying a real map entry
+ android::base::unique_fd fd{
+ bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_time_in_state_map")};
+ ASSERT_GE(fd, 0);
+ time_key_t k;
+ ASSERT_FALSE(getFirstMapKey(fd, &k));
+ std::vector<tis_val_t> vals(get_nprocs_conf());
+ ASSERT_FALSE(findMapEntry(fd, &k, vals.data()));
+ uint32_t copiedUid = k.uid;
+ k.uid = uid;
+ ASSERT_FALSE(writeToMapEntry(fd, &k, vals.data(), BPF_NOEXIST));
+
+ android::base::unique_fd fd2{
+ bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_concurrent_times_map")};
+ k.uid = copiedUid;
+ k.bucket = 0;
+ std::vector<concurrent_val_t> cvals(get_nprocs_conf());
+ ASSERT_FALSE(findMapEntry(fd2, &k, cvals.data()));
+ k.uid = uid;
+ ASSERT_FALSE(writeToMapEntry(fd2, &k, cvals.data(), BPF_NOEXIST));
+ }
+ auto times = getUidCpuFreqTimes(uid);
+ ASSERT_TRUE(times.has_value());
+ ASSERT_FALSE(times->empty());
+
+ auto concurrentTimes = getUidConcurrentTimes(0);
+ ASSERT_TRUE(concurrentTimes.has_value());
+ ASSERT_FALSE(concurrentTimes->active.empty());
+ ASSERT_FALSE(concurrentTimes->policy.empty());
uint64_t sum = 0;
- for (size_t i = 0; i < times.size(); ++i) {
- for (auto x : times[i]) sum += x;
+ for (size_t i = 0; i < times->size(); ++i) {
+ for (auto x : (*times)[i]) sum += x;
}
ASSERT_GT(sum, (uint64_t)0);
- ASSERT_TRUE(clearUidCpuFreqTimes(0));
-
- ASSERT_TRUE(getUidCpuFreqTimes(0, ×2));
- ASSERT_EQ(times2.size(), times.size());
- for (size_t i = 0; i < times.size(); ++i) {
- ASSERT_EQ(times2[i].size(), times[i].size());
- for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
+ uint64_t activeSum = 0;
+ for (size_t i = 0; i < concurrentTimes->active.size(); ++i) {
+ activeSum += concurrentTimes->active[i];
}
+ ASSERT_GT(activeSum, (uint64_t)0);
+
+ ASSERT_TRUE(clearUidTimes(uid));
+
+ auto allTimes = getUidsCpuFreqTimes();
+ ASSERT_TRUE(allTimes.has_value());
+ ASSERT_FALSE(allTimes->empty());
+ ASSERT_EQ(allTimes->find(uid), allTimes->end());
+
+ auto allConcurrentTimes = getUidsConcurrentTimes();
+ ASSERT_TRUE(allConcurrentTimes.has_value());
+ ASSERT_FALSE(allConcurrentTimes->empty());
+ ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
}
} // namespace bpf
diff --git a/libs/cputimeinstate/timeinstate.h b/libs/cputimeinstate/timeinstate.h
new file mode 100644
index 0000000..6d4f913
--- /dev/null
+++ b/libs/cputimeinstate/timeinstate.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <inttypes.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+#define FREQS_PER_ENTRY 32
+#define CPUS_PER_ENTRY 8
+
+struct time_key_t {
+ uint32_t uid;
+ uint32_t bucket;
+};
+
+struct tis_val_t {
+ uint64_t ar[FREQS_PER_ENTRY];
+};
+
+struct concurrent_val_t {
+ uint64_t active[CPUS_PER_ENTRY];
+ uint64_t policy[CPUS_PER_ENTRY];
+};
+
+struct freq_idx_key_t {
+ uint32_t policy;
+ uint32_t freq;
+};
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 56521bf..642c5f2 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -32,5 +32,9 @@
"libutils",
],
+ header_libs: [
+ "libnativeloader-headers",
+ ],
+
export_include_dirs: ["include"],
}
diff --git a/libs/graphicsenv/GpuStatsInfo.cpp b/libs/graphicsenv/GpuStatsInfo.cpp
index 4a801be..85137f5 100644
--- a/libs/graphicsenv/GpuStatsInfo.cpp
+++ b/libs/graphicsenv/GpuStatsInfo.cpp
@@ -86,6 +86,7 @@
if ((status = parcel->writeInt64Vector(vkDriverLoadingTime)) != OK) return status;
if ((status = parcel->writeInt64Vector(angleDriverLoadingTime)) != OK) return status;
if ((status = parcel->writeBool(cpuVulkanInUse)) != OK) return status;
+ if ((status = parcel->writeBool(falsePrerotation)) != OK) return status;
return OK;
}
@@ -97,6 +98,7 @@
if ((status = parcel->readInt64Vector(&vkDriverLoadingTime)) != OK) return status;
if ((status = parcel->readInt64Vector(&angleDriverLoadingTime)) != OK) return status;
if ((status = parcel->readBool(&cpuVulkanInUse)) != OK) return status;
+ if ((status = parcel->readBool(&falsePrerotation)) != OK) return status;
return OK;
}
@@ -105,6 +107,7 @@
StringAppendF(&result, "appPackageName = %s\n", appPackageName.c_str());
StringAppendF(&result, "driverVersionCode = %" PRIu64 "\n", driverVersionCode);
StringAppendF(&result, "cpuVulkanInUse = %d\n", cpuVulkanInUse);
+ StringAppendF(&result, "falsePrerotation = %d\n", falsePrerotation);
result.append("glDriverLoadingTime:");
for (int32_t loadingTime : glDriverLoadingTime) {
StringAppendF(&result, " %d", loadingTime);
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index bb9e263..30f5f73 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -32,6 +32,7 @@
#include <cutils/properties.h>
#include <graphicsenv/IGpuService.h>
#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
#include <sys/prctl.h>
#include <utils/Trace.h>
@@ -39,22 +40,6 @@
#include <string>
#include <thread>
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
- const char* default_library_path, uint64_t type,
- const char* permitted_when_isolated_path,
- android_namespace_t* parent);
-bool android_link_namespaces(android_namespace_t* from, android_namespace_t* to,
- const char* shared_libs_sonames);
-
-enum {
- ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
- ANDROID_NAMESPACE_TYPE_SHARED = 2,
-};
-}
-
// TODO(ianelliott@): Get the following from an ANGLE header:
#define CURRENT_ANGLE_API_VERSION 2 // Current API verion we are targetting
// Version-2 API:
@@ -170,11 +155,11 @@
std::lock_guard<std::mutex> lock(mStatsLock);
if (mGpuStats.glDriverToSend) {
mGpuStats.glDriverToSend = false;
- sendGpuStatsLocked(GraphicsEnv::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
+ sendGpuStatsLocked(GpuStatsInfo::Api::API_GL, true, mGpuStats.glDriverLoadingTime);
}
if (mGpuStats.vkDriverToSend) {
mGpuStats.vkDriverToSend = false;
- sendGpuStatsLocked(GraphicsEnv::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
+ sendGpuStatsLocked(GpuStatsInfo::Api::API_VK, true, mGpuStats.vkDriverLoadingTime);
}
});
trySendGpuStatsThread.detach();
@@ -205,34 +190,34 @@
mGpuStats.vulkanVersion = vulkanVersion;
}
-void GraphicsEnv::setDriverToLoad(GraphicsEnv::Driver driver) {
+void GraphicsEnv::setDriverToLoad(GpuStatsInfo::Driver driver) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
switch (driver) {
- case GraphicsEnv::Driver::GL:
- case GraphicsEnv::Driver::GL_UPDATED:
- case GraphicsEnv::Driver::ANGLE: {
- if (mGpuStats.glDriverToLoad == GraphicsEnv::Driver::NONE ||
- mGpuStats.glDriverToLoad == GraphicsEnv::Driver::GL) {
+ case GpuStatsInfo::Driver::GL:
+ case GpuStatsInfo::Driver::GL_UPDATED:
+ case GpuStatsInfo::Driver::ANGLE: {
+ if (mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::NONE ||
+ mGpuStats.glDriverToLoad == GpuStatsInfo::Driver::GL) {
mGpuStats.glDriverToLoad = driver;
break;
}
- if (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE) {
+ if (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE) {
mGpuStats.glDriverFallback = driver;
}
break;
}
- case Driver::VULKAN:
- case Driver::VULKAN_UPDATED: {
- if (mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::NONE ||
- mGpuStats.vkDriverToLoad == GraphicsEnv::Driver::VULKAN) {
+ case GpuStatsInfo::Driver::VULKAN:
+ case GpuStatsInfo::Driver::VULKAN_UPDATED: {
+ if (mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::NONE ||
+ mGpuStats.vkDriverToLoad == GpuStatsInfo::Driver::VULKAN) {
mGpuStats.vkDriverToLoad = driver;
break;
}
- if (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE) {
+ if (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE) {
mGpuStats.vkDriverFallback = driver;
}
break;
@@ -242,13 +227,13 @@
}
}
-void GraphicsEnv::setDriverLoaded(GraphicsEnv::Api api, bool isDriverLoaded,
+void GraphicsEnv::setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded,
int64_t driverLoadingTime) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
const bool doNotSend = mGpuStats.appPackageName.empty();
- if (api == GraphicsEnv::Api::API_GL) {
+ if (api == GpuStatsInfo::Api::API_GL) {
if (doNotSend) mGpuStats.glDriverToSend = true;
mGpuStats.glDriverLoadingTime = driverLoadingTime;
} else {
@@ -260,7 +245,7 @@
}
static sp<IGpuService> getGpuService() {
- const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
+ static const sp<IBinder> binder = defaultServiceManager()->checkService(String16("gpu"));
if (!binder) {
ALOGE("Failed to get gpu service");
return nullptr;
@@ -269,7 +254,7 @@
return interface_cast<IGpuService>(binder);
}
-void GraphicsEnv::setTargetStats(const Stats stats, const uint64_t value) {
+void GraphicsEnv::setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mStatsLock);
@@ -280,7 +265,7 @@
}
}
-void GraphicsEnv::sendGpuStatsLocked(GraphicsEnv::Api api, bool isDriverLoaded,
+void GraphicsEnv::sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded,
int64_t driverLoadingTime) {
ATRACE_CALL();
@@ -301,16 +286,16 @@
mGpuStats.driverVersionCode, mGpuStats.driverBuildTime, mGpuStats.appPackageName.c_str(),
mGpuStats.vulkanVersion, static_cast<int32_t>(api), isDriverLoaded, driverLoadingTime);
- GraphicsEnv::Driver driver = GraphicsEnv::Driver::NONE;
+ GpuStatsInfo::Driver driver = GpuStatsInfo::Driver::NONE;
bool isIntendedDriverLoaded = false;
- if (api == GraphicsEnv::Api::API_GL) {
+ if (api == GpuStatsInfo::Api::API_GL) {
driver = mGpuStats.glDriverToLoad;
isIntendedDriverLoaded =
- isDriverLoaded && (mGpuStats.glDriverFallback == GraphicsEnv::Driver::NONE);
+ isDriverLoaded && (mGpuStats.glDriverFallback == GpuStatsInfo::Driver::NONE);
} else {
driver = mGpuStats.vkDriverToLoad;
isIntendedDriverLoaded =
- isDriverLoaded && (mGpuStats.vkDriverFallback == GraphicsEnv::Driver::NONE);
+ isDriverLoaded && (mGpuStats.vkDriverFallback == GpuStatsInfo::Driver::NONE);
}
const sp<IGpuService> gpuService = getGpuService();
diff --git a/libs/graphicsenv/IGpuService.cpp b/libs/graphicsenv/IGpuService.cpp
index db16f3c..9f5b0ff 100644
--- a/libs/graphicsenv/IGpuService.cpp
+++ b/libs/graphicsenv/IGpuService.cpp
@@ -30,7 +30,7 @@
virtual void setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
- const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
bool isDriverLoaded, int64_t driverLoadingTime) {
Parcel data, reply;
data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
@@ -93,7 +93,7 @@
}
virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
- const GraphicsEnv::Stats stats, const uint64_t value) {
+ const GpuStatsInfo::Stats stats, const uint64_t value) {
Parcel data, reply;
data.writeInterfaceToken(IGpuService::getInterfaceDescriptor());
@@ -145,7 +145,7 @@
if ((status = data.readInt64(&driverLoadingTime)) != OK) return status;
setGpuStats(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
- appPackageName, vulkanVersion, static_cast<GraphicsEnv::Driver>(driver),
+ appPackageName, vulkanVersion, static_cast<GpuStatsInfo::Driver>(driver),
isDriverLoaded, driverLoadingTime);
return OK;
@@ -192,7 +192,7 @@
if ((status = data.readUint64(&value)) != OK) return status;
setTargetStats(appPackageName, driverVersionCode,
- static_cast<GraphicsEnv::Stats>(stats), value);
+ static_cast<GpuStatsInfo::Stats>(stats), value);
return OK;
}
diff --git a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
index edcccfe..7959652 100644
--- a/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
+++ b/libs/graphicsenv/include/graphicsenv/GpuStatsInfo.h
@@ -70,6 +70,51 @@
std::vector<int64_t> vkDriverLoadingTime = {};
std::vector<int64_t> angleDriverLoadingTime = {};
bool cpuVulkanInUse = false;
+ bool falsePrerotation = false;
+};
+
+/*
+ * class for holding the gpu stats in GraphicsEnv before sending to GpuService.
+ */
+class GpuStatsInfo {
+public:
+ enum Api {
+ API_GL = 0,
+ API_VK = 1,
+ };
+
+ enum Driver {
+ NONE = 0,
+ GL = 1,
+ GL_UPDATED = 2,
+ VULKAN = 3,
+ VULKAN_UPDATED = 4,
+ ANGLE = 5,
+ };
+
+ enum Stats {
+ CPU_VULKAN_IN_USE = 0,
+ FALSE_PREROTATION = 1,
+ };
+
+ GpuStatsInfo() = default;
+ GpuStatsInfo(const GpuStatsInfo&) = default;
+ virtual ~GpuStatsInfo() = default;
+
+ std::string driverPackageName = "";
+ std::string driverVersionName = "";
+ uint64_t driverVersionCode = 0;
+ int64_t driverBuildTime = 0;
+ std::string appPackageName = "";
+ int32_t vulkanVersion = 0;
+ Driver glDriverToLoad = Driver::NONE;
+ Driver glDriverFallback = Driver::NONE;
+ Driver vkDriverToLoad = Driver::NONE;
+ Driver vkDriverFallback = Driver::NONE;
+ bool glDriverToSend = false;
+ bool vkDriverToSend = false;
+ int64_t glDriverLoadingTime = 0;
+ int64_t vkDriverLoadingTime = 0;
};
} // namespace android
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 937bcd9..a47f468 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_UI_GRAPHICS_ENV_H
#define ANDROID_UI_GRAPHICS_ENV_H 1
+#include <graphicsenv/GpuStatsInfo.h>
+
#include <mutex>
#include <string>
#include <vector>
@@ -29,63 +31,14 @@
class GraphicsEnv {
public:
- enum Api {
- API_GL = 0,
- API_VK = 1,
- };
-
- enum Driver {
- NONE = 0,
- GL = 1,
- GL_UPDATED = 2,
- VULKAN = 3,
- VULKAN_UPDATED = 4,
- ANGLE = 5,
- };
-
- enum Stats {
- CPU_VULKAN_IN_USE = 0,
- };
-
-private:
- struct GpuStats {
- std::string driverPackageName;
- std::string driverVersionName;
- uint64_t driverVersionCode;
- int64_t driverBuildTime;
- std::string appPackageName;
- int32_t vulkanVersion;
- Driver glDriverToLoad;
- Driver glDriverFallback;
- Driver vkDriverToLoad;
- Driver vkDriverFallback;
- bool glDriverToSend;
- bool vkDriverToSend;
- int64_t glDriverLoadingTime;
- int64_t vkDriverLoadingTime;
-
- GpuStats()
- : driverPackageName(""),
- driverVersionName(""),
- driverVersionCode(0),
- driverBuildTime(0),
- appPackageName(""),
- vulkanVersion(0),
- glDriverToLoad(Driver::NONE),
- glDriverFallback(Driver::NONE),
- vkDriverToLoad(Driver::NONE),
- vkDriverFallback(Driver::NONE),
- glDriverToSend(false),
- vkDriverToSend(false),
- glDriverLoadingTime(0),
- vkDriverLoadingTime(0) {}
- };
-
-public:
static GraphicsEnv& getInstance();
+ // Check if device is debuggable.
int getCanLoadSystemLibraries();
+ /*
+ * Apis for updatable driver
+ */
// Set a search path for loading graphics drivers. The path is a list of
// directories separated by ':'. A directory can be contained in a zip file
// (drivers must be stored uncompressed and page aligned); such elements
@@ -95,17 +48,31 @@
// graphics drivers. The string is a list of libraries separated by ':',
// which is required by android_link_namespaces.
void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
+ // Get the updatable driver namespace.
android_namespace_t* getDriverNamespace();
+
+ /*
+ * Apis for GpuStats
+ */
+ // Hint there's real activity launching on the app process.
void hintActivityLaunch();
+ // Set the initial GpuStats.
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t versionCode, int64_t driverBuildTime,
const std::string& appPackageName, const int32_t vulkanVersion);
- void setTargetStats(const Stats stats, const uint64_t value = 0);
- void setDriverToLoad(Driver driver);
- void setDriverLoaded(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
- void sendGpuStatsLocked(Api api, bool isDriverLoaded, int64_t driverLoadingTime);
+ // Set stats for target GpuStatsInfo::Stats type.
+ void setTargetStats(const GpuStatsInfo::Stats stats, const uint64_t value = 0);
+ // Set which driver is intended to load.
+ void setDriverToLoad(GpuStatsInfo::Driver driver);
+ // Set which driver is actually loaded.
+ void setDriverLoaded(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime);
+ /*
+ * Apis for ANGLE
+ */
+ // Check if the requested app should use ANGLE.
bool shouldUseAngle(std::string appName);
+ // Check if this app process should use ANGLE.
bool shouldUseAngle();
// Set a search path for loading ANGLE libraries. The path is a list of
// directories separated by ':'. A directory can be contained in a zip file
@@ -114,43 +81,75 @@
// /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
void setAngleInfo(const std::string path, const std::string appName, std::string devOptIn,
const int rulesFd, const long rulesOffset, const long rulesLength);
+ // Get the ANGLE driver namespace.
android_namespace_t* getAngleNamespace();
+ // Get the app name for ANGLE debug message.
std::string& getAngleAppName();
+ /*
+ * Apis for debug layer
+ */
+ // Set additional layer search paths.
void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
+ // Get the app namespace for loading layers.
NativeLoaderNamespace* getAppNamespace();
-
+ // Get additional layer search paths.
const std::string& getLayerPaths();
-
+ // Set the Vulkan debug layers.
void setDebugLayers(const std::string layers);
+ // Set the GL debug layers.
void setDebugLayersGLES(const std::string layers);
+ // Get the debug layers to load.
const std::string& getDebugLayers();
+ // Get the debug layers to load.
const std::string& getDebugLayersGLES();
private:
enum UseAngle { UNKNOWN, YES, NO };
+ // Load requested ANGLE library.
void* loadLibrary(std::string name);
+ // Check ANGLE support with the rules.
bool checkAngleRules(void* so);
+ // Update whether ANGLE should be used.
void updateUseAngle();
+ // Link updatable driver namespace with llndk and vndk-sp libs.
bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
+ // Send the initial complete GpuStats to GpuService.
+ void sendGpuStatsLocked(GpuStatsInfo::Api api, bool isDriverLoaded, int64_t driverLoadingTime);
GraphicsEnv() = default;
+ // Path to updatable driver libs.
std::string mDriverPath;
+ // Path to additional sphal libs linked to updatable driver namespace.
std::string mSphalLibraries;
+ // This mutex protects mGpuStats and get gpuservice call.
std::mutex mStatsLock;
- GpuStats mGpuStats;
+ // Information bookkept for GpuStats.
+ GpuStatsInfo mGpuStats;
+ // Path to ANGLE libs.
std::string mAnglePath;
+ // This App's name.
std::string mAngleAppName;
+ // ANGLE developer opt in status.
std::string mAngleDeveloperOptIn;
+ // ANGLE rules.
std::vector<char> mRulesBuffer;
+ // Use ANGLE flag.
UseAngle mUseAngle = UNKNOWN;
+ // Vulkan debug layers libs.
std::string mDebugLayers;
+ // GL debug layers libs.
std::string mDebugLayersGLES;
+ // Additional debug layers search path.
std::string mLayerPaths;
+ // This mutex protects the namespace creation.
std::mutex mNamespaceMutex;
+ // Updatable driver namespace.
android_namespace_t* mDriverNamespace = nullptr;
+ // ANGLE namespace.
android_namespace_t* mAngleNamespace = nullptr;
+ // This App's namespace.
NativeLoaderNamespace* mAppNamespace = nullptr;
};
diff --git a/libs/graphicsenv/include/graphicsenv/IGpuService.h b/libs/graphicsenv/include/graphicsenv/IGpuService.h
index b8d0bd1..f523d58 100644
--- a/libs/graphicsenv/include/graphicsenv/IGpuService.h
+++ b/libs/graphicsenv/include/graphicsenv/IGpuService.h
@@ -37,12 +37,12 @@
virtual void setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
- const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
bool isDriverLoaded, int64_t driverLoadingTime) = 0;
// set target stats.
virtual void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
- const GraphicsEnv::Stats stats, const uint64_t value = 0) = 0;
+ const GpuStatsInfo::Stats stats, const uint64_t value = 0) = 0;
// get GPU global stats from GpuStats module.
virtual status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const = 0;
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index a615fbf..3f8b436 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -15,6 +15,10 @@
name: "libgui_headers",
vendor_available: true,
export_include_dirs: ["include"],
+
+ // we must build this module to get the required header as that is generated
+ export_shared_lib_headers: [ "android.hidl.token@1.0-utils" ],
+ shared_libs: [ "android.hidl.token@1.0-utils" ],
}
cc_library_shared {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 528bfb1..3a7cb44 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -166,7 +166,9 @@
mCore->mFreeBuffers.push_back(front->mSlot);
}
- listener = mCore->mConnectedProducerListener;
+ if (mCore->mBufferReleasedCbEnabled) {
+ listener = mCore->mConnectedProducerListener;
+ }
++numDroppedBuffers;
}
@@ -457,7 +459,9 @@
mCore->mFreeBuffers.push_back(slot);
}
- listener = mCore->mConnectedProducerListener;
+ if (mCore->mBufferReleasedCbEnabled) {
+ listener = mCore->mConnectedProducerListener;
+ }
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
mCore->mDequeueCondition.notify_all();
@@ -668,7 +672,7 @@
BQ_LOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers);
mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers;
VALIDATE_CONSISTENCY();
- if (delta < 0) {
+ if (delta < 0 && mCore->mBufferReleasedCbEnabled) {
listener = mCore->mConsumerListener;
}
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index e0e3431..d6009d6 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -65,6 +65,7 @@
mConnectedApi(NO_CONNECTED_API),
mLinkedToDeath(),
mConnectedProducerListener(),
+ mBufferReleasedCbEnabled(false),
mSlots(),
mQueue(),
mFreeSlots(),
@@ -97,7 +98,9 @@
mSharedBufferCache(Rect::INVALID_RECT, 0, NATIVE_WINDOW_SCALING_MODE_FREEZE,
HAL_DATASPACE_UNKNOWN),
mLastQueuedSlot(INVALID_BUFFER_SLOT),
- mUniqueId(getUniqueId())
+ mUniqueId(getUniqueId()),
+ mAutoPrerotation(false),
+ mTransformHintInUse(0)
{
int numStartingBuffers = getMaxBufferCountLocked();
for (int s = 0; s < numStartingBuffers; s++) {
@@ -123,10 +126,12 @@
mQueueBufferCanDrop, mLegacyBufferDrop);
outResult->appendFormat("%s default-size=[%dx%d] default-format=%d ", prefix.string(),
mDefaultWidth, mDefaultHeight, mDefaultBufferFormat);
- outResult->appendFormat("transform-hint=%02x frame-counter=%" PRIu64, mTransformHint,
- mFrameCounter);
+ outResult->appendFormat("%s transform-hint=%02x frame-counter=%" PRIu64 "\n", prefix.string(),
+ mTransformHint, mFrameCounter);
+ outResult->appendFormat("%s mTransformHintInUse=%02x mAutoPrerotation=%d\n", prefix.string(),
+ mTransformHintInUse, mAutoPrerotation);
- outResult->appendFormat("\n%sFIFO(%zu):\n", prefix.string(), mQueue.size());
+ outResult->appendFormat("%sFIFO(%zu):\n", prefix.string(), mQueue.size());
Fifo::const_iterator current(mQueue.begin());
while (current != mQueue.end()) {
double timestamp = current->mTimestamp / 1e9;
@@ -260,6 +265,12 @@
}
void BufferQueueCore::discardFreeBuffersLocked() {
+ // Notify producer about the discarded buffers.
+ if (mConnectedProducerListener != nullptr && mFreeBuffers.size() > 0) {
+ std::vector<int32_t> freeBuffers(mFreeBuffers.begin(), mFreeBuffers.end());
+ mConnectedProducerListener->onBuffersDiscarded(freeBuffers);
+ }
+
for (int s : mFreeBuffers) {
mFreeSlots.insert(s);
clearBufferSlotLocked(s);
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 92ab410..5674674 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -408,6 +408,10 @@
if (useDefaultSize) {
width = mCore->mDefaultWidth;
height = mCore->mDefaultHeight;
+ if (mCore->mAutoPrerotation &&
+ (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
+ std::swap(width, height);
+ }
}
int found = BufferItem::INVALID_BUFFER_SLOT;
@@ -960,7 +964,7 @@
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
- output->transformHint = mCore->mTransformHint;
+ output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers = static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
@@ -1141,9 +1145,6 @@
case NATIVE_WINDOW_CONSUMER_IS_PROTECTED:
value = static_cast<int32_t>(mCore->mConsumerIsProtected);
break;
- case NATIVE_WINDOW_MAX_BUFFER_COUNT:
- value = static_cast<int32_t>(mCore->mMaxBufferCount);
- break;
default:
return BAD_VALUE;
}
@@ -1203,11 +1204,12 @@
output->width = mCore->mDefaultWidth;
output->height = mCore->mDefaultHeight;
- output->transformHint = mCore->mTransformHint;
+ output->transformHint = mCore->mTransformHintInUse = mCore->mTransformHint;
output->numPendingBuffers =
static_cast<uint32_t>(mCore->mQueue.size());
output->nextFrameNumber = mCore->mFrameCounter + 1;
output->bufferReplaced = false;
+ output->maxBufferCount = mCore->mMaxBufferCount;
if (listener != nullptr) {
// Set up a death notification so that we can disconnect
@@ -1221,9 +1223,8 @@
}
mCore->mLinkedToDeath = listener;
}
- if (listener->needsReleaseNotify()) {
- mCore->mConnectedProducerListener = listener;
- }
+ mCore->mConnectedProducerListener = listener;
+ mCore->mBufferReleasedCbEnabled = listener->needsReleaseNotify();
}
break;
default:
@@ -1307,6 +1308,7 @@
mCore->mConnectedPid = -1;
mCore->mSidebandStream.clear();
mCore->mDequeueCondition.notify_all();
+ mCore->mAutoPrerotation = false;
listener = mCore->mConsumerListener;
} else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("disconnect: not connected (req=%d)", api);
@@ -1350,6 +1352,8 @@
void BufferQueueProducer::allocateBuffers(uint32_t width, uint32_t height,
PixelFormat format, uint64_t usage) {
ATRACE_CALL();
+
+ const bool useDefaultSize = !width && !height;
while (true) {
size_t newBufferCount = 0;
uint32_t allocWidth = 0;
@@ -1376,6 +1380,11 @@
allocWidth = width > 0 ? width : mCore->mDefaultWidth;
allocHeight = height > 0 ? height : mCore->mDefaultHeight;
+ if (useDefaultSize && mCore->mAutoPrerotation &&
+ (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
+ std::swap(allocWidth, allocHeight);
+ }
+
allocFormat = format != 0 ? format : mCore->mDefaultBufferFormat;
allocUsage = usage | mCore->mConsumerUsageBits;
allocName.assign(mCore->mConsumerName.string(), mCore->mConsumerName.size());
@@ -1406,6 +1415,11 @@
std::unique_lock<std::mutex> lock(mCore->mMutex);
uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
+ if (useDefaultSize && mCore->mAutoPrerotation &&
+ (mCore->mTransformHintInUse & NATIVE_WINDOW_TRANSFORM_ROT_90)) {
+ std::swap(checkWidth, checkHeight);
+ }
+
PixelFormat checkFormat = format != 0 ?
format : mCore->mDefaultBufferFormat;
uint64_t checkUsage = usage | mCore->mConsumerUsageBits;
@@ -1608,4 +1622,14 @@
return NO_ERROR;
}
+status_t BufferQueueProducer::setAutoPrerotation(bool autoPrerotation) {
+ ATRACE_CALL();
+ BQ_LOGV("setAutoPrerotation: %d", autoPrerotation);
+
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
+
+ mCore->mAutoPrerotation = autoPrerotation;
+ return NO_ERROR;
+}
+
} // namespace android
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 8199c98..59f1bcd 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -46,7 +46,6 @@
#include <utils/String8.h>
#include <utils/Trace.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
#define EGL_PROTECTED_CONTENT_EXT 0x32C0
diff --git a/libs/gui/HdrMetadata.cpp b/libs/gui/HdrMetadata.cpp
index add3ef0..058cd9a 100644
--- a/libs/gui/HdrMetadata.cpp
+++ b/libs/gui/HdrMetadata.cpp
@@ -28,8 +28,8 @@
size += sizeof(cta8613);
}
if (validTypes & HDR10PLUS) {
- size += sizeof(size_t);
- size += hdr10plus.size();
+ size += sizeof(uint32_t);
+ size += hdr10plus.size() * sizeof(hdr10plus[0]);
}
return size;
}
@@ -47,10 +47,11 @@
FlattenableUtils::write(buffer, size, cta8613);
}
if (validTypes & HDR10PLUS) {
- size_t metadataSize = hdr10plus.size();
+ uint32_t metadataSize = hdr10plus.size();
FlattenableUtils::write(buffer, size, metadataSize);
- memcpy(buffer, hdr10plus.data(), metadataSize);
- FlattenableUtils::advance(buffer, size, metadataSize);
+ size_t metadataSizeinByte = metadataSize * sizeof(hdr10plus[0]);
+ memcpy(buffer, hdr10plus.data(), metadataSizeinByte);
+ FlattenableUtils::advance(buffer, size, metadataSizeinByte);
}
return NO_ERROR;
@@ -74,20 +75,21 @@
FlattenableUtils::read(buffer, size, cta8613);
}
if (validTypes & HDR10PLUS) {
- if (size < sizeof(size_t)) {
+ if (size < sizeof(uint32_t)) {
return NO_MEMORY;
}
- size_t metadataSize;
+ uint32_t metadataSize;
FlattenableUtils::read(buffer, size, metadataSize);
- if (size < metadataSize) {
+ size_t metadataSizeinByte = metadataSize * sizeof(hdr10plus[0]);
+ if (size < metadataSizeinByte) {
return NO_MEMORY;
}
hdr10plus.resize(metadataSize);
- memcpy(hdr10plus.data(), buffer, metadataSize);
- FlattenableUtils::advance(buffer, size, metadataSize);
+ memcpy(hdr10plus.data(), buffer, metadataSizeinByte);
+ FlattenableUtils::advance(buffer, size, metadataSizeinByte);
}
return NO_ERROR;
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0e03b7d..0009a57 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -73,6 +73,7 @@
GET_UNIQUE_ID,
GET_CONSUMER_USAGE,
SET_LEGACY_BUFFER_DROP,
+ SET_AUTO_PREROTATION,
};
class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -547,6 +548,17 @@
}
return actualResult;
}
+
+ virtual status_t setAutoPrerotation(bool autoPrerotation) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
+ data.writeBool(autoPrerotation);
+ status_t result = remote()->transact(SET_AUTO_PREROTATION, data, &reply);
+ if (result == NO_ERROR) {
+ result = reply.readInt32();
+ }
+ return result;
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -675,6 +687,10 @@
status_t getConsumerUsage(uint64_t* outUsage) const override {
return mBase->getConsumerUsage(outUsage);
}
+
+ status_t setAutoPrerotation(bool autoPrerotation) override {
+ return mBase->setAutoPrerotation(autoPrerotation);
+ }
};
IMPLEMENT_HYBRID_META_INTERFACE(GraphicBufferProducer,
@@ -688,6 +704,12 @@
return INVALID_OPERATION;
}
+status_t IGraphicBufferProducer::setAutoPrerotation(bool autoPrerotation) {
+ // No-op for IGBP other than BufferQueue.
+ (void)autoPrerotation;
+ return INVALID_OPERATION;
+}
+
status_t IGraphicBufferProducer::exportToParcel(Parcel* parcel) {
status_t res = OK;
res = parcel->writeUint32(USE_BUFFER_QUEUE);
@@ -1050,6 +1072,13 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case SET_AUTO_PREROTATION: {
+ CHECK_INTERFACE(IGraphicBuffer, data, reply);
+ bool autoPrerotation = data.readBool();
+ status_t result = setAutoPrerotation(autoPrerotation);
+ reply->writeInt32(result);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
@@ -1141,12 +1170,8 @@
// ----------------------------------------------------------------------------
constexpr size_t IGraphicBufferProducer::QueueBufferOutput::minFlattenedSize() {
- return sizeof(width) +
- sizeof(height) +
- sizeof(transformHint) +
- sizeof(numPendingBuffers) +
- sizeof(nextFrameNumber) +
- sizeof(bufferReplaced);
+ return sizeof(width) + sizeof(height) + sizeof(transformHint) + sizeof(numPendingBuffers) +
+ sizeof(nextFrameNumber) + sizeof(bufferReplaced) + sizeof(maxBufferCount);
}
size_t IGraphicBufferProducer::QueueBufferOutput::getFlattenedSize() const {
@@ -1170,6 +1195,7 @@
FlattenableUtils::write(buffer, size, numPendingBuffers);
FlattenableUtils::write(buffer, size, nextFrameNumber);
FlattenableUtils::write(buffer, size, bufferReplaced);
+ FlattenableUtils::write(buffer, size, maxBufferCount);
return frameTimestamps.flatten(buffer, size, fds, count);
}
@@ -1187,6 +1213,7 @@
FlattenableUtils::read(buffer, size, numPendingBuffers);
FlattenableUtils::read(buffer, size, nextFrameNumber);
FlattenableUtils::read(buffer, size, bufferReplaced);
+ FlattenableUtils::read(buffer, size, maxBufferCount);
return frameTimestamps.unflatten(buffer, size, fds, count);
}
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 936063a..808e336 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -24,6 +24,7 @@
enum {
ON_BUFFER_RELEASED = IBinder::FIRST_CALL_TRANSACTION,
NEEDS_RELEASE_NOTIFY,
+ ON_BUFFERS_DISCARDED,
};
class BpProducerListener : public BpInterface<IProducerListener>
@@ -56,6 +57,13 @@
}
return result;
}
+
+ virtual void onBuffersDiscarded(const std::vector<int>& discardedSlots) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IProducerListener::getInterfaceDescriptor());
+ data.writeInt32Vector(discardedSlots);
+ remote()->transact(ON_BUFFERS_DISCARDED, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -76,6 +84,10 @@
virtual bool needsReleaseNotify() override {
return mBase->needsReleaseNotify();
}
+
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& discardedSlots) override {
+ return mBase->onBuffersDiscarded(discardedSlots);
+ }
};
IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener,
@@ -92,6 +104,17 @@
CHECK_INTERFACE(IProducerListener, data, reply);
reply->writeBool(needsReleaseNotify());
return NO_ERROR;
+ case ON_BUFFERS_DISCARDED: {
+ CHECK_INTERFACE(IProducerListener, data, reply);
+ std::vector<int32_t> discardedSlots;
+ status_t result = data.readInt32Vector(&discardedSlots);
+ if (result != NO_ERROR) {
+ ALOGE("ON_BUFFERS_DISCARDED failed to read discardedSlots: %d", result);
+ return result;
+ }
+ onBuffersDiscarded(discardedSlots);
+ return NO_ERROR;
+ }
}
return BBinder::onTransact(code, data, reply, flags);
}
@@ -104,4 +127,7 @@
return true;
}
+void BnProducerListener::onBuffersDiscarded(const std::vector<int32_t>& /*discardedSlots*/) {
+}
+
} // namespace android
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 12deaf0..5805797 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -69,7 +69,7 @@
const sp<IBinder>& applyToken,
const InputWindowCommands& commands,
int64_t desiredPresentTime,
- const client_cache_t& uncacheBuffer,
+ const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks) {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -90,10 +90,11 @@
data.writeInt64(desiredPresentTime);
data.writeStrongBinder(uncacheBuffer.token.promote());
data.writeUint64(uncacheBuffer.id);
+ data.writeBool(hasListenerCallbacks);
if (data.writeVectorSize(listenerCallbacks) == NO_ERROR) {
for (const auto& [listener, callbackIds] : listenerCallbacks) {
- data.writeStrongBinder(IInterface::asBinder(listener));
+ data.writeStrongBinder(listener);
data.writeInt64Vector(callbackIds);
}
}
@@ -1039,18 +1040,19 @@
uncachedBuffer.token = data.readStrongBinder();
uncachedBuffer.id = data.readUint64();
+ bool hasListenerCallbacks = data.readBool();
+
std::vector<ListenerCallbacks> listenerCallbacks;
int32_t listenersSize = data.readInt32();
for (int32_t i = 0; i < listenersSize; i++) {
- auto listener =
- interface_cast<ITransactionCompletedListener>(data.readStrongBinder());
+ auto listener = data.readStrongBinder();
std::vector<CallbackId> callbackIds;
data.readInt64Vector(&callbackIds);
listenerCallbacks.emplace_back(listener, callbackIds);
}
-
setTransactionState(state, displays, stateFlags, applyToken, inputWindowCommands,
- desiredPresentTime, uncachedBuffer, listenerCallbacks);
+ desiredPresentTime, uncachedBuffer, hasListenerCallbacks,
+ listenerCallbacks);
return NO_ERROR;
}
case BOOT_FINISHED: {
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 129558b..b98e48b 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -34,7 +34,8 @@
CREATE_WITH_SURFACE_PARENT,
CLEAR_LAYER_FRAME_STATS,
GET_LAYER_FRAME_STATS,
- LAST = GET_LAYER_FRAME_STATS,
+ MIRROR_SURFACE,
+ LAST = MIRROR_SURFACE,
};
} // Anonymous namespace
@@ -80,6 +81,12 @@
&ISurfaceComposerClient::getLayerFrameStats)>(Tag::GET_LAYER_FRAME_STATS, handle,
outStats);
}
+
+ status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) override {
+ return callRemote<decltype(&ISurfaceComposerClient::mirrorSurface)>(Tag::MIRROR_SURFACE,
+ mirrorFromHandle,
+ outHandle);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -105,6 +112,8 @@
return callLocal(data, reply, &ISurfaceComposerClient::clearLayerFrameStats);
case Tag::GET_LAYER_FRAME_STATS:
return callLocal(data, reply, &ISurfaceComposerClient::getLayerFrameStats);
+ case Tag::MIRROR_SURFACE:
+ return callLocal(data, reply, &ISurfaceComposerClient::mirrorSurface);
}
}
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 74cd4f1..acda600 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -151,7 +151,7 @@
return NO_ERROR;
}
-ListenerStats ListenerStats::createEmpty(const sp<ITransactionCompletedListener>& listener,
+ListenerStats ListenerStats::createEmpty(const sp<IBinder>& listener,
const std::unordered_set<CallbackId>& callbackIds) {
ListenerStats listenerStats;
listenerStats.listener = listener;
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 42eb921..e004e95 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -86,7 +86,6 @@
memcpy(output.writeInplace(16 * sizeof(float)),
colorTransform.asArray(), 16 * sizeof(float));
output.writeFloat(cornerRadius);
- output.writeBool(hasListenerCallbacks);
output.writeStrongBinder(cachedBuffer.token.promote());
output.writeUint64(cachedBuffer.id);
output.writeParcelable(metadata);
@@ -95,6 +94,22 @@
output.writeUint32(static_cast<uint32_t>(bgColorDataspace));
output.writeBool(colorSpaceAgnostic);
+ auto err = output.writeVectorSize(listeners);
+ if (err) {
+ return err;
+ }
+
+ for (auto listener : listeners) {
+ err = output.writeStrongBinder(listener.transactionCompletedListener);
+ if (err) {
+ return err;
+ }
+ err = output.writeInt64Vector(listener.callbackIds);
+ if (err) {
+ return err;
+ }
+ }
+
return NO_ERROR;
}
@@ -156,7 +171,6 @@
colorTransform = mat4(static_cast<const float*>(input.readInplace(16 * sizeof(float))));
cornerRadius = input.readFloat();
- hasListenerCallbacks = input.readBool();
cachedBuffer.token = input.readStrongBinder();
cachedBuffer.id = input.readUint64();
input.readParcelable(&metadata);
@@ -165,16 +179,22 @@
bgColorDataspace = static_cast<ui::Dataspace>(input.readUint32());
colorSpaceAgnostic = input.readBool();
+ int32_t numListeners = input.readInt32();
+ listeners.clear();
+ for (int i = 0; i < numListeners; i++) {
+ auto listener = input.readStrongBinder();
+ std::vector<CallbackId> callbackIds;
+ input.readInt64Vector(&callbackIds);
+ listeners.emplace_back(listener, callbackIds);
+ }
return NO_ERROR;
}
status_t ComposerState::write(Parcel& output) const {
- output.writeStrongBinder(IInterface::asBinder(client));
return state.write(output);
}
status_t ComposerState::read(const Parcel& input) {
- client = interface_cast<ISurfaceComposerClient>(input.readStrongBinder());
return state.read(input);
}
@@ -267,8 +287,9 @@
}
if (other.what & eFlagsChanged) {
what |= eFlagsChanged;
- flags = other.flags;
- mask = other.mask;
+ flags &= ~other.mask;
+ flags |= (other.flags & other.mask);
+ mask |= other.mask;
}
if (other.what & eLayerStackChanged) {
what |= eLayerStackChanged;
@@ -292,9 +313,6 @@
what |= eOverrideScalingModeChanged;
overrideScalingMode = other.overrideScalingMode;
}
- if (other.what & eGeometryAppliesWithResize) {
- what |= eGeometryAppliesWithResize;
- }
if (other.what & eReparentChildren) {
what |= eReparentChildren;
reparentHandle = other.reparentHandle;
@@ -365,7 +383,6 @@
}
if (other.what & eHasListenerCallbacksChanged) {
what |= eHasListenerCallbacksChanged;
- hasListenerCallbacks = other.hasListenerCallbacks;
}
#ifndef NO_INPUT
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 9fe5de8..e490d6d 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -35,6 +35,7 @@
#include <ui/DisplayStatInfo.h>
#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -96,6 +97,7 @@
mConnectedToCpu = false;
mProducerControlledByApp = controlledByApp;
mSwapIntervalZero = false;
+ mMaxBufferCount = 0;
}
Surface::~Surface() {
@@ -961,6 +963,10 @@
*value = static_cast<int>(mDataSpace);
return NO_ERROR;
}
+ case NATIVE_WINDOW_MAX_BUFFER_COUNT: {
+ *value = mMaxBufferCount;
+ return NO_ERROR;
+ }
}
}
return mGraphicBufferProducer->query(what, value);
@@ -1072,6 +1078,21 @@
case NATIVE_WINDOW_GET_CONSUMER_USAGE64:
res = dispatchGetConsumerUsage64(args);
break;
+ case NATIVE_WINDOW_SET_AUTO_PREROTATION:
+ res = dispatchSetAutoPrerotation(args);
+ break;
+ case NATIVE_WINDOW_GET_LAST_DEQUEUE_START:
+ res = dispatchGetLastDequeueStartTime(args);
+ break;
+ case NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT:
+ res = dispatchSetDequeueTimeout(args);
+ break;
+ case NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION:
+ res = dispatchGetLastDequeueDuration(args);
+ break;
+ case NATIVE_WINDOW_GET_LAST_QUEUE_DURATION:
+ res = dispatchGetLastQueueDuration(args);
+ break;
default:
res = NAME_NOT_FOUND;
break;
@@ -1272,6 +1293,34 @@
return getConsumerUsage(usage);
}
+int Surface::dispatchSetAutoPrerotation(va_list args) {
+ bool autoPrerotation = va_arg(args, int);
+ return setAutoPrerotation(autoPrerotation);
+}
+
+int Surface::dispatchGetLastDequeueStartTime(va_list args) {
+ int64_t* lastDequeueStartTime = va_arg(args, int64_t*);
+ *lastDequeueStartTime = mLastDequeueStartTime;
+ return NO_ERROR;
+}
+
+int Surface::dispatchSetDequeueTimeout(va_list args) {
+ nsecs_t timeout = va_arg(args, int64_t);
+ return setDequeueTimeout(timeout);
+}
+
+int Surface::dispatchGetLastDequeueDuration(va_list args) {
+ int64_t* lastDequeueDuration = va_arg(args, int64_t*);
+ *lastDequeueDuration = mLastDequeueDuration;
+ return NO_ERROR;
+}
+
+int Surface::dispatchGetLastQueueDuration(va_list args) {
+ int64_t* lastQueueDuration = va_arg(args, int64_t*);
+ *lastQueueDuration = mLastQueueDuration;
+ return NO_ERROR;
+}
+
bool Surface::transformToDisplayInverse() {
return (mTransform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY) ==
NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY;
@@ -1287,6 +1336,14 @@
}
int Surface::connect(
+ int api, bool reportBufferRemoval, const sp<SurfaceListener>& sListener) {
+ if (sListener != nullptr) {
+ mListenerProxy = new ProducerListenerProxy(this, sListener);
+ }
+ return connect(api, mListenerProxy, reportBufferRemoval);
+}
+
+int Surface::connect(
int api, const sp<IProducerListener>& listener, bool reportBufferRemoval) {
ATRACE_CALL();
ALOGV("Surface::connect");
@@ -1298,6 +1355,7 @@
mDefaultWidth = output.width;
mDefaultHeight = output.height;
mNextFrameNumber = output.nextFrameNumber;
+ mMaxBufferCount = output.maxBufferCount;
// Ignore transform hint if sticky transform is set or transform to display inverse flag is
// set. Transform hint should be ignored if the client is expected to always submit buffers
@@ -1339,6 +1397,8 @@
mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
mTransform = 0;
mStickyTransform = 0;
+ mAutoPrerotation = false;
+ mEnableFrameTimestamps = false;
if (api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = false;
@@ -1684,6 +1744,28 @@
}
}
+status_t Surface::getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
+ std::vector<sp<GraphicBuffer>>* outBuffers) {
+ ALOGV("Surface::getAndFlushBuffersFromSlots");
+ for (int32_t i : slots) {
+ if (i < 0 || i >= NUM_BUFFER_SLOTS) {
+ ALOGE("%s: Invalid slotIndex: %d", __FUNCTION__, i);
+ return BAD_VALUE;
+ }
+ }
+
+ Mutex::Autolock lock(mMutex);
+ for (int32_t i : slots) {
+ if (mSlots[i].buffer == nullptr) {
+ ALOGW("%s: Discarded slot %d doesn't contain buffer!", __FUNCTION__, i);
+ continue;
+ }
+ outBuffers->push_back(mSlots[i].buffer);
+ mSlots[i].buffer = nullptr;
+ }
+ return OK;
+}
+
void Surface::setSurfaceDamage(android_native_rect_t* rects, size_t numRects) {
ATRACE_CALL();
ALOGV("Surface::setSurfaceDamage");
@@ -1903,11 +1985,6 @@
return mGraphicBufferProducer->getConsumerUsage(outUsage);
}
-nsecs_t Surface::getLastDequeueStartTime() const {
- Mutex::Autolock lock(mMutex);
- return mLastDequeueStartTime;
-}
-
status_t Surface::getAndFlushRemovedBuffers(std::vector<sp<GraphicBuffer>>* out) {
if (out == nullptr) {
ALOGE("%s: out must not be null!", __FUNCTION__);
@@ -1951,4 +2028,40 @@
return err;
}
+int Surface::setAutoPrerotation(bool autoPrerotation) {
+ ATRACE_CALL();
+ ALOGV("Surface::setAutoPrerotation (%d)", autoPrerotation);
+ Mutex::Autolock lock(mMutex);
+
+ if (mAutoPrerotation == autoPrerotation) {
+ return OK;
+ }
+
+ status_t err = mGraphicBufferProducer->setAutoPrerotation(autoPrerotation);
+ if (err == NO_ERROR) {
+ mAutoPrerotation = autoPrerotation;
+ }
+ ALOGE_IF(err, "IGraphicBufferProducer::setAutoPrerotation(%d) returned %s", autoPrerotation,
+ strerror(-err));
+ return err;
+}
+
+void Surface::ProducerListenerProxy::onBuffersDiscarded(const std::vector<int32_t>& slots) {
+ ATRACE_CALL();
+ sp<Surface> parent = mParent.promote();
+ if (parent == nullptr) {
+ return;
+ }
+
+ std::vector<sp<GraphicBuffer>> discardedBufs;
+ status_t res = parent->getAndFlushBuffersFromSlots(slots, &discardedBufs);
+ if (res != OK) {
+ ALOGE("%s: Failed to get buffers from slots: %s(%d)", __FUNCTION__,
+ strerror(-res), res);
+ return;
+ }
+
+ mSurfaceListener->onBuffersDiscarded(discardedBufs);
+}
+
}; // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index def9fe9..7b256f5 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -202,7 +202,8 @@
* callbackIds to generate one super map that contains all the sp<IBinder> to sp<SurfaceControl>
* that could possibly exist for the callbacks.
*/
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
for (const auto& transactionStats : listenerStats.transactionStats) {
for (auto callbackId : transactionStats.callbackIds) {
auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
@@ -322,21 +323,148 @@
mTransactionNestCount(other.mTransactionNestCount),
mAnimation(other.mAnimation),
mEarlyWakeup(other.mEarlyWakeup),
+ mContainsBuffer(other.mContainsBuffer),
mDesiredPresentTime(other.mDesiredPresentTime) {
mDisplayStates = other.mDisplayStates;
mComposerStates = other.mComposerStates;
mInputWindowCommands = other.mInputWindowCommands;
+ mListenerCallbacks = other.mListenerCallbacks;
+}
+
+std::unique_ptr<SurfaceComposerClient::Transaction>
+SurfaceComposerClient::Transaction::createFromParcel(const Parcel* parcel) {
+ auto transaction = std::make_unique<Transaction>();
+ if (transaction->readFromParcel(parcel) == NO_ERROR) {
+ return transaction;
+ }
+ return nullptr;
+}
+
+status_t SurfaceComposerClient::Transaction::readFromParcel(const Parcel* parcel) {
+ const uint32_t forceSynchronous = parcel->readUint32();
+ const uint32_t transactionNestCount = parcel->readUint32();
+ const bool animation = parcel->readBool();
+ const bool earlyWakeup = parcel->readBool();
+ const bool containsBuffer = parcel->readBool();
+ const int64_t desiredPresentTime = parcel->readInt64();
+
+ size_t count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ SortedVector<DisplayState> displayStates;
+ displayStates.setCapacity(count);
+ for (size_t i = 0; i < count; i++) {
+ DisplayState displayState;
+ if (displayState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ displayStates.add(displayState);
+ }
+
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash> listenerCallbacks;
+ listenerCallbacks.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ sp<ITransactionCompletedListener> listener =
+ interface_cast<ITransactionCompletedListener>(parcel->readStrongBinder());
+ size_t numCallbackIds = parcel->readUint32();
+ if (numCallbackIds > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ for (size_t j = 0; j < numCallbackIds; j++) {
+ listenerCallbacks[listener].callbackIds.insert(parcel->readInt64());
+ }
+ size_t numSurfaces = parcel->readUint32();
+ if (numSurfaces > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ for (size_t j = 0; j < numSurfaces; j++) {
+ sp<SurfaceControl> surface;
+ surface = SurfaceControl::readFromParcel(parcel);
+ listenerCallbacks[listener].surfaceControls.insert(surface);
+ }
+ }
+
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> composerStates;
+ composerStates.reserve(count);
+ for (size_t i = 0; i < count; i++) {
+ sp<IBinder> surfaceControlHandle = parcel->readStrongBinder();
+
+ ComposerState composerState;
+ if (composerState.read(*parcel) == BAD_VALUE) {
+ return BAD_VALUE;
+ }
+ composerStates[surfaceControlHandle] = composerState;
+ }
+
+ InputWindowCommands inputWindowCommands;
+ inputWindowCommands.read(*parcel);
+
+ // Parsing was successful. Update the object.
+ mForceSynchronous = forceSynchronous;
+ mTransactionNestCount = transactionNestCount;
+ mAnimation = animation;
+ mEarlyWakeup = earlyWakeup;
+ mContainsBuffer = containsBuffer;
+ mDesiredPresentTime = desiredPresentTime;
+ mDisplayStates = displayStates;
+ mListenerCallbacks = listenerCallbacks;
+ mComposerStates = composerStates;
+ mInputWindowCommands = inputWindowCommands;
+ return NO_ERROR;
+}
+
+status_t SurfaceComposerClient::Transaction::writeToParcel(Parcel* parcel) const {
+ parcel->writeUint32(mForceSynchronous);
+ parcel->writeUint32(mTransactionNestCount);
+ parcel->writeBool(mAnimation);
+ parcel->writeBool(mEarlyWakeup);
+ parcel->writeBool(mContainsBuffer);
+ parcel->writeInt64(mDesiredPresentTime);
+ parcel->writeUint32(static_cast<uint32_t>(mDisplayStates.size()));
+ for (auto const& displayState : mDisplayStates) {
+ displayState.write(*parcel);
+ }
+
+ parcel->writeUint32(static_cast<uint32_t>(mListenerCallbacks.size()));
+ for (auto const& [listener, callbackInfo] : mListenerCallbacks) {
+ parcel->writeStrongBinder(ITransactionCompletedListener::asBinder(listener));
+ parcel->writeUint32(static_cast<uint32_t>(callbackInfo.callbackIds.size()));
+ for (auto callbackId : callbackInfo.callbackIds) {
+ parcel->writeInt64(callbackId);
+ }
+ parcel->writeUint32(static_cast<uint32_t>(callbackInfo.surfaceControls.size()));
+ for (auto surfaceControl : callbackInfo.surfaceControls) {
+ surfaceControl->writeToParcel(parcel);
+ }
+ }
+
+ parcel->writeUint32(static_cast<uint32_t>(mComposerStates.size()));
+ for (auto const& [surfaceHandle, composerState] : mComposerStates) {
+ parcel->writeStrongBinder(surfaceHandle);
+ composerState.write(*parcel);
+ }
+
+ mInputWindowCommands.write(*parcel);
+ return NO_ERROR;
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
- for (auto const& kv : other.mComposerStates) {
- if (mComposerStates.count(kv.first) == 0) {
- mComposerStates[kv.first] = kv.second;
+ for (auto const& [surfaceHandle, composerState] : other.mComposerStates) {
+ if (mComposerStates.count(surfaceHandle) == 0) {
+ mComposerStates[surfaceHandle] = composerState;
} else {
- mComposerStates[kv.first].state.merge(kv.second.state);
+ mComposerStates[surfaceHandle].state.merge(composerState.state);
}
}
- other.mComposerStates.clear();
for (auto const& state : other.mDisplayStates) {
ssize_t index = mDisplayStates.indexOf(state);
@@ -346,46 +474,56 @@
mDisplayStates.editItemAt(static_cast<size_t>(index)).merge(state);
}
}
- other.mDisplayStates.clear();
for (const auto& [listener, callbackInfo] : other.mListenerCallbacks) {
auto& [callbackIds, surfaceControls] = callbackInfo;
mListenerCallbacks[listener].callbackIds.insert(std::make_move_iterator(
callbackIds.begin()),
std::make_move_iterator(callbackIds.end()));
+ // register surface controls for this listener that is merging
+ for (const auto& surfaceControl : surfaceControls) {
+ registerSurfaceControlForCallback(surfaceControl);
+ }
+
mListenerCallbacks[listener]
.surfaceControls.insert(std::make_move_iterator(surfaceControls.begin()),
std::make_move_iterator(surfaceControls.end()));
}
- other.mListenerCallbacks.clear();
mInputWindowCommands.merge(other.mInputWindowCommands);
- other.mInputWindowCommands.clear();
mContainsBuffer = other.mContainsBuffer;
- other.mContainsBuffer = false;
-
mEarlyWakeup = mEarlyWakeup || other.mEarlyWakeup;
- other.mEarlyWakeup = false;
-
+ other.clear();
return *this;
}
-void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client) {
+void SurfaceComposerClient::Transaction::clear() {
+ mComposerStates.clear();
+ mDisplayStates.clear();
+ mListenerCallbacks.clear();
+ mInputWindowCommands.clear();
+ mContainsBuffer = false;
+ mForceSynchronous = 0;
+ mTransactionNestCount = 0;
+ mAnimation = false;
+ mEarlyWakeup = false;
+ mDesiredPresentTime = -1;
+}
+
+void SurfaceComposerClient::doDropReferenceTransaction(const sp<IBinder>& handle) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
Vector<ComposerState> composerStates;
Vector<DisplayState> displayStates;
ComposerState s;
- s.client = client;
s.state.surface = handle;
s.state.what |= layer_state_t::eReparent;
s.state.parentHandleForChild = nullptr;
composerStates.add(s);
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, {});
+ sf->setTransactionState(composerStates, displayStates, 0, applyToken, {}, -1, {}, false, {});
}
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
@@ -396,7 +534,7 @@
uncacheBuffer.id = cacheId;
sp<IBinder> applyToken = IInterface::asBinder(TransactionCompletedListener::getIInstance());
- sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, {});
+ sf->setTransactionState({}, {}, 0, applyToken, {}, -1, uncacheBuffer, false, {});
}
void SurfaceComposerClient::Transaction::cacheBuffers() {
@@ -405,8 +543,8 @@
}
size_t count = 0;
- for (auto& [sc, cs] : mComposerStates) {
- layer_state_t* s = getLayerState(sc);
+ for (auto& [handle, cs] : mComposerStates) {
+ layer_state_t* s = getLayerState(handle);
if (!(s->what & layer_state_t::eBufferChanged)) {
continue;
}
@@ -445,8 +583,8 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ bool hasListenerCallbacks = !mListenerCallbacks.empty();
std::vector<ListenerCallbacks> listenerCallbacks;
-
// For every listener with registered callbacks
for (const auto& [listener, callbackInfo] : mListenerCallbacks) {
auto& [callbackIds, surfaceControls] = callbackInfo;
@@ -454,19 +592,24 @@
continue;
}
- listenerCallbacks.emplace_back(listener, std::move(callbackIds));
-
- // If the listener has any SurfaceControls set on this Transaction update the surface state
- for (const auto& surfaceControl : surfaceControls) {
- layer_state_t* s = getLayerState(surfaceControl);
- if (!s) {
- ALOGE("failed to get layer state");
- continue;
+ if (surfaceControls.empty()) {
+ listenerCallbacks.emplace_back(IInterface::asBinder(listener), std::move(callbackIds));
+ } else {
+ // If the listener has any SurfaceControls set on this Transaction update the surface
+ // state
+ for (const auto& surfaceControl : surfaceControls) {
+ layer_state_t* s = getLayerState(surfaceControl);
+ if (!s) {
+ ALOGE("failed to get layer state");
+ continue;
+ }
+ std::vector<CallbackId> callbacks(callbackIds.begin(), callbackIds.end());
+ s->what |= layer_state_t::eHasListenerCallbacksChanged;
+ s->listeners.emplace_back(IInterface::asBinder(listener), callbacks);
}
- s->what |= layer_state_t::eHasListenerCallbacksChanged;
- s->hasListenerCallbacks = true;
}
}
+
mListenerCallbacks.clear();
cacheBuffers();
@@ -504,7 +647,7 @@
sf->setTransactionState(composerStates, displayStates, flags, applyToken, mInputWindowCommands,
mDesiredPresentTime,
{} /*uncacheBuffer - only set in doUncacheBufferTransaction*/,
- listenerCallbacks);
+ hasListenerCallbacks, listenerCallbacks);
mInputWindowCommands.clear();
mStatus = NO_ERROR;
return NO_ERROR;
@@ -545,16 +688,15 @@
mEarlyWakeup = true;
}
-layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<SurfaceControl>& sc) {
- if (mComposerStates.count(sc) == 0) {
+layer_state_t* SurfaceComposerClient::Transaction::getLayerState(const sp<IBinder>& handle) {
+ if (mComposerStates.count(handle) == 0) {
// we don't have it, add an initialized layer_state to our list
ComposerState s;
- s.client = sc->getClient()->mClient;
- s.state.surface = sc->getHandle();
- mComposerStates[sc] = s;
+ s.state.surface = handle;
+ mComposerStates[handle] = s;
}
- return &(mComposerStates[sc].state);
+ return &(mComposerStates[handle].state);
}
void SurfaceComposerClient::Transaction::registerSurfaceControlForCallback(
@@ -626,6 +768,7 @@
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eRelativeLayerChanged;
s->what &= ~layer_state_t::eLayerChanged;
@@ -701,14 +844,15 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setMetadata(
- const sp<SurfaceControl>& sc, uint32_t key, std::vector<uint8_t> data) {
+ const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p) {
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
return *this;
}
s->what |= layer_state_t::eMetadataChanged;
- s->metadata.mMap[key] = std::move(data);
+
+ s->metadata.mMap[key] = {p.data(), p.data() + p.dataSize()};
registerSurfaceControlForCallback(sc);
return *this;
@@ -1055,6 +1199,7 @@
layer_state_t* s = getLayerState(sc);
if (!s) {
mStatus = BAD_INDEX;
+ return *this;
}
s->what |= layer_state_t::eDetachChildren;
@@ -1091,19 +1236,6 @@
return *this;
}
-SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometryAppliesWithResize(
- const sp<SurfaceControl>& sc) {
- layer_state_t* s = getLayerState(sc);
- if (!s) {
- mStatus = BAD_INDEX;
- return *this;
- }
- s->what |= layer_state_t::eGeometryAppliesWithResize;
-
- registerSurfaceControlForCallback(sc);
- return *this;
-}
-
#ifndef NO_INPUT
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setInputWindowInfo(
const sp<SurfaceControl>& sc,
@@ -1195,7 +1327,9 @@
break;
}
setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]);
- setPosition(sc, x, y);
+ float offsetX = xScale * source.left;
+ float offsetY = yScale * source.top;
+ setPosition(sc, x - offsetX, y - offsetY);
return *this;
}
@@ -1371,6 +1505,20 @@
return err;
}
+sp<SurfaceControl> SurfaceComposerClient::mirrorSurface(SurfaceControl* mirrorFromSurface) {
+ if (mirrorFromSurface == nullptr) {
+ return nullptr;
+ }
+
+ sp<IBinder> handle;
+ sp<IBinder> mirrorFromHandle = mirrorFromSurface->getHandle();
+ status_t err = mClient->mirrorSurface(mirrorFromHandle, &handle);
+ if (err == NO_ERROR) {
+ return new SurfaceControl(this, handle, nullptr, true /* owned */);
+ }
+ return nullptr;
+}
+
status_t SurfaceComposerClient::clearLayerFrameStats(const sp<IBinder>& token) const {
if (mStatus != NO_ERROR) {
return mStatus;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 55488da..071314f 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -65,16 +65,8 @@
{
// 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());
- }
- release();
-}
-
-void SurfaceControl::destroy()
-{
- if (isValid()) {
- SurfaceComposerClient::Transaction().reparent(this, nullptr).apply();
+ if (mHandle != nullptr && mOwned) {
+ SurfaceComposerClient::doDropReferenceTransaction(mHandle);
}
release();
}
@@ -186,8 +178,7 @@
parcel->writeStrongBinder(IGraphicBufferProducer::asBinder(mGraphicBufferProducer));
}
-sp<SurfaceControl> SurfaceControl::readFromParcel(Parcel* parcel)
-{
+sp<SurfaceControl> SurfaceControl::readFromParcel(const Parcel* parcel) {
sp<IBinder> client = parcel->readStrongBinder();
sp<IBinder> handle = parcel->readStrongBinder();
if (client == nullptr || handle == nullptr)
diff --git a/libs/gui/TEST_MAPPING b/libs/gui/TEST_MAPPING
new file mode 100644
index 0000000..1c43530
--- /dev/null
+++ b/libs/gui/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "frameworks/native/libs/nativewindow"
+ }
+ ]
+}
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index 690a85f..3c96089 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -189,8 +189,12 @@
sp<IProducerListener> mLinkedToDeath;
// mConnectedProducerListener is used to handle the onBufferReleased
- // notification.
+ // and onBuffersDiscarded notification.
sp<IProducerListener> mConnectedProducerListener;
+ // mBufferReleasedCbEnabled is used to indicate whether onBufferReleased()
+ // callback is registered by the listener. When set to false,
+ // mConnectedProducerListener will not trigger onBufferReleased() callback.
+ bool mBufferReleasedCbEnabled;
// mSlots is an array of buffer slots that must be mirrored on the producer
// side. This allows buffer ownership to be transferred between the producer
@@ -348,6 +352,14 @@
const uint64_t mUniqueId;
+ // When buffer size is driven by the consumer and mTransformHint specifies
+ // a 90 or 270 degree rotation, this indicates whether the width and height
+ // used by dequeueBuffer will be additionally swapped.
+ bool mAutoPrerotation;
+
+ // mTransformHintInUse is to cache the mTransformHint used by the producer.
+ uint32_t mTransformHintInUse;
+
}; // class BufferQueueCore
} // namespace android
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index d2a47a6..9ad92a6 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -190,6 +190,9 @@
// See IGraphicBufferProducer::getConsumerUsage
virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+ // See IGraphicBufferProducer::setAutoPrerotation
+ virtual status_t setAutoPrerotation(bool autoPrerotation);
+
private:
// This is required by the IBinder::DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who);
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 3dde8c8..abe1e3f 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -412,6 +412,7 @@
uint64_t nextFrameNumber{0};
FrameEventHistoryDelta frameTimestamps;
bool bufferReplaced{false};
+ int maxBufferCount{0};
};
virtual status_t queueBuffer(int slot, const QueueBufferInput& input,
@@ -629,6 +630,14 @@
// NATIVE_WINDOW_CONSUMER_USAGE_BITS attribute.
virtual status_t getConsumerUsage(uint64_t* outUsage) const = 0;
+ // Enable/disable the auto prerotation at buffer allocation when the buffer
+ // size is driven by the consumer.
+ //
+ // When buffer size is driven by the consumer and the transform hint
+ // specifies a 90 or 270 degree rotation, if auto prerotation is enabled,
+ // the width and height used for dequeueBuffer will be additionally swapped.
+ virtual status_t setAutoPrerotation(bool autoPrerotation);
+
// Static method exports any IGraphicBufferProducer object to a parcel. It
// handles null producer as well.
static status_t exportToParcel(const sp<IGraphicBufferProducer>& producer,
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index a13d8e4..32a3690 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_GUI_IPRODUCERLISTENER_H
#define ANDROID_GUI_IPRODUCERLISTENER_H
+#include <vector>
+
#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
#include <binder/IInterface.h>
@@ -44,6 +46,9 @@
// multiple threads.
virtual void onBufferReleased() = 0; // Asynchronous
virtual bool needsReleaseNotify() = 0;
+ // onBuffersFreed is called from IGraphicBufferConsumer::discardFreeBuffers
+ // to notify the producer that certain free buffers are discarded by the consumer.
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) = 0; // Asynchronous
};
class IProducerListener : public ProducerListener, public IInterface
@@ -65,6 +70,7 @@
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags = 0);
virtual bool needsReleaseNotify();
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
};
class DummyProducerListener : public BnProducerListener
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index c84910b..06be1b3 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -140,7 +140,7 @@
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
int64_t desiredPresentTime,
- const client_cache_t& uncacheBuffer,
+ const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks) = 0;
/* signal that we're done booting.
diff --git a/libs/gui/include/gui/ISurfaceComposerClient.h b/libs/gui/include/gui/ISurfaceComposerClient.h
index 32ac9e8..5fe7ca5 100644
--- a/libs/gui/include/gui/ISurfaceComposerClient.h
+++ b/libs/gui/include/gui/ISurfaceComposerClient.h
@@ -76,6 +76,8 @@
* Requires ACCESS_SURFACE_FLINGER permission
*/
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const = 0;
+
+ virtual status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) = 0;
};
class BnSurfaceComposerClient : public SafeBnInterface<ISurfaceComposerClient> {
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 774ad46..178ca2d 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -31,6 +31,7 @@
namespace android {
class ITransactionCompletedListener;
+class ListenerCallbacks;
using CallbackId = int64_t;
@@ -72,10 +73,10 @@
status_t writeToParcel(Parcel* output) const override;
status_t readFromParcel(const Parcel* input) override;
- static ListenerStats createEmpty(const sp<ITransactionCompletedListener>& listener,
+ static ListenerStats createEmpty(const sp<IBinder>& listener,
const std::unordered_set<CallbackId>& callbackIds);
- sp<ITransactionCompletedListener> listener;
+ sp<IBinder> listener;
std::vector<TransactionStats> transactionStats;
};
@@ -97,17 +98,59 @@
class ListenerCallbacks {
public:
- ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
- const std::unordered_set<CallbackId>& callbacks)
+ ListenerCallbacks(const sp<IBinder>& listener, const std::unordered_set<CallbackId>& callbacks)
: transactionCompletedListener(listener),
callbackIds(callbacks.begin(), callbacks.end()) {}
- ListenerCallbacks(const sp<ITransactionCompletedListener>& listener,
- const std::vector<CallbackId>& ids)
+ ListenerCallbacks(const sp<IBinder>& listener, const std::vector<CallbackId>& ids)
: transactionCompletedListener(listener), callbackIds(ids) {}
- sp<ITransactionCompletedListener> transactionCompletedListener;
+ bool operator==(const ListenerCallbacks& rhs) const {
+ if (transactionCompletedListener != rhs.transactionCompletedListener) {
+ return false;
+ }
+ if (callbackIds.empty()) {
+ return rhs.callbackIds.empty();
+ }
+ return callbackIds.front() == rhs.callbackIds.front();
+ }
+
+ sp<IBinder> transactionCompletedListener;
std::vector<CallbackId> callbackIds;
};
+struct IListenerHash {
+ std::size_t operator()(const sp<IBinder>& strongPointer) const {
+ return std::hash<IBinder*>{}(strongPointer.get());
+ }
+};
+
+struct CallbackIdsHash {
+ // CallbackId vectors have several properties that let us get away with this simple hash.
+ // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
+ // empty we can still hash 0.
+ // 2) CallbackId vectors for the same listener either are identical or contain none of the
+ // same members. It is sufficient to just check the first CallbackId in the vectors. If
+ // they match, they are the same. If they do not match, they are not the same.
+ std::size_t operator()(const std::vector<CallbackId>& callbackIds) const {
+ return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front());
+ }
+};
+
+struct ListenerCallbacksHash {
+ std::size_t HashCombine(size_t value1, size_t value2) const {
+ return value1 ^ (value2 + 0x9e3779b9 + (value1 << 6) + (value1 >> 2));
+ }
+
+ std::size_t operator()(const ListenerCallbacks& listenerCallbacks) const {
+ struct IListenerHash listenerHasher;
+ struct CallbackIdsHash callbackIdsHasher;
+
+ std::size_t listenerHash = listenerHasher(listenerCallbacks.transactionCompletedListener);
+ std::size_t callbackIdsHash = callbackIdsHasher(listenerCallbacks.callbackIds);
+
+ return HashCombine(listenerHash, callbackIdsHash);
+ }
+};
+
} // namespace android
diff --git a/libs/gui/include/gui/LayerMetadata.h b/libs/gui/include/gui/LayerMetadata.h
index 47f0ced..d58e019 100644
--- a/libs/gui/include/gui/LayerMetadata.h
+++ b/libs/gui/include/gui/LayerMetadata.h
@@ -22,7 +22,12 @@
namespace android {
-enum { METADATA_OWNER_UID = 1, METADATA_WINDOW_TYPE = 2, METADATA_TASK_ID = 3 };
+enum {
+ METADATA_OWNER_UID = 1,
+ METADATA_WINDOW_TYPE = 2,
+ METADATA_TASK_ID = 3,
+ METADATA_MOUSE_CURSOR = 4,
+};
struct LayerMetadata : public Parcelable {
std::unordered_map<uint32_t, std::vector<uint8_t>> mMap;
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f438eb3..a49ed52 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -23,6 +23,7 @@
#include <utils/Errors.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/ITransactionCompletedListener.h>
#include <math/mat4.h>
#ifndef NO_INPUT
@@ -71,7 +72,7 @@
eCropChanged_legacy = 0x00000100,
eDeferTransaction_legacy = 0x00000200,
eOverrideScalingModeChanged = 0x00000400,
- eGeometryAppliesWithResize = 0x00000800,
+ // AVAILABLE 0x00000800,
eReparentChildren = 0x00001000,
eDetachChildren = 0x00002000,
eRelativeLayerChanged = 0x00004000,
@@ -123,7 +124,6 @@
surfaceDamageRegion(),
api(-1),
colorTransform(mat4()),
- hasListenerCallbacks(false),
bgColorAlpha(0),
bgColorDataspace(ui::Dataspace::UNKNOWN),
colorSpaceAgnostic(false) {
@@ -186,7 +186,6 @@
sp<NativeHandle> sidebandStream;
mat4 colorTransform;
- bool hasListenerCallbacks;
#ifndef NO_INPUT
InputWindowInfo inputInfo;
#endif
@@ -203,10 +202,11 @@
// A color space agnostic layer means the color of this layer can be
// interpreted in any color space.
bool colorSpaceAgnostic;
+
+ std::vector<ListenerCallbacks> listeners;
};
struct ComposerState {
- sp<ISurfaceComposerClient> client;
layer_state_t state;
status_t write(Parcel& output) const;
status_t read(const Parcel& input);
@@ -274,8 +274,6 @@
};
static inline int compare_type(const ComposerState& lhs, const ComposerState& rhs) {
- if (lhs.client < rhs.client) return -1;
- if (lhs.client > rhs.client) return 1;
if (lhs.state.surface < rhs.state.surface) return -1;
if (lhs.state.surface > rhs.state.surface) return 1;
return 0;
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 5c6a1ee..e582509 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -20,6 +20,7 @@
#include <gui/BufferQueueDefs.h>
#include <gui/HdrMetadata.h>
#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
#include <ui/ANativeObjectBase.h>
#include <ui/GraphicTypes.h>
@@ -35,6 +36,21 @@
class ISurfaceComposer;
+/* This is the same as ProducerListener except that onBuffersDiscarded is
+ * called with a vector of graphic buffers instead of buffer slots.
+ */
+class SurfaceListener : public virtual RefBase
+{
+public:
+ SurfaceListener() = default;
+ virtual ~SurfaceListener() = default;
+
+ virtual void onBufferReleased() = 0;
+ virtual bool needsReleaseNotify() = 0;
+
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) = 0;
+};
+
/*
* An implementation of ANativeWindow that feeds graphics buffers into a
* BufferQueue.
@@ -163,9 +179,6 @@
status_t getUniqueId(uint64_t* outId) const;
status_t getConsumerUsage(uint64_t* outUsage) const;
- // Returns the CLOCK_MONOTONIC start time of the last dequeueBuffer call
- nsecs_t getLastDequeueStartTime() const;
-
protected:
virtual ~Surface();
@@ -230,6 +243,11 @@
int dispatchGetWideColorSupport(va_list args);
int dispatchGetHdrSupport(va_list args);
int dispatchGetConsumerUsage64(va_list args);
+ int dispatchSetAutoPrerotation(va_list args);
+ int dispatchGetLastDequeueStartTime(va_list args);
+ int dispatchSetDequeueTimeout(va_list args);
+ int dispatchGetLastDequeueDuration(va_list args);
+ int dispatchGetLastQueueDuration(va_list args);
bool transformToDisplayInverse();
protected:
@@ -265,6 +283,7 @@
virtual int setAsyncMode(bool async);
virtual int setSharedBufferMode(bool sharedBufferMode);
virtual int setAutoRefresh(bool autoRefresh);
+ virtual int setAutoPrerotation(bool autoPrerotation);
virtual int setBuffersDimensions(uint32_t width, uint32_t height);
virtual int lock(ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds);
virtual int unlockAndPost();
@@ -283,6 +302,10 @@
sp<Fence>* outFence);
virtual int attachBuffer(ANativeWindowBuffer*);
+ virtual int connect(
+ int api, bool reportBufferRemoval,
+ const sp<SurfaceListener>& sListener);
+
// When client connects to Surface with reportBufferRemoval set to true, any buffers removed
// from this Surface will be collected and returned here. Once this method returns, these
// buffers will no longer be referenced by this Surface unless they are attached to this
@@ -299,6 +322,26 @@
enum { NUM_BUFFER_SLOTS = BufferQueueDefs::NUM_BUFFER_SLOTS };
enum { DEFAULT_FORMAT = PIXEL_FORMAT_RGBA_8888 };
+ class ProducerListenerProxy : public BnProducerListener {
+ public:
+ ProducerListenerProxy(wp<Surface> parent, sp<SurfaceListener> listener)
+ : mParent(parent), mSurfaceListener(listener) {}
+ virtual ~ProducerListenerProxy() {}
+
+ virtual void onBufferReleased() {
+ mSurfaceListener->onBufferReleased();
+ }
+
+ virtual bool needsReleaseNotify() {
+ return mSurfaceListener->needsReleaseNotify();
+ }
+
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots);
+ private:
+ wp<Surface> mParent;
+ sp<SurfaceListener> mSurfaceListener;
+ };
+
void querySupportedTimestampsLocked() const;
void freeAllBuffers();
@@ -434,6 +477,7 @@
// Caches the values that have been passed to the producer.
bool mSharedBufferMode;
bool mAutoRefresh;
+ bool mAutoPrerotation;
// If in shared buffer mode and auto refresh is enabled, store the shared
// buffer slot and return it for all calls to queue/dequeue without going
@@ -466,6 +510,11 @@
bool mReportRemovedBuffers = false;
std::vector<sp<GraphicBuffer>> mRemovedBuffers;
+ int mMaxBufferCount;
+
+ sp<IProducerListener> mListenerProxy;
+ status_t getAndFlushBuffersFromSlots(const std::vector<int32_t>& slots,
+ std::vector<sp<GraphicBuffer>>* outBuffers);
};
} // namespace android
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 0e17c7b..6676be4 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -163,8 +163,7 @@
* Called from SurfaceControl d'tor to 'destroy' the surface (or rather, reparent it
* to null), but without needing an sp<SurfaceControl> to avoid infinite ressurection.
*/
- static void doDropReferenceTransaction(const sp<IBinder>& handle,
- const sp<ISurfaceComposerClient>& client);
+ static void doDropReferenceTransaction(const sp<IBinder>& handle);
/**
* Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
@@ -246,6 +245,17 @@
LayerMetadata metadata = LayerMetadata() // metadata
);
+ // Creates a mirrored hierarchy for the mirrorFromSurface. This returns a SurfaceControl
+ // which is a parent of the root of the mirrored hierarchy.
+ //
+ // Real Hierarchy Mirror
+ // SC (value that's returned)
+ // |
+ // A A'
+ // | |
+ // B B'
+ sp<SurfaceControl> mirrorSurface(SurfaceControl* mirrorFromSurface);
+
//! Create a virtual display
static sp<IBinder> createDisplay(const String8& displayName, bool secure);
@@ -270,6 +280,12 @@
}
};
+ struct IBinderHash {
+ std::size_t operator()(const sp<IBinder>& iBinder) const {
+ return std::hash<IBinder*>{}(iBinder.get());
+ }
+ };
+
struct TCLHash {
std::size_t operator()(const sp<ITransactionCompletedListener>& tcl) const {
return std::hash<IBinder*>{}((tcl) ? IInterface::asBinder(tcl).get() : nullptr);
@@ -285,8 +301,9 @@
std::unordered_set<sp<SurfaceControl>, SCHash> surfaceControls;
};
- class Transaction {
- std::unordered_map<sp<SurfaceControl>, ComposerState, SCHash> mComposerStates;
+ class Transaction : public Parcelable {
+ protected:
+ std::unordered_map<sp<IBinder>, ComposerState, IBinderHash> mComposerStates;
SortedVector<DisplayState > mDisplayStates;
std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
mListenerCallbacks;
@@ -314,7 +331,10 @@
InputWindowCommands mInputWindowCommands;
int mStatus = NO_ERROR;
- layer_state_t* getLayerState(const sp<SurfaceControl>& sc);
+ layer_state_t* getLayerState(const sp<IBinder>& surfaceHandle);
+ layer_state_t* getLayerState(const sp<SurfaceControl>& sc) {
+ return getLayerState(sc->getHandle());
+ }
DisplayState& getDisplayState(const sp<IBinder>& token);
void cacheBuffers();
@@ -325,6 +345,15 @@
virtual ~Transaction() = default;
Transaction(Transaction const& other);
+ // Factory method that creates a new Transaction instance from the parcel.
+ static std::unique_ptr<Transaction> createFromParcel(const Parcel* parcel);
+
+ status_t writeToParcel(Parcel* parcel) const override;
+ status_t readFromParcel(const Parcel* parcel) override;
+
+ // Clears the contents of the transaction without applying it.
+ void clear();
+
status_t apply(bool synchronous = false);
// Merge another transaction in to this one, clearing other
// as if it had been applied.
@@ -362,8 +391,7 @@
Transaction& setCrop_legacy(const sp<SurfaceControl>& sc, const Rect& crop);
Transaction& setCornerRadius(const sp<SurfaceControl>& sc, float cornerRadius);
Transaction& setLayerStack(const sp<SurfaceControl>& sc, uint32_t layerStack);
- Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key,
- std::vector<uint8_t> data);
+ Transaction& setMetadata(const sp<SurfaceControl>& sc, uint32_t key, const Parcel& p);
// Defers applying any changes made in this transaction until the Layer
// identified by handle reaches the given frameNumber. If the Layer identified
// by handle is removed, then we will apply this transaction regardless of
@@ -430,12 +458,6 @@
Transaction& setOverrideScalingMode(const sp<SurfaceControl>& sc,
int32_t overrideScalingMode);
- // If the size changes in this transaction, all geometry updates specified
- // in this transaction will not complete until a buffer of the new size
- // arrives. As some elements normally apply immediately, this enables
- // freezing the total geometry of a surface until a resize is completed.
- Transaction& setGeometryAppliesWithResize(const sp<SurfaceControl>& sc);
-
#ifndef NO_INPUT
Transaction& setInputWindowInfo(const sp<SurfaceControl>& sc, const InputWindowInfo& info);
Transaction& transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
@@ -551,15 +573,10 @@
CallbackId mCallbackIdCounter GUARDED_BY(mMutex) = 1;
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& iBinder) const {
- return std::hash<IBinder*>{}(iBinder.get());
- }
- };
-
struct CallbackTranslation {
TransactionCompletedCallback callbackFunction;
- std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
+ std::unordered_map<sp<IBinder>, sp<SurfaceControl>, SurfaceComposerClient::IBinderHash>
+ surfaceControls;
};
std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index 23bfc02..ae4a146 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -44,7 +44,7 @@
class SurfaceControl : public RefBase
{
public:
- static sp<SurfaceControl> readFromParcel(Parcel* parcel);
+ static sp<SurfaceControl> readFromParcel(const Parcel* parcel);
void writeToParcel(Parcel* parcel);
static bool isValid(const sp<SurfaceControl>& surface) {
@@ -81,7 +81,7 @@
status_t getLayerFrameStats(FrameStats* outStats) const;
sp<SurfaceComposerClient> getClient() const;
-
+
explicit SurfaceControl(const sp<SurfaceControl>& other);
SurfaceControl(const sp<SurfaceComposerClient>& client, const sp<IBinder>& handle,
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 119e888..6d7b6bb 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -169,6 +169,18 @@
ASSERT_EQ(OK, item.mGraphicBuffer->unlock());
}
+TEST_F(BufferQueueTest, GetMaxBufferCountInQueueBufferOutput_Succeeds) {
+ createBufferQueue();
+ sp<DummyConsumer> dc(new DummyConsumer);
+ mConsumer->consumerConnect(dc, false);
+ int bufferCount = 50;
+ mConsumer->setMaxBufferCount(bufferCount);
+
+ IGraphicBufferProducer::QueueBufferOutput output;
+ mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false, &output);
+ ASSERT_EQ(output.maxBufferCount, bufferCount);
+}
+
TEST_F(BufferQueueTest, AcquireBuffer_ExceedsMaxAcquireCount_Fails) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
@@ -998,12 +1010,31 @@
ASSERT_EQ(true, thirdSegment.usedThirdBuffer);
}
+struct BufferDiscardedListener : public BnProducerListener {
+public:
+ BufferDiscardedListener() = default;
+ virtual ~BufferDiscardedListener() = default;
+
+ virtual void onBufferReleased() {}
+ virtual bool needsReleaseNotify() { return false; }
+ virtual void onBuffersDiscarded(const std::vector<int32_t>& slots) {
+ mDiscardedSlots.insert(mDiscardedSlots.end(), slots.begin(), slots.end());
+ }
+
+ const std::vector<int32_t>& getDiscardedSlots() const { return mDiscardedSlots; }
+private:
+ // No need to use lock given the test triggers the listener in the same
+ // thread context.
+ std::vector<int32_t> mDiscardedSlots;
+};
+
TEST_F(BufferQueueTest, TestDiscardFreeBuffers) {
createBufferQueue();
sp<DummyConsumer> dc(new DummyConsumer);
ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK, mProducer->connect(new DummyProducerListener,
+ sp<BufferDiscardedListener> pl(new BufferDiscardedListener);
+ ASSERT_EQ(OK, mProducer->connect(pl,
NATIVE_WINDOW_API_CPU, false, &output));
int slot = BufferQueue::INVALID_BUFFER_SLOT;
@@ -1044,12 +1075,19 @@
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE));
+ int releasedSlot = item.mSlot;
+
// Acquire 1 buffer, leaving 1 filled buffer in queue
ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
// Now discard the free buffers
ASSERT_EQ(OK, mConsumer->discardFreeBuffers());
+ // Check onBuffersDiscarded is called with correct slots
+ auto buffersDiscarded = pl->getDiscardedSlots();
+ ASSERT_EQ(buffersDiscarded.size(), 1);
+ ASSERT_EQ(buffersDiscarded[0], releasedSlot);
+
// Check no free buffers in dump
String8 dumpString;
mConsumer->dumpState(String8{}, &dumpString);
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ff1ba0a..09eeaea 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -133,27 +133,6 @@
EXPECT_EQ(AMOTION_EVENT_ACTION_UP, mev->getAction());
}
- void expectMotionEvent(int motionEventType, int x, int y) {
- InputEvent *ev = consumeEvent();
- ASSERT_NE(ev, nullptr);
- ASSERT_EQ(ev->getType(), AINPUT_EVENT_TYPE_MOTION);
- MotionEvent *mev = static_cast<MotionEvent *>(ev);
- EXPECT_EQ(motionEventType, mev->getAction());
- EXPECT_EQ(x, mev->getX(0));
- EXPECT_EQ(y, mev->getY(0));
- }
-
- void expectNoMotionEvent(int motionEventType) {
- InputEvent *ev = consumeEvent();
- if (ev == nullptr || ev->getType() != AINPUT_EVENT_TYPE_MOTION) {
- // Didn't find an event or a motion event so assume action didn't occur.
- return;
- }
-
- MotionEvent *mev = static_cast<MotionEvent *>(ev);
- EXPECT_NE(motionEventType, mev->getAction());
- }
-
~InputSurface() {
mInputFlinger->unregisterInputChannel(mServerChannel);
}
@@ -278,15 +257,6 @@
}
}
-void injectMotionEvent(std::string event, int x, int y) {
- char *buf1, *buf2;
- asprintf(&buf1, "%d", x);
- asprintf(&buf2, "%d", y);
- if (fork() == 0) {
- execlp("input", "input", "motionevent", event.c_str(), buf1, buf2, NULL);
- }
-}
-
TEST_F(InputSurfacesTest, can_receive_input) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(100, 100);
@@ -410,6 +380,19 @@
bgSurface->expectTap(1, 1);
}
+TEST_F(InputSurfacesTest, input_respects_scaled_surface_insets_overflow) {
+ std::unique_ptr<InputSurface> fgSurface = makeSurface(100, 100);
+ // In case we pass the very big inset without any checking.
+ fgSurface->mInputInfo.surfaceInset = INT32_MAX;
+ fgSurface->showAt(100, 100);
+
+ fgSurface->doTransaction([&](auto &t, auto &sc) { t.setMatrix(sc, 2.0, 0, 0, 2.0); });
+
+ // expect no crash for overflow, and inset size to be clamped to surface size
+ injectTap(202, 202);
+ fgSurface->expectTap(1, 1);
+}
+
// Ensure we ignore transparent region when getting screen bounds when positioning input frame.
TEST_F(InputSurfacesTest, input_ignores_transparent_region) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
@@ -422,6 +405,9 @@
surface->expectTap(1, 1);
}
+/**
+ * TODO(b/139494112) fix tests once we define expected behavior
+ *
// Ensure we send the input to the right surface when the surface visibility changes due to the
// first buffer being submitted. ref: b/120839715
TEST_F(InputSurfacesTest, input_respects_buffer_layer_buffer) {
@@ -473,6 +459,7 @@
injectTap(11, 11);
bgSurface->expectTap(1, 1);
}
+*/
TEST_F(InputSurfacesTest, input_respects_container_layer_visiblity) {
std::unique_ptr<InputSurface> bgSurface = makeSurface(100, 100);
@@ -491,26 +478,6 @@
bgSurface->expectTap(1, 1);
}
-TEST_F(InputSurfacesTest, transfer_touch_focus) {
- std::unique_ptr<InputSurface> fromSurface = makeSurface(100, 100);
-
- fromSurface->showAt(10, 10);
- injectMotionEvent("DOWN", 11, 11);
- fromSurface->expectMotionEvent(AMOTION_EVENT_ACTION_DOWN, 1, 1);
-
- std::unique_ptr<InputSurface> toSurface = makeSurface(100, 100);
- toSurface->showAt(10, 10);
-
- sp<IBinder> fromToken = fromSurface->mServerChannel->getToken();
- sp<IBinder> toToken = toSurface->mServerChannel->getToken();
- SurfaceComposerClient::Transaction t;
- t.transferTouchFocus(fromToken, toToken).apply(true);
-
- injectMotionEvent("UP", 11, 11);
- toSurface->expectMotionEvent(AMOTION_EVENT_ACTION_UP, 1, 1);
- fromSurface->expectNoMotionEvent(AMOTION_EVENT_ACTION_UP);
-}
-
TEST_F(InputSurfacesTest, input_respects_outscreen) {
std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
surface->showAt(-1, -1);
diff --git a/libs/gui/tests/RegionSampling_test.cpp b/libs/gui/tests/RegionSampling_test.cpp
index d33ecfb..c9de37d 100644
--- a/libs/gui/tests/RegionSampling_test.cpp
+++ b/libs/gui/tests/RegionSampling_test.cpp
@@ -297,4 +297,70 @@
composer->removeRegionSamplingListener(grayListener);
}
+TEST_F(RegionSamplingTest, DISABLED_TestIfInvalidInputParameters) {
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<Listener> listener = new Listener();
+ const Rect sampleArea{100, 100, 200, 200};
+ // Invalid input sampleArea
+ EXPECT_EQ(BAD_VALUE,
+ composer->addRegionSamplingListener(Rect::INVALID_RECT, mTopLayer->getHandle(),
+ listener));
+ listener->reset();
+ // Invalid input binder
+ EXPECT_EQ(NO_ERROR, composer->addRegionSamplingListener(sampleArea, NULL, listener));
+ // Invalid input listener
+ EXPECT_EQ(BAD_VALUE,
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), NULL));
+ EXPECT_EQ(BAD_VALUE, composer->removeRegionSamplingListener(NULL));
+ // remove the listener
+ composer->removeRegionSamplingListener(listener);
+}
+
+TEST_F(RegionSamplingTest, DISABLED_TestCallbackAfterRemoveListener) {
+ fill_render(rgba_green);
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<Listener> listener = new Listener();
+ const Rect sampleArea{100, 100, 200, 200};
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+ fill_render(rgba_green);
+
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+
+ listener->reset();
+ composer->removeRegionSamplingListener(listener);
+ fill_render(rgba_green);
+ EXPECT_FALSE(listener->wait_event(100ms))
+ << "callback should stop after remove the region sampling listener";
+}
+
+TEST_F(RegionSamplingTest, DISABLED_CollectsLumaFromMovingLayer) {
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<Listener> listener = new Listener();
+ Rect sampleArea{100, 100, 200, 200};
+
+ // Test: listener in (100, 100). See layer before move, no layer after move.
+ fill_render(rgba_blue);
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_blue, error_margin);
+ listener->reset();
+ SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply();
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
+ composer->removeRegionSamplingListener(listener);
+
+ // Test: listener offset to (600, 600). No layer before move, see layer after move.
+ fill_render(rgba_green);
+ sampleArea.offsetTo(600, 600);
+ composer->addRegionSamplingListener(sampleArea, mTopLayer->getHandle(), listener);
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_gray, error_margin);
+ listener->reset();
+ SurfaceComposerClient::Transaction{}.setPosition(mContentLayer, 600, 600).apply();
+ EXPECT_TRUE(listener->wait_event(300ms)) << "timed out waiting for luma event to be received";
+ EXPECT_NEAR(listener->luma(), luma_green, error_margin);
+ composer->removeRegionSamplingListener(listener);
+}
+
} // namespace android::test
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 65e09f2..c85e844 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -28,8 +28,6 @@
#include <utils/Log.h>
#include <utils/Thread.h>
-extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-
namespace android {
class SurfaceTextureClientTest : public ::testing::Test {
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d370858..a4fdb35 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -57,6 +57,37 @@
static constexpr uint64_t NO_FRAME_INDEX = std::numeric_limits<uint64_t>::max();
+class DummySurfaceListener : public SurfaceListener {
+public:
+ DummySurfaceListener(bool enableReleasedCb = false) :
+ mEnableReleaseCb(enableReleasedCb),
+ mBuffersReleased(0) {}
+ virtual ~DummySurfaceListener() = default;
+
+ virtual void onBufferReleased() {
+ mBuffersReleased++;
+ }
+ virtual bool needsReleaseNotify() {
+ return mEnableReleaseCb;
+ }
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& buffers) {
+ mDiscardedBuffers.insert(mDiscardedBuffers.end(), buffers.begin(), buffers.end());
+ }
+
+ int getReleaseNotifyCount() const {
+ return mBuffersReleased;
+ }
+ const std::vector<sp<GraphicBuffer>>& getDiscardedBuffers() const {
+ return mDiscardedBuffers;
+ }
+private:
+ // No need to use lock given the test triggers the listener in the same
+ // thread context.
+ bool mEnableReleaseCb;
+ int32_t mBuffersReleased;
+ std::vector<sp<GraphicBuffer>> mDiscardedBuffers;
+};
+
class SurfaceTest : public ::testing::Test {
protected:
SurfaceTest() {
@@ -88,6 +119,86 @@
mComposerClient->dispose();
}
+ void testSurfaceListener(bool hasSurfaceListener, bool enableReleasedCb,
+ int32_t extraDiscardedBuffers) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setConsumerName(String8("TestConsumer"));
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ sp<DummySurfaceListener> listener;
+ if (hasSurfaceListener) {
+ listener = new DummySurfaceListener(enableReleasedCb);
+ }
+ ASSERT_EQ(OK, surface->connect(
+ NATIVE_WINDOW_API_CPU,
+ /*reportBufferRemoval*/true,
+ /*listener*/listener));
+ const int BUFFER_COUNT = 4 + extraDiscardedBuffers;
+ ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(window.get(), BUFFER_COUNT));
+
+ ANativeWindowBuffer* buffers[BUFFER_COUNT];
+ // Dequeue first to allocate a number of buffers
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffers[i]));
+ }
+ for (int i = 0; i < BUFFER_COUNT; i++) {
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffers[i], -1));
+ }
+
+ ANativeWindowBuffer* buffer;
+ // Fill BUFFER_COUNT-1 buffers
+ for (int i = 0; i < BUFFER_COUNT-1; i++) {
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer));
+ ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, -1));
+ }
+
+ // Dequeue 1 buffer
+ ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(window.get(), &buffer));
+
+ // Acquire and free 1+extraDiscardedBuffers buffer, check onBufferReleased is called.
+ std::vector<BufferItem> releasedItems;
+ releasedItems.resize(1+extraDiscardedBuffers);
+ for (int i = 0; i < releasedItems.size(); i++) {
+ ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&releasedItems[i], 0));
+ ASSERT_EQ(NO_ERROR, consumer->releaseBuffer(releasedItems[i].mSlot,
+ releasedItems[i].mFrameNumber, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE));
+ }
+ int32_t expectedReleaseCb = (enableReleasedCb ? releasedItems.size() : 0);
+ if (hasSurfaceListener) {
+ ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount());
+ }
+
+ // Acquire 1 buffer, leaving 1+extraDiscardedBuffers filled buffer in queue
+ BufferItem item;
+ ASSERT_EQ(NO_ERROR, consumer->acquireBuffer(&item, 0));
+
+ // Discard free buffers
+ ASSERT_EQ(NO_ERROR, consumer->discardFreeBuffers());
+
+ if (hasSurfaceListener) {
+ ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount());
+
+ // Check onBufferDiscarded is called with correct buffer
+ auto discardedBuffers = listener->getDiscardedBuffers();
+ ASSERT_EQ(discardedBuffers.size(), releasedItems.size());
+ for (int i = 0; i < releasedItems.size(); i++) {
+ ASSERT_EQ(discardedBuffers[i], releasedItems[i].mGraphicBuffer);
+ }
+
+ ASSERT_EQ(expectedReleaseCb, listener->getReleaseNotifyCount());
+ }
+
+ // Disconnect the surface
+ ASSERT_EQ(NO_ERROR, surface->disconnect(NATIVE_WINDOW_API_CPU));
+ }
+
sp<Surface> mSurface;
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mSurfaceControl;
@@ -480,6 +591,21 @@
ASSERT_LE(removedBuffers.size(), 1u);
}
+TEST_F(SurfaceTest, SurfaceListenerTest) {
+ // Test discarding 1 free buffers with no listener
+ testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/0);
+ // Test discarding 2 free buffers with no listener
+ testSurfaceListener(/*hasListener*/false, /*enableReleaseCb*/false, /*extraDiscardedBuffers*/1);
+ // Test discarding 1 free buffers with a listener, disabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/0);
+ // Test discarding 2 free buffers with a listener, disabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/false, /*extraDiscardedBuffers*/1);
+ // Test discarding 1 free buffers with a listener, enabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/0);
+ // Test discarding 3 free buffers with a listener, enabling onBufferReleased
+ testSurfaceListener(/*hasListener*/true, /*enableReleasedCb*/true, /*extraDiscardedBuffers*/2);
+}
+
TEST_F(SurfaceTest, TestGetLastDequeueStartTime) {
sp<ANativeWindow> anw(mSurface);
ASSERT_EQ(NO_ERROR, native_window_api_connect(anw.get(), NATIVE_WINDOW_API_CPU));
@@ -491,7 +617,7 @@
anw->dequeueBuffer(anw.get(), &buffer, &fenceFd);
nsecs_t after = systemTime(CLOCK_MONOTONIC);
- nsecs_t lastDequeueTime = mSurface->getLastDequeueStartTime();
+ nsecs_t lastDequeueTime = ANativeWindow_getLastDequeueStartTime(anw.get());
ASSERT_LE(before, lastDequeueTime);
ASSERT_GE(after, lastDequeueTime);
}
@@ -562,6 +688,7 @@
const sp<IBinder>& /*applyToken*/,
const InputWindowCommands& /*inputWindowCommands*/,
int64_t /*desiredPresentTime*/, const client_cache_t& /*cachedBuffer*/,
+ bool /*hasListenerCallbacks*/,
const std::vector<ListenerCallbacks>& /*listenerCallbacks*/) override {
}
@@ -1746,4 +1873,74 @@
EXPECT_EQ(-1, outDisplayPresentTime);
}
+TEST_F(SurfaceTest, DequeueWithConsumerDrivenSize) {
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ sp<DummyConsumer> dummyConsumer(new DummyConsumer);
+ consumer->consumerConnect(dummyConsumer, false);
+ consumer->setDefaultBufferSize(10, 10);
+
+ sp<Surface> surface = new Surface(producer);
+ sp<ANativeWindow> window(surface);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+ native_window_set_buffers_dimensions(window.get(), 0, 0);
+
+ int fence;
+ ANativeWindowBuffer* buffer;
+
+ // Buffer size is driven by the consumer
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(10, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Buffer size is driven by the consumer
+ consumer->setDefaultBufferSize(10, 20);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Transform hint isn't synced to producer before queueBuffer or connect
+ consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->queueBuffer(window.get(), buffer, fence));
+
+ // Transform hint is synced to producer but no auto prerotation
+ consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Prerotation is driven by the consumer with the transform hint used by producer
+ native_window_set_auto_prerotation(window.get(), true);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(20, buffer->width);
+ EXPECT_EQ(10, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Turn off auto prerotaton
+ native_window_set_auto_prerotation(window.get(), false);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+
+ // Test auto prerotation bit is disabled after disconnect
+ native_window_set_auto_prerotation(window.get(), true);
+ native_window_api_disconnect(window.get(), NATIVE_WINDOW_API_CPU);
+ native_window_api_connect(window.get(), NATIVE_WINDOW_API_CPU);
+ consumer->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_270);
+ native_window_set_buffers_dimensions(window.get(), 0, 0);
+ ASSERT_EQ(NO_ERROR, window->dequeueBuffer(window.get(), &buffer, &fence));
+ EXPECT_EQ(10, buffer->width);
+ EXPECT_EQ(20, buffer->height);
+ ASSERT_EQ(NO_ERROR, window->cancelBuffer(window.get(), buffer, fence));
+}
+
} // namespace android
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 2d78811..8efaf3d 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -48,6 +48,7 @@
"InputTransport.cpp",
"InputWindow.cpp",
"ISetInputWindowsListener.cpp",
+ "LatencyStatistics.cpp",
"VelocityControl.cpp",
"VelocityTracker.cpp",
],
@@ -55,7 +56,7 @@
shared_libs: [
"libutils",
"libbinder",
- "libui"
+ "libui",
],
sanitize: {
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
index d6a73bf..8ec5165 100644
--- a/libs/input/IInputFlinger.cpp
+++ b/libs/input/IInputFlinger.cpp
@@ -45,16 +45,6 @@
IBinder::FLAG_ONEWAY);
}
- virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
- Parcel data, reply;
- data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
-
- data.writeStrongBinder(fromToken);
- data.writeStrongBinder(toToken);
- remote()->transact(BnInputFlinger::TRANSFER_TOUCH_FOCUS, data, &reply,
- IBinder::FLAG_ONEWAY);
- }
-
virtual void registerInputChannel(const sp<InputChannel>& channel) {
Parcel data, reply;
data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
@@ -92,25 +82,16 @@
}
case REGISTER_INPUT_CHANNEL_TRANSACTION: {
CHECK_INTERFACE(IInputFlinger, data, reply);
- sp<InputChannel> channel = new InputChannel();
- channel->read(data);
+ sp<InputChannel> channel = InputChannel::read(data);
registerInputChannel(channel);
break;
}
case UNREGISTER_INPUT_CHANNEL_TRANSACTION: {
CHECK_INTERFACE(IInputFlinger, data, reply);
- sp<InputChannel> channel = new InputChannel();
- channel->read(data);
+ sp<InputChannel> channel = InputChannel::read(data);
unregisterInputChannel(channel);
break;
}
- case TRANSFER_TOUCH_FOCUS: {
- CHECK_INTERFACE(IInputFlinger, data, reply);
- sp<IBinder> fromToken = data.readStrongBinder();
- sp<IBinder> toToken = data.readStrongBinder();
- transferTouchFocus(fromToken, toToken);
- break;
- }
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 9fd25f9..34b305e 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -17,7 +17,6 @@
#define LOG_TAG "Input"
//#define LOG_NDEBUG 0
-#include <math.h>
#include <limits.h>
#include <input/Input.h>
@@ -235,26 +234,14 @@
// --- MotionEvent ---
-void MotionEvent::initialize(
- int32_t deviceId,
- int32_t source,
- int32_t displayId,
- int32_t action,
- int32_t actionButton,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- MotionClassification classification,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- size_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords) {
+void MotionEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t edgeFlags,
+ int32_t metaState, int32_t buttonState,
+ MotionClassification classification, float xOffset, float yOffset,
+ float xPrecision, float yPrecision, float rawXCursorPosition,
+ float rawYCursorPosition, nsecs_t downTime, nsecs_t eventTime,
+ size_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords) {
InputEvent::initialize(deviceId, source, displayId);
mAction = action;
mActionButton = actionButton;
@@ -267,6 +254,8 @@
mYOffset = yOffset;
mXPrecision = xPrecision;
mYPrecision = yPrecision;
+ mRawXCursorPosition = rawXCursorPosition;
+ mRawYCursorPosition = rawYCursorPosition;
mDownTime = downTime;
mPointerProperties.clear();
mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -288,6 +277,8 @@
mYOffset = other->mYOffset;
mXPrecision = other->mXPrecision;
mYPrecision = other->mYPrecision;
+ mRawXCursorPosition = other->mRawXCursorPosition;
+ mRawYCursorPosition = other->mRawYCursorPosition;
mDownTime = other->mDownTime;
mPointerProperties = other->mPointerProperties;
@@ -312,6 +303,21 @@
mSamplePointerCoords.appendArray(pointerCoords, getPointerCount());
}
+float MotionEvent::getXCursorPosition() const {
+ const float rawX = getRawXCursorPosition();
+ return rawX + mXOffset;
+}
+
+float MotionEvent::getYCursorPosition() const {
+ const float rawY = getRawYCursorPosition();
+ return rawY + mYOffset;
+}
+
+void MotionEvent::setCursorPosition(float x, float y) {
+ mRawXCursorPosition = x - mXOffset;
+ mRawYCursorPosition = y - mYOffset;
+}
+
const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const {
return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex];
}
@@ -431,6 +437,15 @@
float originX, originY;
transformPoint(matrix, 0, 0, &originX, &originY);
+ // Apply the transformation to cursor position.
+ if (isValidCursorPosition(mRawXCursorPosition, mRawYCursorPosition)) {
+ float x = mRawXCursorPosition + oldXOffset;
+ float y = mRawYCursorPosition + oldYOffset;
+ transformPoint(matrix, x, y, &x, &y);
+ mRawXCursorPosition = x - mXOffset;
+ mRawYCursorPosition = y - mYOffset;
+ }
+
// Apply the transformation to all samples.
size_t numSamples = mSamplePointerCoords.size();
for (size_t i = 0; i < numSamples; i++) {
@@ -470,6 +485,8 @@
mYOffset = parcel->readFloat();
mXPrecision = parcel->readFloat();
mYPrecision = parcel->readFloat();
+ mRawXCursorPosition = parcel->readFloat();
+ mRawYCursorPosition = parcel->readFloat();
mDownTime = parcel->readInt64();
mPointerProperties.clear();
@@ -521,6 +538,8 @@
parcel->writeFloat(mYOffset);
parcel->writeFloat(mXPrecision);
parcel->writeFloat(mYPrecision);
+ parcel->writeFloat(mRawXCursorPosition);
+ parcel->writeFloat(mRawYCursorPosition);
parcel->writeInt64(mDownTime);
for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index d02cb8e..366c93c 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -191,6 +191,10 @@
msg->body.motion.xPrecision = body.motion.xPrecision;
// float yPrecision
msg->body.motion.yPrecision = body.motion.yPrecision;
+ // float xCursorPosition
+ msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
+ // float yCursorPosition
+ msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
// uint32_t pointerCount
msg->body.motion.pointerCount = body.motion.pointerCount;
//struct Pointer pointers[MAX_POINTERS]
@@ -222,35 +226,28 @@
// --- InputChannel ---
-InputChannel::InputChannel(const std::string& name, int fd) :
- mName(name) {
+sp<InputChannel> InputChannel::create(const std::string& name, android::base::unique_fd fd) {
+ const int result = fcntl(fd, F_SETFL, O_NONBLOCK);
+ if (result != 0) {
+ LOG_ALWAYS_FATAL("channel '%s' ~ Could not make socket non-blocking: %s", name.c_str(),
+ strerror(errno));
+ return nullptr;
+ }
+ return new InputChannel(name, std::move(fd));
+}
+
+InputChannel::InputChannel(const std::string& name, android::base::unique_fd fd)
+ : mName(name), mFd(std::move(fd)) {
#if DEBUG_CHANNEL_LIFECYCLE
ALOGD("Input channel constructed: name='%s', fd=%d",
mName.c_str(), fd);
#endif
-
- setFd(fd);
}
InputChannel::~InputChannel() {
#if DEBUG_CHANNEL_LIFECYCLE
- ALOGD("Input channel destroyed: name='%s', fd=%d",
- mName.c_str(), mFd);
+ ALOGD("Input channel destroyed: name='%s', fd=%d", mName.c_str(), mFd.get());
#endif
-
- ::close(mFd);
-}
-
-void InputChannel::setFd(int fd) {
- if (mFd > 0) {
- ::close(mFd);
- }
- mFd = fd;
- if (mFd > 0) {
- int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
- LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
- "non-blocking. errno=%d", mName.c_str(), errno);
- }
}
status_t InputChannel::openInputChannelPair(const std::string& name,
@@ -271,13 +268,13 @@
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
- std::string serverChannelName = name;
- serverChannelName += " (server)";
- outServerChannel = new InputChannel(serverChannelName, sockets[0]);
+ std::string serverChannelName = name + " (server)";
+ android::base::unique_fd serverFd(sockets[0]);
+ outServerChannel = InputChannel::create(serverChannelName, std::move(serverFd));
- std::string clientChannelName = name;
- clientChannelName += " (client)";
- outClientChannel = new InputChannel(clientChannelName, sockets[1]);
+ std::string clientChannelName = name + " (client)";
+ android::base::unique_fd clientFd(sockets[1]);
+ outClientChannel = InputChannel::create(clientChannelName, std::move(clientFd));
return OK;
}
@@ -287,7 +284,7 @@
msg->getSanitizedCopy(&cleanMsg);
ssize_t nWrite;
do {
- nWrite = ::send(mFd, &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
+ nWrite = ::send(mFd.get(), &cleanMsg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL);
} while (nWrite == -1 && errno == EINTR);
if (nWrite < 0) {
@@ -322,7 +319,7 @@
status_t InputChannel::receiveMessage(InputMessage* msg) {
ssize_t nRead;
do {
- nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT);
+ nRead = ::recv(mFd.get(), msg, sizeof(InputMessage), MSG_DONTWAIT);
} while (nRead == -1 && errno == EINTR);
if (nRead < 0) {
@@ -360,39 +357,51 @@
}
sp<InputChannel> InputChannel::dup() const {
- int fd = ::dup(getFd());
- return fd >= 0 ? new InputChannel(getName(), fd) : nullptr;
+ android::base::unique_fd newFd(::dup(getFd()));
+ if (!newFd.ok()) {
+ ALOGE("Could not duplicate fd %i for channel %s: %s", getFd(), mName.c_str(),
+ strerror(errno));
+ const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
+ // If this process is out of file descriptors, then throwing that might end up exploding
+ // on the other side of a binder call, which isn't really helpful.
+ // Better to just crash here and hope that the FD leak is slow.
+ // Other failures could be client errors, so we still propagate those back to the caller.
+ LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
+ getName().c_str());
+ return nullptr;
+ }
+ return InputChannel::create(mName, std::move(newFd));
}
-
status_t InputChannel::write(Parcel& out) const {
- status_t s = out.writeString8(String8(getName().c_str()));
-
+ status_t s = out.writeCString(getName().c_str());
if (s != OK) {
return s;
}
+
s = out.writeStrongBinder(mToken);
if (s != OK) {
return s;
}
- s = out.writeDupFileDescriptor(getFd());
-
+ s = out.writeUniqueFileDescriptor(mFd);
return s;
}
-status_t InputChannel::read(const Parcel& from) {
- mName = from.readString8();
- mToken = from.readStrongBinder();
-
- int rawFd = from.readFileDescriptor();
- setFd(::dup(rawFd));
-
- if (mFd < 0) {
- return BAD_VALUE;
+sp<InputChannel> InputChannel::read(const Parcel& from) {
+ std::string name = from.readCString();
+ sp<IBinder> token = from.readStrongBinder();
+ android::base::unique_fd rawFd;
+ status_t fdResult = from.readUniqueFileDescriptor(&rawFd);
+ if (fdResult != OK) {
+ return nullptr;
}
- return OK;
+ sp<InputChannel> channel = InputChannel::create(name, std::move(rawFd));
+ if (channel != nullptr) {
+ channel->setToken(token);
+ }
+ return channel;
}
sp<IBinder> InputChannel::getToken() const {
@@ -465,26 +474,12 @@
}
status_t InputPublisher::publishMotionEvent(
- uint32_t seq,
- int32_t deviceId,
- int32_t source,
- int32_t displayId,
- int32_t action,
- int32_t actionButton,
- int32_t flags,
- int32_t edgeFlags,
- int32_t metaState,
- int32_t buttonState,
- MotionClassification classification,
- float xOffset,
- float yOffset,
- float xPrecision,
- float yPrecision,
- nsecs_t downTime,
- nsecs_t eventTime,
- uint32_t pointerCount,
- const PointerProperties* pointerProperties,
- const PointerCoords* pointerCoords) {
+ uint32_t seq, int32_t deviceId, int32_t source, int32_t displayId, int32_t action,
+ int32_t actionButton, int32_t flags, int32_t edgeFlags, int32_t metaState,
+ int32_t buttonState, MotionClassification classification, float xOffset, float yOffset,
+ float xPrecision, float yPrecision, float xCursorPosition, float yCursorPosition,
+ nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
+ const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) {
if (ATRACE_ENABLED()) {
std::string message = StringPrintf(
"publishMotionEvent(inputChannel=%s, action=%" PRId32 ")",
@@ -532,6 +527,8 @@
msg.body.motion.yOffset = yOffset;
msg.body.motion.xPrecision = xPrecision;
msg.body.motion.yPrecision = yPrecision;
+ msg.body.motion.xCursorPosition = xCursorPosition;
+ msg.body.motion.yCursorPosition = yCursorPosition;
msg.body.motion.downTime = downTime;
msg.body.motion.eventTime = eventTime;
msg.body.motion.pointerCount = pointerCount;
@@ -539,6 +536,7 @@
msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]);
msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]);
}
+
return mChannel->sendMessage(&msg);
}
@@ -1135,26 +1133,16 @@
pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords);
}
- event->initialize(
- msg->body.motion.deviceId,
- msg->body.motion.source,
- msg->body.motion.displayId,
- msg->body.motion.action,
- msg->body.motion.actionButton,
- msg->body.motion.flags,
- msg->body.motion.edgeFlags,
- msg->body.motion.metaState,
- msg->body.motion.buttonState,
- msg->body.motion.classification,
- msg->body.motion.xOffset,
- msg->body.motion.yOffset,
- msg->body.motion.xPrecision,
- msg->body.motion.yPrecision,
- msg->body.motion.downTime,
- msg->body.motion.eventTime,
- pointerCount,
- pointerProperties,
- pointerCoords);
+ event->initialize(msg->body.motion.deviceId, msg->body.motion.source,
+ msg->body.motion.displayId, msg->body.motion.action,
+ msg->body.motion.actionButton, msg->body.motion.flags,
+ msg->body.motion.edgeFlags, msg->body.motion.metaState,
+ msg->body.motion.buttonState, msg->body.motion.classification,
+ msg->body.motion.xOffset, msg->body.motion.yOffset,
+ msg->body.motion.xPrecision, msg->body.motion.yPrecision,
+ msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
+ msg->body.motion.downTime, msg->body.motion.eventTime, pointerCount,
+ pointerProperties, pointerCoords);
}
void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) {
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index 0c22bfe..56900c1 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -38,29 +38,29 @@
KeyMap::~KeyMap() {
}
-status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
+status_t KeyMap::load(const InputDeviceIdentifier& deviceIdentifier,
const PropertyMap* deviceConfiguration) {
// Use the configured key layout if available.
if (deviceConfiguration) {
String8 keyLayoutName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
keyLayoutName)) {
- status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName.c_str());
+ status_t status = loadKeyLayout(deviceIdentifier, keyLayoutName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
"it was not found.",
- deviceIdenfifier.name.c_str(), keyLayoutName.string());
+ deviceIdentifier.name.c_str(), keyLayoutName.string());
}
}
String8 keyCharacterMapName;
if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName.c_str());
+ status_t status = loadKeyCharacterMap(deviceIdentifier, keyCharacterMapName.c_str());
if (status == NAME_NOT_FOUND) {
ALOGE("Configuration for keyboard device '%s' requested keyboard character "
"map '%s' but it was not found.",
- deviceIdenfifier.name.c_str(), keyLayoutName.string());
+ deviceIdentifier.name.c_str(), keyCharacterMapName.string());
}
}
@@ -70,25 +70,25 @@
}
// Try searching by device identifier.
- if (probeKeyMap(deviceIdenfifier, "")) {
+ if (probeKeyMap(deviceIdentifier, "")) {
return OK;
}
// Fall back on the Generic key map.
// TODO Apply some additional heuristics here to figure out what kind of
// generic key map to use (US English, etc.) for typical external keyboards.
- if (probeKeyMap(deviceIdenfifier, "Generic")) {
+ if (probeKeyMap(deviceIdentifier, "Generic")) {
return OK;
}
// Try the Virtual key map as a last resort.
- if (probeKeyMap(deviceIdenfifier, "Virtual")) {
+ if (probeKeyMap(deviceIdentifier, "Virtual")) {
return OK;
}
// Give up!
ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
- deviceIdenfifier.name.c_str());
+ deviceIdentifier.name.c_str());
return NAME_NOT_FOUND;
}
diff --git a/libs/input/LatencyStatistics.cpp b/libs/input/LatencyStatistics.cpp
new file mode 100644
index 0000000..394da22
--- /dev/null
+++ b/libs/input/LatencyStatistics.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <input/LatencyStatistics.h>
+
+#include <android-base/chrono_utils.h>
+
+#include <cmath>
+#include <limits>
+
+namespace android {
+
+LatencyStatistics::LatencyStatistics(std::chrono::seconds period) : mReportPeriod(period) {
+ reset();
+}
+
+/**
+ * Add a raw value to the statistics
+ */
+void LatencyStatistics::addValue(float value) {
+ if (value < mMin) {
+ mMin = value;
+ }
+ if (value > mMax) {
+ mMax = value;
+ }
+ mSum += value;
+ mSum2 += value * value;
+ mCount++;
+}
+
+/**
+ * Get the mean. Should not be called if no samples have been added.
+ */
+float LatencyStatistics::getMean() {
+ return mSum / mCount;
+}
+
+/**
+ * Get the standard deviation. Should not be called if no samples have been added.
+ */
+float LatencyStatistics::getStDev() {
+ float mean = getMean();
+ return sqrt(mSum2 / mCount - mean * mean);
+}
+
+float LatencyStatistics::getMin() {
+ return mMin;
+}
+
+float LatencyStatistics::getMax() {
+ return mMax;
+}
+
+size_t LatencyStatistics::getCount() {
+ return mCount;
+}
+
+/**
+ * Reset internal state. The variable 'when' is the time when the data collection started.
+ * Call this to start a new data collection window.
+ */
+void LatencyStatistics::reset() {
+ mMax = std::numeric_limits<float>::lowest();
+ mMin = std::numeric_limits<float>::max();
+ mSum = 0;
+ mSum2 = 0;
+ mCount = 0;
+ mLastReportTime = std::chrono::steady_clock::now();
+}
+
+bool LatencyStatistics::shouldReport() {
+ std::chrono::duration timeSinceReport = std::chrono::steady_clock::now() - mLastReportTime;
+ return mCount != 0 && timeSinceReport >= mReportPeriod;
+}
+
+} // namespace android
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index ade931e..c1c35e1 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -7,6 +7,7 @@
"InputEvent_test.cpp",
"InputPublisherAndConsumer_test.cpp",
"InputWindow_test.cpp",
+ "LatencyStatistics_test.cpp",
"TouchVideoFrame_test.cpp",
"VelocityTracker_test.cpp",
],
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index f1675c0..af74edd 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -22,11 +22,12 @@
#include <time.h>
#include <errno.h>
+#include <binder/Binder.h>
#include <gtest/gtest.h>
#include <input/InputTransport.h>
-#include <utils/Timers.h>
#include <utils/StopWatch.h>
#include <utils/StrongPointer.h>
+#include <utils/Timers.h>
namespace android {
@@ -43,20 +44,28 @@
// of a pipe and to check for EPIPE on the other end after the channel is destroyed.
Pipe pipe;
- sp<InputChannel> inputChannel = new InputChannel("channel name", pipe.sendFd);
+ android::base::unique_fd sendFd(pipe.sendFd);
+ sp<InputChannel> inputChannel = InputChannel::create("channel name", std::move(sendFd));
+
+ EXPECT_NE(inputChannel, nullptr) << "channel should be successfully created";
EXPECT_STREQ("channel name", inputChannel->getName().c_str())
<< "channel should have provided name";
- EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
- << "channel should have provided fd";
+ EXPECT_NE(-1, inputChannel->getFd()) << "channel should have valid fd";
- inputChannel.clear(); // destroys input channel
+ // InputChannel should be the owner of the file descriptor now
+ ASSERT_FALSE(sendFd.ok());
+}
- EXPECT_EQ(-EPIPE, pipe.readSignal())
- << "channel should have closed fd when destroyed";
+TEST_F(InputChannelTest, SetAndGetToken) {
+ Pipe pipe;
+ sp<InputChannel> channel =
+ InputChannel::create("test channel", android::base::unique_fd(pipe.sendFd));
+ EXPECT_EQ(channel->getToken(), nullptr);
- // clean up fds of Pipe endpoints that were closed so we don't try to close them again
- pipe.sendFd = -1;
+ sp<IBinder> token = new BBinder();
+ channel->setToken(token);
+ EXPECT_EQ(token, channel->getToken());
}
TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index 2b75c82..b90857c 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -255,11 +255,11 @@
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
- AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
- AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
- MotionClassification::NONE, X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
- ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME,
- 2, pointerProperties, pointerCoords);
+ AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, AMOTION_EVENT_EDGE_FLAG_TOP,
+ AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY, MotionClassification::NONE,
+ X_OFFSET, Y_OFFSET, 2.0f, 2.1f, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, ARBITRARY_DOWN_TIME,
+ ARBITRARY_EVENT_TIME, 2, pointerProperties, pointerCoords);
pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -571,10 +571,11 @@
}
MotionEvent event;
event.initialize(0 /*deviceId*/, AINPUT_SOURCE_UNKNOWN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
- 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE,
- AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
- 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
- 0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+ 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+ 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/, 0 /*yOffset*/,
+ 0 /*xPrecision*/, 0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/,
+ 2 /*yCursorPosition*/, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
+ pointerProperties, pointerCoords);
float originalRawX = 0 + 3;
float originalRawY = -RADIUS + 2;
@@ -602,6 +603,14 @@
ASSERT_NEAR(tanf(angle), tanf(event.getOrientation(i)), 0.1);
}
+ // Check cursor positions. The original cursor position is at (3 + RADIUS, 2), where the center
+ // of the circle is (3, 2), so the cursor position is to the right of the center of the circle.
+ // The choice of triangular functions in this test defines the angle of rotation clockwise
+ // relative to the y-axis. Therefore the cursor position's angle is 90 degrees. Here we swap the
+ // triangular function so that we don't have to add the 90 degrees.
+ ASSERT_NEAR(cosf(PI_180 * ROTATION) * RADIUS, event.getXCursorPosition(), 0.001);
+ ASSERT_NEAR(sinf(PI_180 * ROTATION) * RADIUS, event.getYCursorPosition(), 0.001);
+
// Applying the transformation should preserve the raw X and Y of the first point.
ASSERT_NEAR(originalRawX, event.getRawX(0), 0.001);
ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
@@ -626,11 +635,44 @@
for (MotionClassification classification : classifications) {
event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0,
- classification, 0, 0, 0, 0, 0 /*downTime*/, 0 /*eventTime*/,
- pointerCount, pointerProperties, pointerCoords);
+ AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+ 0, classification, 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/, 0 /*eventTime*/,
+ pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(classification, event.getClassification());
}
}
+TEST_F(MotionEventTest, Initialize_SetsCursorPosition) {
+ MotionEvent event;
+ constexpr size_t pointerCount = 1;
+ PointerProperties pointerProperties[pointerCount];
+ PointerCoords pointerCoords[pointerCount];
+ for (size_t i = 0; i < pointerCount; i++) {
+ pointerProperties[i].clear();
+ pointerProperties[i].id = i;
+ pointerCoords[i].clear();
+ }
+
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0,
+ 0, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE, 0,
+ 0, 0, 0, 280 /*xCursorPosition*/, 540 /*yCursorPosition*/, 0 /*downTime*/,
+ 0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
+ event.offsetLocation(20, 60);
+ ASSERT_EQ(280, event.getRawXCursorPosition());
+ ASSERT_EQ(540, event.getRawYCursorPosition());
+ ASSERT_EQ(300, event.getXCursorPosition());
+ ASSERT_EQ(600, event.getYCursorPosition());
+}
+
+TEST_F(MotionEventTest, SetCursorPosition) {
+ MotionEvent event;
+ initializeEventWithHistory(&event);
+ event.setSource(AINPUT_SOURCE_MOUSE);
+
+ event.setCursorPosition(3, 4);
+ ASSERT_EQ(3, event.getXCursorPosition());
+ ASSERT_EQ(4, event.getYCursorPosition());
+}
+
} // namespace android
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index f2cd1be..a362f32 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -146,6 +146,8 @@
constexpr float yOffset = -20;
constexpr float xPrecision = 0.25;
constexpr float yPrecision = 0.5;
+ constexpr float xCursorPosition = 1.3;
+ constexpr float yCursorPosition = 50.6;
constexpr nsecs_t downTime = 3;
constexpr size_t pointerCount = 3;
constexpr nsecs_t eventTime = 4;
@@ -168,10 +170,12 @@
pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 3.5 * i);
}
- status = mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
- flags, edgeFlags, metaState, buttonState, classification,
- xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount,
- pointerProperties, pointerCoords);
+ status =
+ mPublisher->publishMotionEvent(seq, deviceId, source, displayId, action, actionButton,
+ flags, edgeFlags, metaState, buttonState, classification,
+ xOffset, yOffset, xPrecision, yPrecision,
+ xCursorPosition, yCursorPosition, downTime, eventTime,
+ pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(OK, status)
<< "publisher publishMotionEvent should return OK";
@@ -199,6 +203,10 @@
EXPECT_EQ(classification, motionEvent->getClassification());
EXPECT_EQ(xPrecision, motionEvent->getXPrecision());
EXPECT_EQ(yPrecision, motionEvent->getYPrecision());
+ EXPECT_EQ(xCursorPosition, motionEvent->getRawXCursorPosition());
+ EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
+ EXPECT_EQ(xCursorPosition + xOffset, motionEvent->getXCursorPosition());
+ EXPECT_EQ(yCursorPosition + yOffset, motionEvent->getYCursorPosition());
EXPECT_EQ(downTime, motionEvent->getDownTime());
EXPECT_EQ(eventTime, motionEvent->getEventTime());
EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -266,9 +274,11 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
+ status =
+ mPublisher->publishMotionEvent(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE,
+ 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+ pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
@@ -279,9 +289,11 @@
PointerProperties pointerProperties[pointerCount];
PointerCoords pointerCoords[pointerCount];
- status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
+ status =
+ mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE,
+ 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+ pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
@@ -297,9 +309,11 @@
pointerCoords[i].clear();
}
- status = mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- MotionClassification::NONE, 0, 0, 0, 0, 0, 0,
- pointerCount, pointerProperties, pointerCoords);
+ status =
+ mPublisher->publishMotionEvent(1, 0, 0, 0, 0, 0, 0, 0, 0, 0, MotionClassification::NONE,
+ 0, 0, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, 0,
+ pointerCount, pointerProperties, pointerCoords);
ASSERT_EQ(BAD_VALUE, status)
<< "publisher publishMotionEvent should return BAD_VALUE";
}
diff --git a/libs/input/tests/LatencyStatistics_test.cpp b/libs/input/tests/LatencyStatistics_test.cpp
new file mode 100644
index 0000000..eb12d4e
--- /dev/null
+++ b/libs/input/tests/LatencyStatistics_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+#include <input/LatencyStatistics.h>
+#include <cmath>
+#include <limits>
+#include <thread>
+
+namespace android {
+namespace test {
+
+TEST(LatencyStatisticsTest, ResetStats) {
+ LatencyStatistics stats{5min};
+ stats.addValue(5.0);
+ stats.addValue(19.3);
+ stats.addValue(20);
+ stats.reset();
+
+ ASSERT_EQ(stats.getCount(), 0u);
+ ASSERT_EQ(std::isnan(stats.getStDev()), true);
+ ASSERT_EQ(std::isnan(stats.getMean()), true);
+}
+
+TEST(LatencyStatisticsTest, AddStatsValue) {
+ LatencyStatistics stats{5min};
+ stats.addValue(5.0);
+
+ ASSERT_EQ(stats.getMin(), 5.0);
+ ASSERT_EQ(stats.getMax(), 5.0);
+ ASSERT_EQ(stats.getCount(), 1u);
+ ASSERT_EQ(stats.getMean(), 5.0);
+ ASSERT_EQ(stats.getStDev(), 0.0);
+}
+
+TEST(LatencyStatisticsTest, AddMultipleStatsValue) {
+ LatencyStatistics stats{5min};
+ stats.addValue(4.0);
+ stats.addValue(6.0);
+ stats.addValue(8.0);
+ stats.addValue(10.0);
+
+ float stdev = stats.getStDev();
+
+ ASSERT_EQ(stats.getMin(), 4.0);
+ ASSERT_EQ(stats.getMax(), 10.0);
+ ASSERT_EQ(stats.getCount(), 4u);
+ ASSERT_EQ(stats.getMean(), 7.0);
+ ASSERT_EQ(stdev * stdev, 5.0);
+}
+
+TEST(LatencyStatisticsTest, ShouldReportStats) {
+ LatencyStatistics stats{0min};
+ stats.addValue(5.0);
+
+ std::this_thread::sleep_for(1us);
+
+ ASSERT_EQ(stats.shouldReport(), true);
+}
+
+} // namespace test
+} // namespace android
\ No newline at end of file
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 62023fb..8d8cf06 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -64,8 +64,10 @@
CHECK_OFFSET(InputMessage::Body::Motion, yOffset, 68);
CHECK_OFFSET(InputMessage::Body::Motion, xPrecision, 72);
CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 76);
- CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 80);
- CHECK_OFFSET(InputMessage::Body::Motion, pointers, 88);
+ CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 80);
+ CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 84);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 88);
+ CHECK_OFFSET(InputMessage::Body::Motion, pointers, 96);
CHECK_OFFSET(InputMessage::Body::Finished, seq, 0);
CHECK_OFFSET(InputMessage::Body::Finished, handled, 4);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 368446f..968e2fa 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -176,12 +176,13 @@
EXPECT_EQ(pointerIndex, pointerCount);
MotionEvent event;
- event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
- action, 0 /*actionButton*/, 0 /*flags*/,
- AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
- MotionClassification::NONE,
- 0 /*xOffset*/, 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
- 0 /*downTime*/, entry.eventTime.count(), pointerCount, properties, coords);
+ event.initialize(0 /*deviceId*/, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, action,
+ 0 /*actionButton*/, 0 /*flags*/, AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE,
+ 0 /*buttonState*/, MotionClassification::NONE, 0 /*xOffset*/,
+ 0 /*yOffset*/, 0 /*xPrecision*/, 0 /*yPrecision*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0 /*downTime*/,
+ entry.eventTime.count(), pointerCount, properties, coords);
events.emplace_back(event);
}
diff --git a/libs/nativewindow/ANativeWindow.cpp b/libs/nativewindow/ANativeWindow.cpp
index 8435dac..0ba01f4 100644
--- a/libs/nativewindow/ANativeWindow.cpp
+++ b/libs/nativewindow/ANativeWindow.cpp
@@ -33,6 +33,12 @@
return res < 0 ? res : value;
}
+static int64_t query64(ANativeWindow* window, int what) {
+ int64_t value;
+ int res = window->perform(window, what, &value);
+ return res < 0 ? res : value;
+}
+
static bool isDataSpaceValid(ANativeWindow* window, int32_t dataSpace) {
bool supported = false;
switch (dataSpace) {
@@ -262,3 +268,27 @@
int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh) {
return native_window_set_auto_refresh(window, autoRefresh);
}
+
+int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation) {
+ return native_window_set_auto_prerotation(window, autoPrerotation);
+}
+
+/**************************************************************************************************
+ * apex-stable
+ **************************************************************************************************/
+
+int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window) {
+ return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION);
+}
+
+int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window) {
+ return query64(window, NATIVE_WINDOW_GET_LAST_QUEUE_DURATION);
+}
+
+int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window) {
+ return query64(window, NATIVE_WINDOW_GET_LAST_DEQUEUE_START);
+}
+
+int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout) {
+ return window->perform(window, NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT, timeout);
+}
diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING
new file mode 100644
index 0000000..3d7f3c2
--- /dev/null
+++ b/libs/nativewindow/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "libnativewindow_test"
+ }
+ ]
+}
diff --git a/libs/nativewindow/include/apex/window.h b/libs/nativewindow/include/apex/window.h
new file mode 100644
index 0000000..869b22e
--- /dev/null
+++ b/libs/nativewindow/include/apex/window.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <nativebase/nativebase.h>
+
+// apex is a superset of the NDK
+#include <android/native_window.h>
+
+__BEGIN_DECLS
+
+/**
+ * Retrieves how long it took for the last time a buffer was dequeued.
+ *
+ * \return a negative value on error, otherwise returns the duration in
+ * nanoseconds
+ */
+int64_t ANativeWindow_getLastDequeueDuration(ANativeWindow* window);
+
+/**
+ * Retrieves how long it took for the last time a buffer was queued.
+ *
+ * \return a negative value on error, otherwise returns the duration in
+ * nanoseconds.
+ */
+int64_t ANativeWindow_getLastQueueDuration(ANativeWindow* window);
+
+/**
+ * Retrieves the system time in nanoseconds when the last time a buffer
+ * was dequeued.
+ *
+ * \return a negative value on error, otherwise returns the duration in
+ * nanoseconds.
+ */
+int64_t ANativeWindow_getLastDequeueStartTime(ANativeWindow* window);
+
+/**
+ * Sets a timeout in nanoseconds for dequeue calls. All subsequent dequeue calls
+ * made by the window will return -ETIMEDOUT after the timeout if the dequeue
+ * takes too long.
+ *
+ * \return NO_ERROR on succes, -errno on error.
+ */
+int ANativeWindow_setDequeueTimeout(ANativeWindow* window, int64_t timeout);
+
+__END_DECLS
diff --git a/libs/nativewindow/include/system/window.h b/libs/nativewindow/include/system/window.h
index 61590e0..1814ab5 100644
--- a/libs/nativewindow/include/system/window.h
+++ b/libs/nativewindow/include/system/window.h
@@ -41,7 +41,8 @@
#include <unistd.h>
#include <stdbool.h>
-// system/window.h is a superset of the vndk
+// system/window.h is a superset of the vndk and apex apis
+#include <apex/window.h>
#include <vndk/window.h>
@@ -62,9 +63,9 @@
/* attributes queriable with query() */
enum {
- NATIVE_WINDOW_WIDTH = 0,
- NATIVE_WINDOW_HEIGHT = 1,
- NATIVE_WINDOW_FORMAT = 2,
+ NATIVE_WINDOW_WIDTH = 0,
+ NATIVE_WINDOW_HEIGHT = 1,
+ NATIVE_WINDOW_FORMAT = 2,
/* see ANativeWindowQuery in vndk/window.h */
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS = ANATIVEWINDOW_QUERY_MIN_UNDEQUEUED_BUFFERS,
@@ -92,7 +93,6 @@
*/
NATIVE_WINDOW_CONCRETE_TYPE = 5,
-
/*
* Default width and height of ANativeWindow buffers, these are the
* dimensions of the window buffers irrespective of the
@@ -147,11 +147,15 @@
/*
* Returns the duration of the last dequeueBuffer call in microseconds
+ * Deprecated: please use NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION in
+ * perform() instead, which supports nanosecond precision.
*/
NATIVE_WINDOW_LAST_DEQUEUE_DURATION = 14,
/*
* Returns the duration of the last queueBuffer call in microseconds
+ * Deprecated: please use NATIVE_WINDOW_GET_LAST_QUEUE_DURATION in
+ * perform() instead, which supports nanosecond precision.
*/
NATIVE_WINDOW_LAST_QUEUE_DURATION = 15,
@@ -203,41 +207,46 @@
*/
enum {
// clang-format off
- NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
- NATIVE_WINDOW_CONNECT = 1, /* deprecated */
- NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
- NATIVE_WINDOW_SET_CROP = 3, /* private */
- NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
- NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
- NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
- NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
- NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
- NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
- NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
- NATIVE_WINDOW_LOCK = 11, /* private */
- NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
- NATIVE_WINDOW_API_CONNECT = 13, /* private */
- NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
- NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
- NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
- NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
- NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
- NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
- NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
- NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
- NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
- NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
- NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
- NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
- NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
- NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
- NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
- NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
- NATIVE_WINDOW_SET_USAGE64 = 30,
- NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
- NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
- NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
+ NATIVE_WINDOW_SET_USAGE = 0, /* deprecated */
+ NATIVE_WINDOW_CONNECT = 1, /* deprecated */
+ NATIVE_WINDOW_DISCONNECT = 2, /* deprecated */
+ NATIVE_WINDOW_SET_CROP = 3, /* private */
+ NATIVE_WINDOW_SET_BUFFER_COUNT = 4,
+ NATIVE_WINDOW_SET_BUFFERS_GEOMETRY = 5, /* deprecated */
+ NATIVE_WINDOW_SET_BUFFERS_TRANSFORM = 6,
+ NATIVE_WINDOW_SET_BUFFERS_TIMESTAMP = 7,
+ NATIVE_WINDOW_SET_BUFFERS_DIMENSIONS = 8,
+ NATIVE_WINDOW_SET_BUFFERS_FORMAT = 9,
+ NATIVE_WINDOW_SET_SCALING_MODE = 10, /* private */
+ NATIVE_WINDOW_LOCK = 11, /* private */
+ NATIVE_WINDOW_UNLOCK_AND_POST = 12, /* private */
+ NATIVE_WINDOW_API_CONNECT = 13, /* private */
+ NATIVE_WINDOW_API_DISCONNECT = 14, /* private */
+ NATIVE_WINDOW_SET_BUFFERS_USER_DIMENSIONS = 15, /* private */
+ NATIVE_WINDOW_SET_POST_TRANSFORM_CROP = 16, /* deprecated, unimplemented */
+ NATIVE_WINDOW_SET_BUFFERS_STICKY_TRANSFORM = 17, /* private */
+ NATIVE_WINDOW_SET_SIDEBAND_STREAM = 18,
+ NATIVE_WINDOW_SET_BUFFERS_DATASPACE = 19,
+ NATIVE_WINDOW_SET_SURFACE_DAMAGE = 20, /* private */
+ NATIVE_WINDOW_SET_SHARED_BUFFER_MODE = 21,
+ NATIVE_WINDOW_SET_AUTO_REFRESH = 22,
+ NATIVE_WINDOW_GET_REFRESH_CYCLE_DURATION = 23,
+ NATIVE_WINDOW_GET_NEXT_FRAME_ID = 24,
+ NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS = 25,
+ NATIVE_WINDOW_GET_COMPOSITOR_TIMING = 26,
+ NATIVE_WINDOW_GET_FRAME_TIMESTAMPS = 27,
+ NATIVE_WINDOW_GET_WIDE_COLOR_SUPPORT = 28,
+ NATIVE_WINDOW_GET_HDR_SUPPORT = 29,
+ NATIVE_WINDOW_SET_USAGE64 = 30,
+ NATIVE_WINDOW_GET_CONSUMER_USAGE64 = 31,
+ NATIVE_WINDOW_SET_BUFFERS_SMPTE2086_METADATA = 32,
+ NATIVE_WINDOW_SET_BUFFERS_CTA861_3_METADATA = 33,
NATIVE_WINDOW_SET_BUFFERS_HDR10_PLUS_METADATA = 34,
+ NATIVE_WINDOW_SET_AUTO_PREROTATION = 35,
+ NATIVE_WINDOW_GET_LAST_DEQUEUE_START = 36, /* private */
+ NATIVE_WINDOW_SET_DEQUEUE_TIMEOUT = 37, /* private */
+ NATIVE_WINDOW_GET_LAST_DEQUEUE_DURATION = 38, /* private */
+ NATIVE_WINDOW_GET_LAST_QUEUE_DURATION = 39, /* private */
// clang-format on
};
@@ -985,4 +994,18 @@
return window->perform(window, NATIVE_WINDOW_GET_CONSUMER_USAGE64, outUsage);
}
+/*
+ * native_window_set_auto_prerotation(..., autoPrerotation)
+ * Enable/disable the auto prerotation at buffer allocation when the buffer size
+ * is driven by the consumer.
+ *
+ * When buffer size is driven by the consumer and the transform hint specifies
+ * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and
+ * height used for dequeueBuffer will be additionally swapped.
+ */
+static inline int native_window_set_auto_prerotation(struct ANativeWindow* window,
+ bool autoPrerotation) {
+ return window->perform(window, NATIVE_WINDOW_SET_AUTO_PREROTATION, autoPrerotation);
+}
+
__END_DECLS
diff --git a/libs/nativewindow/include/vndk/window.h b/libs/nativewindow/include/vndk/window.h
index 995ba44..500052c 100644
--- a/libs/nativewindow/include/vndk/window.h
+++ b/libs/nativewindow/include/vndk/window.h
@@ -316,6 +316,15 @@
*/
int ANativeWindow_setAutoRefresh(ANativeWindow* window, bool autoRefresh);
+/*
+ * Enable/disable the auto prerotation at buffer allocation when the buffer size
+ * is driven by the consumer.
+ *
+ * When buffer size is driven by the consumer and the transform hint specifies
+ * a 90 or 270 degree rotation, if auto prerotation is enabled, the width and
+ * height used for dequeueBuffer will be additionally swapped.
+ */
+int ANativeWindow_setAutoPrerotation(ANativeWindow* window, bool autoPrerotation);
/*****************************************************************************/
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index bad8b11..b741faa 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -22,12 +22,16 @@
ANativeWindow_getBuffersDataSpace; # introduced=28
ANativeWindow_getFormat;
ANativeWindow_getHeight;
+ ANativeWindow_getLastDequeueDuration; # apex # introduced=30
+ ANativeWindow_getLastDequeueStartTime; # apex # introduced=30
+ ANativeWindow_getLastQueueDuration; # apex # introduced=30
ANativeWindow_getWidth;
ANativeWindow_lock;
ANativeWindow_query; # vndk
ANativeWindow_queryf; # vndk
ANativeWindow_queueBuffer; # vndk
ANativeWindow_release;
+ ANativeWindow_setAutoPrerotation; # vndk
ANativeWindow_setAutoRefresh; # vndk
ANativeWindow_setBufferCount; # vndk
ANativeWindow_setBuffersDataSpace; # introduced=28
@@ -36,6 +40,7 @@
ANativeWindow_setBuffersGeometry;
ANativeWindow_setBuffersTimestamp; # vndk
ANativeWindow_setBuffersTransform;
+ ANativeWindow_setDequeueTimeout; # apex # introduced=30
ANativeWindow_setSharedBufferMode; # vndk
ANativeWindow_setSwapInterval; # vndk
ANativeWindow_setUsage; # vndk
diff --git a/libs/nativewindow/tests/ANativeWindowTest.cpp b/libs/nativewindow/tests/ANativeWindowTest.cpp
new file mode 100644
index 0000000..6cf8291
--- /dev/null
+++ b/libs/nativewindow/tests/ANativeWindowTest.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "ANativeWindow_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/BufferQueue.h>
+#include <gui/Surface.h>
+#include <log/log.h>
+#include <sync/sync.h>
+// We need to use the private system apis since not everything is visible to
+// apexes yet.
+#include <system/window.h>
+
+using namespace android;
+
+class TestableSurface final : public Surface {
+public:
+ explicit TestableSurface(const sp<IGraphicBufferProducer>& bufferProducer)
+ : Surface(bufferProducer) {}
+
+ // Exposes the internal last dequeue duration that's stored on the Surface.
+ nsecs_t getLastDequeueDuration() const { return mLastDequeueDuration; }
+
+ // Exposes the internal last queue duration that's stored on the Surface.
+ nsecs_t getLastQueueDuration() const { return mLastQueueDuration; }
+
+ // Exposes the internal last dequeue start time that's stored on the Surface.
+ nsecs_t getLastDequeueStartTime() const { return mLastDequeueStartTime; }
+};
+
+class ANativeWindowTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ mItemConsumer = new BufferItemConsumer(mConsumer, GRALLOC_USAGE_SW_READ_OFTEN);
+ mWindow = new TestableSurface(mProducer);
+ const int success = native_window_api_connect(mWindow.get(), NATIVE_WINDOW_API_CPU);
+ EXPECT_EQ(0, success);
+ }
+
+ void TearDown() override {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGV("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ const int success = native_window_api_disconnect(mWindow.get(), NATIVE_WINDOW_API_CPU);
+ EXPECT_EQ(0, success);
+ }
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ sp<BufferItemConsumer> mItemConsumer;
+
+ sp<TestableSurface> mWindow;
+};
+
+TEST_F(ANativeWindowTest, getLastDequeueDuration_noDequeue_returnsZero) {
+ int result = ANativeWindow_getLastDequeueDuration(mWindow.get());
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(0, mWindow->getLastDequeueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastDequeueDuration_withDequeue_returnsTime) {
+ ANativeWindowBuffer* buffer;
+ int fd;
+ int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, result);
+
+ result = ANativeWindow_getLastDequeueDuration(mWindow.get());
+ EXPECT_GT(result, 0);
+ EXPECT_EQ(result, mWindow->getLastDequeueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastQueueDuration_noDequeue_returnsZero) {
+ int result = ANativeWindow_getLastQueueDuration(mWindow.get());
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(0, mWindow->getLastQueueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastQueueDuration_noQueue_returnsZero) {
+ ANativeWindowBuffer* buffer;
+ int fd;
+ int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, result);
+
+ result = ANativeWindow_getLastQueueDuration(mWindow.get());
+ EXPECT_EQ(result, 0);
+ EXPECT_EQ(result, mWindow->getLastQueueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastQueueDuration_withQueue_returnsTime) {
+ ANativeWindowBuffer* buffer;
+ int fd;
+ int result = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, result);
+
+ result = ANativeWindow_queueBuffer(mWindow.get(), buffer, 0);
+
+ result = ANativeWindow_getLastQueueDuration(mWindow.get());
+ EXPECT_GT(result, 0);
+ EXPECT_EQ(result, mWindow->getLastQueueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastDequeueStartTime_noDequeue_returnsZero) {
+ int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get());
+ EXPECT_EQ(0, result);
+ EXPECT_EQ(0, mWindow->getLastQueueDuration());
+}
+
+TEST_F(ANativeWindowTest, getLastDequeueStartTime_withDequeue_returnsTime) {
+ ANativeWindowBuffer* buffer;
+ int fd;
+ int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, dequeueResult);
+
+ int64_t result = ANativeWindow_getLastDequeueStartTime(mWindow.get());
+ EXPECT_GT(result, 0);
+ EXPECT_EQ(result, mWindow->getLastDequeueStartTime());
+}
+
+TEST_F(ANativeWindowTest, setDequeueTimeout_causesDequeueTimeout) {
+ nsecs_t timeout = milliseconds_to_nanoseconds(100);
+ int result = ANativeWindow_setDequeueTimeout(mWindow.get(), timeout);
+ EXPECT_EQ(0, result);
+
+ // The two dequeues should not timeout...
+ ANativeWindowBuffer* buffer;
+ int fd;
+ int dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, dequeueResult);
+ int queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1);
+ EXPECT_EQ(0, queueResult);
+ dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ close(fd);
+ EXPECT_EQ(0, dequeueResult);
+ queueResult = ANativeWindow_queueBuffer(mWindow.get(), buffer, -1);
+ EXPECT_EQ(0, queueResult);
+
+ // ...but the third one should since the queue depth is too deep.
+ nsecs_t start = systemTime(SYSTEM_TIME_MONOTONIC);
+ dequeueResult = ANativeWindow_dequeueBuffer(mWindow.get(), &buffer, &fd);
+ nsecs_t end = systemTime(SYSTEM_TIME_MONOTONIC);
+ close(fd);
+ EXPECT_EQ(TIMED_OUT, dequeueResult);
+ EXPECT_GE(end - start, timeout);
+}
diff --git a/libs/nativewindow/tests/Android.bp b/libs/nativewindow/tests/Android.bp
index 20071be..cdb3d20 100644
--- a/libs/nativewindow/tests/Android.bp
+++ b/libs/nativewindow/tests/Android.bp
@@ -15,13 +15,22 @@
//
cc_test {
- name: "AHardwareBufferTest",
+ name: "libnativewindow_test",
+ test_suites: [
+ "device-tests",
+ ],
shared_libs: [
+ "libgui",
+ "liblog",
"libnativewindow",
+ "libsync",
+ "libutils",
"android.hardware.graphics.common@1.0",
],
srcs: [
"AHardwareBufferTest.cpp",
- "c_compatibility.c"],
+ "ANativeWindowTest.cpp",
+ "c_compatibility.c",
+ ],
cflags: ["-Wall", "-Werror"],
}
diff --git a/libs/nativewindow/tests/c_compatibility.c b/libs/nativewindow/tests/c_compatibility.c
index befd88f..aa9b4f7 100644
--- a/libs/nativewindow/tests/c_compatibility.c
+++ b/libs/nativewindow/tests/c_compatibility.c
@@ -16,6 +16,7 @@
#include <android/hardware_buffer.h>
#include <android/native_window.h>
+#include <apex/window.h>
#include <vndk/hardware_buffer.h>
#include <vndk/window.h>
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index cc252d6..136ad0d 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -71,9 +71,6 @@
"-fvisibility=hidden",
"-Werror=format",
],
- cppflags: [
- "-fwhole-program-vtables", // requires ThinLTO
- ],
srcs: [
":librenderengine_sources",
":librenderengine_gl_sources",
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index d2a7525..f39f066 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -461,10 +461,6 @@
mFeatureFlags & USE_COLOR_MANAGEMENT);
}
-bool GLESRenderEngine::isCurrent() const {
- return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
-}
-
base::unique_fd GLESRenderEngine::flush() {
ATRACE_CALL();
if (!GLExtensions::getInstance().hasNativeFenceSync()) {
@@ -831,11 +827,14 @@
drawMesh(mesh);
// The middle part of the layer can turn off blending.
- const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, bounds.bottom - radius);
- setScissor(middleRect);
- mState.cornerRadius = 0.0;
- disableBlending();
- drawMesh(mesh);
+ if (topRect.bottom < bottomRect.top) {
+ const Rect middleRect(bounds.left, bounds.top + radius, bounds.right,
+ bounds.bottom - radius);
+ setScissor(middleRect);
+ mState.cornerRadius = 0.0;
+ disableBlending();
+ drawMesh(mesh);
+ }
disableScissor();
}
@@ -855,7 +854,6 @@
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-
ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
glStatus);
@@ -1076,33 +1074,6 @@
return NO_ERROR;
}
-void GLESRenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- ui::Transform::orientation_flags rotation) {
- setViewportAndProjection(Rect(vpw, vph), sourceCrop);
-
- if (rotation == ui::Transform::ROT_0) {
- return;
- }
-
- // Apply custom rotation to the projection.
- float rot90InRadians = 2.0f * static_cast<float>(M_PI) / 4.0f;
- mat4 m = mState.projectionMatrix;
- switch (rotation) {
- case ui::Transform::ROT_90:
- m = mat4::rotate(rot90InRadians, vec3(0, 0, 1)) * m;
- break;
- case ui::Transform::ROT_180:
- m = mat4::rotate(rot90InRadians * 2.0f, vec3(0, 0, 1)) * m;
- break;
- case ui::Transform::ROT_270:
- m = mat4::rotate(rot90InRadians * 3.0f, vec3(0, 0, 1)) * m;
- break;
- default:
- break;
- }
- mState.projectionMatrix = m;
-}
-
void GLESRenderEngine::setViewportAndProjection(Rect viewport, Rect clip) {
ATRACE_CALL();
mVpWidth = viewport.getWidth();
@@ -1166,14 +1137,6 @@
mState.textureEnabled = true;
}
-void GLESRenderEngine::setupLayerBlackedOut() {
- glBindTexture(GL_TEXTURE_2D, mProtectedTexName);
- Texture texture(Texture::TEXTURE_2D, mProtectedTexName);
- texture.setDimensions(1, 1); // FIXME: we should get that from somewhere
- mState.texture = texture;
- mState.textureEnabled = true;
-}
-
void GLESRenderEngine::setColorTransform(const mat4& colorTransform) {
mState.colorMatrix = colorTransform;
}
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index dd60e50..501b044 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -51,7 +51,6 @@
public:
static std::unique_ptr<GLESRenderEngine> create(int hwcFormat, uint32_t featureFlags,
uint32_t imageCacheSize);
- static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
GLESRenderEngine(uint32_t featureFlags, // See RenderEngine::FeatureFlag
EGLDisplay display, EGLConfig config, EGLContext ctxt, EGLSurface dummy,
@@ -59,17 +58,7 @@
uint32_t imageCacheSize);
~GLESRenderEngine() override EXCLUDES(mRenderingMutex);
- std::unique_ptr<Framebuffer> createFramebuffer() override;
- std::unique_ptr<Image> createImage() override;
-
void primeCache() const override;
- bool isCurrent() const override;
- base::unique_fd flush() override;
- bool finish() override;
- bool waitFence(base::unique_fd fenceFd) override;
- void clearWithColor(float red, float green, float blue, float alpha) override;
- void fillRegionWithColor(const Region& region, float red, float green, float blue,
- float alpha) override;
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;
@@ -79,7 +68,6 @@
void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
- void checkErrors() const override;
bool isProtected() const override { return mInProtectedContext; }
bool supportsProtectedContent() const override;
@@ -88,9 +76,7 @@
ANativeWindowBuffer* buffer, const bool useFramebufferCache,
base::unique_fd&& bufferFence, base::unique_fd* drawFence) override;
- // internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
- EGLConfig getEGLConfig() const { return mEGLConfig; }
// Creates an output image for rendering to
EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected,
bool useFramebufferCache)
@@ -112,27 +98,6 @@
Framebuffer* getFramebufferForDrawing() override;
void dump(std::string& result) override EXCLUDES(mRenderingMutex)
EXCLUDES(mFramebufferImageCacheMutex);
- void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- ui::Transform::orientation_flags rotation) override;
- void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color, float cornerRadius) override;
- void setupLayerTexturing(const Texture& texture) override;
- void setupLayerBlackedOut() override;
- void setupFillWithColor(float r, float g, float b, float a) override;
- void setColorTransform(const mat4& colorTransform) override;
- void disableTexturing() override;
- void disableBlending() override;
- void setupCornerRadiusCropSize(float width, float height) override;
-
- // HDR and color management related functions and state
- void setSourceY410BT2020(bool enable) override;
- void setSourceDataSpace(ui::Dataspace source) override;
- void setOutputDataSpace(ui::Dataspace dataspace) override;
- void setDisplayMaxLuminance(const float maxLuminance) override;
-
- // drawing
- void drawMesh(const Mesh& mesh) override;
-
size_t getMaxTextureSize() const override;
size_t getMaxViewportDims() const override;
@@ -144,12 +109,16 @@
GLES_VERSION_3_0 = 0x30000,
};
+ static EGLConfig chooseEglConfig(EGLDisplay display, int format, bool logConfig);
static GlesVersion parseGlesVersion(const char* str);
static EGLContext createEglContext(EGLDisplay display, EGLConfig config,
EGLContext shareContext, bool useContextPriority,
Protection protection);
static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
int hwcFormat, Protection protection);
+ std::unique_ptr<Framebuffer> createFramebuffer();
+ std::unique_ptr<Image> createImage();
+ void checkErrors() const;
void setScissor(const Rect& region);
void disableScissor();
bool waitSync(EGLSyncKHR sync, EGLint flags);
@@ -176,6 +145,28 @@
// blending is an expensive operation, we want to turn off blending when it's not necessary.
void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer,
const Mesh& mesh);
+ base::unique_fd flush();
+ bool finish();
+ bool waitFence(base::unique_fd fenceFd);
+ void clearWithColor(float red, float green, float blue, float alpha);
+ void fillRegionWithColor(const Region& region, float red, float green, float blue, float alpha);
+ void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
+ const half4& color, float cornerRadius);
+ void setupLayerTexturing(const Texture& texture);
+ void setupFillWithColor(float r, float g, float b, float a);
+ void setColorTransform(const mat4& colorTransform);
+ void disableTexturing();
+ void disableBlending();
+ void setupCornerRadiusCropSize(float width, float height);
+
+ // HDR and color management related functions and state
+ void setSourceY410BT2020(bool enable);
+ void setSourceDataSpace(ui::Dataspace source);
+ void setOutputDataSpace(ui::Dataspace dataspace);
+ void setDisplayMaxLuminance(const float maxLuminance);
+
+ // drawing
+ void drawMesh(const Mesh& mesh);
EGLDisplay mEGLDisplay;
EGLConfig mEGLConfig;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index c6a7bd8..205782b 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -77,10 +77,6 @@
// This interface, while still in use until a suitable replacement is built,
// should be considered deprecated, minus some methods which still may be
// used to support legacy behavior.
-
- virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
- virtual std::unique_ptr<Image> createImage() = 0;
-
virtual void primeCache() const = 0;
// dump the extension strings. always call the base class.
@@ -88,24 +84,6 @@
virtual bool useNativeFenceSync() const = 0;
virtual bool useWaitSync() const = 0;
-
- virtual bool isCurrent() const = 0;
-
- // helpers
- // flush submits RenderEngine command stream for execution and returns a
- // native fence fd that is signaled when the execution has completed. It
- // returns -1 on errors.
- virtual base::unique_fd flush() = 0;
- // finish waits until RenderEngine command stream has been executed. It
- // returns false on errors.
- virtual bool finish() = 0;
- // waitFence inserts a wait on an external fence fd to RenderEngine
- // command stream. It returns false on errors.
- virtual bool waitFence(base::unique_fd fenceFd) = 0;
-
- virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
- virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
- float alpha) = 0;
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;
@@ -136,40 +114,6 @@
virtual status_t bindFrameBuffer(Framebuffer* framebuffer) = 0;
virtual void unbindFrameBuffer(Framebuffer* framebuffer) = 0;
- // set-up
- virtual void checkErrors() const = 0;
- virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
- ui::Transform::orientation_flags rotation) = 0;
- virtual void setupLayerBlending(bool premultipliedAlpha, bool opaque, bool disableTexture,
- const half4& color, float cornerRadius) = 0;
- virtual void setupLayerTexturing(const Texture& texture) = 0;
- virtual void setupLayerBlackedOut() = 0;
- virtual void setupFillWithColor(float r, float g, float b, float a) = 0;
- // Sets up the crop size for corner radius clipping.
- //
- // Having corner radius will force GPU composition on the layer and its children, drawing it
- // with a special shader. The shader will receive the radius and the crop rectangle as input,
- // modifying the opacity of the destination texture, multiplying it by a number between 0 and 1.
- // We query Layer#getRoundedCornerState() to retrieve the radius as well as the rounded crop
- // rectangle to figure out how to apply the radius for this layer. The crop rectangle will be
- // in local layer coordinate space, so we have to take the layer transform into account when
- // walking up the tree.
- virtual void setupCornerRadiusCropSize(float width, float height) = 0;
-
- // Set a color transform matrix that is applied in linear space right before OETF.
- virtual void setColorTransform(const mat4& /* colorTransform */) = 0;
- virtual void disableTexturing() = 0;
- virtual void disableBlending() = 0;
-
- // HDR and color management support
- virtual void setSourceY410BT2020(bool enable) = 0;
- virtual void setSourceDataSpace(ui::Dataspace source) = 0;
- virtual void setOutputDataSpace(ui::Dataspace dataspace) = 0;
- virtual void setDisplayMaxLuminance(const float maxLuminance) = 0;
-
- // drawing
- virtual void drawMesh(const Mesh& mesh) = 0;
-
// queries
virtual size_t getMaxTextureSize() const = 0;
virtual size_t getMaxViewportDims() const = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index b4d3ef2..0750e86 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -34,20 +34,12 @@
RenderEngine();
~RenderEngine() override;
- MOCK_METHOD0(createFramebuffer, std::unique_ptr<renderengine::Framebuffer>());
- MOCK_METHOD0(createImage, std::unique_ptr<renderengine::Image>());
MOCK_METHOD0(getFramebufferForDrawing, Framebuffer*());
MOCK_CONST_METHOD0(primeCache, void());
MOCK_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(useNativeFenceSync, bool());
MOCK_CONST_METHOD0(useWaitSync, bool());
MOCK_CONST_METHOD0(isCurrent, bool());
- MOCK_METHOD0(flush, base::unique_fd());
- MOCK_METHOD0(finish, bool());
- MOCK_METHOD1(waitFence, bool(base::unique_fd*));
- bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
- MOCK_METHOD4(clearWithColor, void(float, float, float, float));
- MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
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&));
@@ -55,22 +47,6 @@
MOCK_METHOD3(bindExternalTextureBuffer,
status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
- MOCK_CONST_METHOD0(checkErrors, void());
- MOCK_METHOD4(setViewportAndProjection,
- void(size_t, size_t, Rect, ui::Transform::orientation_flags));
- MOCK_METHOD5(setupLayerBlending, void(bool, bool, bool, const half4&, float));
- MOCK_METHOD1(setupLayerTexturing, void(const Texture&));
- MOCK_METHOD0(setupLayerBlackedOut, void());
- MOCK_METHOD4(setupFillWithColor, void(float, float, float, float));
- MOCK_METHOD2(setupCornerRadiusCropSize, void(float, float));
- MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD1(setSaturationMatrix, void(const mat4&));
- MOCK_METHOD0(disableTexturing, void());
- MOCK_METHOD0(disableBlending, void());
- MOCK_METHOD1(setSourceY410BT2020, void(bool));
- MOCK_METHOD1(setSourceDataSpace, void(ui::Dataspace));
- MOCK_METHOD1(setOutputDataSpace, void(ui::Dataspace));
- MOCK_METHOD1(setDisplayMaxLuminance, void(const float));
MOCK_METHOD1(bindFrameBuffer, status_t(renderengine::Framebuffer*));
MOCK_METHOD1(unbindFrameBuffer, void(renderengine::Framebuffer*));
MOCK_METHOD1(drawMesh, void(const renderengine::Mesh&));
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index 5200545..8ed09f8 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -199,6 +199,10 @@
int32_t type = data.readInt32();
int32_t format = data.readInt32();
native_handle_t *resource = data.readNativeHandle();
+ // Avoid a crash in native_handle_close if resource is nullptr
+ if (resource == nullptr) {
+ return BAD_VALUE;
+ }
sp<ISensorEventConnection> ch =
createSensorDirectConnection(opPackageName, size, type, format, resource);
native_handle_close(resource);
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2518e93..47137f1 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -66,6 +66,7 @@
"Gralloc.cpp",
"Gralloc2.cpp",
"Gralloc3.cpp",
+ "Gralloc4.cpp",
"GraphicBuffer.cpp",
"GraphicBufferAllocator.cpp",
"GraphicBufferMapper.cpp",
@@ -90,10 +91,12 @@
"android.frameworks.bufferhub@1.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
+ "android.hardware.graphics.allocator@4.0",
"android.hardware.graphics.common@1.2",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@2.1",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libcutils",
"libhidlbase",
@@ -186,3 +189,11 @@
"tests",
"tools",
]
+
+filegroup {
+ name: "libui_host_common",
+ srcs: [
+ "Rect.cpp",
+ "PixelFormat.cpp"
+ ],
+}
diff --git a/libs/ui/BufferHubBuffer.cpp b/libs/ui/BufferHubBuffer.cpp
index da91a97..1dfc1e9 100644
--- a/libs/ui/BufferHubBuffer.cpp
+++ b/libs/ui/BufferHubBuffer.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define LOG_TAG "BufferHubBuffer"
#include <poll.h>
#include <android-base/unique_fd.h>
diff --git a/libs/ui/Gralloc4.cpp b/libs/ui/Gralloc4.cpp
new file mode 100644
index 0000000..dc105c0
--- /dev/null
+++ b/libs/ui/Gralloc4.cpp
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Gralloc4"
+
+#include <hidl/ServiceManagement.h>
+#include <hwbinder/IPCThreadState.h>
+#include <ui/Gralloc4.h>
+
+#include <inttypes.h>
+#include <log/log.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wzero-length-array"
+#include <sync/sync.h>
+#pragma clang diagnostic pop
+
+using android::hardware::graphics::allocator::V4_0::IAllocator;
+using android::hardware::graphics::common::V1_2::BufferUsage;
+using android::hardware::graphics::mapper::V4_0::BufferDescriptor;
+using android::hardware::graphics::mapper::V4_0::Error;
+using android::hardware::graphics::mapper::V4_0::IMapper;
+using android::hardware::graphics::mapper::V4_0::YCbCrLayout;
+
+namespace android {
+
+namespace {
+
+static constexpr Error kTransactionError = Error::NO_RESOURCES;
+
+uint64_t getValidUsageBits() {
+ static const uint64_t validUsageBits = []() -> uint64_t {
+ uint64_t bits = 0;
+ for (const auto bit :
+ hardware::hidl_enum_range<hardware::graphics::common::V1_2::BufferUsage>()) {
+ bits = bits | bit;
+ }
+ return bits;
+ }();
+ return validUsageBits;
+}
+
+static inline IMapper::Rect sGralloc4Rect(const Rect& rect) {
+ IMapper::Rect outRect{};
+ outRect.left = rect.left;
+ outRect.top = rect.top;
+ outRect.width = rect.width();
+ outRect.height = rect.height();
+ return outRect;
+}
+static inline void sBufferDescriptorInfo(uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount,
+ uint64_t usage,
+ IMapper::BufferDescriptorInfo* outDescriptorInfo) {
+ outDescriptorInfo->width = width;
+ outDescriptorInfo->height = height;
+ outDescriptorInfo->layerCount = layerCount;
+ outDescriptorInfo->format = static_cast<hardware::graphics::common::V1_2::PixelFormat>(format);
+ outDescriptorInfo->usage = usage;
+}
+
+} // anonymous namespace
+
+void Gralloc4Mapper::preload() {
+ android::hardware::preloadPassthroughService<IMapper>();
+}
+
+Gralloc4Mapper::Gralloc4Mapper() {
+ mMapper = IMapper::getService();
+ if (mMapper == nullptr) {
+ ALOGI("mapper 4.x is not supported");
+ return;
+ }
+ if (mMapper->isRemote()) {
+ LOG_ALWAYS_FATAL("gralloc-mapper must be in passthrough mode");
+ }
+}
+
+bool Gralloc4Mapper::isLoaded() const {
+ return mMapper != nullptr;
+}
+
+status_t Gralloc4Mapper::validateBufferDescriptorInfo(
+ IMapper::BufferDescriptorInfo* descriptorInfo) const {
+ uint64_t validUsageBits = getValidUsageBits();
+
+ if (descriptorInfo->usage & ~validUsageBits) {
+ ALOGE("buffer descriptor contains invalid usage bits 0x%" PRIx64,
+ descriptorInfo->usage & ~validUsageBits);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+status_t Gralloc4Mapper::createDescriptor(void* bufferDescriptorInfo,
+ void* outBufferDescriptor) const {
+ IMapper::BufferDescriptorInfo* descriptorInfo =
+ static_cast<IMapper::BufferDescriptorInfo*>(bufferDescriptorInfo);
+ BufferDescriptor* outDescriptor = static_cast<BufferDescriptor*>(outBufferDescriptor);
+
+ status_t status = validateBufferDescriptorInfo(descriptorInfo);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ Error error;
+ auto hidl_cb = [&](const auto& tmpError, const auto& tmpDescriptor) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outDescriptor = tmpDescriptor;
+ };
+
+ hardware::Return<void> ret = mMapper->createDescriptor(*descriptorInfo, hidl_cb);
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+status_t Gralloc4Mapper::importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const {
+ Error error;
+ auto ret = mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outBufferHandle = static_cast<buffer_handle_t>(tmpBuffer);
+ });
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+void Gralloc4Mapper::freeBuffer(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->freeBuffer(buffer);
+
+ auto error = (ret.isOk()) ? static_cast<Error>(ret) : kTransactionError;
+ ALOGE_IF(error != Error::NONE, "freeBuffer(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc4Mapper::validateBufferSize(buffer_handle_t bufferHandle, uint32_t width,
+ uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->validateBufferSize(buffer, descriptorInfo, stride);
+
+ return static_cast<status_t>((ret.isOk()) ? static_cast<Error>(ret) : kTransactionError);
+}
+
+void Gralloc4Mapper::getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const {
+ *outNumFds = uint32_t(bufferHandle->numFds);
+ *outNumInts = uint32_t(bufferHandle->numInts);
+
+ Error error;
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+ auto ret = mMapper->getTransportSize(buffer,
+ [&](const auto& tmpError, const auto& tmpNumFds,
+ const auto& tmpNumInts) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outNumFds = tmpNumFds;
+ *outNumInts = tmpNumInts;
+ });
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGE_IF(error != Error::NONE, "getTransportSize(%p) failed with %d", buffer, error);
+}
+
+status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc4Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ Error error;
+ auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpData,
+ const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ *outData = tmpData;
+ if (outBytesPerPixel) {
+ *outBytesPerPixel = tmpBytesPerPixel;
+ }
+ if (outBytesPerStride) {
+ *outBytesPerStride = tmpBytesPerStride;
+ }
+ });
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ error = (ret.isOk()) ? error : kTransactionError;
+
+ ALOGW_IF(error != Error::NONE, "lock(%p, ...) failed: %d", bufferHandle, error);
+
+ return static_cast<status_t>(error);
+}
+
+status_t Gralloc4Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ IMapper::Rect accessRegion = sGralloc4Rect(bounds);
+
+ // put acquireFence in a hidl_handle
+ hardware::hidl_handle acquireFenceHandle;
+ NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
+ if (acquireFence >= 0) {
+ auto h = native_handle_init(acquireFenceStorage, 1, 0);
+ h->data[0] = acquireFence;
+ acquireFenceHandle = h;
+ }
+
+ YCbCrLayout layout;
+ Error error;
+ auto ret = mMapper->lockYCbCr(buffer, usage, accessRegion, acquireFenceHandle,
+ [&](const auto& tmpError, const auto& tmpLayout) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ layout = tmpLayout;
+ });
+
+ if (error == Error::NONE) {
+ ycbcr->y = layout.y;
+ ycbcr->cb = layout.cb;
+ ycbcr->cr = layout.cr;
+ ycbcr->ystride = static_cast<size_t>(layout.yStride);
+ ycbcr->cstride = static_cast<size_t>(layout.cStride);
+ ycbcr->chroma_step = static_cast<size_t>(layout.chromaStep);
+ }
+
+ // we own acquireFence even on errors
+ if (acquireFence >= 0) {
+ close(acquireFence);
+ }
+
+ return static_cast<status_t>((ret.isOk()) ? error : kTransactionError);
+}
+
+int Gralloc4Mapper::unlock(buffer_handle_t bufferHandle) const {
+ auto buffer = const_cast<native_handle_t*>(bufferHandle);
+
+ int releaseFence = -1;
+ Error error;
+ auto ret = mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+
+ auto fenceHandle = tmpReleaseFence.getNativeHandle();
+ if (fenceHandle && fenceHandle->numFds == 1) {
+ int fd = dup(fenceHandle->data[0]);
+ if (fd >= 0) {
+ releaseFence = fd;
+ } else {
+ ALOGD("failed to dup unlock release fence");
+ sync_wait(fenceHandle->data[0], -1);
+ }
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("unlock(%p) failed with %d", buffer, error);
+ }
+
+ return releaseFence;
+}
+
+status_t Gralloc4Mapper::isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage,
+ bool* outSupported) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ Error error;
+ auto ret = mMapper->isSupported(descriptorInfo,
+ [&](const auto& tmpError, const auto& tmpSupported) {
+ error = tmpError;
+ if (error != Error::NONE) {
+ return;
+ }
+ if (outSupported) {
+ *outSupported = tmpSupported;
+ }
+ });
+
+ if (!ret.isOk()) {
+ error = kTransactionError;
+ }
+
+ if (error != Error::NONE) {
+ ALOGE("isSupported(%u, %u, %d, %u, ...) failed with %d", width, height, format, layerCount,
+ error);
+ }
+
+ return static_cast<status_t>(error);
+}
+
+Gralloc4Allocator::Gralloc4Allocator(const Gralloc4Mapper& mapper) : mMapper(mapper) {
+ mAllocator = IAllocator::getService();
+ if (mAllocator == nullptr) {
+ ALOGW("allocator 3.x is not supported");
+ return;
+ }
+}
+
+bool Gralloc4Allocator::isLoaded() const {
+ return mAllocator != nullptr;
+}
+
+std::string Gralloc4Allocator::dumpDebugInfo() const {
+ std::string debugInfo;
+
+ mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
+
+ return debugInfo;
+}
+
+status_t Gralloc4Allocator::allocate(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, uint32_t bufferCount,
+ uint32_t* outStride, buffer_handle_t* outBufferHandles) const {
+ IMapper::BufferDescriptorInfo descriptorInfo;
+ sBufferDescriptorInfo(width, height, format, layerCount, usage, &descriptorInfo);
+
+ BufferDescriptor descriptor;
+ status_t error = mMapper.createDescriptor(static_cast<void*>(&descriptorInfo),
+ static_cast<void*>(&descriptor));
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ auto ret = mAllocator->allocate(descriptor, bufferCount,
+ [&](const auto& tmpError, const auto& tmpStride,
+ const auto& tmpBuffers) {
+ error = static_cast<status_t>(tmpError);
+ if (tmpError != Error::NONE) {
+ return;
+ }
+
+ // import buffers
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ error = mMapper.importBuffer(tmpBuffers[i],
+ &outBufferHandles[i]);
+ if (error != NO_ERROR) {
+ for (uint32_t j = 0; j < i; j++) {
+ mMapper.freeBuffer(outBufferHandles[j]);
+ outBufferHandles[j] = nullptr;
+ }
+ return;
+ }
+ }
+ *outStride = tmpStride;
+ });
+
+ // make sure the kernel driver sees BC_FREE_BUFFER and closes the fds now
+ hardware::IPCThreadState::self()->flushCommands();
+
+ return (ret.isOk()) ? error : static_cast<status_t>(kTransactionError);
+}
+
+} // namespace android
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 3fc6a2d..579e68e 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -626,7 +626,7 @@
bufferHubBuffer->desc().layers, bufferHubBuffer->desc().usage,
bufferHubBuffer->desc().stride);
mBufferId = bufferHubBuffer->id();
- mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));
+ mBufferHubBuffer = std::move(bufferHubBuffer);
return NO_ERROR;
}
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 9c7d1fd..eb787a2 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -33,6 +33,7 @@
#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
#include <ui/Gralloc3.h>
+#include <ui/Gralloc4.h>
#include <ui/GraphicBufferMapper.h>
namespace android {
@@ -47,16 +48,23 @@
GraphicBufferAllocator::alloc_rec_t> GraphicBufferAllocator::sAllocList;
GraphicBufferAllocator::GraphicBufferAllocator() : mMapper(GraphicBufferMapper::getInstance()) {
+ mAllocator = std::make_unique<const Gralloc4Allocator>(
+ reinterpret_cast<const Gralloc4Mapper&>(mMapper.getGrallocMapper()));
+ if (mAllocator->isLoaded()) {
+ return;
+ }
mAllocator = std::make_unique<const Gralloc3Allocator>(
reinterpret_cast<const Gralloc3Mapper&>(mMapper.getGrallocMapper()));
- if (!mAllocator->isLoaded()) {
- mAllocator = std::make_unique<const Gralloc2Allocator>(
- reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ if (mAllocator->isLoaded()) {
+ return;
+ }
+ mAllocator = std::make_unique<const Gralloc2Allocator>(
+ reinterpret_cast<const Gralloc2Mapper&>(mMapper.getGrallocMapper()));
+ if (mAllocator->isLoaded()) {
+ return;
}
- if (!mAllocator->isLoaded()) {
- LOG_ALWAYS_FATAL("gralloc-allocator is missing");
- }
+ LOG_ALWAYS_FATAL("gralloc-allocator is missing");
}
GraphicBufferAllocator::~GraphicBufferAllocator() {}
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 25b7247..4d087d1 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -35,6 +35,7 @@
#include <ui/Gralloc.h>
#include <ui/Gralloc2.h>
#include <ui/Gralloc3.h>
+#include <ui/Gralloc4.h>
#include <ui/GraphicBuffer.h>
#include <system/graphics.h>
@@ -47,20 +48,27 @@
void GraphicBufferMapper::preloadHal() {
Gralloc2Mapper::preload();
Gralloc3Mapper::preload();
+ Gralloc4Mapper::preload();
}
GraphicBufferMapper::GraphicBufferMapper() {
+ mMapper = std::make_unique<const Gralloc4Mapper>();
+ if (mMapper->isLoaded()) {
+ mMapperVersion = Version::GRALLOC_4;
+ return;
+ }
mMapper = std::make_unique<const Gralloc3Mapper>();
- if (!mMapper->isLoaded()) {
- mMapper = std::make_unique<const Gralloc2Mapper>();
- mMapperVersion = Version::GRALLOC_2;
- } else {
+ if (mMapper->isLoaded()) {
mMapperVersion = Version::GRALLOC_3;
+ return;
+ }
+ mMapper = std::make_unique<const Gralloc2Mapper>();
+ if (mMapper->isLoaded()) {
+ mMapperVersion = Version::GRALLOC_2;
+ return;
}
- if (!mMapper->isLoaded()) {
- LOG_ALWAYS_FATAL("gralloc-mapper is missing");
- }
+ LOG_ALWAYS_FATAL("gralloc-mapper is missing");
}
status_t GraphicBufferMapper::importBuffer(buffer_handle_t rawHandle,
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 8976d2d..0772210 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -24,6 +24,8 @@
namespace android {
+constexpr uint32_t NO_LAYER_STACK = static_cast<uint32_t>(-1);
+
struct DisplayInfo {
uint32_t w{0};
uint32_t h{0};
@@ -37,6 +39,7 @@
nsecs_t presentationDeadline{0};
uint32_t viewportW{0};
uint32_t viewportH{0};
+ uint32_t layerStack{NO_LAYER_STACK};
};
/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
@@ -47,6 +50,6 @@
DISPLAY_ORIENTATION_270 = 3
};
-}; // namespace android
+} // namespace android
#endif // ANDROID_COMPOSER_DISPLAY_INFO_H
diff --git a/libs/ui/include/ui/Gralloc4.h b/libs/ui/include/ui/Gralloc4.h
new file mode 100644
index 0000000..14b65bc
--- /dev/null
+++ b/libs/ui/include/ui/Gralloc4.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_UI_GRALLOC4_H
+#define ANDROID_UI_GRALLOC4_H
+
+#include <string>
+
+#include <android/hardware/graphics/allocator/4.0/IAllocator.h>
+#include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/mapper/4.0/IMapper.h>
+#include <ui/Gralloc.h>
+#include <ui/PixelFormat.h>
+#include <ui/Rect.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class Gralloc4Mapper : public GrallocMapper {
+public:
+ static void preload();
+
+ Gralloc4Mapper();
+
+ bool isLoaded() const override;
+
+ status_t createDescriptor(void* bufferDescriptorInfo, void* outBufferDescriptor) const override;
+
+ status_t importBuffer(const hardware::hidl_handle& rawHandle,
+ buffer_handle_t* outBufferHandle) const override;
+
+ void freeBuffer(buffer_handle_t bufferHandle) const override;
+
+ status_t validateBufferSize(buffer_handle_t bufferHandle, uint32_t width, uint32_t height,
+ android::PixelFormat format, uint32_t layerCount, uint64_t usage,
+ uint32_t stride) const override;
+
+ void getTransportSize(buffer_handle_t bufferHandle, uint32_t* outNumFds,
+ uint32_t* outNumInts) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, void** outData, int32_t* outBytesPerPixel,
+ int32_t* outBytesPerStride) const override;
+
+ status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
+ int acquireFence, android_ycbcr* ycbcr) const override;
+
+ int unlock(buffer_handle_t bufferHandle) const override;
+
+ status_t isSupported(uint32_t width, uint32_t height, android::PixelFormat format,
+ uint32_t layerCount, uint64_t usage, bool* outSupported) const override;
+
+private:
+ // Determines whether the passed info is compatible with the mapper.
+ status_t validateBufferDescriptorInfo(
+ hardware::graphics::mapper::V4_0::IMapper::BufferDescriptorInfo* descriptorInfo) const;
+
+ sp<hardware::graphics::mapper::V4_0::IMapper> mMapper;
+};
+
+class Gralloc4Allocator : public GrallocAllocator {
+public:
+ // An allocator relies on a mapper, and that mapper must be alive at all
+ // time.
+ Gralloc4Allocator(const Gralloc4Mapper& mapper);
+
+ bool isLoaded() const override;
+
+ std::string dumpDebugInfo() const override;
+
+ status_t allocate(uint32_t width, uint32_t height, PixelFormat format, uint32_t layerCount,
+ uint64_t usage, uint32_t bufferCount, uint32_t* outStride,
+ buffer_handle_t* outBufferHandles) const override;
+
+private:
+ const Gralloc4Mapper& mMapper;
+ sp<hardware::graphics::allocator::V4_0::IAllocator> mAllocator;
+};
+
+} // namespace android
+
+#endif // ANDROID_UI_GRALLOC4_H
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 2461454..c401a48 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -44,6 +44,7 @@
enum Version {
GRALLOC_2,
GRALLOC_3,
+ GRALLOC_4,
};
static void preloadHal();
static inline GraphicBufferMapper& get() { return getInstance(); }
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 99434b7..0452f84 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -45,6 +45,24 @@
cflags: ["-Wall", "-Werror"],
}
+// This test has a main method, and requires a separate binary to be built.
+cc_test {
+ name: "GraphicBufferOverBinder_test",
+ srcs: ["GraphicBufferOverBinder_test.cpp"],
+ cflags: ["-Wall", "-Werror"],
+ header_libs: [
+ "libdvr_headers",
+ ],
+ shared_libs: [
+ "android.frameworks.bufferhub@1.0",
+ "libbinder",
+ "libgui",
+ "liblog",
+ "libui",
+ "libutils",
+ ],
+}
+
cc_test {
name: "BufferHub_test",
header_libs: [
diff --git a/libs/ui/tests/GraphicBufferOverBinder_test.cpp b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
new file mode 100644
index 0000000..7c0a44a
--- /dev/null
+++ b/libs/ui/tests/GraphicBufferOverBinder_test.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "GraphicBufferOverBinder_test"
+
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <gui/IGraphicBufferConsumer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <ui/BufferHubBuffer.h>
+#include <ui/GraphicBuffer.h>
+#include <utils/Log.h>
+
+namespace android {
+
+constexpr uint32_t kTestWidth = 1024;
+constexpr uint32_t kTestHeight = 1;
+constexpr uint32_t kTestFormat = HAL_PIXEL_FORMAT_BLOB;
+constexpr uint32_t kTestLayerCount = 1;
+constexpr uint64_t kTestUsage = GraphicBuffer::USAGE_SW_WRITE_OFTEN;
+static const String16 kTestServiceName = String16("GraphicBufferOverBinderTestService");
+enum GraphicBufferOverBinderTestServiceCode {
+ GRAPHIC_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+ GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER,
+};
+
+class GraphicBufferOverBinderTestService : public BBinder {
+public:
+ GraphicBufferOverBinderTestService() {
+ // GraphicBuffer
+ mGraphicBuffer = new GraphicBuffer(kTestWidth, kTestHeight, kTestFormat, kTestLayerCount,
+ kTestUsage);
+ ALOGI("mGraphicBuffer id %" PRIi32, mGraphicBuffer->getBufferId());
+
+ // BufferHub-backed GraphicBuffer
+ std::unique_ptr<BufferHubBuffer> bufferHubBuffer =
+ BufferHubBuffer::create(kTestWidth, kTestHeight, kTestLayerCount, kTestFormat,
+ kTestUsage, /*userMetadataSize=*/0);
+ mBufferhubBackedGraphicBuffer = new GraphicBuffer(std::move(bufferHubBuffer));
+ if (!mBufferhubBackedGraphicBuffer->isBufferHubBuffer()) {
+ ALOGE("Failed to back GraphicBuffer with BufferHub.");
+ }
+ if (bufferHubBuffer != nullptr) {
+ ALOGE("Failed to move BufferHubBuffer to GraphicBuffer");
+ }
+ ALOGI("mBufferhubBackedGraphicBuffer id %" PRIi32,
+ mBufferhubBackedGraphicBuffer->getBufferId());
+ }
+
+ ~GraphicBufferOverBinderTestService() = default;
+
+ virtual status_t onTransact(uint32_t code, const Parcel& /*data*/, Parcel* reply,
+ uint32_t /*flags*/ = 0) {
+ switch (code) {
+ case GRAPHIC_BUFFER: {
+ return reply->write(*mGraphicBuffer);
+ }
+ case GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER: {
+ return reply->write(*mBufferhubBackedGraphicBuffer);
+ }
+ default:
+ return UNKNOWN_TRANSACTION;
+ };
+ }
+
+protected:
+ sp<GraphicBuffer> mGraphicBuffer;
+ sp<GraphicBuffer> mBufferhubBackedGraphicBuffer;
+};
+
+static int runBinderServer() {
+ ProcessState::self()->startThreadPool();
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<GraphicBufferOverBinderTestService> service = new GraphicBufferOverBinderTestService;
+ sm->addService(kTestServiceName, service, false);
+
+ ALOGI("Binder server running...");
+
+ while (true) {
+ int stat, retval;
+ retval = wait(&stat);
+ if (retval == -1 && errno == ECHILD) {
+ break;
+ }
+ }
+
+ ALOGI("Binder server exiting...");
+ return 0;
+}
+
+class GraphicBufferOverBinderTest : public ::testing::TestWithParam<uint32_t> {
+protected:
+ virtual void SetUp() {
+ mService = defaultServiceManager()->getService(kTestServiceName);
+ if (mService == nullptr) {
+ ALOGE("Failed to connect to the test service.");
+ return;
+ }
+
+ ALOGI("Binder service is ready for client.");
+ }
+
+ status_t GetGraphicBuffer(sp<GraphicBuffer>* outBuf, uint32_t opCode) {
+ Parcel data;
+ Parcel reply;
+ status_t error = mService->transact(opCode, data, &reply);
+ if (error != NO_ERROR) {
+ ALOGE("Failed to get graphic buffer over binder, error=%d.", error);
+ return error;
+ }
+
+ *outBuf = new GraphicBuffer();
+ return reply.read(**outBuf);
+ }
+
+private:
+ sp<IBinder> mService;
+};
+
+TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferOverBinder) {
+ sp<GraphicBuffer> gb;
+ EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER), OK);
+ EXPECT_NE(gb, nullptr);
+ EXPECT_FALSE(gb->isBufferHubBuffer());
+ void* vaddr;
+ EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK);
+ EXPECT_EQ(gb->unlock(), OK);
+}
+
+TEST_F(GraphicBufferOverBinderTest, SendGraphicBufferFromBufferHubBufferOverBinder) {
+ sp<GraphicBuffer> gb;
+ EXPECT_EQ(GetGraphicBuffer(&gb, GRAPHIC_BUFFER_FROM_BUFFER_HUB_BUFFER), NO_ERROR);
+ EXPECT_NE(gb, nullptr);
+ EXPECT_TRUE(gb->isBufferHubBuffer());
+ void* vaddr;
+ EXPECT_EQ(gb->lock(kTestUsage, &vaddr), OK);
+ EXPECT_EQ(gb->unlock(), OK);
+}
+
+} // namespace android
+
+int main(int argc, char** argv) {
+ pid_t pid = fork();
+ if (pid == 0) {
+ android::ProcessState::self()->startThreadPool();
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+
+ } else {
+ ALOGI("Test process pid: %d.", pid);
+ return android::runBinderServer();
+ }
+}
diff --git a/libs/ui/tests/GraphicBuffer_test.cpp b/libs/ui/tests/GraphicBuffer_test.cpp
index 127f7ee..5e0b094 100644
--- a/libs/ui/tests/GraphicBuffer_test.cpp
+++ b/libs/ui/tests/GraphicBuffer_test.cpp
@@ -44,11 +44,28 @@
TEST_F(GraphicBufferTest, AllocateBadDimensions) {
PixelFormat format = PIXEL_FORMAT_RGBA_8888;
+ if (std::numeric_limits<size_t>::max() / std::numeric_limits<uint32_t>::max() /
+ bytesPerPixel(format) >=
+ std::numeric_limits<uint32_t>::max()) {
+ GTEST_SUCCEED() << "Cannot overflow with this format";
+ }
uint32_t width, height;
width = height = std::numeric_limits<uint32_t>::max();
sp<GraphicBuffer> gb(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
std::string("test")));
ASSERT_EQ(BAD_VALUE, gb->initCheck());
+
+ const size_t targetArea = std::numeric_limits<size_t>::max() / bytesPerPixel(format);
+ const size_t widthCandidate = targetArea / std::numeric_limits<uint32_t>::max();
+ if (widthCandidate == 0) {
+ width = 1;
+ } else {
+ width = std::numeric_limits<uint32_t>::max();
+ }
+ height = (targetArea / width) + 1;
+ sp<GraphicBuffer> gb2(new GraphicBuffer(width, height, format, kTestLayerCount, kTestUsage,
+ std::string("test")));
+ ASSERT_EQ(BAD_VALUE, gb2->initCheck());
}
TEST_F(GraphicBufferTest, CreateFromBufferHubBuffer) {
diff --git a/libs/vr/libbufferhub/consumer_buffer.cpp b/libs/vr/libbufferhub/consumer_buffer.cpp
index 115e866..7823e36 100644
--- a/libs/vr/libbufferhub/consumer_buffer.cpp
+++ b/libs/vr/libbufferhub/consumer_buffer.cpp
@@ -52,12 +52,6 @@
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
- ALOGD(
- "%s Failed to acquire the buffer. Current buffer state was changed to "
- "%" PRIx32
- " when trying to acquire the buffer and modify the buffer state to "
- "%" PRIx32 ". About to try again if the buffer is still posted.",
- __FUNCTION__, current_buffer_state, updated_buffer_state);
if (!BufferHubDefs::isClientPosted(current_buffer_state,
client_state_mask())) {
ALOGE(
@@ -152,12 +146,6 @@
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
- ALOGD(
- "%s: Failed to release the buffer. Current buffer state was changed to "
- "%" PRIx32
- " when trying to release the buffer and modify the buffer state to "
- "%" PRIx32 ". About to try again.",
- __FUNCTION__, current_buffer_state, updated_buffer_state);
// The failure of compare_exchange_weak updates current_buffer_state.
updated_buffer_state = current_buffer_state & (~client_state_mask());
}
diff --git a/libs/vr/libbufferhub/producer_buffer.cpp b/libs/vr/libbufferhub/producer_buffer.cpp
index 3d88ba5..aa9d072 100644
--- a/libs/vr/libbufferhub/producer_buffer.cpp
+++ b/libs/vr/libbufferhub/producer_buffer.cpp
@@ -96,13 +96,6 @@
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
- ALOGD(
- "%s: Failed to post the buffer. Current buffer state was changed to "
- "%" PRIx32
- " when trying to post the buffer and modify the buffer state to "
- "%" PRIx32
- ". About to try again if the buffer is still gained by this client.",
- __FUNCTION__, current_buffer_state, updated_buffer_state);
if (!BufferHubDefs::isClientGained(current_buffer_state,
client_state_mask())) {
ALOGE(
@@ -186,15 +179,6 @@
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
- ALOGD(
- "%s: Failed to gain the buffer. Current buffer state was changed to "
- "%" PRIx32
- " when trying to gain the buffer and modify the buffer state to "
- "%" PRIx32
- ". About to try again if the buffer is still not read by other "
- "clients.",
- __FUNCTION__, current_buffer_state, updated_buffer_state);
-
if (BufferHubDefs::isAnyClientAcquired(current_buffer_state) ||
BufferHubDefs::isAnyClientGained(current_buffer_state) ||
(BufferHubDefs::isAnyClientPosted(
diff --git a/libs/vr/libdisplay/display_client.cpp b/libs/vr/libdisplay/display_client.cpp
index f67e258..62856df 100644
--- a/libs/vr/libdisplay/display_client.cpp
+++ b/libs/vr/libdisplay/display_client.cpp
@@ -178,6 +178,10 @@
return status;
}
+Status<uint8_t> DisplayClient::GetDisplayIdentificationPort() {
+ return InvokeRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>();
+}
+
Status<std::unique_ptr<Surface>> DisplayClient::CreateSurface(
const SurfaceAttributes& attributes) {
int error;
diff --git a/libs/vr/libdisplay/include/private/dvr/display_client.h b/libs/vr/libdisplay/include/private/dvr/display_client.h
index f8f5b3d..81546ac 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_client.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_client.h
@@ -72,6 +72,7 @@
public:
pdx::Status<Metrics> GetDisplayMetrics();
pdx::Status<std::string> GetConfigurationData(ConfigFileType config_type);
+ pdx::Status<uint8_t> GetDisplayIdentificationPort();
pdx::Status<std::unique_ptr<IonBuffer>> SetupGlobalBuffer(
DvrGlobalBufferKey key, size_t size, uint64_t usage);
pdx::Status<void> DeleteGlobalBuffer(DvrGlobalBufferKey key);
diff --git a/libs/vr/libdisplay/include/private/dvr/display_protocol.h b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
index 3786d1d..9f4cc4a 100644
--- a/libs/vr/libdisplay/include/private/dvr/display_protocol.h
+++ b/libs/vr/libdisplay/include/private/dvr/display_protocol.h
@@ -191,7 +191,8 @@
enum class ConfigFileType : uint32_t {
kLensMetrics,
kDeviceMetrics,
- kDeviceConfiguration
+ kDeviceConfiguration,
+ kDeviceEdid
};
struct DisplayProtocol {
@@ -210,6 +211,7 @@
kOpGetSurfaceInfo,
kOpCreateQueue,
kOpSetAttributes,
+ kOpGetDisplayIdentificationPort,
};
// Aliases.
@@ -220,6 +222,8 @@
PDX_REMOTE_METHOD(GetMetrics, kOpGetMetrics, Metrics(Void));
PDX_REMOTE_METHOD(GetConfigurationData, kOpGetConfigurationData,
std::string(ConfigFileType config_type));
+ PDX_REMOTE_METHOD(GetDisplayIdentificationPort,
+ kOpGetDisplayIdentificationPort, uint8_t(Void));
PDX_REMOTE_METHOD(SetupGlobalBuffer, kOpSetupGlobalBuffer,
LocalNativeBufferHandle(DvrGlobalBufferKey key, size_t size,
uint64_t usage));
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index e383bb2..b7abb99 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -85,6 +85,8 @@
DVR_CONFIGURATION_DATA_DEVICE_METRICS = 1,
// Request the per device configuration data file.
DVR_CONFIGURATION_DATA_DEVICE_CONFIG = 2,
+ // Request the edid data for the display.
+ DVR_CONFIGURATION_DATA_DEVICE_EDID = 3,
};
// dvr_display_manager.h
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 12ce74b..2053344 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -35,7 +35,7 @@
]
sharedLibraries = [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
diff --git a/libs/vr/libvrflinger/display_service.cpp b/libs/vr/libvrflinger/display_service.cpp
index 87162c0..582fed3 100644
--- a/libs/vr/libvrflinger/display_service.cpp
+++ b/libs/vr/libvrflinger/display_service.cpp
@@ -18,6 +18,8 @@
#include <private/dvr/trusted_uids.h>
#include <private/dvr/types.h>
+#include "DisplayHardware/DisplayIdentification.h"
+
using android::dvr::display::DisplayProtocol;
using android::pdx::Channel;
using android::pdx::ErrorStatus;
@@ -139,6 +141,11 @@
*this, &DisplayService::OnGetConfigurationData, message);
return {};
+ case DisplayProtocol::GetDisplayIdentificationPort::Opcode:
+ DispatchRemoteMethod<DisplayProtocol::GetDisplayIdentificationPort>(
+ *this, &DisplayService::OnGetDisplayIdentificationPort, message);
+ return {};
+
case DisplayProtocol::CreateSurface::Opcode:
DispatchRemoteMethod<DisplayProtocol::CreateSurface>(
*this, &DisplayService::OnCreateSurface, message);
@@ -194,6 +201,7 @@
pdx::Status<std::string> DisplayService::OnGetConfigurationData(
pdx::Message& /*message*/, display::ConfigFileType config_type) {
std::string property_name;
+ DisplayIdentificationData display_identification_data;
switch (config_type) {
case display::ConfigFileType::kLensMetrics:
property_name = kDvrLensMetricsProperty;
@@ -204,6 +212,14 @@
case display::ConfigFileType::kDeviceConfiguration:
property_name = kDvrDeviceConfigProperty;
break;
+ case display::ConfigFileType::kDeviceEdid:
+ display_identification_data =
+ hardware_composer_.GetCurrentDisplayIdentificationData();
+ if (display_identification_data.size() == 0) {
+ return ErrorStatus(ENOENT);
+ }
+ return std::string(display_identification_data.begin(),
+ display_identification_data.end());
default:
return ErrorStatus(EINVAL);
}
@@ -220,6 +236,11 @@
return std::move(data);
}
+pdx::Status<uint8_t> DisplayService::OnGetDisplayIdentificationPort(
+ pdx::Message& /*message*/) {
+ return hardware_composer_.GetCurrentDisplayPort();
+}
+
// Creates a new DisplaySurface and associates it with this channel. This may
// only be done once per channel.
Status<display::SurfaceInfo> DisplayService::OnCreateSurface(
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index e0f2edd..89f1eae 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -80,6 +80,7 @@
pdx::Status<display::Metrics> OnGetMetrics(pdx::Message& message);
pdx::Status<std::string> OnGetConfigurationData(
pdx::Message& message, display::ConfigFileType config_type);
+ pdx::Status<uint8_t> OnGetDisplayIdentificationPort(pdx::Message& message);
pdx::Status<display::SurfaceInfo> OnCreateSurface(
pdx::Message& message, const display::SurfaceAttributes& attributes);
pdx::Status<BorrowedNativeBufferHandle> OnSetupGlobalBuffer(
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index e1240d6..67607af 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -51,8 +51,6 @@
const char kRightEyeOffsetProperty[] = "dvr.right_eye_offset_ns";
-const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display";
-
// Surface flinger uses "VSYNC-sf" and "VSYNC-app" for its version of these
// events. Name ours similarly.
const char kVsyncTraceEventName[] = "VSYNC-vrflinger";
@@ -139,6 +137,20 @@
composer_callback_->SetVsyncService(nullptr);
}
+void HardwareComposer::UpdateEdidData(Hwc2::Composer* composer,
+ hwc2_display_t hw_id) {
+ const auto error = composer->getDisplayIdentificationData(
+ hw_id, &display_port_, &display_identification_data_);
+ if (error != android::hardware::graphics::composer::V2_1::Error::NONE) {
+ if (error !=
+ android::hardware::graphics::composer::V2_1::Error::UNSUPPORTED) {
+ ALOGI("hardware_composer: identification data error\n");
+ } else {
+ ALOGI("hardware_composer: identification data unsupported\n");
+ }
+ }
+}
+
bool HardwareComposer::Initialize(
Hwc2::Composer* composer, hwc2_display_t primary_display_id,
RequestDisplayCallback request_display_callback) {
@@ -166,6 +178,8 @@
"HardwareComposer: Failed to create interrupt event fd : %s",
strerror(errno));
+ UpdateEdidData(composer, primary_display_id);
+
post_thread_ = std::thread(&HardwareComposer::PostThread, this);
initialized_ = true;
@@ -965,18 +979,9 @@
external_display_ = GetDisplayParams(composer_.get(),
*displays.external_display, /*is_primary*/ false);
- if (property_get_bool(kUseExternalDisplayProperty, false)) {
- ALOGI("External display connected. Switching to external display.");
- target_display_ = &(*external_display_);
- target_display_changed = true;
- } else {
- ALOGI("External display connected, but sysprop %s is unset, so"
- " using primary display.", kUseExternalDisplayProperty);
- if (was_using_external_display) {
- target_display_ = &primary_display_;
- target_display_changed = true;
- }
- }
+ ALOGI("External display connected. Switching to external display.");
+ target_display_ = &(*external_display_);
+ target_display_changed = true;
} else {
// External display was disconnected
external_display_ = std::nullopt;
@@ -999,6 +1004,9 @@
EnableDisplay(*external_display_, false);
}
+ // Update the cached edid data for the current display.
+ UpdateEdidData(composer_.get(), target_display_->id);
+
// Turn the new target display on.
EnableDisplay(*target_display_, true);
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index db0d6a7..989ce35 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -25,6 +25,7 @@
#include <private/dvr/shared_buffer_helpers.h>
#include <private/dvr/vsync_service.h>
+#include "DisplayHardware/DisplayIdentification.h"
#include "acquired_buffer.h"
#include "display_surface.h"
@@ -334,6 +335,14 @@
int OnNewGlobalBuffer(DvrGlobalBufferKey key, IonBuffer& ion_buffer);
void OnDeletedGlobalBuffer(DvrGlobalBufferKey key);
+ // Gets the edid data for the current active display (internal or external)
+ DisplayIdentificationData GetCurrentDisplayIdentificationData() {
+ return display_identification_data_;
+ }
+
+ // Gets the edid port for the current active display (internal or external)
+ uint8_t GetCurrentDisplayPort() { return display_port_; }
+
private:
DisplayParams GetDisplayParams(Hwc2::Composer* composer,
hwc2_display_t display, bool is_primary);
@@ -544,6 +553,11 @@
bool vsync_trace_parity_ = false;
sp<VsyncService> vsync_service_;
+ // Edid section.
+ void UpdateEdidData(Hwc2::Composer* composer, hwc2_display_t hw_id);
+ DisplayIdentificationData display_identification_data_;
+ uint8_t display_port_;
+
static constexpr int kPostThreadInterrupted = 1;
HardwareComposer(const HardwareComposer&) = delete;
diff --git a/opengl/libagl/Android.bp b/opengl/libagl/Android.bp
deleted file mode 100644
index f5bf015..0000000
--- a/opengl/libagl/Android.bp
+++ /dev/null
@@ -1,100 +0,0 @@
-//
-// Build the software OpenGL ES library
-//
-
-cc_defaults {
- name: "libGLES_android_defaults",
-
- cflags: [
- "-DLOG_TAG=\"libagl\"",
- "-DGL_GLEXT_PROTOTYPES",
- "-DEGL_EGLEXT_PROTOTYPES",
- "-fvisibility=hidden",
- "-Wall",
- "-Werror",
- ],
-
- shared_libs: [
- "libcutils",
- "libhardware",
- "libutils",
- "liblog",
- "libpixelflinger",
- "libETC1",
- "libui",
- "libnativewindow",
- ],
-
- header_libs: [
- "bionic_libc_platform_headers",
- ],
-
- arch: {
- arm: {
- cflags: ["-fstrict-aliasing"],
- },
-
- mips: {
- cflags: [
- "-fstrict-aliasing",
- // The graphics code can generate division by zero
- "-mno-check-zero-division",
- ],
- },
- },
-}
-
-cc_library_shared {
- name: "libGLES_android",
- defaults: ["libGLES_android_defaults"],
-
- whole_static_libs: ["libGLES_android_arm"],
-
- srcs: [
- "egl.cpp",
- "state.cpp",
- "texture.cpp",
- "Tokenizer.cpp",
- "TokenManager.cpp",
- "TextureObjectManager.cpp",
- "BufferObjectManager.cpp",
- ],
-
- arch: {
- arm: {
- srcs: [
- "fixed_asm.S",
- "iterators.S",
- ],
- },
-
- mips: {
- rev6: {
- srcs: ["arch-mips/fixed_asm.S"],
- },
- },
- },
-
- relative_install_path: "egl",
-}
-
-cc_library_static {
- name: "libGLES_android_arm",
- defaults: ["libGLES_android_defaults"],
-
- srcs: [
- "array.cpp",
- "fp.cpp",
- "light.cpp",
- "matrix.cpp",
- "mipmap.cpp",
- "primitives.cpp",
- "vertex.cpp",
- ],
-
- arch: {
- arm: {
- instruction_set: "arm",
- },
- },
-}
diff --git a/opengl/libagl/BufferObjectManager.cpp b/opengl/libagl/BufferObjectManager.cpp
deleted file mode 100644
index 3d93c19..0000000
--- a/opengl/libagl/BufferObjectManager.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- ** Copyright 2008, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <cutils/atomic.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/Errors.h>
-
-#include <GLES/gl.h>
-
-#include "BufferObjectManager.h"
-
-
-namespace android {
-
-using namespace gl;
-
-// ----------------------------------------------------------------------------
-
-EGLBufferObjectManager::EGLBufferObjectManager()
-: TokenManager(), mCount(0)
-{
-}
-
-EGLBufferObjectManager::~EGLBufferObjectManager()
-{
- // destroy all the buffer objects and their storage
- GLsizei n = mBuffers.size();
- for (GLsizei i=0 ; i<n ; i++) {
- buffer_t* bo = mBuffers.valueAt(i);
- free(bo->data);
- delete bo;
- }
-}
-
-buffer_t const* EGLBufferObjectManager::bind(GLuint buffer)
-{
- Mutex::Autolock _l(mLock);
- int32_t i = mBuffers.indexOfKey(buffer);
- if (i >= 0) {
- return mBuffers.valueAt(i);
- }
- buffer_t* bo = new buffer_t;
- bo->data = 0;
- bo->usage = GL_STATIC_DRAW;
- bo->size = 0;
- bo->name = buffer;
- mBuffers.add(buffer, bo);
- return bo;
-}
-
-int EGLBufferObjectManager::allocateStore(buffer_t* bo,
- GLsizeiptr size, GLenum usage)
-{
- Mutex::Autolock _l(mLock);
- if (size != bo->size) {
- uint8_t* data = (uint8_t*)malloc(size);
- if (data == 0)
- return -1;
- free(bo->data);
- bo->data = data;
- bo->size = size;
- }
- bo->usage = usage;
- return 0;
-}
-
-void EGLBufferObjectManager::deleteBuffers(GLsizei n, const GLuint* buffers)
-{
- Mutex::Autolock _l(mLock);
- while (n--) {
- const GLuint t = *buffers++;
- if (t) {
- int32_t index = mBuffers.indexOfKey(t);
- if (index >= 0) {
- buffer_t* bo = mBuffers.valueAt(index);
- free(bo->data);
- mBuffers.removeItemsAt(index);
- delete bo;
- }
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/opengl/libagl/BufferObjectManager.h b/opengl/libagl/BufferObjectManager.h
deleted file mode 100644
index fcdae5b..0000000
--- a/opengl/libagl/BufferObjectManager.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- **
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#ifndef ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
-#define ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
-
-#include <atomic>
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/Errors.h>
-
-#include <GLES/gl.h>
-
-#include "Tokenizer.h"
-#include "TokenManager.h"
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-namespace gl {
-
-struct buffer_t {
- GLsizeiptr size;
- GLenum usage;
- uint8_t* data;
- uint32_t name;
-};
-
-};
-
-class EGLBufferObjectManager : public TokenManager
-{
-public:
- EGLBufferObjectManager();
- ~EGLBufferObjectManager();
-
- // protocol for sp<>
- inline void incStrong(const void* id) const;
- inline void decStrong(const void* id) const;
- typedef void weakref_type;
-
- gl::buffer_t const* bind(GLuint buffer);
- int allocateStore(gl::buffer_t* bo, GLsizeiptr size, GLenum usage);
- void deleteBuffers(GLsizei n, const GLuint* buffers);
-
-private:
- mutable std::atomic_size_t mCount;
- mutable Mutex mLock;
- KeyedVector<GLuint, gl::buffer_t*> mBuffers;
-};
-
-void EGLBufferObjectManager::incStrong(const void* /*id*/) const {
- mCount.fetch_add(1, std::memory_order_relaxed);
-}
-void EGLBufferObjectManager::decStrong(const void* /*id*/) const {
- if (mCount.fetch_sub(1, std::memory_order_release) == 0) {
- std::atomic_thread_fence(std::memory_order_acquire);
- delete this;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_BUFFER_OBJECT_MANAGER_H
-
diff --git a/opengl/libagl/TextureObjectManager.cpp b/opengl/libagl/TextureObjectManager.cpp
deleted file mode 100644
index 06d45cc..0000000
--- a/opengl/libagl/TextureObjectManager.cpp
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- ** Copyright 2006, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "context.h"
-#include "TextureObjectManager.h"
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-EGLTextureObject::EGLTextureObject()
- : mSize(0)
-{
- init();
-}
-
-EGLTextureObject::~EGLTextureObject()
-{
- if (!direct) {
- if (mSize && surface.data)
- free(surface.data);
- if (mMipmaps)
- freeMipmaps();
- }
-}
-
-void EGLTextureObject::init()
-{
- memset(&surface, 0, sizeof(surface));
- surface.version = sizeof(surface);
- mMipmaps = 0;
- mNumExtraLod = 0;
- mIsComplete = false;
- wraps = GL_REPEAT;
- wrapt = GL_REPEAT;
- min_filter = GL_LINEAR;
- mag_filter = GL_LINEAR;
- internalformat = 0;
- memset(crop_rect, 0, sizeof(crop_rect));
- generate_mipmap = GL_FALSE;
- direct = GL_FALSE;
- buffer = 0;
-}
-
-void EGLTextureObject::copyParameters(const sp<EGLTextureObject>& old)
-{
- wraps = old->wraps;
- wrapt = old->wrapt;
- min_filter = old->min_filter;
- mag_filter = old->mag_filter;
- memcpy(crop_rect, old->crop_rect, sizeof(crop_rect));
- generate_mipmap = old->generate_mipmap;
- direct = old->direct;
-}
-
-status_t EGLTextureObject::allocateMipmaps()
-{
- // here, by construction, mMipmaps=0 && mNumExtraLod=0
-
- if (!surface.data)
- return NO_INIT;
-
- int w = surface.width;
- int h = surface.height;
- const int numLods = 31 - gglClz(max(w,h));
- if (numLods <= 0)
- return NO_ERROR;
-
- mMipmaps = (GGLSurface*)malloc(numLods * sizeof(GGLSurface));
- if (!mMipmaps)
- return NO_MEMORY;
-
- memset(mMipmaps, 0, numLods * sizeof(GGLSurface));
- mNumExtraLod = numLods;
- return NO_ERROR;
-}
-
-void EGLTextureObject::freeMipmaps()
-{
- if (mMipmaps) {
- for (int i=0 ; i<mNumExtraLod ; i++) {
- if (mMipmaps[i].data) {
- free(mMipmaps[i].data);
- }
- }
- free(mMipmaps);
- mMipmaps = 0;
- mNumExtraLod = 0;
- }
-}
-
-const GGLSurface& EGLTextureObject::mip(int lod) const
-{
- if (lod<=0 || !mMipmaps)
- return surface;
- lod = min(lod-1, mNumExtraLod-1);
- return mMipmaps[lod];
-}
-
-GGLSurface& EGLTextureObject::editMip(int lod)
-{
- return const_cast<GGLSurface&>(mip(lod));
-}
-
-status_t EGLTextureObject::setSurface(GGLSurface const* s)
-{
- // XXX: glFlush() on 's'
- if (mSize && surface.data) {
- free(surface.data);
- }
- surface = *s;
- internalformat = 0;
- buffer = 0;
-
- // we should keep the crop_rect, but it's delicate because
- // the new size of the surface could make it invalid.
- // so for now, we just loose it.
- memset(crop_rect, 0, sizeof(crop_rect));
-
- // it would be nice if we could keep the generate_mipmap flag,
- // we would have to generate them right now though.
- generate_mipmap = GL_FALSE;
-
- direct = GL_TRUE;
- mSize = 0; // we don't own this surface
- if (mMipmaps)
- freeMipmaps();
- mIsComplete = true;
- return NO_ERROR;
-}
-
-status_t EGLTextureObject::setImage(ANativeWindowBuffer* native_buffer)
-{
- GGLSurface sur;
- sur.version = sizeof(GGLSurface);
- sur.width = native_buffer->width;
- sur.height= native_buffer->height;
- sur.stride= native_buffer->stride;
- sur.format= native_buffer->format;
- sur.data = 0;
- setSurface(&sur);
- buffer = native_buffer;
- return NO_ERROR;
-}
-
-status_t EGLTextureObject::reallocate(
- GLint level, int w, int h, int s,
- int format, int compressedFormat, int bpr)
-{
- const size_t size = h * bpr;
- if (level == 0)
- {
- if (size!=mSize || !surface.data) {
- if (mSize && surface.data) {
- free(surface.data);
- }
- surface.data = (GGLubyte*)malloc(size);
- if (!surface.data) {
- mSize = 0;
- mIsComplete = false;
- return NO_MEMORY;
- }
- mSize = size;
- }
- surface.version = sizeof(GGLSurface);
- surface.width = w;
- surface.height = h;
- surface.stride = s;
- surface.format = format;
- surface.compressedFormat = compressedFormat;
- if (mMipmaps)
- freeMipmaps();
- mIsComplete = true;
- }
- else
- {
- if (!mMipmaps) {
- if (allocateMipmaps() != NO_ERROR)
- return NO_MEMORY;
- }
-
- ALOGW_IF(level-1 >= mNumExtraLod,
- "specifying mipmap level %d, but # of level is %d",
- level, mNumExtraLod+1);
-
- GGLSurface& mipmap = editMip(level);
- if (mipmap.data)
- free(mipmap.data);
-
- mipmap.data = (GGLubyte*)malloc(size);
- if (!mipmap.data) {
- memset(&mipmap, 0, sizeof(GGLSurface));
- mIsComplete = false;
- return NO_MEMORY;
- }
-
- mipmap.version = sizeof(GGLSurface);
- mipmap.width = w;
- mipmap.height = h;
- mipmap.stride = s;
- mipmap.format = format;
- mipmap.compressedFormat = compressedFormat;
-
- // check if the texture is complete
- mIsComplete = true;
- const GGLSurface* prev = &surface;
- for (int i=0 ; i<mNumExtraLod ; i++) {
- const GGLSurface* curr = mMipmaps + i;
- if (curr->format != surface.format) {
- mIsComplete = false;
- break;
- }
-
- uint32_t w = (prev->width >> 1) ? : 1;
- uint32_t h = (prev->height >> 1) ? : 1;
- if (w != curr->width || h != curr->height) {
- mIsComplete = false;
- break;
- }
- prev = curr;
- }
- }
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-EGLSurfaceManager::EGLSurfaceManager()
- : TokenManager()
-{
-}
-
-EGLSurfaceManager::~EGLSurfaceManager()
-{
- // everything gets freed automatically here...
-}
-
-sp<EGLTextureObject> EGLSurfaceManager::createTexture(GLuint name)
-{
- sp<EGLTextureObject> result;
-
- Mutex::Autolock _l(mLock);
- if (mTextures.indexOfKey(name) >= 0)
- return result; // already exists!
-
- result = new EGLTextureObject();
-
- status_t err = mTextures.add(name, result);
- if (err < 0)
- result.clear();
-
- return result;
-}
-
-sp<EGLTextureObject> EGLSurfaceManager::removeTexture(GLuint name)
-{
- Mutex::Autolock _l(mLock);
- const ssize_t index = mTextures.indexOfKey(name);
- if (index >= 0) {
- sp<EGLTextureObject> result(mTextures.valueAt(index));
- mTextures.removeItemsAt(index);
- return result;
- }
- return 0;
-}
-
-sp<EGLTextureObject> EGLSurfaceManager::replaceTexture(GLuint name)
-{
- sp<EGLTextureObject> tex;
- Mutex::Autolock _l(mLock);
- const ssize_t index = mTextures.indexOfKey(name);
- if (index >= 0) {
- const sp<EGLTextureObject>& old = mTextures.valueAt(index);
- const uint32_t refs = old->getStrongCount();
- if (ggl_likely(refs == 1)) {
- // we're the only owner
- tex = old;
- } else {
- // keep the texture's parameters
- tex = new EGLTextureObject();
- tex->copyParameters(old);
- mTextures.removeItemsAt(index);
- mTextures.add(name, tex);
- }
- }
- return tex;
-}
-
-void EGLSurfaceManager::deleteTextures(GLsizei n, const GLuint *tokens)
-{
- // free all textures
- Mutex::Autolock _l(mLock);
- for (GLsizei i=0 ; i<n ; i++) {
- const GLuint t(*tokens++);
- if (t) {
- mTextures.removeItem(t);
- }
- }
-}
-
-sp<EGLTextureObject> EGLSurfaceManager::texture(GLuint name)
-{
- Mutex::Autolock _l(mLock);
- const ssize_t index = mTextures.indexOfKey(name);
- if (index >= 0)
- return mTextures.valueAt(index);
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/opengl/libagl/TextureObjectManager.h b/opengl/libagl/TextureObjectManager.h
deleted file mode 100644
index 9cf8771..0000000
--- a/opengl/libagl/TextureObjectManager.h
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_SURFACE_H
-#define ANDROID_OPENGLES_SURFACE_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <cutils/atomic.h>
-#include <utils/threads.h>
-#include <utils/RefBase.h>
-#include <utils/KeyedVector.h>
-#include <utils/Errors.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include <GLES/gl.h>
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#include "Tokenizer.h"
-#include "TokenManager.h"
-
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class EGLTextureObject : public LightRefBase<EGLTextureObject>
-{
-public:
- EGLTextureObject();
- ~EGLTextureObject();
-
- status_t setSurface(GGLSurface const* s);
- status_t setImage(ANativeWindowBuffer* buffer);
- void setImageBits(void* vaddr) { surface.data = (GGLubyte*)vaddr; }
-
- status_t reallocate(GLint level,
- int w, int h, int s,
- int format, int compressedFormat, int bpr);
- inline size_t size() const { return mSize; }
- const GGLSurface& mip(int lod) const;
- GGLSurface& editMip(int lod);
- bool hasMipmaps() const { return mMipmaps!=0; }
- bool isComplete() const { return mIsComplete; }
- void copyParameters(const sp<EGLTextureObject>& old);
-
-private:
- status_t allocateMipmaps();
- void freeMipmaps();
- void init();
- size_t mSize;
- GGLSurface *mMipmaps;
- int mNumExtraLod;
- bool mIsComplete;
-
-public:
- GGLSurface surface;
- GLenum wraps;
- GLenum wrapt;
- GLenum min_filter;
- GLenum mag_filter;
- GLenum internalformat;
- GLint crop_rect[4];
- GLint generate_mipmap;
- GLint direct;
- ANativeWindowBuffer* buffer;
-};
-
-// ----------------------------------------------------------------------------
-
-class EGLSurfaceManager :
- public LightRefBase<EGLSurfaceManager>,
- public TokenManager
-{
-public:
- EGLSurfaceManager();
- ~EGLSurfaceManager();
-
- sp<EGLTextureObject> createTexture(GLuint name);
- sp<EGLTextureObject> removeTexture(GLuint name);
- sp<EGLTextureObject> replaceTexture(GLuint name);
- void deleteTextures(GLsizei n, const GLuint *tokens);
- sp<EGLTextureObject> texture(GLuint name);
-
-private:
- mutable Mutex mLock;
- KeyedVector< GLuint, sp<EGLTextureObject> > mTextures;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_SURFACE_H
-
diff --git a/opengl/libagl/TokenManager.cpp b/opengl/libagl/TokenManager.cpp
deleted file mode 100644
index eea6025..0000000
--- a/opengl/libagl/TokenManager.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* libs/opengles/surface.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "TokenManager.h"
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-TokenManager::TokenManager()
-{
- // token 0 is always reserved
- mTokenizer.reserve(0);
-}
-
-TokenManager::~TokenManager()
-{
-}
-
-status_t TokenManager::getToken(GLsizei n, GLuint *tokens)
-{
- Mutex::Autolock _l(mLock);
- for (GLsizei i=0 ; i<n ; i++)
- *tokens++ = mTokenizer.acquire();
- return NO_ERROR;
-}
-
-void TokenManager::recycleTokens(GLsizei n, const GLuint *tokens)
-{
- Mutex::Autolock _l(mLock);
- for (int i=0 ; i<n ; i++) {
- const GLuint token = *tokens++;
- if (token) {
- mTokenizer.release(token);
- }
- }
-}
-
-bool TokenManager::isTokenValid(GLuint token) const
-{
- Mutex::Autolock _l(mLock);
- return mTokenizer.isAcquired(token);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/opengl/libagl/TokenManager.h b/opengl/libagl/TokenManager.h
deleted file mode 100644
index 49c1469..0000000
--- a/opengl/libagl/TokenManager.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_TOKEN_MANAGER_H
-#define ANDROID_OPENGLES_TOKEN_MANAGER_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <utils/threads.h>
-
-#include <GLES/gl.h>
-
-#include "Tokenizer.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-class TokenManager
-{
-public:
- TokenManager();
- ~TokenManager();
-
- status_t getToken(GLsizei n, GLuint *tokens);
- void recycleTokens(GLsizei n, const GLuint *tokens);
- bool isTokenValid(GLuint token) const;
-
-private:
- mutable Mutex mLock;
- Tokenizer mTokenizer;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_TOKEN_MANAGER_H
-
diff --git a/opengl/libagl/Tokenizer.cpp b/opengl/libagl/Tokenizer.cpp
deleted file mode 100644
index ac0a48c..0000000
--- a/opengl/libagl/Tokenizer.cpp
+++ /dev/null
@@ -1,173 +0,0 @@
-/* libs/opengles/Tokenizer.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-
-#include "Tokenizer.h"
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-ANDROID_BASIC_TYPES_TRAITS(Tokenizer::run_t)
-
-Tokenizer::Tokenizer()
-{
-}
-
-Tokenizer::Tokenizer(const Tokenizer& other)
- : mRanges(other.mRanges)
-{
-}
-
-Tokenizer::~Tokenizer()
-{
-}
-
-uint32_t Tokenizer::acquire()
-{
- if (!mRanges.size() || mRanges[0].first) {
- _insertTokenAt(0,0);
- return 0;
- }
-
- // just extend the first run
- const run_t& run = mRanges[0];
- uint32_t token = run.first + run.length;
- _insertTokenAt(token, 1);
- return token;
-}
-
-bool Tokenizer::isAcquired(uint32_t token) const
-{
- return (_indexOrderOf(token) >= 0);
-}
-
-status_t Tokenizer::reserve(uint32_t token)
-{
- size_t o;
- const ssize_t i = _indexOrderOf(token, &o);
- if (i >= 0) {
- return BAD_VALUE; // this token is already taken
- }
- ssize_t err = _insertTokenAt(token, o);
- return (err<0) ? err : status_t(NO_ERROR);
-}
-
-status_t Tokenizer::release(uint32_t token)
-{
- const ssize_t i = _indexOrderOf(token);
- if (i >= 0) {
- const run_t& run = mRanges[i];
- if ((token >= run.first) && (token < run.first+run.length)) {
- // token in this range, we need to split
- run_t& run = mRanges.editItemAt(i);
- if ((token == run.first) || (token == run.first+run.length-1)) {
- if (token == run.first) {
- run.first += 1;
- }
- run.length -= 1;
- if (run.length == 0) {
- // XXX: should we systematically remove a run that's empty?
- mRanges.removeItemsAt(i);
- }
- } else {
- // split the run
- run_t new_run;
- new_run.first = token+1;
- new_run.length = run.first+run.length - new_run.first;
- run.length = token - run.first;
- mRanges.insertAt(new_run, i+1);
- }
- return NO_ERROR;
- }
- }
- return NAME_NOT_FOUND;
-}
-
-ssize_t Tokenizer::_indexOrderOf(uint32_t token, size_t* order) const
-{
- // binary search
- ssize_t err = NAME_NOT_FOUND;
- ssize_t l = 0;
- ssize_t h = mRanges.size()-1;
- ssize_t mid;
- const run_t* a = mRanges.array();
- while (l <= h) {
- mid = l + (h - l)/2;
- const run_t* const curr = a + mid;
- int c = 0;
- if (token < curr->first) c = 1;
- else if (token >= curr->first+curr->length) c = -1;
- if (c == 0) {
- err = l = mid;
- break;
- } else if (c < 0) {
- l = mid + 1;
- } else {
- h = mid - 1;
- }
- }
- if (order) *order = l;
- return err;
-}
-
-ssize_t Tokenizer::_insertTokenAt(uint32_t token, size_t index)
-{
- const size_t c = mRanges.size();
-
- if (index >= 1) {
- // do we need to merge with the previous run?
- run_t& p = mRanges.editItemAt(index-1);
- if (p.first+p.length == token) {
- p.length += 1;
- if (index < c) {
- const run_t& n = mRanges[index];
- if (token+1 == n.first) {
- p.length += n.length;
- mRanges.removeItemsAt(index);
- }
- }
- return index;
- }
- }
-
- if (index < c) {
- // do we need to merge with the next run?
- run_t& n = mRanges.editItemAt(index);
- if (token+1 == n.first) {
- n.first -= 1;
- n.length += 1;
- return index;
- }
- }
-
- return mRanges.insertAt(run_t(token,1), index);
-}
-
-void Tokenizer::dump() const
-{
- const run_t* ranges = mRanges.array();
- const size_t c = mRanges.size();
- ALOGD("Tokenizer (%p, size = %zu)\n", this, c);
- for (size_t i=0 ; i<c ; i++) {
- ALOGD("%zu: (%u, %u)\n", i, ranges[i].first, ranges[i].length);
- }
-}
-
-}; // namespace android
-
diff --git a/opengl/libagl/Tokenizer.h b/opengl/libagl/Tokenizer.h
deleted file mode 100644
index ac555cb..0000000
--- a/opengl/libagl/Tokenizer.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* libs/opengles/Tokenizer.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
-#ifndef ANDROID_OPENGLES_TOKENIZER_H
-#define ANDROID_OPENGLES_TOKENIZER_H
-
-#include <utils/Vector.h>
-#include <utils/Errors.h>
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-class Tokenizer
-{
-public:
- Tokenizer();
- Tokenizer(const Tokenizer& other);
- ~Tokenizer();
-
- uint32_t acquire();
- status_t reserve(uint32_t token);
- status_t release(uint32_t token);
- bool isAcquired(uint32_t token) const;
-
- void dump() const;
-
- struct run_t {
- run_t() {};
- run_t(uint32_t f, uint32_t l) : first(f), length(l) {}
- uint32_t first;
- uint32_t length;
- };
-private:
- ssize_t _indexOrderOf(uint32_t token, size_t* order=0) const;
- ssize_t _insertTokenAt(uint32_t token, size_t index);
- Vector<run_t> mRanges;
-};
-
-}; // namespace android
-
-// ----------------------------------------------------------------------------
-
-#endif // ANDROID_OPENGLES_TOKENIZER_H
diff --git a/opengl/libagl/arch-mips/fixed_asm.S b/opengl/libagl/arch-mips/fixed_asm.S
deleted file mode 100644
index a30ffc5..0000000
--- a/opengl/libagl/arch-mips/fixed_asm.S
+++ /dev/null
@@ -1,61 +0,0 @@
-/* libs/opengles/arch-mips/fixed_asm.S
-**
-** Copyright 2012, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
- .text
- .align 4
-
-/*
- * this version rounds-to-nearest and saturates numbers
- * outside the range (but not NaNs).
- */
-
- .global gglFloatToFixed
- .ent gglFloatToFixed
- .type gglFloatToFixed, @function
-gglFloatToFixed:
-#if !defined(__mips_soft_float)
- mfc1 $a0,$f12
-#endif
- srl $t0,$a0,31 /* t0 <- sign bit */
- srl $t1,$a0,23
- andi $t1,$t1,0xff /* get the e */
- li $t2,0x8e
- subu $t1,$t2,$t1 /* t1=127+15-e */
- blez $t1,0f /* t1<=0? */
- sll $t2,$a0,8 /* mantissa<<8 */
- lui $t3,0x8000
- or $t2,$t2,$t3 /* add the missing 1 */
- subu $t1,$t1,1
- srl $v0,$t2,$t1
- sltiu $t3,$t1,32 /* t3=1 if t1<32, else t3=0. t1>=32 means the float value is too small. */
- andi $t4,$v0,0x1
- srl $v0,$v0,1 /* scale to 16.16 */
- addu $v0,$v0,$t4 /* round-to-nearest */
- subu $t2,$zero,$v0
- movn $v0,$t2,$t0 /* if negative? */
- or $t1,$a0,$zero /* a0=0? */
- movz $v0,$zero,$t1
- movz $v0,$zero,$t3 /* t3=0 then res=0 */
- jr $ra
-0:
- lui $t1,0x8000
- and $v0,$a0,$t1 /* keep only the sign bit */
- li $t1,0x7fffffff
- movz $v0,$t1,$t0 /* positive, maximum value */
- jr $ra
- .end gglFloatToFixed
diff --git a/opengl/libagl/array.cpp b/opengl/libagl/array.cpp
deleted file mode 100644
index 2d36c61..0000000
--- a/opengl/libagl/array.cpp
+++ /dev/null
@@ -1,1590 +0,0 @@
-/*
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "context.h"
-#include "fp.h"
-#include "state.h"
-#include "matrix.h"
-#include "vertex.h"
-#include "light.h"
-#include "primitives.h"
-#include "texture.h"
-#include "BufferObjectManager.h"
-
-// ----------------------------------------------------------------------------
-
-#define VC_CACHE_STATISTICS 0
-#define VC_CACHE_TYPE_NONE 0
-#define VC_CACHE_TYPE_INDEXED 1
-#define VC_CACHE_TYPE_LRU 2
-#define VC_CACHE_TYPE VC_CACHE_TYPE_INDEXED
-
-#if VC_CACHE_STATISTICS
-#include <utils/Timers.h>
-#endif
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-static void validate_arrays(ogles_context_t* c, GLenum mode);
-
-static void compileElements__generic(ogles_context_t*,
- vertex_t*, GLint, GLsizei);
-static void compileElement__generic(ogles_context_t*,
- vertex_t*, GLint);
-
-static void drawPrimitivesPoints(ogles_context_t*, GLint, GLsizei);
-static void drawPrimitivesLineStrip(ogles_context_t*, GLint, GLsizei);
-static void drawPrimitivesLineLoop(ogles_context_t*, GLint, GLsizei);
-static void drawPrimitivesLines(ogles_context_t*, GLint, GLsizei);
-static void drawPrimitivesTriangleStrip(ogles_context_t*, GLint, GLsizei);
-static void drawPrimitivesTriangleFan(ogles_context_t*, GLint, GLsizei);
-static void drawPrimitivesTriangles(ogles_context_t*, GLint, GLsizei);
-
-static void drawIndexedPrimitivesPoints(ogles_context_t*,
- GLsizei, const GLvoid*);
-static void drawIndexedPrimitivesLineStrip(ogles_context_t*,
- GLsizei, const GLvoid*);
-static void drawIndexedPrimitivesLineLoop(ogles_context_t*,
- GLsizei, const GLvoid*);
-static void drawIndexedPrimitivesLines(ogles_context_t*,
- GLsizei, const GLvoid*);
-static void drawIndexedPrimitivesTriangleStrip(ogles_context_t*,
- GLsizei, const GLvoid*);
-static void drawIndexedPrimitivesTriangleFan(ogles_context_t*,
- GLsizei, const GLvoid*);
-static void drawIndexedPrimitivesTriangles(ogles_context_t*,
- GLsizei, const GLvoid*);
-
-// ----------------------------------------------------------------------------
-
-typedef void (*arrays_prims_fct_t)(ogles_context_t*, GLint, GLsizei);
-static const arrays_prims_fct_t drawArraysPrims[] = {
- drawPrimitivesPoints,
- drawPrimitivesLines,
- drawPrimitivesLineLoop,
- drawPrimitivesLineStrip,
- drawPrimitivesTriangles,
- drawPrimitivesTriangleStrip,
- drawPrimitivesTriangleFan
-};
-
-typedef void (*elements_prims_fct_t)(ogles_context_t*, GLsizei, const GLvoid*);
-static const elements_prims_fct_t drawElementsPrims[] = {
- drawIndexedPrimitivesPoints,
- drawIndexedPrimitivesLines,
- drawIndexedPrimitivesLineLoop,
- drawIndexedPrimitivesLineStrip,
- drawIndexedPrimitivesTriangles,
- drawIndexedPrimitivesTriangleStrip,
- drawIndexedPrimitivesTriangleFan
-};
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void ogles_init_array(ogles_context_t* c)
-{
- c->arrays.vertex.size = 4;
- c->arrays.vertex.type = GL_FLOAT;
- c->arrays.color.size = 4;
- c->arrays.color.type = GL_FLOAT;
- c->arrays.normal.size = 4;
- c->arrays.normal.type = GL_FLOAT;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- c->arrays.texture[i].size = 4;
- c->arrays.texture[i].type = GL_FLOAT;
- }
- c->vc.init();
-
- if (!c->vc.vBuffer) {
- // this could have failed
- ogles_error(c, GL_OUT_OF_MEMORY);
- }
-}
-
-void ogles_uninit_array(ogles_context_t* c)
-{
- c->vc.uninit();
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Array fetchers
-#endif
-
-static void currentColor(ogles_context_t* c, GLfixed* v, const GLvoid*) {
- memcpy(v, c->current.color.v, sizeof(vec4_t));
-}
-static void currentNormal(ogles_context_t* c, GLfixed* v, const GLvoid*) {
- memcpy(v, c->currentNormal.v, sizeof(vec3_t));
-}
-static void currentTexCoord(ogles_context_t* c, GLfixed* v, const GLvoid*) {
- memcpy(v, c->current.texture[c->arrays.tmu].v, sizeof(vec4_t));
-}
-
-
-static void fetchNop(ogles_context_t*, GLfixed*, const GLvoid*) {
-}
-static void fetch2b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
- v[0] = gglIntToFixed(p[0]);
- v[1] = gglIntToFixed(p[1]);
-}
-static void fetch2s(ogles_context_t*, GLfixed* v, const GLshort* p) {
- v[0] = gglIntToFixed(p[0]);
- v[1] = gglIntToFixed(p[1]);
-}
-static void fetch2x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
- memcpy(v, p, 2*sizeof(GLfixed));
-}
-static void fetch2f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
- v[0] = gglFloatToFixed(p[0]);
- v[1] = gglFloatToFixed(p[1]);
-}
-static void fetch3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
- v[0] = gglIntToFixed(p[0]);
- v[1] = gglIntToFixed(p[1]);
- v[2] = gglIntToFixed(p[2]);
-}
-static void fetch3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
- v[0] = gglIntToFixed(p[0]);
- v[1] = gglIntToFixed(p[1]);
- v[2] = gglIntToFixed(p[2]);
-}
-static void fetch3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
- memcpy(v, p, 3*sizeof(GLfixed));
-}
-static void fetch3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
- v[0] = gglFloatToFixed(p[0]);
- v[1] = gglFloatToFixed(p[1]);
- v[2] = gglFloatToFixed(p[2]);
-}
-static void fetch4b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
- v[0] = gglIntToFixed(p[0]);
- v[1] = gglIntToFixed(p[1]);
- v[2] = gglIntToFixed(p[2]);
- v[3] = gglIntToFixed(p[3]);
-}
-static void fetch4s(ogles_context_t*, GLfixed* v, const GLshort* p) {
- v[0] = gglIntToFixed(p[0]);
- v[1] = gglIntToFixed(p[1]);
- v[2] = gglIntToFixed(p[2]);
- v[3] = gglIntToFixed(p[3]);
-}
-static void fetch4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
- memcpy(v, p, 4*sizeof(GLfixed));
-}
-static void fetch4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
- v[0] = gglFloatToFixed(p[0]);
- v[1] = gglFloatToFixed(p[1]);
- v[2] = gglFloatToFixed(p[2]);
- v[3] = gglFloatToFixed(p[3]);
-}
-static void fetchExpand4ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
- v[0] = GGL_UB_TO_X(p[0]);
- v[1] = GGL_UB_TO_X(p[1]);
- v[2] = GGL_UB_TO_X(p[2]);
- v[3] = GGL_UB_TO_X(p[3]);
-}
-static void fetchClamp4x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
- v[0] = gglClampx(p[0]);
- v[1] = gglClampx(p[1]);
- v[2] = gglClampx(p[2]);
- v[3] = gglClampx(p[3]);
-}
-static void fetchClamp4f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
- v[0] = gglClampx(gglFloatToFixed(p[0]));
- v[1] = gglClampx(gglFloatToFixed(p[1]));
- v[2] = gglClampx(gglFloatToFixed(p[2]));
- v[3] = gglClampx(gglFloatToFixed(p[3]));
-}
-static void fetchExpand3ub(ogles_context_t*, GLfixed* v, const GLubyte* p) {
- v[0] = GGL_UB_TO_X(p[0]);
- v[1] = GGL_UB_TO_X(p[1]);
- v[2] = GGL_UB_TO_X(p[2]);
- v[3] = 0x10000;
-}
-static void fetchClamp3x(ogles_context_t*, GLfixed* v, const GLfixed* p) {
- v[0] = gglClampx(p[0]);
- v[1] = gglClampx(p[1]);
- v[2] = gglClampx(p[2]);
- v[3] = 0x10000;
-}
-static void fetchClamp3f(ogles_context_t*, GLfixed* v, const GLfloat* p) {
- v[0] = gglClampx(gglFloatToFixed(p[0]));
- v[1] = gglClampx(gglFloatToFixed(p[1]));
- v[2] = gglClampx(gglFloatToFixed(p[2]));
- v[3] = 0x10000;
-}
-static void fetchExpand3b(ogles_context_t*, GLfixed* v, const GLbyte* p) {
- v[0] = GGL_B_TO_X(p[0]);
- v[1] = GGL_B_TO_X(p[1]);
- v[2] = GGL_B_TO_X(p[2]);
-}
-static void fetchExpand3s(ogles_context_t*, GLfixed* v, const GLshort* p) {
- v[0] = GGL_S_TO_X(p[0]);
- v[1] = GGL_S_TO_X(p[1]);
- v[2] = GGL_S_TO_X(p[2]);
-}
-
-typedef array_t::fetcher_t fn_t;
-
-static const fn_t color_fct[2][16] = { // size={3,4}, type={ub,f,x}
- { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
- (fn_t)fetch3f, 0, 0, 0, 0, 0,
- (fn_t)fetch3x },
- { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
- (fn_t)fetch4f, 0, 0, 0, 0, 0,
- (fn_t)fetch4x },
-};
-static const fn_t color_clamp_fct[2][16] = { // size={3,4}, type={ub,f,x}
- { 0, (fn_t)fetchExpand3ub, 0, 0, 0, 0,
- (fn_t)fetchClamp3f, 0, 0, 0, 0, 0,
- (fn_t)fetchClamp3x },
- { 0, (fn_t)fetchExpand4ub, 0, 0, 0, 0,
- (fn_t)fetchClamp4f, 0, 0, 0, 0, 0,
- (fn_t)fetchClamp4x },
-};
-static const fn_t normal_fct[1][16] = { // size={3}, type={b,s,f,x}
- { (fn_t)fetchExpand3b, 0,
- (fn_t)fetchExpand3s, 0, 0, 0,
- (fn_t)fetch3f, 0, 0, 0, 0, 0,
- (fn_t)fetch3x },
-};
-static const fn_t vertex_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
- { (fn_t)fetch2b, 0,
- (fn_t)fetch2s, 0, 0, 0,
- (fn_t)fetch2f, 0, 0, 0, 0, 0,
- (fn_t)fetch3x },
- { (fn_t)fetch3b, 0,
- (fn_t)fetch3s, 0, 0, 0,
- (fn_t)fetch3f, 0, 0, 0, 0, 0,
- (fn_t)fetch3x },
- { (fn_t)fetch4b, 0,
- (fn_t)fetch4s, 0, 0, 0,
- (fn_t)fetch4f, 0, 0, 0, 0, 0,
- (fn_t)fetch4x }
-};
-static const fn_t texture_fct[3][16] = { // size={2,3,4}, type={b,s,f,x}
- { (fn_t)fetch2b, 0,
- (fn_t)fetch2s, 0, 0, 0,
- (fn_t)fetch2f, 0, 0, 0, 0, 0,
- (fn_t)fetch2x },
- { (fn_t)fetch3b, 0,
- (fn_t)fetch3s, 0, 0, 0,
- (fn_t)fetch3f, 0, 0, 0, 0, 0,
- (fn_t)fetch3x },
- { (fn_t)fetch4b, 0,
- (fn_t)fetch4s, 0, 0, 0,
- (fn_t)fetch4f, 0, 0, 0, 0, 0,
- (fn_t)fetch4x }
-};
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark array_t
-#endif
-
-void array_t::init(
- GLint size, GLenum type, GLsizei stride,
- const GLvoid *pointer, const buffer_t* bo, GLsizei count)
-{
- if (!stride) {
- stride = size;
- switch (type) {
- case GL_SHORT:
- case GL_UNSIGNED_SHORT:
- stride *= 2;
- break;
- case GL_FLOAT:
- case GL_FIXED:
- stride *= 4;
- break;
- }
- }
- this->size = size;
- this->type = type;
- this->stride = stride;
- this->pointer = pointer;
- this->bo = bo;
- this->bounds = count;
-}
-
-inline void array_t::resolve()
-{
- physical_pointer = (bo) ? (bo->data + uintptr_t(pointer)) : pointer;
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark vertex_cache_t
-#endif
-
-void vertex_cache_t::init()
-{
- // make sure the size of vertex_t allows cache-line alignment
- CTA<(sizeof(vertex_t) & 0x1F) == 0> assertAlignedSize;
- (void)assertAlignedSize; // suppress unused warning.
-
- const int align = 32;
- const size_t s = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
- const size_t size = s*sizeof(vertex_t) + align;
- base = malloc(size);
- if (base) {
- memset(base, 0, size);
- vBuffer = (vertex_t*)((size_t(base) + align - 1) & ~(align-1));
- vCache = vBuffer + VERTEX_BUFFER_SIZE;
- sequence = 0;
- }
-}
-
-void vertex_cache_t::uninit()
-{
- free(base);
- base = vBuffer = vCache = 0;
-}
-
-void vertex_cache_t::clear()
-{
-#if VC_CACHE_STATISTICS
- startTime = systemTime(SYSTEM_TIME_THREAD);
- total = 0;
- misses = 0;
-#endif
-
-#if VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
- vertex_t* v = vBuffer;
- size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
- do {
- v->mru = 0;
- v++;
- } while (--count);
-#endif
-
- sequence += INDEX_SEQ;
- if (sequence >= 0x80000000LU) {
- sequence = INDEX_SEQ;
- vertex_t* v = vBuffer;
- size_t count = VERTEX_BUFFER_SIZE + VERTEX_CACHE_SIZE;
- do {
- v->index = 0;
- v++;
- } while (--count);
- }
-}
-
-#if VC_CACHE_STATISTICS
-void vertex_cache_t::dump_stats(GLenum mode)
-{
- nsecs_t time = systemTime(SYSTEM_TIME_THREAD) - startTime;
- uint32_t hits = total - misses;
- uint32_t prim_count;
- switch (mode) {
- case GL_POINTS: prim_count = total; break;
- case GL_LINE_STRIP: prim_count = total - 1; break;
- case GL_LINE_LOOP: prim_count = total - 1; break;
- case GL_LINES: prim_count = total / 2; break;
- case GL_TRIANGLE_STRIP: prim_count = total - 2; break;
- case GL_TRIANGLE_FAN: prim_count = total - 2; break;
- case GL_TRIANGLES: prim_count = total / 3; break;
- default: return;
- }
- printf( "total=%5u, hits=%5u, miss=%5u, hitrate=%3u%%,"
- " prims=%5u, time=%6u us, prims/s=%d, v/t=%f\n",
- total, hits, misses, (hits*100)/total,
- prim_count, int(ns2us(time)), int(prim_count*float(seconds(1))/time),
- float(misses) / prim_count);
-}
-#else
-void vertex_cache_t::dump_stats(GLenum /*mode*/)
-{
-}
-#endif
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-static __attribute__((noinline))
-void enableDisableClientState(ogles_context_t* c, GLenum array, bool enable)
-{
- const int tmu = c->arrays.activeTexture;
- array_t* a;
- switch (array) {
- case GL_COLOR_ARRAY: a = &c->arrays.color; break;
- case GL_NORMAL_ARRAY: a = &c->arrays.normal; break;
- case GL_TEXTURE_COORD_ARRAY: a = &c->arrays.texture[tmu]; break;
- case GL_VERTEX_ARRAY: a = &c->arrays.vertex; break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- a->enable = enable ? GL_TRUE : GL_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Vertex Cache
-#endif
-
-static __attribute__((noinline))
-vertex_t* cache_vertex(ogles_context_t* c, vertex_t* v, uint32_t index)
-{
- #if VC_CACHE_STATISTICS
- c->vc.misses++;
- #endif
- if (ggl_unlikely(v->locked)) {
- // we're just looking for an entry in the cache that is not locked.
- // and we know that there cannot be more than 2 locked entries
- // because a triangle needs at most 3 vertices.
- // We never use the first and second entries because they might be in
- // use by the striper or faner. Any other entry will do as long as
- // it's not locked.
- // We compute directly the index of a "free" entry from the locked
- // state of v[2] and v[3].
- v = c->vc.vBuffer + 2;
- v += v[0].locked | (v[1].locked<<1);
- }
- // note: compileElement clears v->flags
- c->arrays.compileElement(c, v, index);
- v->locked = 1;
- return v;
-}
-
-static __attribute__((noinline))
-vertex_t* fetch_vertex(ogles_context_t* c, size_t index)
-{
- index |= c->vc.sequence;
-
-#if VC_CACHE_TYPE == VC_CACHE_TYPE_INDEXED
-
- vertex_t* const v = c->vc.vCache +
- (index & (vertex_cache_t::VERTEX_CACHE_SIZE-1));
-
- if (ggl_likely(v->index == index)) {
- v->locked = 1;
- return v;
- }
- return cache_vertex(c, v, index);
-
-#elif VC_CACHE_TYPE == VC_CACHE_TYPE_LRU
-
- vertex_t* v = c->vc.vCache +
- (index & ((vertex_cache_t::VERTEX_CACHE_SIZE-1)>>1))*2;
-
- // always record LRU in v[0]
- if (ggl_likely(v[0].index == index)) {
- v[0].locked = 1;
- v[0].mru = 0;
- return &v[0];
- }
-
- if (ggl_likely(v[1].index == index)) {
- v[1].locked = 1;
- v[0].mru = 1;
- return &v[1];
- }
-
- const int lru = 1 - v[0].mru;
- v[0].mru = lru;
- return cache_vertex(c, &v[lru], index);
-
-#elif VC_CACHE_TYPE == VC_CACHE_TYPE_NONE
-
- // just for debugging...
- vertex_t* v = c->vc.vBuffer + 2;
- return cache_vertex(c, v, index);
-
-#endif
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Primitive Assembly
-#endif
-
-void drawPrimitivesPoints(ogles_context_t* c, GLint first, GLsizei count)
-{
- if (ggl_unlikely(count < 1))
- return;
-
- // vertex cache size must be multiple of 1
- const GLsizei vcs =
- (vertex_cache_t::VERTEX_BUFFER_SIZE +
- vertex_cache_t::VERTEX_CACHE_SIZE);
- do {
- vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
- c->arrays.cull = vertex_t::CLIP_ALL;
- c->arrays.compileElements(c, v, first, num);
- first += num;
- count -= num;
- if (!c->arrays.cull) {
- // quick/trivial reject of the whole batch
- do {
- const uint32_t cc = v[0].flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderPoint(c, v);
- v++;
- num--;
- } while (num);
- }
- } while (count);
-}
-
-// ----------------------------------------------------------------------------
-
-void drawPrimitivesLineStrip(ogles_context_t* c, GLint first, GLsizei count)
-{
- if (ggl_unlikely(count < 2))
- return;
-
- vertex_t *v, *v0, *v1;
- c->arrays.cull = vertex_t::CLIP_ALL;
- c->arrays.compileElement(c, c->vc.vBuffer, first);
- first += 1;
- count -= 1;
-
- // vertex cache size must be multiple of 1
- const GLsizei vcs =
- (vertex_cache_t::VERTEX_BUFFER_SIZE +
- vertex_cache_t::VERTEX_CACHE_SIZE - 1);
- do {
- v0 = c->vc.vBuffer + 0;
- v = c->vc.vBuffer + 1;
- GLsizei num = count > vcs ? vcs : count;
- c->arrays.compileElements(c, v, first, num);
- first += num;
- count -= num;
- if (!c->arrays.cull) {
- // quick/trivial reject of the whole batch
- do {
- v1 = v++;
- const uint32_t cc = v0->flags & v1->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v0, v1);
- v0 = v1;
- num--;
- } while (num);
- }
- // copy back the last processed vertex
- c->vc.vBuffer[0] = *v0;
- c->arrays.cull = v0->flags & vertex_t::CLIP_ALL;
- } while (count);
-}
-
-void drawPrimitivesLineLoop(ogles_context_t* c, GLint first, GLsizei count)
-{
- if (ggl_unlikely(count < 2))
- return;
- drawPrimitivesLineStrip(c, first, count);
- if (ggl_likely(count >= 3)) {
- vertex_t* v0 = c->vc.vBuffer;
- vertex_t* v1 = c->vc.vBuffer + 1;
- c->arrays.compileElement(c, v1, first);
- const uint32_t cc = v0->flags & v1->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v0, v1);
- }
-}
-
-void drawPrimitivesLines(ogles_context_t* c, GLint first, GLsizei count)
-{
- if (ggl_unlikely(count < 2))
- return;
-
- // vertex cache size must be multiple of 2
- const GLsizei vcs =
- ((vertex_cache_t::VERTEX_BUFFER_SIZE +
- vertex_cache_t::VERTEX_CACHE_SIZE) / 2) * 2;
- do {
- vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
- c->arrays.cull = vertex_t::CLIP_ALL;
- c->arrays.compileElements(c, v, first, num);
- first += num;
- count -= num;
- if (!c->arrays.cull) {
- // quick/trivial reject of the whole batch
- num -= 2;
- do {
- const uint32_t cc = v[0].flags & v[1].flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v, v+1);
- v += 2;
- num -= 2;
- } while (num >= 0);
- }
- } while (count >= 2);
-}
-
-// ----------------------------------------------------------------------------
-
-static void drawPrimitivesTriangleFanOrStrip(ogles_context_t* c,
- GLint first, GLsizei count, int winding)
-{
- // winding == 2 : fan
- // winding == 1 : strip
-
- if (ggl_unlikely(count < 3))
- return;
-
- vertex_t *v, *v0, *v1, *v2;
- c->arrays.cull = vertex_t::CLIP_ALL;
- c->arrays.compileElements(c, c->vc.vBuffer, first, 2);
- first += 2;
- count -= 2;
-
- // vertex cache size must be multiple of 2. This is extremely important
- // because it allows us to preserve the same winding when the whole
- // batch is culled. We also need 2 extra vertices in the array, because
- // we always keep the two first ones.
- const GLsizei vcs =
- ((vertex_cache_t::VERTEX_BUFFER_SIZE +
- vertex_cache_t::VERTEX_CACHE_SIZE - 2) / 2) * 2;
- do {
- v0 = c->vc.vBuffer + 0;
- v1 = c->vc.vBuffer + 1;
- v = c->vc.vBuffer + 2;
- GLsizei num = count > vcs ? vcs : count;
- c->arrays.compileElements(c, v, first, num);
- first += num;
- count -= num;
- if (!c->arrays.cull) {
- // quick/trivial reject of the whole batch
- do {
- v2 = v++;
- const uint32_t cc = v0->flags & v1->flags & v2->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderTriangle(c, v0, v1, v2);
- swap(((winding^=1) ? v1 : v0), v2);
- num--;
- } while (num);
- }
- if (count) {
- v0 = c->vc.vBuffer + 2 + vcs - 2;
- v1 = c->vc.vBuffer + 2 + vcs - 1;
- if ((winding&2) == 0) {
- // for strips copy back the two last compiled vertices
- c->vc.vBuffer[0] = *v0;
- }
- c->vc.vBuffer[1] = *v1;
- c->arrays.cull = v0->flags & v1->flags & vertex_t::CLIP_ALL;
- }
- } while (count > 0);
-}
-
-void drawPrimitivesTriangleStrip(ogles_context_t* c,
- GLint first, GLsizei count) {
- drawPrimitivesTriangleFanOrStrip(c, first, count, 1);
-}
-
-void drawPrimitivesTriangleFan(ogles_context_t* c,
- GLint first, GLsizei count) {
- drawPrimitivesTriangleFanOrStrip(c, first, count, 2);
-}
-
-void drawPrimitivesTriangles(ogles_context_t* c, GLint first, GLsizei count)
-{
- if (ggl_unlikely(count < 3))
- return;
-
- // vertex cache size must be multiple of 3
- const GLsizei vcs =
- ((vertex_cache_t::VERTEX_BUFFER_SIZE +
- vertex_cache_t::VERTEX_CACHE_SIZE) / 3) * 3;
- do {
- vertex_t* v = c->vc.vBuffer;
- GLsizei num = count > vcs ? vcs : count;
- c->arrays.cull = vertex_t::CLIP_ALL;
- c->arrays.compileElements(c, v, first, num);
- first += num;
- count -= num;
- if (!c->arrays.cull) {
- // quick/trivial reject of the whole batch
- num -= 3;
- do {
- const uint32_t cc = v[0].flags & v[1].flags & v[2].flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderTriangle(c, v, v+1, v+2);
- v += 3;
- num -= 3;
- } while (num >= 0);
- }
- } while (count >= 3);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-// this looks goofy, but gcc does a great job with this...
-static inline unsigned int read_index(int type, const GLvoid*& p) {
- unsigned int r;
- if (type) {
- r = *(const GLubyte*)p;
- p = (const GLubyte*)p + 1;
- } else {
- r = *(const GLushort*)p;
- p = (const GLushort*)p + 1;
- }
- return r;
-}
-
-// ----------------------------------------------------------------------------
-
-void drawIndexedPrimitivesPoints(ogles_context_t* c,
- GLsizei count, const GLvoid *indices)
-{
- if (ggl_unlikely(count < 1))
- return;
- const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
- do {
- vertex_t * v = fetch_vertex(c, read_index(type, indices));
- if (ggl_likely(!(v->flags & vertex_t::CLIP_ALL)))
- c->prims.renderPoint(c, v);
- v->locked = 0;
- count--;
- } while(count);
-}
-
-// ----------------------------------------------------------------------------
-
-void drawIndexedPrimitivesLineStrip(ogles_context_t* c,
- GLsizei count, const GLvoid *indices)
-{
- if (ggl_unlikely(count < 2))
- return;
-
- vertex_t * const v = c->vc.vBuffer;
- vertex_t* v0 = v;
- vertex_t* v1;
-
- const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
- c->arrays.compileElement(c, v0, read_index(type, indices));
- count -= 1;
- do {
- v1 = fetch_vertex(c, read_index(type, indices));
- const uint32_t cc = v0->flags & v1->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v0, v1);
- v0->locked = 0;
- v0 = v1;
- count--;
- } while (count);
- v1->locked = 0;
-}
-
-void drawIndexedPrimitivesLineLoop(ogles_context_t* c,
- GLsizei count, const GLvoid *indices)
-{
- if (ggl_unlikely(count <= 2)) {
- drawIndexedPrimitivesLines(c, count, indices);
- return;
- }
-
- vertex_t * const v = c->vc.vBuffer;
- vertex_t* v0 = v;
- vertex_t* v1;
-
- const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
- c->arrays.compileElement(c, v0, read_index(type, indices));
- count -= 1;
- do {
- v1 = fetch_vertex(c, read_index(type, indices));
- const uint32_t cc = v0->flags & v1->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v0, v1);
- v0->locked = 0;
- v0 = v1;
- count--;
- } while (count);
- v1->locked = 0;
-
- v1 = c->vc.vBuffer;
- const uint32_t cc = v0->flags & v1->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v0, v1);
-}
-
-void drawIndexedPrimitivesLines(ogles_context_t* c,
- GLsizei count, const GLvoid *indices)
-{
- if (ggl_unlikely(count < 2))
- return;
-
- count -= 2;
- const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
- do {
- vertex_t* const v0 = fetch_vertex(c, read_index(type, indices));
- vertex_t* const v1 = fetch_vertex(c, read_index(type, indices));
- const uint32_t cc = v0->flags & v1->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderLine(c, v0, v1);
- v0->locked = 0;
- v1->locked = 0;
- count -= 2;
- } while (count >= 0);
-}
-
-// ----------------------------------------------------------------------------
-
-static void drawIndexedPrimitivesTriangleFanOrStrip(ogles_context_t* c,
- GLsizei count, const GLvoid *indices, int winding)
-{
- // winding == 2 : fan
- // winding == 1 : strip
-
- if (ggl_unlikely(count < 3))
- return;
-
- vertex_t * const v = c->vc.vBuffer;
- vertex_t* v0 = v;
- vertex_t* v1 = v+1;
- vertex_t* v2;
-
- const int type = (c->arrays.indicesType == GL_UNSIGNED_BYTE);
- c->arrays.compileElement(c, v0, read_index(type, indices));
- c->arrays.compileElement(c, v1, read_index(type, indices));
- count -= 2;
-
- // note: GCC 4.1.1 here makes a prety interesting optimization
- // where it duplicates the loop below based on c->arrays.indicesType
-
- do {
- v2 = fetch_vertex(c, read_index(type, indices));
- const uint32_t cc = v0->flags & v1->flags & v2->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderTriangle(c, v0, v1, v2);
- vertex_t* & consumed = ((winding^=1) ? v1 : v0);
- consumed->locked = 0;
- consumed = v2;
- count--;
- } while (count);
- v0->locked = v1->locked = 0;
- v2->locked = 0;
-}
-
-void drawIndexedPrimitivesTriangleStrip(ogles_context_t* c,
- GLsizei count, const GLvoid *indices) {
- drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 1);
-}
-
-void drawIndexedPrimitivesTriangleFan(ogles_context_t* c,
- GLsizei count, const GLvoid *indices) {
- drawIndexedPrimitivesTriangleFanOrStrip(c, count, indices, 2);
-}
-
-void drawIndexedPrimitivesTriangles(ogles_context_t* c,
- GLsizei count, const GLvoid *indices)
-{
- if (ggl_unlikely(count < 3))
- return;
-
- count -= 3;
- if (ggl_likely(c->arrays.indicesType == GL_UNSIGNED_SHORT)) {
- // This case is probably our most common case...
- uint16_t const * p = (uint16_t const *)indices;
- do {
- vertex_t* const v0 = fetch_vertex(c, *p++);
- vertex_t* const v1 = fetch_vertex(c, *p++);
- vertex_t* const v2 = fetch_vertex(c, *p++);
- const uint32_t cc = v0->flags & v1->flags & v2->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderTriangle(c, v0, v1, v2);
- v0->locked = 0;
- v1->locked = 0;
- v2->locked = 0;
- count -= 3;
- } while (count >= 0);
- } else {
- uint8_t const * p = (uint8_t const *)indices;
- do {
- vertex_t* const v0 = fetch_vertex(c, *p++);
- vertex_t* const v1 = fetch_vertex(c, *p++);
- vertex_t* const v2 = fetch_vertex(c, *p++);
- const uint32_t cc = v0->flags & v1->flags & v2->flags;
- if (ggl_likely(!(cc & vertex_t::CLIP_ALL)))
- c->prims.renderTriangle(c, v0, v1, v2);
- v0->locked = 0;
- v1->locked = 0;
- v2->locked = 0;
- count -= 3;
- } while (count >= 0);
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Array compilers
-#endif
-
-void compileElement__generic(ogles_context_t* c,
- vertex_t* v, GLint first)
-{
- v->flags = 0;
- v->index = first;
- first &= vertex_cache_t::INDEX_MASK;
- const GLubyte* vp = c->arrays.vertex.element(first);
- v->obj.z = 0;
- v->obj.w = 0x10000;
- c->arrays.vertex.fetch(c, v->obj.v, vp);
- c->arrays.mvp_transform(&c->transforms.mvp, &v->clip, &v->obj);
- c->arrays.perspective(c, v);
-}
-
-void compileElements__generic(ogles_context_t* c,
- vertex_t* v, GLint first, GLsizei count)
-{
- const GLubyte* vp = c->arrays.vertex.element(
- first & vertex_cache_t::INDEX_MASK);
- const size_t stride = c->arrays.vertex.stride;
- transform_t const* const mvp = &c->transforms.mvp;
- do {
- v->flags = 0;
- v->index = first++;
- v->obj.z = 0;
- v->obj.w = 0x10000;
- c->arrays.vertex.fetch(c, v->obj.v, vp);
- c->arrays.mvp_transform(mvp, &v->clip, &v->obj);
- c->arrays.perspective(c, v);
- vp += stride;
- v++;
- } while (--count);
-}
-
-/*
-void compileElements__3x_full(ogles_context_t* c,
- vertex_t* v, GLint first, GLsizei count)
-{
- const GLfixed* vp = (const GLfixed*)c->arrays.vertex.element(first);
- const size_t stride = c->arrays.vertex.stride / 4;
-// const GLfixed* const& m = c->transforms.mvp.matrix.m;
-
- GLfixed m[16];
- memcpy(&m, c->transforms.mvp.matrix.m, sizeof(m));
-
- do {
- const GLfixed rx = vp[0];
- const GLfixed ry = vp[1];
- const GLfixed rz = vp[2];
- vp += stride;
- v->index = first++;
- v->clip.x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
- v->clip.y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
- v->clip.z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
- v->clip.w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
-
- const GLfixed w = v->clip.w;
- uint32_t clip = 0;
- if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
- if (v->clip.x > w) clip |= vertex_t::CLIP_R;
- if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
- if (v->clip.y > w) clip |= vertex_t::CLIP_T;
- if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
- if (v->clip.z > w) clip |= vertex_t::CLIP_F;
- v->flags = clip;
- c->arrays.cull &= clip;
-
- //c->arrays.perspective(c, v);
- v++;
- } while (--count);
-}
-*/
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark clippers
-#endif
-
-static void clipVec4(vec4_t& nv,
- GLfixed t, const vec4_t& s, const vec4_t& p)
-{
- for (int i=0; i<4 ; i++)
- nv.v[i] = gglMulAddx(t, s.v[i] - p.v[i], p.v[i], 28);
-}
-
-static void clipVertex(ogles_context_t* c, vertex_t* nv,
- GLfixed t, const vertex_t* s, const vertex_t* p)
-{
- clipVec4(nv->clip, t, s->clip, p->clip);
- nv->fog = gglMulAddx(t, s->fog - p->fog, p->fog, 28);
- ogles_vertex_project(c, nv);
- nv->flags |= vertex_t::LIT | vertex_t::EYE | vertex_t::TT;
- nv->flags &= ~vertex_t::CLIP_ALL;
-}
-
-static void clipVertexC(ogles_context_t* c, vertex_t* nv,
- GLfixed t, const vertex_t* s, const vertex_t* p)
-{
- clipVec4(nv->color, t, s->color, p->color);
- clipVertex(c, nv, t, s, p);
-}
-
-static void clipVertexT(ogles_context_t* c, vertex_t* nv,
- GLfixed t, const vertex_t* s, const vertex_t* p)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (c->rasterizer.state.texture[i].enable)
- clipVec4(nv->texture[i], t, s->texture[i], p->texture[i]);
- }
- clipVertex(c, nv, t, s, p);
-}
-
-static void clipVertexAll(ogles_context_t* c, vertex_t* nv,
- GLfixed t, const vertex_t* s, const vertex_t* p)
-{
- clipVec4(nv->color, t, s->color, p->color);
- clipVertexT(c, nv, t, s, p);
-}
-
-static void clipEye(ogles_context_t* c, vertex_t* nv,
- GLfixed t, const vertex_t* s, const vertex_t* p)
-{
- nv->clear();
- c->arrays.clipVertex(c, nv, t, p, s);
- clipVec4(nv->eye, t, s->eye, p->eye);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void validate_arrays(ogles_context_t* c, GLenum mode)
-{
- uint32_t enables = c->rasterizer.state.enables;
-
- // Perspective correction is not need if Ortho transform, but
- // the user can still provide the w coordinate manually, so we can't
- // automatically turn it off (in fact we could when the 4th coordinate
- // is not spcified in the vertex array).
- // W interpolation is never needed for points.
- GLboolean perspective =
- c->perspective && mode!=GL_POINTS && (enables & GGL_ENABLE_TMUS);
- c->rasterizer.procs.enableDisable(c, GGL_W_LERP, perspective);
-
- // set anti-aliasing
- GLboolean smooth = GL_FALSE;
- switch (mode) {
- case GL_POINTS:
- smooth = c->point.smooth;
- break;
- case GL_LINES:
- case GL_LINE_LOOP:
- case GL_LINE_STRIP:
- smooth = c->line.smooth;
- break;
- }
- if (((enables & GGL_ENABLE_AA)?1:0) != smooth)
- c->rasterizer.procs.enableDisable(c, GGL_AA, smooth);
-
- // set the shade model for this primitive
- c->rasterizer.procs.shadeModel(c,
- (mode == GL_POINTS) ? GL_FLAT : c->lighting.shadeModel);
-
- // compute all the matrices we'll need...
- uint32_t want =
- transform_state_t::MVP |
- transform_state_t::VIEWPORT;
- if (c->lighting.enable) { // needs normal transforms and eye coords
- want |= transform_state_t::MVUI;
- want |= transform_state_t::MODELVIEW;
- }
- if (enables & GGL_ENABLE_TMUS) { // needs texture transforms
- want |= transform_state_t::TEXTURE;
- }
- if (c->clipPlanes.enable || (enables & GGL_ENABLE_FOG)) {
- want |= transform_state_t::MODELVIEW; // needs eye coords
- }
- ogles_validate_transform(c, want);
-
- // textures...
- if (enables & GGL_ENABLE_TMUS)
- ogles_validate_texture(c);
-
- // vertex compilers
- c->arrays.compileElement = compileElement__generic;
- c->arrays.compileElements = compileElements__generic;
-
- // vertex transform
- c->arrays.mvp_transform =
- c->transforms.mvp.pointv[c->arrays.vertex.size - 2];
-
- c->arrays.mv_transform =
- c->transforms.modelview.transform.pointv[c->arrays.vertex.size - 2];
-
- /*
- * ***********************************************************************
- * pick fetchers
- * ***********************************************************************
- */
-
- array_machine_t& am = c->arrays;
- am.vertex.fetch = fetchNop;
- am.normal.fetch = currentNormal;
- am.color.fetch = currentColor;
-
- if (am.vertex.enable) {
- am.vertex.resolve();
- if (am.vertex.bo || am.vertex.pointer) {
- am.vertex.fetch = vertex_fct[am.vertex.size-2][am.vertex.type & 0xF];
- }
- }
-
- if (am.normal.enable) {
- am.normal.resolve();
- if (am.normal.bo || am.normal.pointer) {
- am.normal.fetch = normal_fct[am.normal.size-3][am.normal.type & 0xF];
- }
- }
-
- if (am.color.enable) {
- am.color.resolve();
- if (c->lighting.enable) {
- if (am.color.bo || am.color.pointer) {
- am.color.fetch = color_fct[am.color.size-3][am.color.type & 0xF];
- }
- } else {
- if (am.color.bo || am.color.pointer) {
- am.color.fetch = color_clamp_fct[am.color.size-3][am.color.type & 0xF];
- }
- }
- }
-
- int activeTmuCount = 0;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- am.texture[i].fetch = currentTexCoord;
- if (c->rasterizer.state.texture[i].enable) {
-
- // texture fetchers...
- if (am.texture[i].enable) {
- am.texture[i].resolve();
- if (am.texture[i].bo || am.texture[i].pointer) {
- am.texture[i].fetch = texture_fct[am.texture[i].size-2][am.texture[i].type & 0xF];
- }
- }
-
- // texture transform...
- const int index = c->arrays.texture[i].size - 2;
- c->arrays.tex_transform[i] =
- c->transforms.texture[i].transform.pointv[index];
-
- am.tmu = i;
- activeTmuCount++;
- }
- }
-
- // pick the vertex-clipper
- uint32_t clipper = 0;
- // we must reload 'enables' here
- enables = c->rasterizer.state.enables;
- if (enables & GGL_ENABLE_SMOOTH)
- clipper |= 1; // we need to interpolate colors
- if (enables & GGL_ENABLE_TMUS)
- clipper |= 2; // we need to interpolate textures
- switch (clipper) {
- case 0: c->arrays.clipVertex = clipVertex; break;
- case 1: c->arrays.clipVertex = clipVertexC; break;
- case 2: c->arrays.clipVertex = clipVertexT; break;
- case 3: c->arrays.clipVertex = clipVertexAll; break;
- }
- c->arrays.clipEye = clipEye;
-
- // pick the primitive rasterizer
- ogles_validate_primitives(c);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-#if 0
-#pragma mark -
-#pragma mark array API
-#endif
-
-void glVertexPointer(
- GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (size<2 || size>4 || stride<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- switch (type) {
- case GL_BYTE:
- case GL_SHORT:
- case GL_FIXED:
- case GL_FLOAT:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->arrays.vertex.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
-}
-
-void glColorPointer(
- GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (size!=4 || stride<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- switch (type) {
- case GL_UNSIGNED_BYTE:
- case GL_FIXED:
- case GL_FLOAT:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->arrays.color.init(size, type, stride, pointer, c->arrays.array_buffer, 0);
-}
-
-void glNormalPointer(
- GLenum type, GLsizei stride, const GLvoid *pointer)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (stride<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- switch (type) {
- case GL_BYTE:
- case GL_SHORT:
- case GL_FIXED:
- case GL_FLOAT:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->arrays.normal.init(3, type, stride, pointer, c->arrays.array_buffer, 0);
-}
-
-void glTexCoordPointer(
- GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (size<2 || size>4 || stride<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- switch (type) {
- case GL_BYTE:
- case GL_SHORT:
- case GL_FIXED:
- case GL_FLOAT:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- const int tmu = c->arrays.activeTexture;
- c->arrays.texture[tmu].init(size, type, stride, pointer,
- c->arrays.array_buffer, 0);
-}
-
-
-void glEnableClientState(GLenum array) {
- ogles_context_t* c = ogles_context_t::get();
- enableDisableClientState(c, array, true);
-}
-
-void glDisableClientState(GLenum array) {
- ogles_context_t* c = ogles_context_t::get();
- enableDisableClientState(c, array, false);
-}
-
-void glClientActiveTexture(GLenum texture)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (texture<GL_TEXTURE0 || texture>=GL_TEXTURE0+GGL_TEXTURE_UNIT_COUNT) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->arrays.activeTexture = texture - GL_TEXTURE0;
-}
-
-void glDrawArrays(GLenum mode, GLint first, GLsizei count)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (count<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- switch (mode) {
- case GL_POINTS:
- case GL_LINE_STRIP:
- case GL_LINE_LOOP:
- case GL_LINES:
- case GL_TRIANGLE_STRIP:
- case GL_TRIANGLE_FAN:
- case GL_TRIANGLES:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- if (count == 0 || !c->arrays.vertex.enable)
- return;
- if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
- return; // all triangles are culled
-
-
- validate_arrays(c, mode);
-
- const uint32_t enables = c->rasterizer.state.enables;
- if (enables & GGL_ENABLE_TMUS)
- ogles_lock_textures(c);
-
- drawArraysPrims[mode](c, first, count);
-
- if (enables & GGL_ENABLE_TMUS)
- ogles_unlock_textures(c);
-
-#if VC_CACHE_STATISTICS
- c->vc.total = count;
- c->vc.dump_stats(mode);
-#endif
-}
-
-void glDrawElements(
- GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (count<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- switch (mode) {
- case GL_POINTS:
- case GL_LINE_STRIP:
- case GL_LINE_LOOP:
- case GL_LINES:
- case GL_TRIANGLE_STRIP:
- case GL_TRIANGLE_FAN:
- case GL_TRIANGLES:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- switch (type) {
- case GL_UNSIGNED_BYTE:
- case GL_UNSIGNED_SHORT:
- c->arrays.indicesType = type;
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (count == 0 || !c->arrays.vertex.enable)
- return;
- if ((c->cull.enable) && (c->cull.cullFace == GL_FRONT_AND_BACK))
- return; // all triangles are culled
-
- // clear the vertex-cache
- c->vc.clear();
- validate_arrays(c, mode);
-
- // if indices are in a buffer object, the pointer is treated as an
- // offset in that buffer.
- if (c->arrays.element_array_buffer) {
- indices = c->arrays.element_array_buffer->data + uintptr_t(indices);
- }
-
- const uint32_t enables = c->rasterizer.state.enables;
- if (enables & GGL_ENABLE_TMUS)
- ogles_lock_textures(c);
-
- drawElementsPrims[mode](c, count, indices);
-
- if (enables & GGL_ENABLE_TMUS)
- ogles_unlock_textures(c);
-
-
-#if VC_CACHE_STATISTICS
- c->vc.total = count;
- c->vc.dump_stats(mode);
-#endif
-}
-
-// ----------------------------------------------------------------------------
-// buffers
-// ----------------------------------------------------------------------------
-
-void glBindBuffer(GLenum target, GLuint buffer)
-{
- ogles_context_t* c = ogles_context_t::get();
- if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- // create a buffer object, or bind an existing one
- buffer_t const* bo = 0;
- if (buffer) {
- bo = c->bufferObjectManager->bind(buffer);
- if (!bo) {
- ogles_error(c, GL_OUT_OF_MEMORY);
- return;
- }
- }
- ((target == GL_ARRAY_BUFFER) ?
- c->arrays.array_buffer : c->arrays.element_array_buffer) = bo;
-}
-
-void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
- ogles_context_t* c = ogles_context_t::get();
- if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (size<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if ((usage!=GL_STATIC_DRAW) && (usage!=GL_DYNAMIC_DRAW)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
- c->arrays.array_buffer : c->arrays.element_array_buffer);
-
- if (bo == 0) {
- // can't modify buffer 0
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
-
- buffer_t* edit_bo = const_cast<buffer_t*>(bo);
- if (c->bufferObjectManager->allocateStore(edit_bo, size, usage) != 0) {
- ogles_error(c, GL_OUT_OF_MEMORY);
- return;
- }
- if (data) {
- memcpy(bo->data, data, size);
- }
-}
-
-void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
- ogles_context_t* c = ogles_context_t::get();
- if ((target!=GL_ARRAY_BUFFER) && (target!=GL_ELEMENT_ARRAY_BUFFER)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (offset<0 || size<0 || data==0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- buffer_t const* bo = ((target == GL_ARRAY_BUFFER) ?
- c->arrays.array_buffer : c->arrays.element_array_buffer);
-
- if (bo == 0) {
- // can't modify buffer 0
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
- if (offset+size > bo->size) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- memcpy(bo->data + offset, data, size);
-}
-
-void glDeleteBuffers(GLsizei n, const GLuint* buffers)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (n<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- for (int i=0 ; i<n ; i++) {
- GLuint name = buffers[i];
- if (name) {
- // unbind bound deleted buffers...
- if (c->arrays.element_array_buffer) {
- if (c->arrays.element_array_buffer->name == name) {
- c->arrays.element_array_buffer = 0;
- }
- }
- if (c->arrays.array_buffer) {
- if (c->arrays.array_buffer->name == name) {
- c->arrays.array_buffer = 0;
- }
- }
- if (c->arrays.vertex.bo) {
- if (c->arrays.vertex.bo->name == name) {
- c->arrays.vertex.bo = 0;
- }
- }
- if (c->arrays.normal.bo) {
- if (c->arrays.normal.bo->name == name) {
- c->arrays.normal.bo = 0;
- }
- }
- if (c->arrays.color.bo) {
- if (c->arrays.color.bo->name == name) {
- c->arrays.color.bo = 0;
- }
- }
- for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
- if (c->arrays.texture[t].bo) {
- if (c->arrays.texture[t].bo->name == name) {
- c->arrays.texture[t].bo = 0;
- }
- }
- }
- }
- }
- c->bufferObjectManager->deleteBuffers(n, buffers);
- c->bufferObjectManager->recycleTokens(n, buffers);
-}
-
-void glGenBuffers(GLsizei n, GLuint* buffers)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (n<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- c->bufferObjectManager->getToken(n, buffers);
-}
diff --git a/opengl/libagl/array.h b/opengl/libagl/array.h
deleted file mode 100644
index e156978..0000000
--- a/opengl/libagl/array.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* libs/opengles/array.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_ARRAY_H
-#define ANDROID_OPENGLES_ARRAY_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-namespace android {
-
-namespace gl {
-struct ogles_context_t;
-};
-
-void ogles_init_array(ogles_context_t* c);
-void ogles_uninit_array(ogles_context_t* c);
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_ARRAY_H
-
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
deleted file mode 100644
index 6e77a23..0000000
--- a/opengl/libagl/context.h
+++ /dev/null
@@ -1,647 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_OPENGLES_CONTEXT_H
-#define ANDROID_OPENGLES_CONTEXT_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-#include <pthread.h>
-#ifdef __ANDROID__
-#include <bionic/tls.h>
-#endif
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include <system/window.h>
-
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-namespace android {
-
-
-const unsigned int OGLES_NUM_COMPRESSED_TEXTURE_FORMATS = 10
-#ifdef GL_OES_compressed_ETC1_RGB8_texture
- + 1
-#endif
- ;
-
-class EGLTextureObject;
-class EGLSurfaceManager;
-class EGLBufferObjectManager;
-
-namespace gl {
-
-struct ogles_context_t;
-struct matrixx_t;
-struct transform_t;
-struct buffer_t;
-
-ogles_context_t* getGlContext();
-
-template<typename T>
-static inline void swap(T& a, T& b) {
- T t(a); a = b; b = t;
-}
-template<typename T>
-inline T max(T a, T b) {
- return a<b ? b : a;
-}
-template<typename T>
-inline T max(T a, T b, T c) {
- return max(a, max(b, c));
-}
-template<typename T>
-inline T min(T a, T b) {
- return a<b ? a : b;
-}
-template<typename T>
-inline T min(T a, T b, T c) {
- return min(a, min(b, c));
-}
-template<typename T>
-inline T min(T a, T b, T c, T d) {
- return min(min(a,b), min(c,d));
-}
-
-// ----------------------------------------------------------------------------
-// vertices
-// ----------------------------------------------------------------------------
-
-struct vec3_t {
- union {
- struct { GLfixed x, y, z; };
- struct { GLfixed r, g, b; };
- struct { GLfixed S, T, R; };
- GLfixed v[3];
- };
-};
-
-struct vec4_t {
- union {
- struct { GLfixed x, y, z, w; };
- struct { GLfixed r, g, b, a; };
- struct { GLfixed S, T, R, Q; };
- GLfixed v[4];
- };
-};
-
-struct vertex_t {
- enum {
- // these constant matter for our clipping
- CLIP_L = 0x0001, // clipping flags
- CLIP_R = 0x0002,
- CLIP_B = 0x0004,
- CLIP_T = 0x0008,
- CLIP_N = 0x0010,
- CLIP_F = 0x0020,
-
- EYE = 0x0040,
- RESERVED = 0x0080,
-
- USER_CLIP_0 = 0x0100, // user clipping flags
- USER_CLIP_1 = 0x0200,
- USER_CLIP_2 = 0x0400,
- USER_CLIP_3 = 0x0800,
- USER_CLIP_4 = 0x1000,
- USER_CLIP_5 = 0x2000,
-
- LIT = 0x4000, // lighting has been applied
- TT = 0x8000, // texture coords transformed
-
- FRUSTUM_CLIP_ALL= 0x003F,
- USER_CLIP_ALL = 0x3F00,
- CLIP_ALL = 0x3F3F,
- };
-
- // the fields below are arranged to minimize d-cache usage
- // we group together, by cache-line, the fields most likely to be used
-
- union {
- vec4_t obj;
- vec4_t eye;
- };
- vec4_t clip;
-
- uint32_t flags;
- size_t index; // cache tag, and vertex index
- GLfixed fog;
- uint8_t locked;
- uint8_t mru;
- uint8_t reserved[2];
- vec4_t window;
-
- vec4_t color;
- vec4_t texture[GGL_TEXTURE_UNIT_COUNT];
-#ifdef __LP64__
- uint32_t reserved1[2];
-#else
- uint32_t reserved1[4];
-#endif
-
- inline void clear() {
- flags = index = locked = mru = 0;
- }
-};
-
-struct point_size_t {
- GGLcoord size;
- GLboolean smooth;
-};
-
-struct line_width_t {
- GGLcoord width;
- GLboolean smooth;
-};
-
-struct polygon_offset_t {
- GLfixed factor;
- GLfixed units;
- GLboolean enable;
-};
-
-// ----------------------------------------------------------------------------
-// arrays
-// ----------------------------------------------------------------------------
-
-struct array_t {
- typedef void (*fetcher_t)(ogles_context_t*, GLfixed*, const GLvoid*);
- fetcher_t fetch;
- GLvoid const* physical_pointer;
- GLint size;
- GLsizei stride;
- GLvoid const* pointer;
- buffer_t const* bo;
- uint16_t type;
- GLboolean enable;
- GLboolean pad;
- GLsizei bounds;
- void init(GLint, GLenum, GLsizei, const GLvoid *, const buffer_t*, GLsizei);
- inline void resolve();
- inline const GLubyte* element(GLint i) const {
- return (const GLubyte*)physical_pointer + i * stride;
- }
-};
-
-struct array_machine_t {
- array_t vertex;
- array_t normal;
- array_t color;
- array_t texture[GGL_TEXTURE_UNIT_COUNT];
- uint8_t activeTexture;
- uint8_t tmu;
- uint16_t cull;
- uint32_t flags;
- GLenum indicesType;
- buffer_t const* array_buffer;
- buffer_t const* element_array_buffer;
-
- void (*compileElements)(ogles_context_t*, vertex_t*, GLint, GLsizei);
- void (*compileElement)(ogles_context_t*, vertex_t*, GLint);
-
- void (*mvp_transform)(transform_t const*, vec4_t*, vec4_t const*);
- void (*mv_transform)(transform_t const*, vec4_t*, vec4_t const*);
- void (*tex_transform[2])(transform_t const*, vec4_t*, vec4_t const*);
- void (*perspective)(ogles_context_t*c, vertex_t* v);
- void (*clipVertex)(ogles_context_t* c, vertex_t* nv,
- GGLfixed t, const vertex_t* s, const vertex_t* p);
- void (*clipEye)(ogles_context_t* c, vertex_t* nv,
- GGLfixed t, const vertex_t* s, const vertex_t* p);
-};
-
-struct vertex_cache_t {
- enum {
- // must be at least 4
- // 3 vertice for triangles
- // or 2 + 2 for indexed triangles w/ cache contention
- VERTEX_BUFFER_SIZE = 8,
- // must be a power of two and at least 3
- VERTEX_CACHE_SIZE = 64, // 8 KB
-
- INDEX_BITS = 16,
- INDEX_MASK = ((1LU<<INDEX_BITS)-1),
- INDEX_SEQ = 1LU<<INDEX_BITS,
- };
- vertex_t* vBuffer;
- vertex_t* vCache;
- uint32_t sequence;
- void* base;
- uint32_t total;
- uint32_t misses;
- int64_t startTime;
- void init();
- void uninit();
- void clear();
- void dump_stats(GLenum mode);
-};
-
-// ----------------------------------------------------------------------------
-// fog
-// ----------------------------------------------------------------------------
-
-struct fog_t {
- GLfixed density;
- GLfixed start;
- GLfixed end;
- GLfixed invEndMinusStart;
- GLenum mode;
- GLfixed (*fog)(ogles_context_t* c, GLfixed z);
-};
-
-// ----------------------------------------------------------------------------
-// user clip planes
-// ----------------------------------------------------------------------------
-
-const unsigned int OGLES_MAX_CLIP_PLANES = 6;
-
-struct clip_plane_t {
- vec4_t equation;
-};
-
-struct user_clip_planes_t {
- clip_plane_t plane[OGLES_MAX_CLIP_PLANES];
- uint32_t enable;
-};
-
-// ----------------------------------------------------------------------------
-// lighting
-// ----------------------------------------------------------------------------
-
-const unsigned int OGLES_MAX_LIGHTS = 8;
-
-struct light_t {
- vec4_t ambient;
- vec4_t diffuse;
- vec4_t specular;
- vec4_t implicitAmbient;
- vec4_t implicitDiffuse;
- vec4_t implicitSpecular;
- vec4_t position; // position in eye space
- vec4_t objPosition;
- vec4_t normalizedObjPosition;
- vec4_t spotDir;
- vec4_t normalizedSpotDir;
- GLfixed spotExp;
- GLfixed spotCutoff;
- GLfixed spotCutoffCosine;
- GLfixed attenuation[3];
- GLfixed rConstAttenuation;
- GLboolean enable;
-};
-
-struct material_t {
- vec4_t ambient;
- vec4_t diffuse;
- vec4_t specular;
- vec4_t emission;
- GLfixed shininess;
-};
-
-struct light_model_t {
- vec4_t ambient;
- GLboolean twoSide;
-};
-
-struct color_material_t {
- GLenum face;
- GLenum mode;
- GLboolean enable;
-};
-
-struct lighting_t {
- light_t lights[OGLES_MAX_LIGHTS];
- material_t front;
- light_model_t lightModel;
- color_material_t colorMaterial;
- vec4_t implicitSceneEmissionAndAmbient;
- vec4_t objViewer;
- uint32_t enabledLights;
- GLboolean enable;
- GLenum shadeModel;
- typedef void (*light_fct_t)(ogles_context_t*, vertex_t*);
- void (*lightVertex)(ogles_context_t* c, vertex_t* v);
- void (*lightTriangle)(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-};
-
-struct culling_t {
- GLenum cullFace;
- GLenum frontFace;
- GLboolean enable;
-};
-
-// ----------------------------------------------------------------------------
-// textures
-// ----------------------------------------------------------------------------
-
-struct texture_unit_t {
- GLuint name;
- EGLTextureObject* texture;
- uint8_t dirty;
-};
-
-struct texture_state_t
-{
- texture_unit_t tmu[GGL_TEXTURE_UNIT_COUNT];
- int active; // active tmu
- EGLTextureObject* defaultTexture;
- GGLContext* ggl;
- uint8_t packAlignment;
- uint8_t unpackAlignment;
-};
-
-// ----------------------------------------------------------------------------
-// transformation and matrices
-// ----------------------------------------------------------------------------
-
-struct matrixf_t;
-
-struct matrixx_t {
- GLfixed m[16];
- void load(const matrixf_t& rhs);
-};
-
-struct matrix_stack_t;
-
-
-struct matrixf_t {
- void loadIdentity();
- void load(const matrixf_t& rhs);
-
- inline GLfloat* editElements() { return m; }
- inline GLfloat const* elements() const { return m; }
-
- void set(const GLfixed* rhs);
- void set(const GLfloat* rhs);
-
- static void multiply(matrixf_t& r,
- const matrixf_t& lhs, const matrixf_t& rhs);
-
- void dump(const char* what);
-
-private:
- friend struct matrix_stack_t;
- GLfloat m[16];
- void load(const GLfixed* rhs);
- void load(const GLfloat* rhs);
- void multiply(const matrixf_t& rhs);
- void translate(GLfloat x, GLfloat y, GLfloat z);
- void scale(GLfloat x, GLfloat y, GLfloat z);
- void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
-};
-
-enum {
- OP_IDENTITY = 0x00,
- OP_TRANSLATE = 0x01,
- OP_UNIFORM_SCALE = 0x02,
- OP_SCALE = 0x05,
- OP_ROTATE = 0x08,
- OP_SKEW = 0x10,
- OP_ALL = 0x1F
-};
-
-struct transform_t {
- enum {
- FLAGS_2D_PROJECTION = 0x1
- };
- matrixx_t matrix;
- uint32_t flags;
- uint32_t ops;
-
- union {
- struct {
- void (*point2)(transform_t const* t, vec4_t*, vec4_t const*);
- void (*point3)(transform_t const* t, vec4_t*, vec4_t const*);
- void (*point4)(transform_t const* t, vec4_t*, vec4_t const*);
- };
- void (*pointv[3])(transform_t const* t, vec4_t*, vec4_t const*);
- };
-
- void loadIdentity();
- void picker();
- void dump(const char* what);
-};
-
-struct mvui_transform_t : public transform_t
-{
- void picker();
-};
-
-struct matrix_stack_t {
- enum {
- DO_PICKER = 0x1,
- DO_FLOAT_TO_FIXED = 0x2
- };
- transform_t transform;
- uint8_t maxDepth;
- uint8_t depth;
- uint8_t dirty;
- uint8_t reserved;
- matrixf_t *stack;
- uint8_t *ops;
- void init(int depth);
- void uninit();
- void loadIdentity();
- void load(const GLfixed* rhs);
- void load(const GLfloat* rhs);
- void multiply(const matrixf_t& rhs);
- void translate(GLfloat x, GLfloat y, GLfloat z);
- void scale(GLfloat x, GLfloat y, GLfloat z);
- void rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z);
- GLint push();
- GLint pop();
- void validate();
- matrixf_t& top() { return stack[depth]; }
- const matrixf_t& top() const { return stack[depth]; }
- uint32_t top_ops() const { return ops[depth]; }
- inline bool isRigidBody() const {
- return !(ops[depth] & ~(OP_TRANSLATE|OP_UNIFORM_SCALE|OP_ROTATE));
- }
-};
-
-struct vp_transform_t {
- transform_t transform;
- matrixf_t matrix;
- GLfloat zNear;
- GLfloat zFar;
- void loadIdentity();
-};
-
-struct transform_state_t {
- enum {
- MODELVIEW = 0x01,
- PROJECTION = 0x02,
- VIEWPORT = 0x04,
- TEXTURE = 0x08,
- MVUI = 0x10,
- MVIT = 0x20,
- MVP = 0x40,
- };
- matrix_stack_t *current;
- matrix_stack_t modelview;
- matrix_stack_t projection;
- matrix_stack_t texture[GGL_TEXTURE_UNIT_COUNT];
-
- // modelview * projection
- transform_t mvp __attribute__((aligned(32)));
- // viewport transformation
- vp_transform_t vpt __attribute__((aligned(32)));
- // same for 4-D vertices
- transform_t mvp4;
- // full modelview inverse transpose
- transform_t mvit4;
- // upper 3x3 of mv-inverse-transpose (for normals)
- mvui_transform_t mvui;
-
- GLenum matrixMode;
- GLenum rescaleNormals;
- uint32_t dirty;
- void invalidate();
- void update_mvp();
- void update_mvit();
- void update_mvui();
-};
-
-struct viewport_t {
- GLint x;
- GLint y;
- GLsizei w;
- GLsizei h;
- struct {
- GLint x;
- GLint y;
- } surfaceport;
- struct {
- GLint x;
- GLint y;
- GLsizei w;
- GLsizei h;
- } scissor;
-};
-
-// ----------------------------------------------------------------------------
-// Lerping
-// ----------------------------------------------------------------------------
-
-struct compute_iterators_t
-{
- void initTriangle(
- vertex_t const* v0,
- vertex_t const* v1,
- vertex_t const* v2);
-
- void initLine(
- vertex_t const* v0,
- vertex_t const* v1);
-
- inline void initLerp(vertex_t const* v0, uint32_t enables);
-
- int iteratorsScale(int32_t it[3],
- int32_t c0, int32_t c1, int32_t c2) const;
-
- void iterators1616(GGLfixed it[3],
- GGLfixed c0, GGLfixed c1, GGLfixed c2) const;
-
- void iterators0032(int32_t it[3],
- int32_t c0, int32_t c1, int32_t c2) const;
-
- void iterators0032(int64_t it[3],
- int32_t c0, int32_t c1, int32_t c2) const;
-
- GGLcoord area() const { return m_area; }
-
-private:
- // don't change order of members here -- used by iterators.S
- GGLcoord m_dx01, m_dy10, m_dx20, m_dy02;
- GGLcoord m_x0, m_y0;
- GGLcoord m_area;
- uint8_t m_scale;
- uint8_t m_area_scale;
- uint8_t m_reserved[2];
-
-};
-
-// ----------------------------------------------------------------------------
-// state
-// ----------------------------------------------------------------------------
-
-#ifdef __ANDROID__
- // We have a dedicated TLS slot in bionic
- inline void setGlThreadSpecific(ogles_context_t *value) {
- __get_tls()[TLS_SLOT_OPENGL] = value;
- }
- inline ogles_context_t* getGlThreadSpecific() {
- return static_cast<ogles_context_t*>(__get_tls()[TLS_SLOT_OPENGL]);
- }
-#else
- extern pthread_key_t gGLKey;
- inline void setGlThreadSpecific(ogles_context_t *value) {
- pthread_setspecific(gGLKey, value);
- }
- inline ogles_context_t* getGlThreadSpecific() {
- return static_cast<ogles_context_t*>(pthread_getspecific(gGLKey));
- }
-#endif
-
-
-struct prims_t {
- typedef ogles_context_t* GL;
- void (*renderPoint)(GL, vertex_t*);
- void (*renderLine)(GL, vertex_t*, vertex_t*);
- void (*renderTriangle)(GL, vertex_t*, vertex_t*, vertex_t*);
-};
-
-struct ogles_context_t {
- context_t rasterizer;
- array_machine_t arrays __attribute__((aligned(32)));
- texture_state_t textures;
- transform_state_t transforms;
- vertex_cache_t vc;
- prims_t prims;
- culling_t cull;
- lighting_t lighting;
- user_clip_planes_t clipPlanes;
- compute_iterators_t lerp __attribute__((aligned(32)));
- vertex_t current;
- vec4_t currentColorClamped;
- vec3_t currentNormal;
- viewport_t viewport;
- point_size_t point;
- line_width_t line;
- polygon_offset_t polygonOffset;
- fog_t fog;
- uint32_t perspective : 1;
- uint32_t transformTextures : 1;
- EGLSurfaceManager* surfaceManager;
- EGLBufferObjectManager* bufferObjectManager;
-
- GLenum error;
-
- static inline ogles_context_t* get() {
- return getGlThreadSpecific();
- }
-
-};
-
-}; // namespace gl
-}; // namespace android
-
-using namespace android::gl;
-
-#endif // ANDROID_OPENGLES_CONTEXT_H
-
diff --git a/opengl/libagl/dxt.cpp b/opengl/libagl/dxt.cpp
deleted file mode 100644
index 238c81f..0000000
--- a/opengl/libagl/dxt.cpp
+++ /dev/null
@@ -1,636 +0,0 @@
-/* libs/opengles/dxt.cpp
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#define TIMING 0
-
-#if TIMING
-#include <sys/time.h> // for optimization timing
-#include <stdio.h>
-#include <stdlib.h>
-#endif
-
-#include <GLES/gl.h>
-#include <utils/Endian.h>
-
-#include "context.h"
-
-#define TIMING 0
-
-namespace android {
-
-static uint8_t avg23tab[64*64];
-static volatile int tables_initialized = 0;
-
-// Definitions below are equivalent to these over the valid range of arguments
-// #define div5(x) ((x)/5)
-// #define div7(x) ((x)/7)
-
-// Use fixed-point to divide by 5 and 7
-// 3277 = 2^14/5 + 1
-// 2341 = 2^14/7 + 1
-#define div5(x) (((x)*3277) >> 14)
-#define div7(x) (((x)*2341) >> 14)
-
-// Table with entry [a << 6 | b] = (2*a + b)/3 for 0 <= a,b < 64
-#define avg23(x0,x1) avg23tab[((x0) << 6) | (x1)]
-
-// Extract 5/6/5 RGB
-#define red(x) (((x) >> 11) & 0x1f)
-#define green(x) (((x) >> 5) & 0x3f)
-#define blue(x) ( (x) & 0x1f)
-
-/*
- * Convert 5/6/5 RGB (as 3 ints) to 8/8/8
- *
- * Operation count: 8 <<, 0 &, 5 |
- */
-inline static int rgb565SepTo888(int r, int g, int b)
-
-{
- return ((((r << 3) | (r >> 2)) << 16) |
- (((g << 2) | (g >> 4)) << 8) |
- ((b << 3) | (b >> 2)));
-}
-
-/*
- * Convert 5/6/5 RGB (as a single 16-bit word) to 8/8/8
- *
- * r4r3r2r1 r0g5g4g3 g2g1g0b4 b3b2b1b0 rgb
- * r4r3r2 r1r0g5g4 g3g2g1g0 b4b3b2b1 b0 0 0 0 rgb << 3
- * r4r3r2r1 r0r4r3r2 g5g4g3g2 g1g0g5g4 b4b3b2b1 b0b4b3b2 desired result
- *
- * Construct the 24-bit RGB word as:
- *
- * r4r3r2r1 r0------ -------- -------- -------- -------- (rgb << 8) & 0xf80000
- * r4r3r2 -------- -------- -------- -------- (rgb << 3) & 0x070000
- * g5g4g3g2 g1g0---- -------- -------- (rgb << 5) & 0x00fc00
- * g5g4 -------- -------- (rgb >> 1) & 0x000300
- * b4b3b2b1 b0------ (rgb << 3) & 0x0000f8
- * b4b3b2 (rgb >> 2) & 0x000007
- *
- * Operation count: 5 <<, 6 &, 5 | (n.b. rgb >> 3 is used twice)
- */
-inline static int rgb565To888(int rgb)
-
-{
- int rgb3 = rgb >> 3;
- return (((rgb << 8) & 0xf80000) |
- ( rgb3 & 0x070000) |
- ((rgb << 5) & 0x00fc00) |
- ((rgb >> 1) & 0x000300) |
- ( rgb3 & 0x0000f8) |
- ((rgb >> 2) & 0x000007));
-}
-
-#if __BYTE_ORDER == __BIG_ENDIAN
-static uint32_t swap(uint32_t x) {
- int b0 = (x >> 24) & 0xff;
- int b1 = (x >> 16) & 0xff;
- int b2 = (x >> 8) & 0xff;
- int b3 = (x ) & 0xff;
-
- return (uint32_t)((b3 << 24) | (b2 << 16) | (b1 << 8) | b0);
-}
-#endif
-
-static void
-init_tables()
-{
- if (tables_initialized) {
- return;
- }
-
- for (int i = 0; i < 64; i++) {
- for (int j = 0; j < 64; j++) {
- int avg = (2*i + j)/3;
- avg23tab[(i << 6) | j] = avg;
- }
- }
-
- asm volatile ("" : : : "memory");
- tables_initialized = 1;
-}
-
-/*
- * Utility to scan a DXT1 compressed texture to determine whether it
- * contains a transparent pixel (color0 < color1, code == 3). This
- * may be useful if the application lacks information as to whether
- * the true format is GL_COMPRESSED_RGB_S3TC_DXT1_EXT or
- * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT.
- */
-bool
-DXT1HasAlpha(const GLvoid *data, int width, int height) {
-#if TIMING
- struct timeval start_t, end_t;
- struct timezone tz;
-
- gettimeofday(&start_t, &tz);
-#endif
-
- bool hasAlpha = false;
-
- int xblocks = (width + 3)/4;
- int yblocks = (height + 3)/4;
- int numblocks = xblocks*yblocks;
-
- uint32_t const *d32 = (uint32_t *)data;
- for (int b = 0; b < numblocks; b++) {
- uint32_t colors = *d32++;
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- colors = swap(colors);
-#endif
-
- uint16_t color0 = colors & 0xffff;
- uint16_t color1 = colors >> 16;
-
- if (color0 < color1) {
- // There's no need to endian-swap within 'bits'
- // since we don't care which pixel is the transparent one
- uint32_t bits = *d32++;
-
- // Detect if any (odd, even) pair of bits are '11'
- // bits: b31 b30 b29 ... b3 b2 b1 b0
- // bits >> 1: b31 b31 b30 ... b4 b3 b2 b1
- // &: b31 (b31 & b30) (b29 & b28) ... (b2 & b1) (b1 & b0)
- // & 0x55..: 0 (b31 & b30) 0 ... 0 (b1 & b0)
- if (((bits & (bits >> 1)) & 0x55555555) != 0) {
- hasAlpha = true;
- goto done;
- }
- } else {
- // Skip 4 bytes
- ++d32;
- }
- }
-
- done:
-#if TIMING
- gettimeofday(&end_t, &tz);
- long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
- (end_t.tv_usec - start_t.tv_usec);
-
- printf("Scanned w=%d h=%d in %ld usec\n", width, height, usec);
-#endif
-
- return hasAlpha;
-}
-
-static void
-decodeDXT1(const GLvoid *data, int width, int height,
- void *surface, int stride,
- bool hasAlpha)
-
-{
- init_tables();
-
- uint32_t const *d32 = (uint32_t *)data;
-
- // Color table for the current block
- uint16_t c[4];
- c[0] = c[1] = c[2] = c[3] = 0;
-
- // Specified colors from the previous block
- uint16_t prev_color0 = 0x0000;
- uint16_t prev_color1 = 0x0000;
-
- uint16_t* rowPtr = (uint16_t*)surface;
- for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
- uint16_t *blockPtr = rowPtr;
- for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
- uint32_t colors = *d32++;
- uint32_t bits = *d32++;
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- colors = swap(colors);
- bits = swap(bits);
-#endif
-
- // Raw colors
- uint16_t color0 = colors & 0xffff;
- uint16_t color1 = colors >> 16;
-
- // If the new block has the same base colors as the
- // previous one, we don't need to recompute the color
- // table c[]
- if (color0 != prev_color0 || color1 != prev_color1) {
- // Store raw colors for comparison with next block
- prev_color0 = color0;
- prev_color1 = color1;
-
- int r0 = red(color0);
- int g0 = green(color0);
- int b0 = blue(color0);
-
- int r1 = red(color1);
- int g1 = green(color1);
- int b1 = blue(color1);
-
- if (hasAlpha) {
- c[0] = (r0 << 11) | ((g0 >> 1) << 6) | (b0 << 1) | 0x1;
- c[1] = (r1 << 11) | ((g1 >> 1) << 6) | (b1 << 1) | 0x1;
- } else {
- c[0] = color0;
- c[1] = color1;
- }
-
- int r2, g2, b2, r3, g3, b3, a3;
-
- int bbits = bits >> 1;
- bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
- bool has3 = ((bbits & bits) & 0x55555555) != 0;
-
- if (has2 || has3) {
- if (color0 > color1) {
- r2 = avg23(r0, r1);
- g2 = avg23(g0, g1);
- b2 = avg23(b0, b1);
-
- r3 = avg23(r1, r0);
- g3 = avg23(g1, g0);
- b3 = avg23(b1, b0);
- a3 = 1;
- } else {
- r2 = (r0 + r1) >> 1;
- g2 = (g0 + g1) >> 1;
- b2 = (b0 + b1) >> 1;
-
- r3 = g3 = b3 = a3 = 0;
- }
- if (hasAlpha) {
- c[2] = (r2 << 11) | ((g2 >> 1) << 6) |
- (b2 << 1) | 0x1;
- c[3] = (r3 << 11) | ((g3 >> 1) << 6) |
- (b3 << 1) | a3;
- } else {
- c[2] = (r2 << 11) | (g2 << 5) | b2;
- c[3] = (r3 << 11) | (g3 << 5) | b3;
- }
- }
- }
-
- uint16_t* blockRowPtr = blockPtr;
- for (int y = 0; y < 4; y++, blockRowPtr += stride) {
- // Don't process rows past the botom
- if (base_y + y >= height) {
- break;
- }
-
- int w = min(width - base_x, 4);
- for (int x = 0; x < w; x++) {
- int code = bits & 0x3;
- bits >>= 2;
-
- blockRowPtr[x] = c[code];
- }
- }
- }
- }
-}
-
-// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
-static void
-decodeDXT3(const GLvoid *data, int width, int height,
- void *surface, int stride)
-
-{
- init_tables();
-
- uint32_t const *d32 = (uint32_t *)data;
-
- // Specified colors from the previous block
- uint16_t prev_color0 = 0x0000;
- uint16_t prev_color1 = 0x0000;
-
- // Color table for the current block
- uint32_t c[4];
- c[0] = c[1] = c[2] = c[3] = 0;
-
- uint32_t* rowPtr = (uint32_t*)surface;
- for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
- uint32_t *blockPtr = rowPtr;
- for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- uint32_t alphahi = *d32++;
- uint32_t alphalo = *d32++;
- alphahi = swap(alphahi);
- alphalo = swap(alphalo);
-#else
- uint32_t alphalo = *d32++;
- uint32_t alphahi = *d32++;
-#endif
-
- uint32_t colors = *d32++;
- uint32_t bits = *d32++;
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- colors = swap(colors);
- bits = swap(bits);
-#endif
-
- uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
-
- // Raw colors
- uint16_t color0 = colors & 0xffff;
- uint16_t color1 = colors >> 16;
-
- // If the new block has the same base colors as the
- // previous one, we don't need to recompute the color
- // table c[]
- if (color0 != prev_color0 || color1 != prev_color1) {
- // Store raw colors for comparison with next block
- prev_color0 = color0;
- prev_color1 = color1;
-
- int bbits = bits >> 1;
- bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
- bool has3 = ((bbits & bits) & 0x55555555) != 0;
-
- if (has2 || has3) {
- int r0 = red(color0);
- int g0 = green(color0);
- int b0 = blue(color0);
-
- int r1 = red(color1);
- int g1 = green(color1);
- int b1 = blue(color1);
-
- int r2 = avg23(r0, r1);
- int g2 = avg23(g0, g1);
- int b2 = avg23(b0, b1);
-
- int r3 = avg23(r1, r0);
- int g3 = avg23(g1, g0);
- int b3 = avg23(b1, b0);
-
- c[0] = rgb565SepTo888(r0, g0, b0);
- c[1] = rgb565SepTo888(r1, g1, b1);
- c[2] = rgb565SepTo888(r2, g2, b2);
- c[3] = rgb565SepTo888(r3, g3, b3);
- } else {
- // Convert to 8 bits
- c[0] = rgb565To888(color0);
- c[1] = rgb565To888(color1);
- }
- }
-
- uint32_t* blockRowPtr = blockPtr;
- for (int y = 0; y < 4; y++, blockRowPtr += stride) {
- // Don't process rows past the botom
- if (base_y + y >= height) {
- break;
- }
-
- int w = min(width - base_x, 4);
- for (int x = 0; x < w; x++) {
- int a = alpha & 0xf;
- alpha >>= 4;
-
- int code = bits & 0x3;
- bits >>= 2;
-
- blockRowPtr[x] = c[code] | (a << 28) | (a << 24);
- }
- }
- }
- }
-}
-
-// Output data as internalformat=GL_RGBA, type=GL_UNSIGNED_BYTE
-static void
-decodeDXT5(const GLvoid *data, int width, int height,
- void *surface, int stride)
-
-{
- init_tables();
-
- uint32_t const *d32 = (uint32_t *)data;
-
- // Specified alphas from the previous block
- uint8_t prev_alpha0 = 0x00;
- uint8_t prev_alpha1 = 0x00;
-
- // Specified colors from the previous block
- uint16_t prev_color0 = 0x0000;
- uint16_t prev_color1 = 0x0000;
-
- // Alpha table for the current block
- uint8_t a[8];
- a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = 0;
-
- // Color table for the current block
- uint32_t c[4];
- c[0] = c[1] = c[2] = c[3] = 0;
-
- int good_a5 = 0;
- int bad_a5 = 0;
- int good_a6 = 0;
- int bad_a6 = 0;
- int good_a7 = 0;
- int bad_a7 = 0;
-
- uint32_t* rowPtr = (uint32_t*)surface;
- for (int base_y = 0; base_y < height; base_y += 4, rowPtr += 4*stride) {
- uint32_t *blockPtr = rowPtr;
- for (int base_x = 0; base_x < width; base_x += 4, blockPtr += 4) {
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- uint32_t alphahi = *d32++;
- uint32_t alphalo = *d32++;
- alphahi = swap(alphahi);
- alphalo = swap(alphalo);
-#else
- uint32_t alphalo = *d32++;
- uint32_t alphahi = *d32++;
-#endif
-
- uint32_t colors = *d32++;
- uint32_t bits = *d32++;
-
-#if __BYTE_ORDER == __BIG_ENDIANx
- colors = swap(colors);
- bits = swap(bits);
-#endif
-
- uint64_t alpha = ((uint64_t)alphahi << 32) | alphalo;
- uint64_t alpha0 = alpha & 0xff;
- alpha >>= 8;
- uint64_t alpha1 = alpha & 0xff;
- alpha >>= 8;
-
- if (alpha0 != prev_alpha0 || alpha1 != prev_alpha1) {
- prev_alpha0 = alpha0;
- prev_alpha1 = alpha1;
-
- a[0] = alpha0;
- a[1] = alpha1;
- int a01 = alpha0 + alpha1 - 1;
- if (alpha0 > alpha1) {
- a[2] = div7(6*alpha0 + alpha1);
- a[4] = div7(4*alpha0 + 3*alpha1);
- a[6] = div7(2*alpha0 + 5*alpha1);
-
- // Use symmetry to derive half of the values
- // A few values will be off by 1 (~.5%)
- // Alternate which values are computed directly
- // and which are derived to try to reduce bias
- a[3] = a01 - a[6];
- a[5] = a01 - a[4];
- a[7] = a01 - a[2];
- } else {
- a[2] = div5(4*alpha0 + alpha1);
- a[4] = div5(2*alpha0 + 3*alpha1);
- a[3] = a01 - a[4];
- a[5] = a01 - a[2];
- a[6] = 0x00;
- a[7] = 0xff;
- }
- }
-
- // Raw colors
- uint16_t color0 = colors & 0xffff;
- uint16_t color1 = colors >> 16;
-
- // If the new block has the same base colors as the
- // previous one, we don't need to recompute the color
- // table c[]
- if (color0 != prev_color0 || color1 != prev_color1) {
- // Store raw colors for comparison with next block
- prev_color0 = color0;
- prev_color1 = color1;
-
- int bbits = bits >> 1;
- bool has2 = ((bbits & ~bits) & 0x55555555) != 0;
- bool has3 = ((bbits & bits) & 0x55555555) != 0;
-
- if (has2 || has3) {
- int r0 = red(color0);
- int g0 = green(color0);
- int b0 = blue(color0);
-
- int r1 = red(color1);
- int g1 = green(color1);
- int b1 = blue(color1);
-
- int r2 = avg23(r0, r1);
- int g2 = avg23(g0, g1);
- int b2 = avg23(b0, b1);
-
- int r3 = avg23(r1, r0);
- int g3 = avg23(g1, g0);
- int b3 = avg23(b1, b0);
-
- c[0] = rgb565SepTo888(r0, g0, b0);
- c[1] = rgb565SepTo888(r1, g1, b1);
- c[2] = rgb565SepTo888(r2, g2, b2);
- c[3] = rgb565SepTo888(r3, g3, b3);
- } else {
- // Convert to 8 bits
- c[0] = rgb565To888(color0);
- c[1] = rgb565To888(color1);
- }
- }
-
- uint32_t* blockRowPtr = blockPtr;
- for (int y = 0; y < 4; y++, blockRowPtr += stride) {
- // Don't process rows past the botom
- if (base_y + y >= height) {
- break;
- }
-
- int w = min(width - base_x, 4);
- for (int x = 0; x < w; x++) {
- int acode = alpha & 0x7;
- alpha >>= 3;
-
- int code = bits & 0x3;
- bits >>= 2;
-
- blockRowPtr[x] = c[code] | (a[acode] << 24);
- }
- }
- }
- }
-}
-
-/*
- * Decode a DXT-compressed texture into memory. DXT textures consist of
- * a series of 4x4 pixel blocks in left-to-right, top-down order.
- * The number of blocks is given by ceil(width/4)*ceil(height/4).
- *
- * 'data' points to the texture data. 'width' and 'height' indicate the
- * dimensions of the texture. We assume width and height are >= 0 but
- * do not require them to be powers of 2 or divisible by any factor.
- *
- * The output is written to 'surface' with each scanline separated by
- * 'stride' 2- or 4-byte words.
- *
- * 'format' indicates the type of compression and must be one of the following:
- *
- * GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- * The output is written as 5/6/5 opaque RGB (16 bit words).
- * 8 bytes are read from 'data' for each block.
- *
- * GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
- * The output is written as 5/5/5/1 RGBA (16 bit words)
- * 8 bytes are read from 'data' for each block.
- *
- * GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
- * GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
- * The output is written as 8/8/8/8 ARGB (32 bit words)
- * 16 bytes are read from 'data' for each block.
- */
-void
-decodeDXT(const GLvoid *data, int width, int height,
- void *surface, int stride, int format)
-{
-#if TIMING
- struct timeval start_t, end_t;
- struct timezone tz;
-
- gettimeofday(&start_t, &tz);
-#endif
-
- switch (format) {
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- decodeDXT1(data, width, height, surface, stride, false);
- break;
-
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- decodeDXT1(data, width, height, surface, stride, true);
- break;
-
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- decodeDXT3(data, width, height, surface, stride);
- break;
-
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- decodeDXT5(data, width, height, surface, stride);
- break;
- }
-
-#if TIMING
- gettimeofday(&end_t, &tz);
- long usec = (end_t.tv_sec - start_t.tv_sec)*1000000 +
- (end_t.tv_usec - start_t.tv_usec);
-
- printf("Loaded w=%d h=%d in %ld usec\n", width, height, usec);
-#endif
-}
-
-} // namespace android
diff --git a/opengl/libagl/dxt.h b/opengl/libagl/dxt.h
deleted file mode 100644
index d95a36c..0000000
--- a/opengl/libagl/dxt.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* libs/opengles/dxt.h
-**
-** Copyright 2007, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_TEXTURE_H
-#define ANDROID_OPENGLES_TEXTURE_H
-
-#include <stdlib.h>
-
-#include <GLES/gl.h>
-
-namespace android {
-
- bool DXT1HasAlpha(const GLvoid *data, int width, int height);
- void decodeDXT(const GLvoid *data, int width, int height,
- void *surface, int stride, int format);
-
-} // namespace android
-
-#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
deleted file mode 100644
index be43705..0000000
--- a/opengl/libagl/egl.cpp
+++ /dev/null
@@ -1,2230 +0,0 @@
-/*
-**
-** Copyright 2007 The Android Open Source Project
-**
-** Licensed under the Apache License Version 2.0(the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing software
-** distributed under the License is distributed on an "AS IS" BASIS
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <assert.h>
-#include <atomic>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-#include <log/log.h>
-
-#include <utils/threads.h>
-#include <ui/ANativeObjectBase.h>
-#include <ui/Fence.h>
-#include <ui/GraphicBufferMapper.h>
-#include <ui/Rect.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <pixelflinger/format.h>
-#include <pixelflinger/pixelflinger.h>
-
-#include "context.h"
-#include "state.h"
-#include "texture.h"
-#include "matrix.h"
-
-#undef NELEM
-#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-
-// ----------------------------------------------------------------------------
-
-EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
- EGLint left, EGLint top, EGLint width, EGLint height);
-
-
-typedef struct egl_native_pixmap_t
-{
- int32_t version; /* must be 32 */
- int32_t width;
- int32_t height;
- int32_t stride;
- uint8_t* data;
- uint8_t format;
- uint8_t rfu[3];
- union {
- uint32_t compressedFormat;
- int32_t vstride;
- };
- int32_t reserved;
-} egl_native_pixmap_t;
-
-
-// ----------------------------------------------------------------------------
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-const unsigned int NUM_DISPLAYS = 1;
-
-#ifndef __ANDROID__
-static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
-#endif
-static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_key_t gEGLErrorKey = -1;
-#ifndef __ANDROID__
-namespace gl {
-pthread_key_t gGLKey = -1;
-}; // namespace gl
-#endif
-
-template<typename T>
-static T setError(GLint error, T returnValue) {
- if (ggl_unlikely(gEGLErrorKey == -1)) {
- pthread_mutex_lock(&gErrorKeyMutex);
- if (gEGLErrorKey == -1)
- pthread_key_create(&gEGLErrorKey, NULL);
- pthread_mutex_unlock(&gErrorKeyMutex);
- }
- pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)error);
- return returnValue;
-}
-
-static GLint getError() {
- if (ggl_unlikely(gEGLErrorKey == -1))
- return EGL_SUCCESS;
- GLint error = (GLint)(uintptr_t)pthread_getspecific(gEGLErrorKey);
- if (error == 0) {
- // The TLS key has been created by another thread, but the value for
- // this thread has not been initialized.
- return EGL_SUCCESS;
- }
- pthread_setspecific(gEGLErrorKey, (void*)(uintptr_t)EGL_SUCCESS);
- return error;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_display_t
-{
- egl_display_t() : type(0), initialized(0) { }
-
- static egl_display_t& get_display(EGLDisplay dpy);
-
- static EGLBoolean is_valid(EGLDisplay dpy) {
- return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
- }
-
- NativeDisplayType type;
- std::atomic_size_t initialized;
-};
-
-static egl_display_t gDisplays[NUM_DISPLAYS];
-
-egl_display_t& egl_display_t::get_display(EGLDisplay dpy) {
- return gDisplays[uintptr_t(dpy)-1U];
-}
-
-struct egl_context_t {
- enum {
- IS_CURRENT = 0x00010000,
- NEVER_CURRENT = 0x00020000
- };
- uint32_t flags;
- EGLDisplay dpy;
- EGLConfig config;
- EGLSurface read;
- EGLSurface draw;
-
- static inline egl_context_t* context(EGLContext ctx) {
- ogles_context_t* const gl = static_cast<ogles_context_t*>(ctx);
- return static_cast<egl_context_t*>(gl->rasterizer.base);
- }
-};
-
-// ----------------------------------------------------------------------------
-
-struct egl_surface_t
-{
- enum {
- PAGE_FLIP = 0x00000001,
- MAGIC = 0x31415265
- };
-
- uint32_t magic;
- EGLDisplay dpy;
- EGLConfig config;
- EGLContext ctx;
- bool zombie;
-
- egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
- virtual ~egl_surface_t();
- bool isValid() const;
- virtual bool initCheck() const = 0;
-
- virtual EGLBoolean bindDrawSurface(ogles_context_t* gl) = 0;
- virtual EGLBoolean bindReadSurface(ogles_context_t* gl) = 0;
- virtual EGLBoolean connect() { return EGL_TRUE; }
- virtual void disconnect() {}
- virtual EGLint getWidth() const = 0;
- virtual EGLint getHeight() const = 0;
-
- virtual EGLint getHorizontalResolution() const;
- virtual EGLint getVerticalResolution() const;
- virtual EGLint getRefreshRate() const;
- virtual EGLint getSwapBehavior() const;
- virtual EGLBoolean swapBuffers();
- virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
-protected:
- GGLSurface depth;
-};
-
-egl_surface_t::egl_surface_t(EGLDisplay dpy,
- EGLConfig config,
- int32_t depthFormat)
- : magic(MAGIC), dpy(dpy), config(config), ctx(0), zombie(false)
-{
- depth.version = sizeof(GGLSurface);
- depth.data = 0;
- depth.format = depthFormat;
-}
-egl_surface_t::~egl_surface_t()
-{
- magic = 0;
- free(depth.data);
-}
-bool egl_surface_t::isValid() const {
- ALOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
- return magic == MAGIC;
-}
-
-EGLBoolean egl_surface_t::swapBuffers() {
- return EGL_FALSE;
-}
-EGLint egl_surface_t::getHorizontalResolution() const {
- return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_surface_t::getVerticalResolution() const {
- return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_surface_t::getRefreshRate() const {
- return (60 * EGL_DISPLAY_SCALING);
-}
-EGLint egl_surface_t::getSwapBehavior() const {
- return EGL_BUFFER_PRESERVED;
-}
-EGLBoolean egl_surface_t::setSwapRectangle(
- EGLint /*l*/, EGLint /*t*/, EGLint /*w*/, EGLint /*h*/)
-{
- return EGL_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_window_surface_v2_t : public egl_surface_t
-{
- egl_window_surface_v2_t(
- EGLDisplay dpy, EGLConfig config,
- int32_t depthFormat,
- ANativeWindow* window);
-
- ~egl_window_surface_v2_t();
-
- virtual bool initCheck() const { return true; } // TODO: report failure if ctor fails
- virtual EGLBoolean swapBuffers();
- virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
- virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
- virtual EGLBoolean connect();
- virtual void disconnect();
- virtual EGLint getWidth() const { return width; }
- virtual EGLint getHeight() const { return height; }
- virtual EGLint getHorizontalResolution() const;
- virtual EGLint getVerticalResolution() const;
- virtual EGLint getRefreshRate() const;
- virtual EGLint getSwapBehavior() const;
- virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
-
-private:
- status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
- status_t unlock(ANativeWindowBuffer* buf);
- ANativeWindow* nativeWindow;
- ANativeWindowBuffer* buffer;
- ANativeWindowBuffer* previousBuffer;
- int width;
- int height;
- void* bits;
- GGLFormat const* pixelFormatTable;
-
- struct Rect {
- inline Rect() { };
- inline Rect(int32_t w, int32_t h)
- : left(0), top(0), right(w), bottom(h) { }
- inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
- : left(l), top(t), right(r), bottom(b) { }
- Rect& andSelf(const Rect& r) {
- left = max(left, r.left);
- top = max(top, r.top);
- right = min(right, r.right);
- bottom = min(bottom, r.bottom);
- return *this;
- }
- bool isEmpty() const {
- return (left>=right || top>=bottom);
- }
- void dump(char const* what) {
- ALOGD("%s { %5d, %5d, w=%5d, h=%5d }",
- what, left, top, right-left, bottom-top);
- }
-
- int32_t left;
- int32_t top;
- int32_t right;
- int32_t bottom;
- };
-
- struct Region {
- inline Region() : count(0) { }
- typedef Rect const* const_iterator;
- const_iterator begin() const { return storage; }
- const_iterator end() const { return storage+count; }
- static Region subtract(const Rect& lhs, const Rect& rhs) {
- Region reg;
- Rect* storage = reg.storage;
- if (!lhs.isEmpty()) {
- if (lhs.top < rhs.top) { // top rect
- storage->left = lhs.left;
- storage->top = lhs.top;
- storage->right = lhs.right;
- storage->bottom = rhs.top;
- storage++;
- }
- const int32_t top = max(lhs.top, rhs.top);
- const int32_t bot = min(lhs.bottom, rhs.bottom);
- if (top < bot) {
- if (lhs.left < rhs.left) { // left-side rect
- storage->left = lhs.left;
- storage->top = top;
- storage->right = rhs.left;
- storage->bottom = bot;
- storage++;
- }
- if (lhs.right > rhs.right) { // right-side rect
- storage->left = rhs.right;
- storage->top = top;
- storage->right = lhs.right;
- storage->bottom = bot;
- storage++;
- }
- }
- if (lhs.bottom > rhs.bottom) { // bottom rect
- storage->left = lhs.left;
- storage->top = rhs.bottom;
- storage->right = lhs.right;
- storage->bottom = lhs.bottom;
- storage++;
- }
- reg.count = storage - reg.storage;
- }
- return reg;
- }
- bool isEmpty() const {
- return count<=0;
- }
- private:
- Rect storage[4];
- ssize_t count;
- };
-
- void copyBlt(
- ANativeWindowBuffer* dst, void* dst_vaddr,
- ANativeWindowBuffer* src, void const* src_vaddr,
- const Region& clip);
-
- Rect dirtyRegion;
- Rect oldDirtyRegion;
-};
-
-egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
- EGLConfig config,
- int32_t depthFormat,
- ANativeWindow* window)
- : egl_surface_t(dpy, config, depthFormat),
- nativeWindow(window), buffer(0), previousBuffer(0), bits(NULL)
-{
-
- pixelFormatTable = gglGetPixelFormatTable();
-
- // keep a reference on the window
- nativeWindow->common.incRef(&nativeWindow->common);
- nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
- nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
-}
-
-egl_window_surface_v2_t::~egl_window_surface_v2_t() {
- if (buffer) {
- buffer->common.decRef(&buffer->common);
- }
- if (previousBuffer) {
- previousBuffer->common.decRef(&previousBuffer->common);
- }
- nativeWindow->common.decRef(&nativeWindow->common);
-}
-
-EGLBoolean egl_window_surface_v2_t::connect()
-{
- // we're intending to do software rendering
- native_window_set_usage(nativeWindow,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
- // dequeue a buffer
- int fenceFd = -1;
- if (nativeWindow->dequeueBuffer(nativeWindow, &buffer,
- &fenceFd) != NO_ERROR) {
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
-
- // wait for the buffer
- sp<Fence> fence(new Fence(fenceFd));
- if (fence->wait(Fence::TIMEOUT_NEVER) != NO_ERROR) {
- nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
-
- // allocate a corresponding depth-buffer
- width = buffer->width;
- height = buffer->height;
- if (depth.format) {
- depth.width = width;
- depth.height = height;
- depth.stride = depth.width; // use the width here
- uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
- static_cast<uint64_t>(depth.height) * 2;
- if (depth.stride < 0 || depth.height > INT_MAX ||
- allocSize > UINT32_MAX) {
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
- depth.data = (GGLubyte*)malloc(allocSize);
- if (depth.data == 0) {
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
- }
-
- // keep a reference on the buffer
- buffer->common.incRef(&buffer->common);
-
- // pin the buffer down
- if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
- ALOGE("connect() failed to lock buffer %p (%ux%u)",
- buffer, buffer->width, buffer->height);
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- // FIXME: we should make sure we're not accessing the buffer anymore
- }
- return EGL_TRUE;
-}
-
-void egl_window_surface_v2_t::disconnect()
-{
- if (buffer && bits) {
- bits = NULL;
- unlock(buffer);
- }
- if (buffer) {
- nativeWindow->cancelBuffer(nativeWindow, buffer, -1);
- buffer->common.decRef(&buffer->common);
- buffer = 0;
- }
- if (previousBuffer) {
- previousBuffer->common.decRef(&previousBuffer->common);
- previousBuffer = 0;
- }
-}
-
-status_t egl_window_surface_v2_t::lock(
- ANativeWindowBuffer* buf, int usage, void** vaddr)
-{
- auto& mapper = GraphicBufferMapper::get();
- return mapper.lock(buf->handle, usage,
- android::Rect(buf->width, buf->height), vaddr);
-}
-
-status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
-{
- if (!buf) return BAD_VALUE;
- auto& mapper = GraphicBufferMapper::get();
- return mapper.unlock(buf->handle);
-}
-
-void egl_window_surface_v2_t::copyBlt(
- ANativeWindowBuffer* dst, void* dst_vaddr,
- ANativeWindowBuffer* src, void const* src_vaddr,
- const Region& clip)
-{
- // NOTE: dst and src must be the same format
-
- Region::const_iterator cur = clip.begin();
- Region::const_iterator end = clip.end();
-
- const size_t bpp = pixelFormatTable[src->format].size;
- const size_t dbpr = dst->stride * bpp;
- const size_t sbpr = src->stride * bpp;
-
- uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
- uint8_t * const dst_bits = (uint8_t *)dst_vaddr;
-
- while (cur != end) {
- const Rect& r(*cur++);
- ssize_t w = r.right - r.left;
- ssize_t h = r.bottom - r.top;
- if (w <= 0 || h<=0) continue;
- size_t size = w * bpp;
- uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
- uint8_t * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
- if (dbpr==sbpr && size==sbpr) {
- size *= h;
- h = 1;
- }
- do {
- memcpy(d, s, size);
- d += dbpr;
- s += sbpr;
- } while (--h > 0);
- }
-}
-
-EGLBoolean egl_window_surface_v2_t::swapBuffers()
-{
- if (!buffer) {
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- }
-
- /*
- * Handle eglSetSwapRectangleANDROID()
- * We copyback from the front buffer
- */
- if (!dirtyRegion.isEmpty()) {
- dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
- if (previousBuffer) {
- // This was const Region copyBack, but that causes an
- // internal compile error on simulator builds
- /*const*/ Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
- if (!copyBack.isEmpty()) {
- void* prevBits;
- if (lock(previousBuffer,
- GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
- // copy from previousBuffer to buffer
- copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
- unlock(previousBuffer);
- }
- }
- }
- oldDirtyRegion = dirtyRegion;
- }
-
- if (previousBuffer) {
- previousBuffer->common.decRef(&previousBuffer->common);
- previousBuffer = 0;
- }
-
- unlock(buffer);
- previousBuffer = buffer;
- nativeWindow->queueBuffer(nativeWindow, buffer, -1);
- buffer = 0;
-
- // dequeue a new buffer
- int fenceFd = -1;
- if (nativeWindow->dequeueBuffer(nativeWindow, &buffer, &fenceFd) == NO_ERROR) {
- sp<Fence> fence(new Fence(fenceFd));
- if (fence->wait(Fence::TIMEOUT_NEVER)) {
- nativeWindow->cancelBuffer(nativeWindow, buffer, fenceFd);
- return setError(EGL_BAD_ALLOC, EGL_FALSE);
- }
-
- // reallocate the depth-buffer if needed
- if ((width != buffer->width) || (height != buffer->height)) {
- // TODO: we probably should reset the swap rect here
- // if the window size has changed
- width = buffer->width;
- height = buffer->height;
- if (depth.data) {
- free(depth.data);
- depth.width = width;
- depth.height = height;
- depth.stride = buffer->stride;
- uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
- static_cast<uint64_t>(depth.height) * 2;
- if (depth.stride < 0 || depth.height > INT_MAX ||
- allocSize > UINT32_MAX) {
- setError(EGL_BAD_ALLOC, EGL_FALSE);
- return EGL_FALSE;
- }
- depth.data = (GGLubyte*)malloc(allocSize);
- if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_FALSE);
- return EGL_FALSE;
- }
- }
- }
-
- // keep a reference on the buffer
- buffer->common.incRef(&buffer->common);
-
- // finally pin the buffer down
- if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
- ALOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
- buffer, buffer->width, buffer->height);
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- // FIXME: we should make sure we're not accessing the buffer anymore
- }
- } else {
- return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
- }
-
- return EGL_TRUE;
-}
-
-EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
- EGLint l, EGLint t, EGLint w, EGLint h)
-{
- dirtyRegion = Rect(l, t, l+w, t+h);
- return EGL_TRUE;
-}
-
-EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
-{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = this->buffer->width;
- buffer.height = this->buffer->height;
- buffer.stride = this->buffer->stride;
- buffer.data = (GGLubyte*)bits;
- buffer.format = this->buffer->format;
- gl->rasterizer.procs.colorBuffer(gl, &buffer);
- if (depth.data != gl->rasterizer.state.buffers.depth.data)
- gl->rasterizer.procs.depthBuffer(gl, &depth);
-
- return EGL_TRUE;
-}
-EGLBoolean egl_window_surface_v2_t::bindReadSurface(ogles_context_t* gl)
-{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = this->buffer->width;
- buffer.height = this->buffer->height;
- buffer.stride = this->buffer->stride;
- buffer.data = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
- buffer.format = this->buffer->format;
- gl->rasterizer.procs.readBuffer(gl, &buffer);
- return EGL_TRUE;
-}
-EGLint egl_window_surface_v2_t::getHorizontalResolution() const {
- return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_window_surface_v2_t::getVerticalResolution() const {
- return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_window_surface_v2_t::getRefreshRate() const {
- return (60 * EGL_DISPLAY_SCALING); // FIXME
-}
-EGLint egl_window_surface_v2_t::getSwapBehavior() const
-{
- /*
- * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
- * the content of the swapped buffer.
- *
- * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
- *
- * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
- * only applies to the area specified by eglSetSwapRectangleANDROID(), that
- * is, everything outside of this area is preserved.
- *
- * This implementation of EGL assumes the later case.
- *
- */
-
- return EGL_BUFFER_DESTROYED;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_pixmap_surface_t : public egl_surface_t
-{
- egl_pixmap_surface_t(
- EGLDisplay dpy, EGLConfig config,
- int32_t depthFormat,
- egl_native_pixmap_t const * pixmap);
-
- virtual ~egl_pixmap_surface_t() { }
-
- virtual bool initCheck() const { return !depth.format || depth.data!=0; }
- virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
- virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
- virtual EGLint getWidth() const { return nativePixmap.width; }
- virtual EGLint getHeight() const { return nativePixmap.height; }
-private:
- egl_native_pixmap_t nativePixmap;
-};
-
-egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
- EGLConfig config,
- int32_t depthFormat,
- egl_native_pixmap_t const * pixmap)
- : egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
-{
- if (depthFormat) {
- depth.width = pixmap->width;
- depth.height = pixmap->height;
- depth.stride = depth.width; // use the width here
- uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
- static_cast<uint64_t>(depth.height) * 2;
- if (depth.stride < 0 || depth.height > INT_MAX ||
- allocSize > UINT32_MAX) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
- }
- depth.data = (GGLubyte*)malloc(allocSize);
- if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- }
- }
-}
-EGLBoolean egl_pixmap_surface_t::bindDrawSurface(ogles_context_t* gl)
-{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = nativePixmap.width;
- buffer.height = nativePixmap.height;
- buffer.stride = nativePixmap.stride;
- buffer.data = nativePixmap.data;
- buffer.format = nativePixmap.format;
-
- gl->rasterizer.procs.colorBuffer(gl, &buffer);
- if (depth.data != gl->rasterizer.state.buffers.depth.data)
- gl->rasterizer.procs.depthBuffer(gl, &depth);
- return EGL_TRUE;
-}
-EGLBoolean egl_pixmap_surface_t::bindReadSurface(ogles_context_t* gl)
-{
- GGLSurface buffer;
- buffer.version = sizeof(GGLSurface);
- buffer.width = nativePixmap.width;
- buffer.height = nativePixmap.height;
- buffer.stride = nativePixmap.stride;
- buffer.data = nativePixmap.data;
- buffer.format = nativePixmap.format;
- gl->rasterizer.procs.readBuffer(gl, &buffer);
- return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_pbuffer_surface_t : public egl_surface_t
-{
- egl_pbuffer_surface_t(
- EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
- int32_t w, int32_t h, int32_t f);
-
- virtual ~egl_pbuffer_surface_t();
-
- virtual bool initCheck() const { return pbuffer.data != 0; }
- virtual EGLBoolean bindDrawSurface(ogles_context_t* gl);
- virtual EGLBoolean bindReadSurface(ogles_context_t* gl);
- virtual EGLint getWidth() const { return pbuffer.width; }
- virtual EGLint getHeight() const { return pbuffer.height; }
-private:
- GGLSurface pbuffer;
-};
-
-egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
- EGLConfig config, int32_t depthFormat,
- int32_t w, int32_t h, int32_t f)
- : egl_surface_t(dpy, config, depthFormat)
-{
- size_t size = w*h;
- switch (f) {
- case GGL_PIXEL_FORMAT_A_8: size *= 1; break;
- case GGL_PIXEL_FORMAT_RGB_565: size *= 2; break;
- case GGL_PIXEL_FORMAT_RGBA_8888: size *= 4; break;
- case GGL_PIXEL_FORMAT_RGBX_8888: size *= 4; break;
- case GGL_PIXEL_FORMAT_BGRA_8888: size *= 4; break;
- default:
- ALOGE("incompatible pixel format for pbuffer (format=%d)", f);
- pbuffer.data = 0;
- break;
- }
- pbuffer.version = sizeof(GGLSurface);
- pbuffer.width = w;
- pbuffer.height = h;
- pbuffer.stride = w;
- pbuffer.data = (GGLubyte*)malloc(size);
- pbuffer.format = f;
-
- if (depthFormat) {
- depth.width = pbuffer.width;
- depth.height = pbuffer.height;
- depth.stride = depth.width; // use the width here
- uint64_t allocSize = static_cast<uint64_t>(depth.stride) *
- static_cast<uint64_t>(depth.height) * 2;
- if (depth.stride < 0 || depth.height > INT_MAX ||
- allocSize > UINT32_MAX) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
- }
- depth.data = (GGLubyte*)malloc(allocSize);
- if (depth.data == 0) {
- setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
- return;
- }
- }
-}
-egl_pbuffer_surface_t::~egl_pbuffer_surface_t() {
- free(pbuffer.data);
-}
-EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(ogles_context_t* gl)
-{
- gl->rasterizer.procs.colorBuffer(gl, &pbuffer);
- if (depth.data != gl->rasterizer.state.buffers.depth.data)
- gl->rasterizer.procs.depthBuffer(gl, &depth);
- return EGL_TRUE;
-}
-EGLBoolean egl_pbuffer_surface_t::bindReadSurface(ogles_context_t* gl)
-{
- gl->rasterizer.procs.readBuffer(gl, &pbuffer);
- return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct config_pair_t {
- GLint key;
- GLint value;
-};
-
-struct configs_t {
- const config_pair_t* array;
- int size;
-};
-
-struct config_management_t {
- GLint key;
- bool (*match)(GLint reqValue, GLint confValue);
- static bool atLeast(GLint reqValue, GLint confValue) {
- return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
- }
- static bool exact(GLint reqValue, GLint confValue) {
- return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
- }
- static bool mask(GLint reqValue, GLint confValue) {
- return (confValue & reqValue) == reqValue;
- }
- static bool ignore(GLint /*reqValue*/, GLint /*confValue*/) {
- return true;
- }
-};
-
-// ----------------------------------------------------------------------------
-
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 2
-static char const * const gVendorString = "Google Inc.";
-static char const * const gVersionString = "1.2 Android Driver 1.2.0";
-static char const * const gClientApiString = "OpenGL_ES";
-static char const * const gExtensionsString =
- "EGL_KHR_fence_sync "
- "EGL_KHR_image_base "
- // "KHR_image_pixmap "
- "EGL_ANDROID_image_native_buffer "
- "EGL_ANDROID_swap_rectangle "
- ;
-
-// ----------------------------------------------------------------------------
-
-struct extention_map_t {
- const char * const name;
- __eglMustCastToProperFunctionPointerType address;
-};
-
-static const extention_map_t gExtentionMap[] = {
- { "glDrawTexsOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
- { "glDrawTexiOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
- { "glDrawTexfOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
- { "glDrawTexxOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
- { "glDrawTexsvOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
- { "glDrawTexivOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
- { "glDrawTexfvOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
- { "glDrawTexxvOES",
- (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
- { "glQueryMatrixxOES",
- (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
- { "glEGLImageTargetTexture2DOES",
- (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
- { "glEGLImageTargetRenderbufferStorageOES",
- (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
- { "glClipPlanef",
- (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
- { "glClipPlanex",
- (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
- { "glBindBuffer",
- (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
- { "glBufferData",
- (__eglMustCastToProperFunctionPointerType)&glBufferData },
- { "glBufferSubData",
- (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
- { "glDeleteBuffers",
- (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
- { "glGenBuffers",
- (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
- { "eglCreateImageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
- { "eglDestroyImageKHR",
- (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
- { "eglCreateSyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglCreateSyncKHR },
- { "eglDestroySyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglDestroySyncKHR },
- { "eglClientWaitSyncKHR",
- (__eglMustCastToProperFunctionPointerType)&eglClientWaitSyncKHR },
- { "eglGetSyncAttribKHR",
- (__eglMustCastToProperFunctionPointerType)&eglGetSyncAttribKHR },
- { "eglSetSwapRectangleANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
-};
-
-/*
- * In the lists below, attributes names MUST be sorted.
- * Additionally, all configs must be sorted according to
- * the EGL specification.
- */
-
-static config_pair_t const config_base_attribute_list[] = {
- { EGL_STENCIL_SIZE, 0 },
- { EGL_CONFIG_CAVEAT, EGL_SLOW_CONFIG },
- { EGL_LEVEL, 0 },
- { EGL_MAX_PBUFFER_HEIGHT, GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_PIXELS,
- GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS },
- { EGL_MAX_PBUFFER_WIDTH, GGL_MAX_VIEWPORT_DIMS },
- { EGL_NATIVE_RENDERABLE, EGL_TRUE },
- { EGL_NATIVE_VISUAL_ID, 0 },
- { EGL_NATIVE_VISUAL_TYPE, GGL_PIXEL_FORMAT_RGB_565 },
- { EGL_SAMPLES, 0 },
- { EGL_SAMPLE_BUFFERS, 0 },
- { EGL_TRANSPARENT_TYPE, EGL_NONE },
- { EGL_TRANSPARENT_BLUE_VALUE, 0 },
- { EGL_TRANSPARENT_GREEN_VALUE, 0 },
- { EGL_TRANSPARENT_RED_VALUE, 0 },
- { EGL_BIND_TO_TEXTURE_RGBA, EGL_FALSE },
- { EGL_BIND_TO_TEXTURE_RGB, EGL_FALSE },
- { EGL_MIN_SWAP_INTERVAL, 1 },
- { EGL_MAX_SWAP_INTERVAL, 1 },
- { EGL_LUMINANCE_SIZE, 0 },
- { EGL_ALPHA_MASK_SIZE, 0 },
- { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER },
- { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT },
- { EGL_CONFORMANT, 0 }
-};
-
-// These configs can override the base attribute list
-// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
-
-// 565 configs
-static config_pair_t const config_0_attribute_list[] = {
- { EGL_BUFFER_SIZE, 16 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 5 },
- { EGL_GREEN_SIZE, 6 },
- { EGL_RED_SIZE, 5 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 0 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_1_attribute_list[] = {
- { EGL_BUFFER_SIZE, 16 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 5 },
- { EGL_GREEN_SIZE, 6 },
- { EGL_RED_SIZE, 5 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 1 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// RGB 888 configs
-static config_pair_t const config_2_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 6 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_3_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 0 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 7 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// 8888 configs
-static config_pair_t const config_4_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 2 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_5_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 3 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// A8 configs
-static config_pair_t const config_6_attribute_list[] = {
- { EGL_BUFFER_SIZE, 8 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 0 },
- { EGL_GREEN_SIZE, 0 },
- { EGL_RED_SIZE, 0 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 4 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_7_attribute_list[] = {
- { EGL_BUFFER_SIZE, 8 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 0 },
- { EGL_GREEN_SIZE, 0 },
- { EGL_RED_SIZE, 0 },
- { EGL_DEPTH_SIZE, 16 },
- { EGL_CONFIG_ID, 5 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// BGRA 8888 config
-static config_pair_t const config_8_attribute_list[] = {
- { EGL_BUFFER_SIZE, 32 },
- { EGL_ALPHA_SIZE, 8 },
- { EGL_BLUE_SIZE, 8 },
- { EGL_GREEN_SIZE, 8 },
- { EGL_RED_SIZE, 8 },
- { EGL_DEPTH_SIZE, 0 },
- { EGL_CONFIG_ID, 8 },
- { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_BGRA_8888 },
- { EGL_SURFACE_TYPE, EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static configs_t const gConfigs[] = {
- { config_0_attribute_list, NELEM(config_0_attribute_list) },
- { config_1_attribute_list, NELEM(config_1_attribute_list) },
- { config_2_attribute_list, NELEM(config_2_attribute_list) },
- { config_3_attribute_list, NELEM(config_3_attribute_list) },
- { config_4_attribute_list, NELEM(config_4_attribute_list) },
- { config_5_attribute_list, NELEM(config_5_attribute_list) },
- { config_6_attribute_list, NELEM(config_6_attribute_list) },
- { config_7_attribute_list, NELEM(config_7_attribute_list) },
- { config_8_attribute_list, NELEM(config_8_attribute_list) },
-};
-
-static config_management_t const gConfigManagement[] = {
- { EGL_BUFFER_SIZE, config_management_t::atLeast },
- { EGL_ALPHA_SIZE, config_management_t::atLeast },
- { EGL_BLUE_SIZE, config_management_t::atLeast },
- { EGL_GREEN_SIZE, config_management_t::atLeast },
- { EGL_RED_SIZE, config_management_t::atLeast },
- { EGL_DEPTH_SIZE, config_management_t::atLeast },
- { EGL_STENCIL_SIZE, config_management_t::atLeast },
- { EGL_CONFIG_CAVEAT, config_management_t::exact },
- { EGL_CONFIG_ID, config_management_t::exact },
- { EGL_LEVEL, config_management_t::exact },
- { EGL_MAX_PBUFFER_HEIGHT, config_management_t::ignore },
- { EGL_MAX_PBUFFER_PIXELS, config_management_t::ignore },
- { EGL_MAX_PBUFFER_WIDTH, config_management_t::ignore },
- { EGL_NATIVE_RENDERABLE, config_management_t::exact },
- { EGL_NATIVE_VISUAL_ID, config_management_t::ignore },
- { EGL_NATIVE_VISUAL_TYPE, config_management_t::exact },
- { EGL_SAMPLES, config_management_t::exact },
- { EGL_SAMPLE_BUFFERS, config_management_t::exact },
- { EGL_SURFACE_TYPE, config_management_t::mask },
- { EGL_TRANSPARENT_TYPE, config_management_t::exact },
- { EGL_TRANSPARENT_BLUE_VALUE, config_management_t::exact },
- { EGL_TRANSPARENT_GREEN_VALUE, config_management_t::exact },
- { EGL_TRANSPARENT_RED_VALUE, config_management_t::exact },
- { EGL_BIND_TO_TEXTURE_RGBA, config_management_t::exact },
- { EGL_BIND_TO_TEXTURE_RGB, config_management_t::exact },
- { EGL_MIN_SWAP_INTERVAL, config_management_t::exact },
- { EGL_MAX_SWAP_INTERVAL, config_management_t::exact },
- { EGL_LUMINANCE_SIZE, config_management_t::atLeast },
- { EGL_ALPHA_MASK_SIZE, config_management_t::atLeast },
- { EGL_COLOR_BUFFER_TYPE, config_management_t::exact },
- { EGL_RENDERABLE_TYPE, config_management_t::mask },
- { EGL_CONFORMANT, config_management_t::mask }
-};
-
-
-static config_pair_t const config_defaults[] = {
- // attributes that are not specified are simply ignored, if a particular
- // one needs not be ignored, it must be specified here, eg:
- // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
-};
-
-// ----------------------------------------------------------------------------
-
-static status_t getConfigFormatInfo(EGLint configID,
- int32_t& pixelFormat, int32_t& depthFormat)
-{
- switch(configID) {
- case 0:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = 0;
- break;
- case 1:
- pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 2:
- pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
- depthFormat = 0;
- break;
- case 3:
- pixelFormat = GGL_PIXEL_FORMAT_RGBX_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 4:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = 0;
- break;
- case 5:
- pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 6:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = 0;
- break;
- case 7:
- pixelFormat = GGL_PIXEL_FORMAT_A_8;
- depthFormat = GGL_PIXEL_FORMAT_Z_16;
- break;
- case 8:
- pixelFormat = GGL_PIXEL_FORMAT_BGRA_8888;
- depthFormat = 0;
- break;
- default:
- return NAME_NOT_FOUND;
- }
- return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-template<typename T>
-static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
-{
- while (first <= last) {
- int mid = (first + last) / 2;
- if (key > sortedArray[mid].key) {
- first = mid + 1;
- } else if (key < sortedArray[mid].key) {
- last = mid - 1;
- } else {
- return mid;
- }
- }
- return -1;
-}
-
-static int isAttributeMatching(int i, EGLint attr, EGLint val)
-{
- // look for the attribute in all of our configs
- config_pair_t const* configFound = gConfigs[i].array;
- int index = binarySearch<config_pair_t>(
- gConfigs[i].array,
- 0, gConfigs[i].size-1,
- attr);
- if (index < 0) {
- configFound = config_base_attribute_list;
- index = binarySearch<config_pair_t>(
- config_base_attribute_list,
- 0, NELEM(config_base_attribute_list)-1,
- attr);
- }
- if (index >= 0) {
- // attribute found, check if this config could match
- int cfgMgtIndex = binarySearch<config_management_t>(
- gConfigManagement,
- 0, NELEM(gConfigManagement)-1,
- attr);
- if (cfgMgtIndex >= 0) {
- bool match = gConfigManagement[cfgMgtIndex].match(
- val, configFound[index].value);
- if (match) {
- // this config matches
- return 1;
- }
- } else {
- // attribute not found. this should NEVER happen.
- }
- } else {
- // error, this attribute doesn't exist
- }
- return 0;
-}
-
-static int makeCurrent(ogles_context_t* gl)
-{
- ogles_context_t* current = (ogles_context_t*)getGlThreadSpecific();
- if (gl) {
- egl_context_t* c = egl_context_t::context(gl);
- if (c->flags & egl_context_t::IS_CURRENT) {
- if (current != gl) {
- // it is an error to set a context current, if it's already
- // current to another thread
- return -1;
- }
- } else {
- if (current) {
- // mark the current context as not current, and flush
- glFlush();
- egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
- }
- }
- if (!(c->flags & egl_context_t::IS_CURRENT)) {
- // The context is not current, make it current!
- setGlThreadSpecific(gl);
- c->flags |= egl_context_t::IS_CURRENT;
- }
- } else {
- if (current) {
- // mark the current context as not current, and flush
- glFlush();
- egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
- }
- // this thread has no context attached to it
- setGlThreadSpecific(0);
- }
- return 0;
-}
-
-static EGLBoolean getConfigAttrib(EGLDisplay /*dpy*/, EGLConfig config,
- EGLint attribute, EGLint *value)
-{
- size_t numConfigs = NELEM(gConfigs);
- int index = (int)(uintptr_t)config;
- if (uint32_t(index) >= numConfigs)
- return setError(EGL_BAD_CONFIG, EGL_FALSE);
-
- int attrIndex;
- attrIndex = binarySearch<config_pair_t>(
- gConfigs[index].array,
- 0, gConfigs[index].size-1,
- attribute);
- if (attrIndex>=0) {
- *value = gConfigs[index].array[attrIndex].value;
- return EGL_TRUE;
- }
-
- attrIndex = binarySearch<config_pair_t>(
- config_base_attribute_list,
- 0, NELEM(config_base_attribute_list)-1,
- attribute);
- if (attrIndex>=0) {
- *value = config_base_attribute_list[attrIndex].value;
- return EGL_TRUE;
- }
- return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-}
-
-static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
- NativeWindowType window, const EGLint* /*attrib_list*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- if (window == 0)
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- EGLint surfaceType;
- if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
- return EGL_FALSE;
-
- if (!(surfaceType & EGL_WINDOW_BIT))
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- if (static_cast<ANativeWindow*>(window)->common.magic !=
- ANDROID_NATIVE_WINDOW_MAGIC) {
- return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
- }
-
- EGLint configID;
- if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
- return EGL_FALSE;
-
- int32_t depthFormat;
- int32_t pixelFormat;
- if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- }
-
- // FIXME: we don't have access to the pixelFormat here just yet.
- // (it's possible that the surface is not fully initialized)
- // maybe this should be done after the page-flip
- //if (EGLint(info.format) != pixelFormat)
- // return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- egl_surface_t* surface;
- surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
- static_cast<ANativeWindow*>(window));
-
- if (!surface->initCheck()) {
- // there was a problem in the ctor, the error
- // flag has been set.
- delete surface;
- surface = 0;
- }
- return surface;
-}
-
-static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap, const EGLint* /*attrib_list*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- if (pixmap == 0)
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- EGLint surfaceType;
- if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
- return EGL_FALSE;
-
- if (!(surfaceType & EGL_PIXMAP_BIT))
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- if (static_cast<egl_native_pixmap_t*>(pixmap)->version !=
- sizeof(egl_native_pixmap_t)) {
- return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
- }
-
- EGLint configID;
- if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
- return EGL_FALSE;
-
- int32_t depthFormat;
- int32_t pixelFormat;
- if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- }
-
- if (pixmap->format != pixelFormat)
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- egl_surface_t* surface =
- new egl_pixmap_surface_t(dpy, config, depthFormat,
- static_cast<egl_native_pixmap_t*>(pixmap));
-
- if (!surface->initCheck()) {
- // there was a problem in the ctor, the error
- // flag has been set.
- delete surface;
- surface = 0;
- }
- return surface;
-}
-
-static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-
- EGLint surfaceType;
- if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
- return EGL_FALSE;
-
- if (!(surfaceType & EGL_PBUFFER_BIT))
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
- EGLint configID;
- if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
- return EGL_FALSE;
-
- int32_t depthFormat;
- int32_t pixelFormat;
- if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
- return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
- }
-
- int32_t w = 0;
- int32_t h = 0;
- while (attrib_list[0] != EGL_NONE) {
- if (attrib_list[0] == EGL_WIDTH) w = attrib_list[1];
- if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
- attrib_list+=2;
- }
-
- egl_surface_t* surface =
- new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
-
- if (!surface->initCheck()) {
- // there was a problem in the ctor, the error
- // flag has been set.
- delete surface;
- surface = 0;
- }
- return surface;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-// Initialization
-// ----------------------------------------------------------------------------
-
-EGLDisplay eglGetDisplay(NativeDisplayType display)
-{
-#ifndef __ANDROID__
- // this just needs to be done once
- if (gGLKey == -1) {
- pthread_mutex_lock(&gInitMutex);
- if (gGLKey == -1)
- pthread_key_create(&gGLKey, NULL);
- pthread_mutex_unlock(&gInitMutex);
- }
-#endif
- if (display == EGL_DEFAULT_DISPLAY) {
- EGLDisplay dpy = (EGLDisplay)1;
- egl_display_t& d = egl_display_t::get_display(dpy);
- d.type = display;
- return dpy;
- }
- return EGL_NO_DISPLAY;
-}
-
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- EGLBoolean res = EGL_TRUE;
- egl_display_t& d = egl_display_t::get_display(dpy);
-
- if (d.initialized.fetch_add(1, std::memory_order_acquire) == 0) {
- // initialize stuff here if needed
- //pthread_mutex_lock(&gInitMutex);
- //pthread_mutex_unlock(&gInitMutex);
- }
-
- if (res == EGL_TRUE) {
- if (major != NULL) *major = VERSION_MAJOR;
- if (minor != NULL) *minor = VERSION_MINOR;
- }
- return res;
-}
-
-EGLBoolean eglTerminate(EGLDisplay dpy)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- EGLBoolean res = EGL_TRUE;
- egl_display_t& d = egl_display_t::get_display(dpy);
- if (d.initialized.fetch_sub(1, std::memory_order_release) == 1) {
- std::atomic_thread_fence(std::memory_order_acquire);
- // TODO: destroy all resources (surfaces, contexts, etc...)
- //pthread_mutex_lock(&gInitMutex);
- //pthread_mutex_unlock(&gInitMutex);
- }
- return res;
-}
-
-// ----------------------------------------------------------------------------
-// configuration
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglGetConfigs( EGLDisplay dpy,
- EGLConfig *configs,
- EGLint config_size, EGLint *num_config)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- if (ggl_unlikely(num_config==NULL))
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
- GLint numConfigs = NELEM(gConfigs);
- if (!configs) {
- *num_config = numConfigs;
- return EGL_TRUE;
- }
- GLint i;
- for (i=0 ; i<numConfigs && i<config_size ; i++) {
- *configs++ = (EGLConfig)(uintptr_t)i;
- }
- *num_config = i;
- return EGL_TRUE;
-}
-
-EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- if (ggl_unlikely(num_config==NULL)) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- if (ggl_unlikely(attrib_list==0)) {
- /*
- * A NULL attrib_list should be treated as though it was an empty
- * one (terminated with EGL_NONE) as defined in
- * section 3.4.1 "Querying Configurations" in the EGL specification.
- */
- static const EGLint dummy = EGL_NONE;
- attrib_list = &dummy;
- }
-
- int numAttributes = 0;
- int numConfigs = NELEM(gConfigs);
- uint32_t possibleMatch = (1<<numConfigs)-1;
- while(possibleMatch && *attrib_list != EGL_NONE) {
- numAttributes++;
- EGLint attr = *attrib_list++;
- EGLint val = *attrib_list++;
- for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
- if (!(possibleMatch & (1<<i)))
- continue;
- if (isAttributeMatching(i, attr, val) == 0) {
- possibleMatch &= ~(1<<i);
- }
- }
- }
-
- // now, handle the attributes which have a useful default value
- for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
- // see if this attribute was specified, if not, apply its
- // default value
- if (binarySearch<config_pair_t>(
- (config_pair_t const*)attrib_list,
- 0, numAttributes-1,
- config_defaults[j].key) < 0)
- {
- for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
- if (!(possibleMatch & (1<<i)))
- continue;
- if (isAttributeMatching(i,
- config_defaults[j].key,
- config_defaults[j].value) == 0)
- {
- possibleMatch &= ~(1<<i);
- }
- }
- }
- }
-
- // return the configurations found
- int n=0;
- if (possibleMatch) {
- if (configs) {
- for (int i=0 ; config_size && i<numConfigs ; i++) {
- if (possibleMatch & (1<<i)) {
- *configs++ = (EGLConfig)(uintptr_t)i;
- config_size--;
- n++;
- }
- }
- } else {
- for (int i=0 ; i<numConfigs ; i++) {
- if (possibleMatch & (1<<i)) {
- n++;
- }
- }
- }
- }
- *num_config = n;
- return EGL_TRUE;
-}
-
-EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
- EGLint attribute, EGLint *value)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- return getConfigAttrib(dpy, config, attribute, value);
-}
-
-// ----------------------------------------------------------------------------
-// surfaces
-// ----------------------------------------------------------------------------
-
-EGLSurface eglCreateWindowSurface( EGLDisplay dpy, EGLConfig config,
- NativeWindowType window,
- const EGLint *attrib_list)
-{
- return createWindowSurface(dpy, config, window, attrib_list);
-}
-
-EGLSurface eglCreatePixmapSurface( EGLDisplay dpy, EGLConfig config,
- NativePixmapType pixmap,
- const EGLint *attrib_list)
-{
- return createPixmapSurface(dpy, config, pixmap, attrib_list);
-}
-
-EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list)
-{
- return createPbufferSurface(dpy, config, attrib_list);
-}
-
-EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (eglSurface != EGL_NO_SURFACE) {
- egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
- if (!surface->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (surface->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (surface->ctx) {
- // defer disconnect/delete until no longer current
- surface->zombie = true;
- } else {
- surface->disconnect();
- delete surface;
- }
- }
- return EGL_TRUE;
-}
-
-EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
- EGLint attribute, EGLint *value)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
- if (!surface->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (surface->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- EGLBoolean ret = EGL_TRUE;
- switch (attribute) {
- case EGL_CONFIG_ID:
- ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
- break;
- case EGL_WIDTH:
- *value = surface->getWidth();
- break;
- case EGL_HEIGHT:
- *value = surface->getHeight();
- break;
- case EGL_LARGEST_PBUFFER:
- // not modified for a window or pixmap surface
- break;
- case EGL_TEXTURE_FORMAT:
- *value = EGL_NO_TEXTURE;
- break;
- case EGL_TEXTURE_TARGET:
- *value = EGL_NO_TEXTURE;
- break;
- case EGL_MIPMAP_TEXTURE:
- *value = EGL_FALSE;
- break;
- case EGL_MIPMAP_LEVEL:
- *value = 0;
- break;
- case EGL_RENDER_BUFFER:
- // TODO: return the real RENDER_BUFFER here
- *value = EGL_BACK_BUFFER;
- break;
- case EGL_HORIZONTAL_RESOLUTION:
- // pixel/mm * EGL_DISPLAY_SCALING
- *value = surface->getHorizontalResolution();
- break;
- case EGL_VERTICAL_RESOLUTION:
- // pixel/mm * EGL_DISPLAY_SCALING
- *value = surface->getVerticalResolution();
- break;
- case EGL_PIXEL_ASPECT_RATIO: {
- // w/h * EGL_DISPLAY_SCALING
- int wr = surface->getHorizontalResolution();
- int hr = surface->getVerticalResolution();
- *value = (wr * EGL_DISPLAY_SCALING) / hr;
- } break;
- case EGL_SWAP_BEHAVIOR:
- *value = surface->getSwapBehavior();
- break;
- default:
- ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
- }
- return ret;
-}
-
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext /*share_list*/, const EGLint* /*attrib_list*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-
- ogles_context_t* gl = ogles_init(sizeof(egl_context_t));
- if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
-
- egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
- c->flags = egl_context_t::NEVER_CURRENT;
- c->dpy = dpy;
- c->config = config;
- c->read = 0;
- c->draw = 0;
- return (EGLContext)gl;
-}
-
-EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_context_t* c = egl_context_t::context(ctx);
- if (c->flags & egl_context_t::IS_CURRENT)
- setGlThreadSpecific(0);
- ogles_uninit((ogles_context_t*)ctx);
- return EGL_TRUE;
-}
-
-EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- if (draw) {
- egl_surface_t* s = (egl_surface_t*)draw;
- if (!s->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (s->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that draw is compatible with the context
- }
- if (read && read!=draw) {
- egl_surface_t* s = (egl_surface_t*)read;
- if (!s->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (s->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: check that read is compatible with the context
- }
-
- EGLContext current_ctx = EGL_NO_CONTEXT;
-
- if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
- return setError(EGL_BAD_MATCH, EGL_FALSE);
-
- if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
- return setError(EGL_BAD_MATCH, EGL_FALSE);
-
- if (ctx == EGL_NO_CONTEXT) {
- // if we're detaching, we need the current context
- current_ctx = (EGLContext)getGlThreadSpecific();
- } else {
- egl_surface_t* d = (egl_surface_t*)draw;
- egl_surface_t* r = (egl_surface_t*)read;
- if ((d && d->ctx && d->ctx != ctx) ||
- (r && r->ctx && r->ctx != ctx)) {
- // one of the surface is bound to a context in another thread
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
- }
- }
-
- ogles_context_t* gl = (ogles_context_t*)ctx;
- if (makeCurrent(gl) == 0) {
- if (ctx) {
- egl_context_t* c = egl_context_t::context(ctx);
- egl_surface_t* d = (egl_surface_t*)draw;
- egl_surface_t* r = (egl_surface_t*)read;
-
- if (c->draw) {
- egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
- s->disconnect();
- s->ctx = EGL_NO_CONTEXT;
- if (s->zombie)
- delete s;
- }
- if (c->read) {
- // FIXME: unlock/disconnect the read surface too
- }
-
- c->draw = draw;
- c->read = read;
-
- if (c->flags & egl_context_t::NEVER_CURRENT) {
- c->flags &= ~egl_context_t::NEVER_CURRENT;
- GLint w = 0;
- GLint h = 0;
- if (draw) {
- w = d->getWidth();
- h = d->getHeight();
- }
- ogles_surfaceport(gl, 0, 0);
- ogles_viewport(gl, 0, 0, w, h);
- ogles_scissor(gl, 0, 0, w, h);
- }
- if (d) {
- if (d->connect() == EGL_FALSE) {
- return EGL_FALSE;
- }
- d->ctx = ctx;
- d->bindDrawSurface(gl);
- }
- if (r) {
- // FIXME: lock/connect the read surface too
- r->ctx = ctx;
- r->bindReadSurface(gl);
- }
- } else {
- // if surfaces were bound to the context bound to this thread
- // mark then as unbound.
- if (current_ctx) {
- egl_context_t* c = egl_context_t::context(current_ctx);
- egl_surface_t* d = (egl_surface_t*)c->draw;
- egl_surface_t* r = (egl_surface_t*)c->read;
- if (d) {
- c->draw = 0;
- d->disconnect();
- d->ctx = EGL_NO_CONTEXT;
- if (d->zombie)
- delete d;
- }
- if (r) {
- c->read = 0;
- r->ctx = EGL_NO_CONTEXT;
- // FIXME: unlock/disconnect the read surface too
- }
- }
- }
- return EGL_TRUE;
- }
- return setError(EGL_BAD_ACCESS, EGL_FALSE);
-}
-
-EGLContext eglGetCurrentContext(void)
-{
- // eglGetCurrentContext returns the current EGL rendering context,
- // as specified by eglMakeCurrent. If no context is current,
- // EGL_NO_CONTEXT is returned.
- return (EGLContext)getGlThreadSpecific();
-}
-
-EGLSurface eglGetCurrentSurface(EGLint readdraw)
-{
- // eglGetCurrentSurface returns the read or draw surface attached
- // to the current EGL rendering context, as specified by eglMakeCurrent.
- // If no context is current, EGL_NO_SURFACE is returned.
- EGLContext ctx = (EGLContext)getGlThreadSpecific();
- if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
- egl_context_t* c = egl_context_t::context(ctx);
- if (readdraw == EGL_READ) {
- return c->read;
- } else if (readdraw == EGL_DRAW) {
- return c->draw;
- }
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
-}
-
-EGLDisplay eglGetCurrentDisplay(void)
-{
- // eglGetCurrentDisplay returns the current EGL display connection
- // for the current EGL rendering context, as specified by eglMakeCurrent.
- // If no context is current, EGL_NO_DISPLAY is returned.
- EGLContext ctx = (EGLContext)getGlThreadSpecific();
- if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
- egl_context_t* c = egl_context_t::context(ctx);
- return c->dpy;
-}
-
-EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
- EGLint attribute, EGLint *value)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- egl_context_t* c = egl_context_t::context(ctx);
- switch (attribute) {
- case EGL_CONFIG_ID:
- // Returns the ID of the EGL frame buffer configuration with
- // respect to which the context was created
- return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
- }
- return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-}
-
-EGLBoolean eglWaitGL(void)
-{
- return EGL_TRUE;
-}
-
-EGLBoolean eglWaitNative(EGLint /*engine*/)
-{
- return EGL_TRUE;
-}
-
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- egl_surface_t* d = static_cast<egl_surface_t*>(draw);
- if (!d->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- // post the surface
- d->swapBuffers();
-
- // if it's bound to a context, update the buffer
- if (d->ctx != EGL_NO_CONTEXT) {
- d->bindDrawSurface((ogles_context_t*)d->ctx);
- // if this surface is also the read surface of the context
- // it is bound to, make sure to update the read buffer as well.
- // The EGL spec is a little unclear about this.
- egl_context_t* c = egl_context_t::context(d->ctx);
- if (c->read == draw) {
- d->bindReadSurface((ogles_context_t*)d->ctx);
- }
- }
-
- return EGL_TRUE;
-}
-
-EGLBoolean eglCopyBuffers( EGLDisplay dpy, EGLSurface /*surface*/,
- NativePixmapType /*target*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglCopyBuffers()
- return EGL_FALSE;
-}
-
-EGLint eglGetError(void)
-{
- return getError();
-}
-
-const char* eglQueryString(EGLDisplay dpy, EGLint name)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, (const char*)0);
-
- switch (name) {
- case EGL_VENDOR:
- return gVendorString;
- case EGL_VERSION:
- return gVersionString;
- case EGL_EXTENSIONS:
- return gExtensionsString;
- case EGL_CLIENT_APIS:
- return gClientApiString;
- }
- return setError(EGL_BAD_PARAMETER, (const char *)0);
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.1
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSurfaceAttrib(
- EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*attribute*/, EGLint /*value*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglSurfaceAttrib()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglBindTexImage(
- EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglBindTexImage()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglReleaseTexImage(
- EGLDisplay dpy, EGLSurface /*surface*/, EGLint /*buffer*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglReleaseTexImage()
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint /*interval*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- // TODO: eglSwapInterval()
- return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.2
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglBindAPI(EGLenum api)
-{
- if (api != EGL_OPENGL_ES_API)
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- return EGL_TRUE;
-}
-
-EGLenum eglQueryAPI(void)
-{
- return EGL_OPENGL_ES_API;
-}
-
-EGLBoolean eglWaitClient(void)
-{
- glFinish();
- return EGL_TRUE;
-}
-
-EGLBoolean eglReleaseThread(void)
-{
- // TODO: eglReleaseThread()
- return EGL_TRUE;
-}
-
-EGLSurface eglCreatePbufferFromClientBuffer(
- EGLDisplay dpy, EGLenum /*buftype*/, EGLClientBuffer /*buffer*/,
- EGLConfig /*config*/, const EGLint* /*attrib_list*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
- // TODO: eglCreatePbufferFromClientBuffer()
- return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 3
-// ----------------------------------------------------------------------------
-
-void (*eglGetProcAddress (const char *procname))()
-{
- extention_map_t const * const map = gExtentionMap;
- for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
- if (!strcmp(procname, map[i].name)) {
- return map[i].address;
- }
- }
- return NULL;
-}
-
-EGLBoolean eglLockSurfaceKHR(EGLDisplay /*dpy*/, EGLSurface /*surface*/,
- const EGLint* /*attrib_list*/)
-{
- EGLBoolean result = EGL_FALSE;
- return result;
-}
-
-EGLBoolean eglUnlockSurfaceKHR(EGLDisplay /*dpy*/, EGLSurface /*surface*/)
-{
- EGLBoolean result = EGL_FALSE;
- return result;
-}
-
-EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
- EGLClientBuffer buffer, const EGLint* /*attrib_list*/)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
- return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
- }
- if (ctx != EGL_NO_CONTEXT) {
- return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
- }
- if (target != EGL_NATIVE_BUFFER_ANDROID) {
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- }
-
- ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
-
- if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-
- if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-
- switch (native_buffer->format) {
- case HAL_PIXEL_FORMAT_RGBA_8888:
- case HAL_PIXEL_FORMAT_RGBX_8888:
- case HAL_PIXEL_FORMAT_RGB_888:
- case HAL_PIXEL_FORMAT_RGB_565:
- case HAL_PIXEL_FORMAT_BGRA_8888:
- break;
- default:
- return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
- }
-
- native_buffer->common.incRef(&native_buffer->common);
- return (EGLImageKHR)native_buffer;
-}
-
-EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
- }
-
- ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
-
- if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
- if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
- native_buffer->common.decRef(&native_buffer->common);
-
- return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// EGL_KHR_fence_sync
-// ----------------------------------------------------------------------------
-
-#define FENCE_SYNC_HANDLE ((EGLSyncKHR)0xFE4CE)
-
-EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type,
- const EGLint *attrib_list)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
- return setError(EGL_BAD_DISPLAY, EGL_NO_SYNC_KHR);
- }
-
- if (type != EGL_SYNC_FENCE_KHR ||
- (attrib_list != NULL && attrib_list[0] != EGL_NONE)) {
- return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SYNC_KHR);
- }
-
- if (eglGetCurrentContext() == EGL_NO_CONTEXT) {
- return setError(EGL_BAD_MATCH, EGL_NO_SYNC_KHR);
- }
-
- // AGL is synchronous; nothing to do here.
-
- return FENCE_SYNC_HANDLE;
-}
-
-EGLBoolean eglDestroySyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync)
-{
- if (sync != FENCE_SYNC_HANDLE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- return EGL_TRUE;
-}
-
-EGLint eglClientWaitSyncKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync, EGLint /*flags*/,
- EGLTimeKHR /*timeout*/)
-{
- if (sync != FENCE_SYNC_HANDLE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- return EGL_CONDITION_SATISFIED_KHR;
-}
-
-EGLBoolean eglGetSyncAttribKHR(EGLDisplay /*dpy*/, EGLSyncKHR sync,
- EGLint attribute, EGLint *value)
-{
- if (sync != FENCE_SYNC_HANDLE) {
- return setError(EGL_BAD_PARAMETER, EGL_FALSE);
- }
-
- switch (attribute) {
- case EGL_SYNC_TYPE_KHR:
- *value = EGL_SYNC_FENCE_KHR;
- return EGL_TRUE;
- case EGL_SYNC_STATUS_KHR:
- *value = EGL_SIGNALED_KHR;
- return EGL_TRUE;
- case EGL_SYNC_CONDITION_KHR:
- *value = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
- return EGL_TRUE;
- default:
- return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
- }
-}
-
-// ----------------------------------------------------------------------------
-// ANDROID extensions
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
- EGLint left, EGLint top, EGLint width, EGLint height)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- egl_surface_t* d = static_cast<egl_surface_t*>(draw);
- if (!d->isValid())
- return setError(EGL_BAD_SURFACE, EGL_FALSE);
- if (d->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
- // post the surface
- d->setSwapRectangle(left, top, width, height);
-
- return EGL_TRUE;
-}
diff --git a/opengl/libagl/fixed_asm.S b/opengl/libagl/fixed_asm.S
deleted file mode 100644
index 5e08856..0000000
--- a/opengl/libagl/fixed_asm.S
+++ /dev/null
@@ -1,67 +0,0 @@
-/* libs/opengles/fixed_asm.S
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
- .text
- .align 2
-
- .global gglFloatToFixed
- .type gglFloatToFixed, %function
- .global gglFloatToFixedFast
- .type gglFloatToFixedFast, %function
-
-
-/*
- * Converts a float to a s15.16 fixed-point number.
- * this doesn't handle floats out of the [-32768, +32768[ range
- * and doesn't performs round-to-nearest.
- * however, it's very fast :-)
- */
-
-gglFloatToFixedFast:
- movs r1, r0, lsl #1 /* remove bit sign */
- mov r2, #0x8E /* 127 + 15 */
- sub r1, r2, r1, lsr #24 /* compute shift */
- mov r2, r0, lsl #8 /* mantissa<<8 */
- orr r2, r2, #0x80000000 /* add the missing 1 */
- mov r0, r2, lsr r1 /* scale to 16.16 */
- rsbcs r0, r0, #0 /* negate if needed */
- bx lr
-
-/*
- * this version rounds-to-nearest and saturates numbers
- * outside the range (but not NaNs).
- */
-
-gglFloatToFixed:
- mov r1, r0, lsl #1 /* remove bit sign */
- mov r2, #0x8E /* 127 + 15 */
- subs r1, r2, r1, lsr #24 /* compute shift */
- bls 0f /* too big */
- mov r2, r0, lsl #8 /* mantissa<<8 */
- orr r2, r2, #0x80000000 /* add the missing 1 */
- mov r3, r0
- movs r0, r2, lsr r1 /* scale to 16.16 */
- addcs r0, r0, #1 /* round-to-nearest */
- tst r3, #0x80000000 /* negative? */
- rsbne r0, r0, #0 /* negate if needed */
- bx lr
-
-0: ands r0, r0, #0x80000000 /* keep only the sign bit */
- moveq r0, #0x7fffffff /* positive, maximum value */
- bx lr
-
diff --git a/opengl/libagl/fp.cpp b/opengl/libagl/fp.cpp
deleted file mode 100644
index a7a4f7b..0000000
--- a/opengl/libagl/fp.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/* libs/opengles/fp.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include "fp.h"
-
-// ----------------------------------------------------------------------------
-
-#if !(defined(__arm__) || (defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6))
-GGLfixed gglFloatToFixed(float v) {
- return GGLfixed(floorf(v * 65536.0f + 0.5f));
-}
-#endif
-
-// ----------------------------------------------------------------------------
-
-namespace android {
-
-namespace gl {
-
-GLfloat fixedToFloat(GLfixed x)
-{
-#if DEBUG_USE_FLOATS
- return x / 65536.0f;
-#else
- if (!x) return 0;
- const uint32_t s = x & 0x80000000;
- union {
- uint32_t i;
- float f;
- };
- i = s ? -x : x;
- const int c = gglClz(i) - 8;
- i = (c>=0) ? (i<<c) : (i>>-c);
- const uint32_t e = 134 - c;
- i &= ~0x800000;
- i |= e<<23;
- i |= s;
- return f;
-#endif
-}
-
-float sinef(float x)
-{
- const float A = 1.0f / (2.0f*M_PI);
- const float B = -16.0f;
- const float C = 8.0f;
-
- // scale angle for easy argument reduction
- x *= A;
-
- if (fabsf(x) >= 0.5f) {
- // Argument reduction
- x = x - ceilf(x + 0.5f) + 1.0f;
- }
-
- const float y = B*x*fabsf(x) + C*x;
- return 0.2215f * (y*fabsf(y) - y) + y;
-}
-
-float cosinef(float x)
-{
- return sinef(x + float(M_PI/2));
-}
-
-void sincosf(GLfloat angle, GLfloat* s, GLfloat* c) {
- *s = sinef(angle);
- *c = cosinef(angle);
-}
-
-}; // namespace fp_utils
-
-// ----------------------------------------------------------------------------
-}; // namespace android
diff --git a/opengl/libagl/fp.h b/opengl/libagl/fp.h
deleted file mode 100644
index 6d0c183..0000000
--- a/opengl/libagl/fp.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/* libs/opengles/fp.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_FP_H
-#define ANDROID_OPENGLES_FP_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-#include <math.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include <GLES/gl.h>
-
-#define DEBUG_USE_FLOATS 0
-
-// ----------------------------------------------------------------------------
-
-extern "C" GLfixed gglFloatToFixed(float f) __attribute__((const));
-
-// ----------------------------------------------------------------------------
-namespace android {
-
-namespace gl {
-
- GLfloat fixedToFloat(GLfixed) CONST;
-
- void sincosf(GLfloat angle, GLfloat* s, GLfloat* c);
- float sinef(GLfloat x) CONST;
- float cosinef(GLfloat x) CONST;
-
-inline bool cmpf(GLfloat a, GLfloat b) CONST;
-inline bool isZerof(GLfloat) CONST;
-inline bool isOnef(GLfloat) CONST;
-
-inline int isZeroOrNegativef(GLfloat) CONST;
-
-inline int exponent(GLfloat) CONST;
-inline int32_t mantissa(GLfloat) CONST;
-inline GLfloat clampToZerof(GLfloat) CONST;
-inline GLfloat reciprocalf(GLfloat) CONST;
-inline GLfloat rsqrtf(GLfloat) CONST;
-inline GLfloat sqrf(GLfloat) CONST;
-inline GLfloat addExpf(GLfloat v, int e) CONST;
-inline GLfloat mul2f(GLfloat v) CONST;
-inline GLfloat div2f(GLfloat v) CONST;
-inline GLfloat absf(GLfloat v) CONST;
-
-
-/*
- * float fastexpf(float) : a fast approximation of expf(x)
- * give somewhat accurate results for -88 <= x <= 88
- *
- * exp(x) = 2^(x/ln(2))
- * we use the properties of float encoding
- * to get a fast 2^ and linear interpolation
- *
- */
-
-inline float fastexpf(float y) __attribute__((const));
-
-inline float fastexpf(float y)
-{
- union {
- float r;
- int32_t i;
- } u;
-
- // 127*ln(2) = 88
- if (y < -88.0f) {
- u.r = 0.0f;
- } else if (y > 88.0f) {
- u.r = INFINITY;
- } else {
- const float kOneOverLogTwo = (1L<<23) / M_LN2;
- const int32_t kExponentBias = 127L<<23;
- const int32_t e = int32_t(y*kOneOverLogTwo);
- u.i = e + kExponentBias;
- }
-
- return u.r;
-}
-
-
-bool cmpf(GLfloat a, GLfloat b) {
-#if DEBUG_USE_FLOATS
- return a == b;
-#else
- union {
- float f;
- uint32_t i;
- } ua, ub;
- ua.f = a;
- ub.f = b;
- return ua.i == ub.i;
-#endif
-}
-
-bool isZerof(GLfloat v) {
-#if DEBUG_USE_FLOATS
- return v == 0;
-#else
- union {
- float f;
- int32_t i;
- };
- f = v;
- return (i<<1) == 0;
-#endif
-}
-
-bool isOnef(GLfloat v) {
- return cmpf(v, 1.0f);
-}
-
-int isZeroOrNegativef(GLfloat v) {
-#if DEBUG_USE_FLOATS
- return v <= 0;
-#else
- union {
- float f;
- int32_t i;
- };
- f = v;
- return isZerof(v) | (i>>31);
-#endif
-}
-
-int exponent(GLfloat v) {
- union {
- float f;
- uint32_t i;
- };
- f = v;
- return ((i << 1) >> 24) - 127;
-}
-
-int32_t mantissa(GLfloat v) {
- union {
- float f;
- uint32_t i;
- };
- f = v;
- if (!(i&0x7F800000)) return 0;
- const int s = i >> 31;
- i |= (1L<<23);
- i &= ~0xFF000000;
- return s ? -i : i;
-}
-
-GLfloat clampToZerof(GLfloat v) {
-#if DEBUG_USE_FLOATS
- return v<0 ? 0 : (v>1 ? 1 : v);
-#else
- union {
- float f;
- int32_t i;
- };
- f = v;
- i &= ~(i>>31);
- return f;
-#endif
-}
-
-GLfloat reciprocalf(GLfloat v) {
- // XXX: do better
- return 1.0f / v;
-}
-
-GLfloat rsqrtf(GLfloat v) {
- // XXX: do better
- return 1.0f / sqrtf(v);
-}
-
-GLfloat sqrf(GLfloat v) {
- // XXX: do better
- return v*v;
-}
-
-GLfloat addExpf(GLfloat v, int e) {
- union {
- float f;
- int32_t i;
- };
- f = v;
- if (i<<1) { // XXX: deal with over/underflow
- i += int32_t(e)<<23;
- }
- return f;
-}
-
-GLfloat mul2f(GLfloat v) {
-#if DEBUG_USE_FLOATS
- return v*2;
-#else
- return addExpf(v, 1);
-#endif
-}
-
-GLfloat div2f(GLfloat v) {
-#if DEBUG_USE_FLOATS
- return v*0.5f;
-#else
- return addExpf(v, -1);
-#endif
-}
-
-GLfloat absf(GLfloat v) {
-#if DEBUG_USE_FLOATS
- return v<0 ? -v : v;
-#else
- union {
- float f;
- int32_t i;
- };
- f = v;
- i &= ~0x80000000;
- return f;
-#endif
-}
-
-}; // namespace gl
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_FP_H
-
diff --git a/opengl/libagl/iterators.S b/opengl/libagl/iterators.S
deleted file mode 100644
index 8fe9039..0000000
--- a/opengl/libagl/iterators.S
+++ /dev/null
@@ -1,89 +0,0 @@
-/* libs/opengles/iterators.S
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-
- .text
- .align 2
- .arm
-
- .global iterators0032
- .type iterators0032, %function
-
-/*
- * iterators0032
- *
- * MUST BE CALLED FROM ARM CODE
- *
- * r0: const compute_iterators_t* (this)
- * r0 + 0: m_dx01
- * r0 + 4: m_dy10
- * r0 + 8: m_dx20
- * r0 +12: m_dy02
- * r0 +16: m_x0
- * r0 +20: m_y0
- * r0 +24: m_area
- * r0 +28: m_scale
- * r0 +29: m_area_scale;
- * r1: int32_t* (out)
- * r1 + 0: c
- * r1 + 4: dcdx
- * r1 + 8: dcdy
- * r2: c0
- * r3: c1
- * [sp]: c2
- */
-
-iterators0032:
- stmfd sp!, {r4, r5, r6, r7, r8, lr}
- ldr r4, [sp, #4*6]
-
- ldrb r12, [r0, #29]
- sub r3, r3, r2
- sub r4, r4, r2
- sub r12, r12, #16
- mov r3, r3, asr r12
- mov r4, r4, asr r12
-
- ldr r5, [r0, #0]
- ldr r12, [r0, #4]
- smull r8, lr, r4, r5
- ldr r5, [r0, #8]
- smull r6, r7, r4, r12
- ldr r12, [r0, #12]
- smlal r8, lr, r3, r5
- smlal r6, r7, r3, r12
-
- ldr r3, [r0, #16] // m_x0
- ldr r4, [r0, #20] // m_x1
-
- str r6, [r1, #4]
- str r8, [r1, #8]
-
- umull r6, r5, r3, r6
- umull r8, r0, r4, r8
- mla r7, r3, r7, r5
- mla lr, r4, lr, r0
- adds r6, r6, r8
- adc r7, r7, lr
-
- movs r6, r6, lsr #4
- adc r6, r6, r7, lsl #28
- rsb r6, r6, r2, lsl #16
- str r6, [r1, #0]
-
- ldmfd sp!, {r4, r5, r6, r7, r8, pc}
-
diff --git a/opengl/libagl/light.cpp b/opengl/libagl/light.cpp
deleted file mode 100644
index 216c725..0000000
--- a/opengl/libagl/light.cpp
+++ /dev/null
@@ -1,882 +0,0 @@
-/* libs/opengles/light.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include "context.h"
-#include "fp.h"
-#include "light.h"
-#include "state.h"
-#include "matrix.h"
-
-
-#if defined(__arm__) && defined(__thumb__)
-#warning "light.cpp should not be compiled in thumb on ARM."
-#endif
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static void invalidate_lighting(ogles_context_t* c);
-static void lightVertexValidate(ogles_context_t* c, vertex_t* v);
-static void lightVertexNop(ogles_context_t* c, vertex_t* v);
-static void lightVertex(ogles_context_t* c, vertex_t* v);
-static void lightVertexMaterial(ogles_context_t* c, vertex_t* v);
-
-static inline void vscale3(GLfixed* d, const GLfixed* m, GLfixed s);
-
-static __attribute__((noinline))
-void vnorm3(GLfixed* d, const GLfixed* a);
-
-static inline void vsa3(GLfixed* d,
- const GLfixed* m, GLfixed s, const GLfixed* a);
-static inline void vss3(GLfixed* d,
- const GLfixed* m, GLfixed s, const GLfixed* a);
-static inline void vmla3(GLfixed* d,
- const GLfixed* m0, const GLfixed* m1, const GLfixed* a);
-static inline void vmul3(GLfixed* d,
- const GLfixed* m0, const GLfixed* m1);
-
-static GLfixed fog_linear(ogles_context_t* c, GLfixed z);
-static GLfixed fog_exp(ogles_context_t* c, GLfixed z);
-static GLfixed fog_exp2(ogles_context_t* c, GLfixed z);
-
-
-// ----------------------------------------------------------------------------
-
-static void init_white(vec4_t& c) {
- c.r = c.g = c.b = c.a = 0x10000;
-}
-
-void ogles_init_light(ogles_context_t* c)
-{
- for (unsigned int i=0 ; i<OGLES_MAX_LIGHTS ; i++) {
- c->lighting.lights[i].ambient.a = 0x10000;
- c->lighting.lights[i].position.z = 0x10000;
- c->lighting.lights[i].spotDir.z = -0x10000;
- c->lighting.lights[i].spotCutoff = gglIntToFixed(180);
- c->lighting.lights[i].attenuation[0] = 0x10000;
- }
- init_white(c->lighting.lights[0].diffuse);
- init_white(c->lighting.lights[0].specular);
-
- c->lighting.front.ambient.r =
- c->lighting.front.ambient.g =
- c->lighting.front.ambient.b = gglFloatToFixed(0.2f);
- c->lighting.front.ambient.a = 0x10000;
- c->lighting.front.diffuse.r =
- c->lighting.front.diffuse.g =
- c->lighting.front.diffuse.b = gglFloatToFixed(0.8f);
- c->lighting.front.diffuse.a = 0x10000;
- c->lighting.front.specular.a = 0x10000;
- c->lighting.front.emission.a = 0x10000;
-
- c->lighting.lightModel.ambient.r =
- c->lighting.lightModel.ambient.g =
- c->lighting.lightModel.ambient.b = gglFloatToFixed(0.2f);
- c->lighting.lightModel.ambient.a = 0x10000;
-
- c->lighting.colorMaterial.face = GL_FRONT_AND_BACK;
- c->lighting.colorMaterial.mode = GL_AMBIENT_AND_DIFFUSE;
-
- c->fog.mode = GL_EXP;
- c->fog.fog = fog_exp;
- c->fog.density = 0x10000;
- c->fog.end = 0x10000;
- c->fog.invEndMinusStart = 0x10000;
-
- invalidate_lighting(c);
-
- c->rasterizer.procs.shadeModel(c, GL_SMOOTH);
- c->lighting.shadeModel = GL_SMOOTH;
-}
-
-void ogles_uninit_light(ogles_context_t* /*c*/)
-{
-}
-
-static inline int32_t clampF(GLfixed f) CONST;
-int32_t clampF(GLfixed f) {
- f = (f & ~(f>>31));
- if (f >= 0x10000)
- f = 0x10000;
- return f;
-}
-
-static GLfixed fog_linear(ogles_context_t* c, GLfixed z) {
- return clampF(gglMulx((c->fog.end - ((z<0)?-z:z)), c->fog.invEndMinusStart));
-}
-
-static GLfixed fog_exp(ogles_context_t* c, GLfixed z) {
- const float e = fixedToFloat(gglMulx(c->fog.density, ((z<0)?-z:z)));
- return clampF(gglFloatToFixed(fastexpf(-e)));
-}
-
-static GLfixed fog_exp2(ogles_context_t* c, GLfixed z) {
- const float e = fixedToFloat(gglMulx(c->fog.density, z));
- return clampF(gglFloatToFixed(fastexpf(-e*e)));
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark math helpers
-#endif
-
-static inline
-void vscale3(GLfixed* d, const GLfixed* m, GLfixed s) {
- d[0] = gglMulx(m[0], s);
- d[1] = gglMulx(m[1], s);
- d[2] = gglMulx(m[2], s);
-}
-
-static inline
-void vsa3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
- d[0] = gglMulAddx(m[0], s, a[0]);
- d[1] = gglMulAddx(m[1], s, a[1]);
- d[2] = gglMulAddx(m[2], s, a[2]);
-}
-
-static inline
-void vss3(GLfixed* d, const GLfixed* m, GLfixed s, const GLfixed* a) {
- d[0] = gglMulSubx(m[0], s, a[0]);
- d[1] = gglMulSubx(m[1], s, a[1]);
- d[2] = gglMulSubx(m[2], s, a[2]);
-}
-
-static inline
-void vmla3(GLfixed* d,
- const GLfixed* m0, const GLfixed* m1, const GLfixed* a)
-{
- d[0] = gglMulAddx(m0[0], m1[0], a[0]);
- d[1] = gglMulAddx(m0[1], m1[1], a[1]);
- d[2] = gglMulAddx(m0[2], m1[2], a[2]);
-}
-
-static inline
-void vmul3(GLfixed* d, const GLfixed* m0, const GLfixed* m1) {
- d[0] = gglMulx(m0[0], m1[0]);
- d[1] = gglMulx(m0[1], m1[1]);
- d[2] = gglMulx(m0[2], m1[2]);
-}
-
-void vnorm3(GLfixed* d, const GLfixed* a)
-{
- // we must take care of overflows when normalizing a vector
- GLfixed n;
- int32_t x = a[0]; x = x>=0 ? x : -x;
- int32_t y = a[1]; y = y>=0 ? y : -y;
- int32_t z = a[2]; z = z>=0 ? z : -z;
- if (ggl_likely(x<=0x6800 && y<=0x6800 && z<= 0x6800)) {
- // in this case this will all fit on 32 bits
- n = x*x + y*y + z*z;
- n = gglSqrtRecipx(n);
- n <<= 8;
- } else {
- // here norm^2 is at least 0x7EC00000 (>>32 == 0.495117)
- n = vsquare3(x, y, z);
- n = gglSqrtRecipx(n);
- }
- vscale3(d, a, n);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark lighting equations
-#endif
-
-static inline void light_picker(ogles_context_t* c)
-{
- if (ggl_likely(!c->lighting.enable)) {
- c->lighting.lightVertex = lightVertexNop;
- return;
- }
- if (c->lighting.colorMaterial.enable) {
- c->lighting.lightVertex = lightVertexMaterial;
- } else {
- c->lighting.lightVertex = lightVertex;
- }
-}
-
-static inline void validate_light_mvi(ogles_context_t* c)
-{
- uint32_t en = c->lighting.enabledLights;
- // Vector from object to viewer, in eye coordinates
- while (en) {
- const int i = 31 - gglClz(en);
- en &= ~(1<<i);
- light_t& l = c->lighting.lights[i];
-#if OBJECT_SPACE_LIGHTING
- c->transforms.mvui.point4(&c->transforms.mvui,
- &l.objPosition, &l.position);
-#else
- l.objPosition = l.position;
-#endif
- vnorm3(l.normalizedObjPosition.v, l.objPosition.v);
- }
- const vec4_t eyeViewer = {{{ 0, 0, 0x10000, 0 }}};
-#if OBJECT_SPACE_LIGHTING
- c->transforms.mvui.point3(&c->transforms.mvui,
- &c->lighting.objViewer, &eyeViewer);
- vnorm3(c->lighting.objViewer.v, c->lighting.objViewer.v);
-#else
- c->lighting.objViewer = eyeViewer;
-#endif
-}
-
-static inline void validate_light(ogles_context_t* c)
-{
- // if colorMaterial is enabled, we get the color from the vertex
- if (!c->lighting.colorMaterial.enable) {
- material_t& material = c->lighting.front;
- uint32_t en = c->lighting.enabledLights;
- while (en) {
- const int i = 31 - gglClz(en);
- en &= ~(1<<i);
- light_t& l = c->lighting.lights[i];
- vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
- vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
- vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
-
- // this is just a flag to tell if we have a specular component
- l.implicitSpecular.v[3] =
- l.implicitSpecular.r |
- l.implicitSpecular.g |
- l.implicitSpecular.b;
-
- l.rConstAttenuation = (l.attenuation[1] | l.attenuation[2])==0;
- if (l.rConstAttenuation)
- l.rConstAttenuation = gglRecipFast(l.attenuation[0]);
- }
- // emission and ambient for the whole scene
- vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
- c->lighting.lightModel.ambient.v,
- material.ambient.v,
- material.emission.v);
- c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
- }
- validate_light_mvi(c);
-}
-
-void invalidate_lighting(ogles_context_t* c)
-{
- // TODO: pick lightVertexValidate or lightVertexValidateMVI
- // instead of systematically the heavier lightVertexValidate()
- c->lighting.lightVertex = lightVertexValidate;
-}
-
-void ogles_invalidate_lighting_mvui(ogles_context_t* c)
-{
- invalidate_lighting(c);
-}
-
-void lightVertexNop(ogles_context_t*, vertex_t* /*v*/)
-{
- // we should never end-up here
-}
-
-void lightVertexValidateMVI(ogles_context_t* c, vertex_t* v)
-{
- validate_light_mvi(c);
- light_picker(c);
- c->lighting.lightVertex(c, v);
-}
-
-void lightVertexValidate(ogles_context_t* c, vertex_t* v)
-{
- validate_light(c);
- light_picker(c);
- c->lighting.lightVertex(c, v);
-}
-
-void lightVertexMaterial(ogles_context_t* c, vertex_t* v)
-{
- // fetch the material color
- const GLvoid* cp = c->arrays.color.element(
- v->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v->color.v, cp);
-
- // acquire the color-material from the vertex
- material_t& material = c->lighting.front;
- material.ambient =
- material.diffuse = v->color;
- // implicit arguments need to be computed per/vertex
- uint32_t en = c->lighting.enabledLights;
- while (en) {
- const int i = 31 - gglClz(en);
- en &= ~(1<<i);
- light_t& l = c->lighting.lights[i];
- vmul3(l.implicitAmbient.v, material.ambient.v, l.ambient.v);
- vmul3(l.implicitDiffuse.v, material.diffuse.v, l.diffuse.v);
- vmul3(l.implicitSpecular.v, material.specular.v, l.specular.v);
- // this is just a flag to tell if we have a specular component
- l.implicitSpecular.v[3] =
- l.implicitSpecular.r |
- l.implicitSpecular.g |
- l.implicitSpecular.b;
- }
- // emission and ambient for the whole scene
- vmla3( c->lighting.implicitSceneEmissionAndAmbient.v,
- c->lighting.lightModel.ambient.v,
- material.ambient.v,
- material.emission.v);
- c->lighting.implicitSceneEmissionAndAmbient.a = material.diffuse.a;
-
- // now we can light our vertex as usual
- lightVertex(c, v);
-}
-
-void lightVertex(ogles_context_t* c, vertex_t* v)
-{
- // emission and ambient for the whole scene
- vec4_t r = c->lighting.implicitSceneEmissionAndAmbient;
- const vec4_t objViewer = c->lighting.objViewer;
-
- uint32_t en = c->lighting.enabledLights;
- if (ggl_likely(en)) {
- // since we do the lighting in object-space, we don't need to
- // transform each normal. However, we might still have to normalize
- // it if GL_NORMALIZE is enabled.
- vec4_t n;
- c->arrays.normal.fetch(c, n.v,
- c->arrays.normal.element(v->index & vertex_cache_t::INDEX_MASK));
-
-#if !OBJECT_SPACE_LIGHTING
- c->transforms.mvui.point3(&c->transforms.mvui, &n, &n);
-#endif
-
- // TODO: right now we handle GL_RESCALE_NORMALS as if it were
- // GL_NORMALIZE. We could optimize this by scaling mvui
- // appropriately instead.
- if (c->transforms.rescaleNormals)
- vnorm3(n.v, n.v);
-
- const material_t& material = c->lighting.front;
- const int twoSide = c->lighting.lightModel.twoSide;
-
- while (en) {
- const int i = 31 - gglClz(en);
- en &= ~(1<<i);
- const light_t& l = c->lighting.lights[i];
-
- vec4_t d, t;
- GLfixed s;
- GLfixed sqDist = 0x10000;
-
- // compute vertex-to-light vector
- if (ggl_unlikely(l.position.w)) {
- // lightPos/1.0 - vertex/vertex.w == lightPos*vertex.w - vertex
-#if !OBJECT_SPACE_LIGHTING
- vec4_t o;
- const transform_t& mv = c->transforms.modelview.transform;
- mv.point4(&mv, &o, &v->obj);
- vss3(d.v, l.objPosition.v, o.w, o.v);
-#else
- vss3(d.v, l.objPosition.v, v->obj.w, v->obj.v);
-#endif
- sqDist = dot3(d.v, d.v);
- vscale3(d.v, d.v, gglSqrtRecipx(sqDist));
- } else {
- // TODO: avoid copy here
- d = l.normalizedObjPosition;
- }
-
- // ambient & diffuse
- s = dot3(n.v, d.v);
- s = (s<0) ? (twoSide?(-s):0) : s;
- vsa3(t.v, l.implicitDiffuse.v, s, l.implicitAmbient.v);
-
- // specular
- if (ggl_unlikely(s && l.implicitSpecular.v[3])) {
- vec4_t h;
- h.x = d.x + objViewer.x;
- h.y = d.y + objViewer.y;
- h.z = d.z + objViewer.z;
- vnorm3(h.v, h.v);
- s = dot3(n.v, h.v);
- s = (s<0) ? (twoSide?(-s):0) : s;
- if (s > 0) {
- s = gglPowx(s, material.shininess);
- vsa3(t.v, l.implicitSpecular.v, s, t.v);
- }
- }
-
- // spot
- if (ggl_unlikely(l.spotCutoff != gglIntToFixed(180))) {
- GLfixed spotAtt = -dot3(l.normalizedSpotDir.v, d.v);
- if (spotAtt >= l.spotCutoffCosine) {
- vscale3(t.v, t.v, gglPowx(spotAtt, l.spotExp));
- }
- }
-
- // attenuation
- if (ggl_unlikely(l.position.w)) {
- if (l.rConstAttenuation) {
- s = l.rConstAttenuation;
- } else {
- s = gglMulAddx(sqDist, l.attenuation[2], l.attenuation[0]);
- if (l.attenuation[1])
- s = gglMulAddx(gglSqrtx(sqDist), l.attenuation[1], s);
- s = gglRecipFast(s);
- }
- vscale3(t.v, t.v, s);
- }
-
- r.r += t.r;
- r.g += t.g;
- r.b += t.b;
- }
- }
- v->color.r = gglClampx(r.r);
- v->color.g = gglClampx(r.g);
- v->color.b = gglClampx(r.b);
- v->color.a = gglClampx(r.a);
- v->flags |= vertex_t::LIT;
-}
-
-static void lightModelx(GLenum pname, GLfixed param, ogles_context_t* c)
-{
- if (ggl_unlikely(pname != GL_LIGHT_MODEL_TWO_SIDE)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->lighting.lightModel.twoSide = param ? GL_TRUE : GL_FALSE;
- invalidate_lighting(c);
-}
-
-static void lightx(GLenum i, GLenum pname, GLfixed param, ogles_context_t* c)
-{
- if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- light_t& light = c->lighting.lights[i-GL_LIGHT0];
- switch (pname) {
- case GL_SPOT_EXPONENT:
- if (GGLfixed(param) >= gglIntToFixed(128)) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- light.spotExp = param;
- break;
- case GL_SPOT_CUTOFF:
- if (param!=gglIntToFixed(180) && GGLfixed(param)>=gglIntToFixed(90)) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- light.spotCutoff = param;
- light.spotCutoffCosine =
- gglFloatToFixed(cosinef((M_PI/(180.0f*65536.0f))*param));
- break;
- case GL_CONSTANT_ATTENUATION:
- if (param < 0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- light.attenuation[0] = param;
- break;
- case GL_LINEAR_ATTENUATION:
- if (param < 0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- light.attenuation[1] = param;
- break;
- case GL_QUADRATIC_ATTENUATION:
- if (param < 0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- light.attenuation[2] = param;
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- invalidate_lighting(c);
-}
-
-static void lightxv(GLenum i, GLenum pname, const GLfixed *params, ogles_context_t* c)
-{
- if (ggl_unlikely(uint32_t(i-GL_LIGHT0) >= OGLES_MAX_LIGHTS)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- GLfixed* what;
- light_t& light = c->lighting.lights[i-GL_LIGHT0];
- switch (pname) {
- case GL_AMBIENT:
- what = light.ambient.v;
- break;
- case GL_DIFFUSE:
- what = light.diffuse.v;
- break;
- case GL_SPECULAR:
- what = light.specular.v;
- break;
- case GL_POSITION: {
- ogles_validate_transform(c, transform_state_t::MODELVIEW);
- transform_t& mv = c->transforms.modelview.transform;
- mv.point4(&mv, &light.position, reinterpret_cast<vec4_t const*>(params));
- invalidate_lighting(c);
- return;
- }
- case GL_SPOT_DIRECTION: {
-#if OBJECT_SPACE_LIGHTING
- ogles_validate_transform(c, transform_state_t::MVUI);
- transform_t& mvui = c->transforms.mvui;
- mvui.point3(&mvui, &light.spotDir, reinterpret_cast<vec4_t const*>(params));
-#else
- light.spotDir = *reinterpret_cast<vec4_t const*>(params);
-#endif
- vnorm3(light.normalizedSpotDir.v, light.spotDir.v);
- invalidate_lighting(c);
- return;
- }
- default:
- lightx(i, pname, params[0], c);
- return;
- }
- what[0] = params[0];
- what[1] = params[1];
- what[2] = params[2];
- what[3] = params[3];
- invalidate_lighting(c);
-}
-
-static void materialx(GLenum face, GLenum pname, GLfixed param, ogles_context_t* c)
-{
- if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (ggl_unlikely(pname != GL_SHININESS)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->lighting.front.shininess = param;
- invalidate_lighting(c);
-}
-
-static void fogx(GLenum pname, GLfixed param, ogles_context_t* c)
-{
- switch (pname) {
- case GL_FOG_DENSITY:
- if (param >= 0) {
- c->fog.density = param;
- break;
- }
- ogles_error(c, GL_INVALID_VALUE);
- break;
- case GL_FOG_START:
- c->fog.start = param;
- c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
- break;
- case GL_FOG_END:
- c->fog.end = param;
- c->fog.invEndMinusStart = gglRecip(c->fog.end - c->fog.start);
- break;
- case GL_FOG_MODE:
- switch (param) {
- case GL_LINEAR:
- c->fog.mode = param;
- c->fog.fog = fog_linear;
- break;
- case GL_EXP:
- c->fog.mode = param;
- c->fog.fog = fog_exp;
- break;
- case GL_EXP2:
- c->fog.mode = param;
- c->fog.fog = fog_exp2;
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- break;
- }
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- break;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-#if 0
-#pragma mark -
-#pragma mark lighting APIs
-#endif
-
-void glShadeModel(GLenum mode)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (ggl_unlikely(mode != GL_SMOOTH && mode != GL_FLAT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->lighting.shadeModel = mode;
-}
-
-void glLightModelf(GLenum pname, GLfloat param)
-{
- ogles_context_t* c = ogles_context_t::get();
- lightModelx(pname, gglFloatToFixed(param), c);
-}
-
-void glLightModelx(GLenum pname, GLfixed param)
-{
- ogles_context_t* c = ogles_context_t::get();
- lightModelx(pname, param, c);
-}
-
-void glLightModelfv(GLenum pname, const GLfloat *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
- lightModelx(pname, gglFloatToFixed(params[0]), c);
- return;
- }
-
- if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- c->lighting.lightModel.ambient.r = gglFloatToFixed(params[0]);
- c->lighting.lightModel.ambient.g = gglFloatToFixed(params[1]);
- c->lighting.lightModel.ambient.b = gglFloatToFixed(params[2]);
- c->lighting.lightModel.ambient.a = gglFloatToFixed(params[3]);
- invalidate_lighting(c);
-}
-
-void glLightModelxv(GLenum pname, const GLfixed *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (pname == GL_LIGHT_MODEL_TWO_SIDE) {
- lightModelx(pname, params[0], c);
- return;
- }
-
- if (ggl_unlikely(pname != GL_LIGHT_MODEL_AMBIENT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- c->lighting.lightModel.ambient.r = params[0];
- c->lighting.lightModel.ambient.g = params[1];
- c->lighting.lightModel.ambient.b = params[2];
- c->lighting.lightModel.ambient.a = params[3];
- invalidate_lighting(c);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void glLightf(GLenum i, GLenum pname, GLfloat param)
-{
- ogles_context_t* c = ogles_context_t::get();
- lightx(i, pname, gglFloatToFixed(param), c);
-}
-
-void glLightx(GLenum i, GLenum pname, GLfixed param)
-{
- ogles_context_t* c = ogles_context_t::get();
- lightx(i, pname, param, c);
-}
-
-void glLightfv(GLenum i, GLenum pname, const GLfloat *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- switch (pname) {
- case GL_SPOT_EXPONENT:
- case GL_SPOT_CUTOFF:
- case GL_CONSTANT_ATTENUATION:
- case GL_LINEAR_ATTENUATION:
- case GL_QUADRATIC_ATTENUATION:
- lightx(i, pname, gglFloatToFixed(params[0]), c);
- return;
- }
-
- GLfixed paramsx[4];
- paramsx[0] = gglFloatToFixed(params[0]);
- paramsx[1] = gglFloatToFixed(params[1]);
- paramsx[2] = gglFloatToFixed(params[2]);
- if (pname != GL_SPOT_DIRECTION)
- paramsx[3] = gglFloatToFixed(params[3]);
-
- lightxv(i, pname, paramsx, c);
-}
-
-void glLightxv(GLenum i, GLenum pname, const GLfixed *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- lightxv(i, pname, params, c);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void glMaterialf(GLenum face, GLenum pname, GLfloat param)
-{
- ogles_context_t* c = ogles_context_t::get();
- materialx(face, pname, gglFloatToFixed(param), c);
-}
-
-void glMaterialx(GLenum face, GLenum pname, GLfixed param)
-{
- ogles_context_t* c = ogles_context_t::get();
- materialx(face, pname, param, c);
-}
-
-void glMaterialfv(
- GLenum face, GLenum pname, const GLfloat *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- GLfixed* what=0;
- GLfixed* other=0;
- switch (pname) {
- case GL_AMBIENT: what = c->lighting.front.ambient.v; break;
- case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break;
- case GL_SPECULAR: what = c->lighting.front.specular.v; break;
- case GL_EMISSION: what = c->lighting.front.emission.v; break;
- case GL_AMBIENT_AND_DIFFUSE:
- what = c->lighting.front.ambient.v;
- other = c->lighting.front.diffuse.v;
- break;
- case GL_SHININESS:
- c->lighting.front.shininess = gglFloatToFixed(params[0]);
- invalidate_lighting(c);
- return;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- what[0] = gglFloatToFixed(params[0]);
- what[1] = gglFloatToFixed(params[1]);
- what[2] = gglFloatToFixed(params[2]);
- what[3] = gglFloatToFixed(params[3]);
- if (other) {
- other[0] = what[0];
- other[1] = what[1];
- other[2] = what[2];
- other[3] = what[3];
- }
- invalidate_lighting(c);
-}
-
-void glMaterialxv(
- GLenum face, GLenum pname, const GLfixed *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (ggl_unlikely(face != GL_FRONT_AND_BACK)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- GLfixed* what=0;
- GLfixed* other=0;
- switch (pname) {
- case GL_AMBIENT: what = c->lighting.front.ambient.v; break;
- case GL_DIFFUSE: what = c->lighting.front.diffuse.v; break;
- case GL_SPECULAR: what = c->lighting.front.specular.v; break;
- case GL_EMISSION: what = c->lighting.front.emission.v; break;
- case GL_AMBIENT_AND_DIFFUSE:
- what = c->lighting.front.ambient.v;
- other = c->lighting.front.diffuse.v;
- break;
- case GL_SHININESS:
- c->lighting.front.shininess = gglFloatToFixed(params[0]);
- invalidate_lighting(c);
- return;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- what[0] = params[0];
- what[1] = params[1];
- what[2] = params[2];
- what[3] = params[3];
- if (other) {
- other[0] = what[0];
- other[1] = what[1];
- other[2] = what[2];
- other[3] = what[3];
- }
- invalidate_lighting(c);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark fog
-#endif
-
-void glFogf(GLenum pname, GLfloat param) {
- ogles_context_t* c = ogles_context_t::get();
- GLfixed paramx = (GLfixed)param;
- if (pname != GL_FOG_MODE)
- paramx = gglFloatToFixed(param);
- fogx(pname, paramx, c);
-}
-
-void glFogx(GLenum pname, GLfixed param) {
- ogles_context_t* c = ogles_context_t::get();
- fogx(pname, param, c);
-}
-
-void glFogfv(GLenum pname, const GLfloat *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (pname != GL_FOG_COLOR) {
- GLfixed paramx = (GLfixed)params[0];
- if (pname != GL_FOG_MODE)
- paramx = gglFloatToFixed(params[0]);
- fogx(pname, paramx, c);
- return;
- }
- GLfixed paramsx[4];
- paramsx[0] = gglFloatToFixed(params[0]);
- paramsx[1] = gglFloatToFixed(params[1]);
- paramsx[2] = gglFloatToFixed(params[2]);
- paramsx[3] = gglFloatToFixed(params[3]);
- c->rasterizer.procs.fogColor3xv(c, paramsx);
-}
-
-void glFogxv(GLenum pname, const GLfixed *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (pname != GL_FOG_COLOR) {
- fogx(pname, params[0], c);
- return;
- }
- c->rasterizer.procs.fogColor3xv(c, params);
-}
diff --git a/opengl/libagl/light.h b/opengl/libagl/light.h
deleted file mode 100644
index 39e3309..0000000
--- a/opengl/libagl/light.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/* libs/opengles/light.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_LIGHT_H
-#define ANDROID_OPENGLES_LIGHT_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-
-// Set to 1 for object-space lighting evaluation.
-// There are still some bugs with object-space lighting,
-// especially visible in the San Angeles demo.
-#define OBJECT_SPACE_LIGHTING 0
-
-
-namespace android {
-
-namespace gl {
-struct ogles_context_t;
-};
-
-void ogles_init_light(ogles_context_t* c);
-void ogles_uninit_light(ogles_context_t* c);
-void ogles_invalidate_lighting_mvui(ogles_context_t* c);
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_LIGHT_H
-
diff --git a/opengl/libagl/matrix.cpp b/opengl/libagl/matrix.cpp
deleted file mode 100644
index edd474d..0000000
--- a/opengl/libagl/matrix.cpp
+++ /dev/null
@@ -1,1123 +0,0 @@
-/* libs/opengles/matrix.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdlib.h>
-#include <stdio.h>
-
-#include "context.h"
-#include "fp.h"
-#include "state.h"
-#include "matrix.h"
-#include "vertex.h"
-#include "light.h"
-
-#if defined(__arm__) && defined(__thumb__)
-#warning "matrix.cpp should not be compiled in thumb on ARM."
-#endif
-
-#define I(_i, _j) ((_j)+ 4*(_i))
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static const GLfloat gIdentityf[16] = { 1,0,0,0,
- 0,1,0,0,
- 0,0,1,0,
- 0,0,0,1 };
-
-static const matrixx_t gIdentityx = {
- { 0x10000,0,0,0,
- 0,0x10000,0,0,
- 0,0,0x10000,0,
- 0,0,0,0x10000
- }
- };
-
-static void point2__nop(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point3__nop(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point4__nop(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point2__generic(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point3__generic(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point4__generic(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point3__mvui(transform_t const*, vec4_t* c, vec4_t const* o);
-static void point4__mvui(transform_t const*, vec4_t* c, vec4_t const* o);
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void ogles_init_matrix(ogles_context_t* c)
-{
- c->transforms.modelview.init(OGLES_MODELVIEW_STACK_DEPTH);
- c->transforms.projection.init(OGLES_PROJECTION_STACK_DEPTH);
- for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
- c->transforms.texture[i].init(OGLES_TEXTURE_STACK_DEPTH);
-
- c->transforms.current = &c->transforms.modelview;
- c->transforms.matrixMode = GL_MODELVIEW;
- c->transforms.dirty = transform_state_t::VIEWPORT |
- transform_state_t::MVUI |
- transform_state_t::MVIT |
- transform_state_t::MVP;
- c->transforms.mvp.loadIdentity();
- c->transforms.mvp4.loadIdentity();
- c->transforms.mvit4.loadIdentity();
- c->transforms.mvui.loadIdentity();
- c->transforms.vpt.loadIdentity();
- c->transforms.vpt.zNear = 0.0f;
- c->transforms.vpt.zFar = 1.0f;
-}
-
-void ogles_uninit_matrix(ogles_context_t* c)
-{
- c->transforms.modelview.uninit();
- c->transforms.projection.uninit();
- for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
- c->transforms.texture[i].uninit();
-}
-
-static void validate_perspective(ogles_context_t* c, vertex_t* v)
-{
- const uint32_t enables = c->rasterizer.state.enables;
- c->arrays.perspective = (c->clipPlanes.enable) ?
- ogles_vertex_clipAllPerspective3D : ogles_vertex_perspective3D;
- if (enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)) {
- c->arrays.perspective = ogles_vertex_perspective3DZ;
- if (c->clipPlanes.enable || (enables&GGL_ENABLE_FOG))
- c->arrays.perspective = ogles_vertex_clipAllPerspective3DZ;
- }
- if ((c->arrays.vertex.size != 4) &&
- (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)) {
- c->arrays.perspective = ogles_vertex_perspective2D;
- }
- c->arrays.perspective(c, v);
-}
-
-void ogles_invalidate_perspective(ogles_context_t* c)
-{
- c->arrays.perspective = validate_perspective;
-}
-
-void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want)
-{
- int dirty = c->transforms.dirty & want;
-
- // Validate the modelview
- if (dirty & transform_state_t::MODELVIEW) {
- c->transforms.modelview.validate();
- }
-
- // Validate the projection stack (in fact, it's never needed)
- if (dirty & transform_state_t::PROJECTION) {
- c->transforms.projection.validate();
- }
-
- // Validate the viewport transformation
- if (dirty & transform_state_t::VIEWPORT) {
- vp_transform_t& vpt = c->transforms.vpt;
- vpt.transform.matrix.load(vpt.matrix);
- vpt.transform.picker();
- }
-
- // We need to update the mvp (used to transform each vertex)
- if (dirty & transform_state_t::MVP) {
- c->transforms.update_mvp();
- // invalidate perspective (divide by W) and view volume clipping
- ogles_invalidate_perspective(c);
- }
-
- // Validate the mvui (for normal transformation)
- if (dirty & transform_state_t::MVUI) {
- c->transforms.update_mvui();
- ogles_invalidate_lighting_mvui(c);
- }
-
- // Validate the texture stack
- if (dirty & transform_state_t::TEXTURE) {
- for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++)
- c->transforms.texture[i].validate();
- }
-
- // Validate the mvit4 (user-clip planes)
- if (dirty & transform_state_t::MVIT) {
- c->transforms.update_mvit();
- }
-
- c->transforms.dirty &= ~want;
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark transform_t
-#endif
-
-void transform_t::loadIdentity() {
- matrix = gIdentityx;
- flags = 0;
- ops = OP_IDENTITY;
- point2 = point2__nop;
- point3 = point3__nop;
- point4 = point4__nop;
-}
-
-
-static inline
-int notZero(GLfixed v) {
- return abs(v) & ~0x3;
-}
-
-static inline
-int notOne(GLfixed v) {
- return notZero(v - 0x10000);
-}
-
-void transform_t::picker()
-{
- const GLfixed* const m = matrix.m;
-
- // XXX: picker needs to be smarter
- flags = 0;
- ops = OP_ALL;
- point2 = point2__generic;
- point3 = point3__generic;
- point4 = point4__generic;
-
- // find out if this is a 2D projection
- if (!(notZero(m[3]) | notZero(m[7]) | notZero(m[11]) | notOne(m[15]))) {
- flags |= FLAGS_2D_PROJECTION;
- }
-}
-
-void mvui_transform_t::picker()
-{
- flags = 0;
- ops = OP_ALL;
- point3 = point3__mvui;
- point4 = point4__mvui;
-}
-
-void transform_t::dump(const char* what)
-{
- GLfixed const * const m = matrix.m;
- ALOGD("%s:", what);
- for (int i=0 ; i<4 ; i++)
- ALOGD("[%08x %08x %08x %08x] [%f %f %f %f]\n",
- m[I(0,i)], m[I(1,i)], m[I(2,i)], m[I(3,i)],
- fixedToFloat(m[I(0,i)]),
- fixedToFloat(m[I(1,i)]),
- fixedToFloat(m[I(2,i)]),
- fixedToFloat(m[I(3,i)]));
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark matrixx_t
-#endif
-
-void matrixx_t::load(const matrixf_t& rhs) {
- GLfixed* xp = m;
- GLfloat const* fp = rhs.elements();
- unsigned int i = 16;
- do {
- const GLfloat f = *fp++;
- *xp++ = isZerof(f) ? 0 : gglFloatToFixed(f);
- } while (--i);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark matrixf_t
-#endif
-
-void matrixf_t::multiply(matrixf_t& r, const matrixf_t& lhs, const matrixf_t& rhs)
-{
- GLfloat const* const m = lhs.m;
- for (int i=0 ; i<4 ; i++) {
- const float rhs_i0 = rhs.m[ I(i,0) ];
- float ri0 = m[ I(0,0) ] * rhs_i0;
- float ri1 = m[ I(0,1) ] * rhs_i0;
- float ri2 = m[ I(0,2) ] * rhs_i0;
- float ri3 = m[ I(0,3) ] * rhs_i0;
- for (int j=1 ; j<4 ; j++) {
- const float rhs_ij = rhs.m[ I(i,j) ];
- ri0 += m[ I(j,0) ] * rhs_ij;
- ri1 += m[ I(j,1) ] * rhs_ij;
- ri2 += m[ I(j,2) ] * rhs_ij;
- ri3 += m[ I(j,3) ] * rhs_ij;
- }
- r.m[ I(i,0) ] = ri0;
- r.m[ I(i,1) ] = ri1;
- r.m[ I(i,2) ] = ri2;
- r.m[ I(i,3) ] = ri3;
- }
-}
-
-void matrixf_t::dump(const char* what) {
- ALOGD("%s", what);
- ALOGD("[ %9f %9f %9f %9f ]", m[I(0,0)], m[I(1,0)], m[I(2,0)], m[I(3,0)]);
- ALOGD("[ %9f %9f %9f %9f ]", m[I(0,1)], m[I(1,1)], m[I(2,1)], m[I(3,1)]);
- ALOGD("[ %9f %9f %9f %9f ]", m[I(0,2)], m[I(1,2)], m[I(2,2)], m[I(3,2)]);
- ALOGD("[ %9f %9f %9f %9f ]", m[I(0,3)], m[I(1,3)], m[I(2,3)], m[I(3,3)]);
-}
-
-void matrixf_t::loadIdentity() {
- memcpy(m, gIdentityf, sizeof(m));
-}
-
-void matrixf_t::set(const GLfixed* rhs) {
- load(rhs);
-}
-
-void matrixf_t::set(const GLfloat* rhs) {
- load(rhs);
-}
-
-void matrixf_t::load(const GLfixed* rhs) {
- GLfloat* fp = m;
- unsigned int i = 16;
- do {
- *fp++ = fixedToFloat(*rhs++);
- } while (--i);
-}
-
-void matrixf_t::load(const GLfloat* rhs) {
- memcpy(m, rhs, sizeof(m));
-}
-
-void matrixf_t::load(const matrixf_t& rhs) {
- operator = (rhs);
-}
-
-void matrixf_t::multiply(const matrixf_t& rhs) {
- matrixf_t r;
- multiply(r, *this, rhs);
- operator = (r);
-}
-
-void matrixf_t::translate(GLfloat x, GLfloat y, GLfloat z) {
- for (int i=0 ; i<4 ; i++) {
- m[12+i] += m[i]*x + m[4+i]*y + m[8+i]*z;
- }
-}
-
-void matrixf_t::scale(GLfloat x, GLfloat y, GLfloat z) {
- for (int i=0 ; i<4 ; i++) {
- m[ i] *= x;
- m[4+i] *= y;
- m[8+i] *= z;
- }
-}
-
-void matrixf_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
-{
- matrixf_t rotation;
- GLfloat* r = rotation.m;
- GLfloat c, s;
- r[3] = 0; r[7] = 0; r[11]= 0;
- r[12]= 0; r[13]= 0; r[14]= 0; r[15]= 1;
- a *= GLfloat(M_PI / 180.0f);
- sincosf(a, &s, &c);
- if (isOnef(x) && isZerof(y) && isZerof(z)) {
- r[5] = c; r[10]= c;
- r[6] = s; r[9] = -s;
- r[1] = 0; r[2] = 0;
- r[4] = 0; r[8] = 0;
- r[0] = 1;
- } else if (isZerof(x) && isOnef(y) && isZerof(z)) {
- r[0] = c; r[10]= c;
- r[8] = s; r[2] = -s;
- r[1] = 0; r[4] = 0;
- r[6] = 0; r[9] = 0;
- r[5] = 1;
- } else if (isZerof(x) && isZerof(y) && isOnef(z)) {
- r[0] = c; r[5] = c;
- r[1] = s; r[4] = -s;
- r[2] = 0; r[6] = 0;
- r[8] = 0; r[9] = 0;
- r[10]= 1;
- } else {
- const GLfloat len = sqrtf(x*x + y*y + z*z);
- if (!isOnef(len)) {
- const GLfloat recipLen = reciprocalf(len);
- x *= recipLen;
- y *= recipLen;
- z *= recipLen;
- }
- const GLfloat nc = 1.0f - c;
- const GLfloat xy = x * y;
- const GLfloat yz = y * z;
- const GLfloat zx = z * x;
- const GLfloat xs = x * s;
- const GLfloat ys = y * s;
- const GLfloat zs = z * s;
- r[ 0] = x*x*nc + c; r[ 4] = xy*nc - zs; r[ 8] = zx*nc + ys;
- r[ 1] = xy*nc + zs; r[ 5] = y*y*nc + c; r[ 9] = yz*nc - xs;
- r[ 2] = zx*nc - ys; r[ 6] = yz*nc + xs; r[10] = z*z*nc + c;
- }
- multiply(rotation);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark matrix_stack_t
-#endif
-
-void matrix_stack_t::init(int depth) {
- stack = new matrixf_t[depth];
- ops = new uint8_t[depth];
- maxDepth = depth;
- depth = 0;
- dirty = 0;
- loadIdentity();
-}
-
-void matrix_stack_t::uninit() {
- delete [] stack;
- delete [] ops;
-}
-
-void matrix_stack_t::loadIdentity() {
- transform.loadIdentity();
- stack[depth].loadIdentity();
- ops[depth] = OP_IDENTITY;
-}
-
-void matrix_stack_t::load(const GLfixed* rhs)
-{
- memcpy(transform.matrix.m, rhs, sizeof(transform.matrix.m));
- stack[depth].load(rhs);
- ops[depth] = OP_ALL; // TODO: we should look at the matrix
-}
-
-void matrix_stack_t::load(const GLfloat* rhs)
-{
- stack[depth].load(rhs);
- ops[depth] = OP_ALL; // TODO: we should look at the matrix
-}
-
-void matrix_stack_t::multiply(const matrixf_t& rhs)
-{
- stack[depth].multiply(rhs);
- ops[depth] = OP_ALL; // TODO: we should look at the matrix
-}
-
-void matrix_stack_t::translate(GLfloat x, GLfloat y, GLfloat z)
-{
- stack[depth].translate(x,y,z);
- ops[depth] |= OP_TRANSLATE;
-}
-
-void matrix_stack_t::scale(GLfloat x, GLfloat y, GLfloat z)
-{
- stack[depth].scale(x,y,z);
- if (x==y && y==z) {
- ops[depth] |= OP_UNIFORM_SCALE;
- } else {
- ops[depth] |= OP_SCALE;
- }
-}
-
-void matrix_stack_t::rotate(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
-{
- stack[depth].rotate(a,x,y,z);
- ops[depth] |= OP_ROTATE;
-}
-
-void matrix_stack_t::validate()
-{
- if (dirty & DO_FLOAT_TO_FIXED) {
- transform.matrix.load(top());
- }
- if (dirty & DO_PICKER) {
- transform.picker();
- }
- dirty = 0;
-}
-
-GLint matrix_stack_t::push()
-{
- if (depth >= (maxDepth-1)) {
- return GL_STACK_OVERFLOW;
- }
- stack[depth+1] = stack[depth];
- ops[depth+1] = ops[depth];
- depth++;
- return 0;
-}
-
-GLint matrix_stack_t::pop()
-{
- if (depth == 0) {
- return GL_STACK_UNDERFLOW;
- }
- depth--;
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark vp_transform_t
-#endif
-
-void vp_transform_t::loadIdentity() {
- transform.loadIdentity();
- matrix.loadIdentity();
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark transform_state_t
-#endif
-
-void transform_state_t::invalidate()
-{
- switch (matrixMode) {
- case GL_MODELVIEW: dirty |= MODELVIEW | MVP | MVUI | MVIT; break;
- case GL_PROJECTION: dirty |= PROJECTION | MVP; break;
- case GL_TEXTURE: dirty |= TEXTURE | MVP; break;
- }
- current->dirty = matrix_stack_t::DO_PICKER |
- matrix_stack_t::DO_FLOAT_TO_FIXED;
-}
-
-void transform_state_t::update_mvp()
-{
- matrixf_t temp_mvp;
- matrixf_t::multiply(temp_mvp, projection.top(), modelview.top());
- mvp4.matrix.load(temp_mvp);
- mvp4.picker();
-
- if (mvp4.flags & transform_t::FLAGS_2D_PROJECTION) {
- // the mvp matrix doesn't transform W, in this case we can
- // premultiply it with the viewport transformation. In addition to
- // being more efficient, this is also much more accurate and in fact
- // is needed for 2D drawing with a resulting 1:1 mapping.
- matrixf_t mvpv;
- matrixf_t::multiply(mvpv, vpt.matrix, temp_mvp);
- mvp.matrix.load(mvpv);
- mvp.picker();
- } else {
- mvp = mvp4;
- }
-}
-
-static __attribute__((noinline))
-void invert(GLfloat* inverse, const GLfloat* src)
-{
- double t;
- int i, j, k, swap;
- GLfloat tmp[4][4];
-
- memcpy(inverse, gIdentityf, sizeof(gIdentityf));
- memcpy(tmp, src, sizeof(GLfloat)*16);
-
- for (i = 0; i < 4; i++) {
- // look for largest element in column
- swap = i;
- for (j = i + 1; j < 4; j++) {
- if (fabs(tmp[j][i]) > fabs(tmp[i][i])) {
- swap = j;
- }
- }
-
- if (swap != i) {
- /* swap rows. */
- for (k = 0; k < 4; k++) {
- t = tmp[i][k];
- tmp[i][k] = tmp[swap][k];
- tmp[swap][k] = t;
-
- t = inverse[i*4+k];
- inverse[i*4+k] = inverse[swap*4+k];
- inverse[swap*4+k] = t;
- }
- }
-
- t = 1.0f / tmp[i][i];
- for (k = 0; k < 4; k++) {
- tmp[i][k] *= t;
- inverse[i*4+k] *= t;
- }
- for (j = 0; j < 4; j++) {
- if (j != i) {
- t = tmp[j][i];
- for (k = 0; k < 4; k++) {
- tmp[j][k] -= tmp[i][k]*t;
- inverse[j*4+k] -= inverse[i*4+k]*t;
- }
- }
- }
- }
-}
-
-void transform_state_t::update_mvit()
-{
- GLfloat r[16];
- const GLfloat* const mv = modelview.top().elements();
- invert(r, mv);
- // convert to fixed-point and transpose
- GLfixed* const x = mvit4.matrix.m;
- for (int i=0 ; i<4 ; i++)
- for (int j=0 ; j<4 ; j++)
- x[I(i,j)] = gglFloatToFixed(r[I(j,i)]);
- mvit4.picker();
-}
-
-void transform_state_t::update_mvui()
-{
- GLfloat r[16];
- const GLfloat* const mv = modelview.top().elements();
-
- /*
- When evaluating the lighting equation in eye-space, normals
- are transformed by the upper 3x3 modelview inverse-transpose.
- http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node26.html
-
- (note that inverse-transpose is distributive).
- Also note that:
- l(obj) = inv(modelview).l(eye) for local light
- l(obj) = tr(modelview).l(eye) for infinite light
- */
-
- invert(r, mv);
-
- GLfixed* const x = mvui.matrix.m;
-
-#if OBJECT_SPACE_LIGHTING
- for (int i=0 ; i<4 ; i++)
- for (int j=0 ; j<4 ; j++)
- x[I(i,j)] = gglFloatToFixed(r[I(i,j)]);
-#else
- for (int i=0 ; i<4 ; i++)
- for (int j=0 ; j<4 ; j++)
- x[I(i,j)] = gglFloatToFixed(r[I(j,i)]);
-#endif
-
- mvui.picker();
-}
-
-
-// ----------------------------------------------------------------------------
-// transformation and matrices API
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark transformation and matrices API
-#endif
-
-int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y)
-{
- c->viewport.surfaceport.x = x;
- c->viewport.surfaceport.y = y;
-
- ogles_viewport(c,
- c->viewport.x,
- c->viewport.y,
- c->viewport.w,
- c->viewport.h);
-
- ogles_scissor(c,
- c->viewport.scissor.x,
- c->viewport.scissor.y,
- c->viewport.scissor.w,
- c->viewport.scissor.h);
-
- return 0;
-}
-
-void ogles_scissor(ogles_context_t* c,
- GLint x, GLint y, GLsizei w, GLsizei h)
-{
- if ((w|h) < 0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- c->viewport.scissor.x = x;
- c->viewport.scissor.y = y;
- c->viewport.scissor.w = w;
- c->viewport.scissor.h = h;
-
- x += c->viewport.surfaceport.x;
- y += c->viewport.surfaceport.y;
-
- y = c->rasterizer.state.buffers.color.height - (y + h);
- c->rasterizer.procs.scissor(c, x, y, w, h);
-}
-
-void ogles_viewport(ogles_context_t* c,
- GLint x, GLint y, GLsizei w, GLsizei h)
-{
- if ((w|h)<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- c->viewport.x = x;
- c->viewport.y = y;
- c->viewport.w = w;
- c->viewport.h = h;
-
- x += c->viewport.surfaceport.x;
- y += c->viewport.surfaceport.y;
-
- GLint H = c->rasterizer.state.buffers.color.height;
- GLfloat sx = div2f(w);
- GLfloat ox = sx + x;
- GLfloat sy = div2f(h);
- GLfloat oy = sy - y + (H - h);
-
- GLfloat near = c->transforms.vpt.zNear;
- GLfloat far = c->transforms.vpt.zFar;
- GLfloat A = div2f(far - near);
- GLfloat B = div2f(far + near);
-
- // compute viewport matrix
- GLfloat* const f = c->transforms.vpt.matrix.editElements();
- f[0] = sx; f[4] = 0; f[ 8] = 0; f[12] = ox;
- f[1] = 0; f[5] =-sy; f[ 9] = 0; f[13] = oy;
- f[2] = 0; f[6] = 0; f[10] = A; f[14] = B;
- f[3] = 0; f[7] = 0; f[11] = 0; f[15] = 1;
- c->transforms.dirty |= transform_state_t::VIEWPORT;
- if (c->transforms.mvp4.flags & transform_t::FLAGS_2D_PROJECTION)
- c->transforms.dirty |= transform_state_t::MVP;
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark matrix * vertex
-#endif
-
-void point2__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
- const GLfixed* const m = mx->matrix.m;
- const GLfixed rx = rhs->x;
- const GLfixed ry = rhs->y;
- lhs->x = mla2a(rx, m[ 0], ry, m[ 4], m[12]);
- lhs->y = mla2a(rx, m[ 1], ry, m[ 5], m[13]);
- lhs->z = mla2a(rx, m[ 2], ry, m[ 6], m[14]);
- lhs->w = mla2a(rx, m[ 3], ry, m[ 7], m[15]);
-}
-
-void point3__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
- const GLfixed* const m = mx->matrix.m;
- const GLfixed rx = rhs->x;
- const GLfixed ry = rhs->y;
- const GLfixed rz = rhs->z;
- lhs->x = mla3a(rx, m[ 0], ry, m[ 4], rz, m[ 8], m[12]);
- lhs->y = mla3a(rx, m[ 1], ry, m[ 5], rz, m[ 9], m[13]);
- lhs->z = mla3a(rx, m[ 2], ry, m[ 6], rz, m[10], m[14]);
- lhs->w = mla3a(rx, m[ 3], ry, m[ 7], rz, m[11], m[15]);
-}
-
-void point4__generic(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
- const GLfixed* const m = mx->matrix.m;
- const GLfixed rx = rhs->x;
- const GLfixed ry = rhs->y;
- const GLfixed rz = rhs->z;
- const GLfixed rw = rhs->w;
- lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]);
- lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]);
- lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]);
- lhs->w = mla4(rx, m[ 3], ry, m[ 7], rz, m[11], rw, m[15]);
-}
-
-void point3__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
- // this is used for transforming light positions back to object space.
- // w is used as a switch for directional lights, so we need
- // to preserve it.
- const GLfixed* const m = mx->matrix.m;
- const GLfixed rx = rhs->x;
- const GLfixed ry = rhs->y;
- const GLfixed rz = rhs->z;
- lhs->x = mla3(rx, m[ 0], ry, m[ 4], rz, m[ 8]);
- lhs->y = mla3(rx, m[ 1], ry, m[ 5], rz, m[ 9]);
- lhs->z = mla3(rx, m[ 2], ry, m[ 6], rz, m[10]);
- lhs->w = 0;
-}
-
-void point4__mvui(transform_t const* mx, vec4_t* lhs, vec4_t const* rhs) {
- // this is used for transforming light positions back to object space.
- // w is used as a switch for directional lights, so we need
- // to preserve it.
- const GLfixed* const m = mx->matrix.m;
- const GLfixed rx = rhs->x;
- const GLfixed ry = rhs->y;
- const GLfixed rz = rhs->z;
- const GLfixed rw = rhs->w;
- lhs->x = mla4(rx, m[ 0], ry, m[ 4], rz, m[ 8], rw, m[12]);
- lhs->y = mla4(rx, m[ 1], ry, m[ 5], rz, m[ 9], rw, m[13]);
- lhs->z = mla4(rx, m[ 2], ry, m[ 6], rz, m[10], rw, m[14]);
- lhs->w = rw;
-}
-
-void point2__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
- lhs->z = 0;
- lhs->w = 0x10000;
- if (lhs != rhs) {
- lhs->x = rhs->x;
- lhs->y = rhs->y;
- }
-}
-
-void point3__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
- lhs->w = 0x10000;
- if (lhs != rhs) {
- lhs->x = rhs->x;
- lhs->y = rhs->y;
- lhs->z = rhs->z;
- }
-}
-
-void point4__nop(transform_t const*, vec4_t* lhs, vec4_t const* rhs) {
- if (lhs != rhs)
- *lhs = *rhs;
-}
-
-
-static void frustumf(
- GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top,
- GLfloat zNear, GLfloat zFar,
- ogles_context_t* c)
- {
- if (cmpf(left,right) ||
- cmpf(top, bottom) ||
- cmpf(zNear, zFar) ||
- isZeroOrNegativef(zNear) ||
- isZeroOrNegativef(zFar))
- {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- const GLfloat r_width = reciprocalf(right - left);
- const GLfloat r_height = reciprocalf(top - bottom);
- const GLfloat r_depth = reciprocalf(zNear - zFar);
- const GLfloat x = mul2f(zNear * r_width);
- const GLfloat y = mul2f(zNear * r_height);
- const GLfloat A = mul2f((right + left) * r_width);
- const GLfloat B = (top + bottom) * r_height;
- const GLfloat C = (zFar + zNear) * r_depth;
- const GLfloat D = mul2f(zFar * zNear * r_depth);
- GLfloat f[16];
- f[ 0] = x;
- f[ 5] = y;
- f[ 8] = A;
- f[ 9] = B;
- f[10] = C;
- f[14] = D;
- f[11] = -1.0f;
- f[ 1] = f[ 2] = f[ 3] =
- f[ 4] = f[ 6] = f[ 7] =
- f[12] = f[13] = f[15] = 0.0f;
-
- matrixf_t rhs;
- rhs.set(f);
- c->transforms.current->multiply(rhs);
- c->transforms.invalidate();
-}
-
-static void orthof(
- GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top,
- GLfloat zNear, GLfloat zFar,
- ogles_context_t* c)
-{
- if (cmpf(left,right) ||
- cmpf(top, bottom) ||
- cmpf(zNear, zFar))
- {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- const GLfloat r_width = reciprocalf(right - left);
- const GLfloat r_height = reciprocalf(top - bottom);
- const GLfloat r_depth = reciprocalf(zFar - zNear);
- const GLfloat x = mul2f(r_width);
- const GLfloat y = mul2f(r_height);
- const GLfloat z = -mul2f(r_depth);
- const GLfloat tx = -(right + left) * r_width;
- const GLfloat ty = -(top + bottom) * r_height;
- const GLfloat tz = -(zFar + zNear) * r_depth;
- GLfloat f[16];
- f[ 0] = x;
- f[ 5] = y;
- f[10] = z;
- f[12] = tx;
- f[13] = ty;
- f[14] = tz;
- f[15] = 1.0f;
- f[ 1] = f[ 2] = f[ 3] =
- f[ 4] = f[ 6] = f[ 7] =
- f[ 8] = f[ 9] = f[11] = 0.0f;
- matrixf_t rhs;
- rhs.set(f);
- c->transforms.current->multiply(rhs);
- c->transforms.invalidate();
-}
-
-static void depthRangef(GLclampf zNear, GLclampf zFar, ogles_context_t* c)
-{
- zNear = clampToZerof(zNear > 1 ? 1 : zNear);
- zFar = clampToZerof(zFar > 1 ? 1 : zFar);
- GLfloat* const f = c->transforms.vpt.matrix.editElements();
- f[10] = div2f(zFar - zNear);
- f[14] = div2f(zFar + zNear);
- c->transforms.dirty |= transform_state_t::VIEWPORT;
- c->transforms.vpt.zNear = zNear;
- c->transforms.vpt.zFar = zFar;
-}
-
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-using namespace android;
-
-void glMatrixMode(GLenum mode)
-{
- ogles_context_t* c = ogles_context_t::get();
- matrix_stack_t* stack = 0;
- switch (mode) {
- case GL_MODELVIEW:
- stack = &c->transforms.modelview;
- break;
- case GL_PROJECTION:
- stack = &c->transforms.projection;
- break;
- case GL_TEXTURE:
- stack = &c->transforms.texture[c->textures.active];
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->transforms.matrixMode = mode;
- c->transforms.current = stack;
-}
-
-void glLoadIdentity()
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->loadIdentity(); // also loads the GLfixed transform
- c->transforms.invalidate();
- c->transforms.current->dirty = 0;
-}
-
-void glLoadMatrixf(const GLfloat* m)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->load(m);
- c->transforms.invalidate();
-}
-
-void glLoadMatrixx(const GLfixed* m)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->load(m); // also loads the GLfixed transform
- c->transforms.invalidate();
- c->transforms.current->dirty &= ~matrix_stack_t::DO_FLOAT_TO_FIXED;
-}
-
-void glMultMatrixf(const GLfloat* m)
-{
- ogles_context_t* c = ogles_context_t::get();
- matrixf_t rhs;
- rhs.set(m);
- c->transforms.current->multiply(rhs);
- c->transforms.invalidate();
-}
-
-void glMultMatrixx(const GLfixed* m)
-{
- ogles_context_t* c = ogles_context_t::get();
- matrixf_t rhs;
- rhs.set(m);
- c->transforms.current->multiply(rhs);
- c->transforms.invalidate();
-}
-
-void glPopMatrix()
-{
- ogles_context_t* c = ogles_context_t::get();
- GLint err = c->transforms.current->pop();
- if (ggl_unlikely(err)) {
- ogles_error(c, err);
- return;
- }
- c->transforms.invalidate();
-}
-
-void glPushMatrix()
-{
- ogles_context_t* c = ogles_context_t::get();
- GLint err = c->transforms.current->push();
- if (ggl_unlikely(err)) {
- ogles_error(c, err);
- return;
- }
- c->transforms.invalidate();
-}
-
-void glFrustumf(
- GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top,
- GLfloat zNear, GLfloat zFar)
-{
- ogles_context_t* c = ogles_context_t::get();
- frustumf(left, right, bottom, top, zNear, zFar, c);
-}
-
-void glFrustumx(
- GLfixed left, GLfixed right,
- GLfixed bottom, GLfixed top,
- GLfixed zNear, GLfixed zFar)
-{
- ogles_context_t* c = ogles_context_t::get();
- frustumf( fixedToFloat(left), fixedToFloat(right),
- fixedToFloat(bottom), fixedToFloat(top),
- fixedToFloat(zNear), fixedToFloat(zFar),
- c);
-}
-
-void glOrthof(
- GLfloat left, GLfloat right,
- GLfloat bottom, GLfloat top,
- GLfloat zNear, GLfloat zFar)
-{
- ogles_context_t* c = ogles_context_t::get();
- orthof(left, right, bottom, top, zNear, zFar, c);
-}
-
-void glOrthox(
- GLfixed left, GLfixed right,
- GLfixed bottom, GLfixed top,
- GLfixed zNear, GLfixed zFar)
-{
- ogles_context_t* c = ogles_context_t::get();
- orthof( fixedToFloat(left), fixedToFloat(right),
- fixedToFloat(bottom), fixedToFloat(top),
- fixedToFloat(zNear), fixedToFloat(zFar),
- c);
-}
-
-void glRotatef(GLfloat a, GLfloat x, GLfloat y, GLfloat z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->rotate(a, x, y, z);
- c->transforms.invalidate();
-}
-
-void glRotatex(GLfixed a, GLfixed x, GLfixed y, GLfixed z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->rotate(
- fixedToFloat(a), fixedToFloat(x),
- fixedToFloat(y), fixedToFloat(z));
- c->transforms.invalidate();
-}
-
-void glScalef(GLfloat x, GLfloat y, GLfloat z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->scale(x, y, z);
- c->transforms.invalidate();
-}
-
-void glScalex(GLfixed x, GLfixed y, GLfixed z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->scale(
- fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
- c->transforms.invalidate();
-}
-
-void glTranslatef(GLfloat x, GLfloat y, GLfloat z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->translate(x, y, z);
- c->transforms.invalidate();
-}
-
-void glTranslatex(GLfixed x, GLfixed y, GLfixed z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->transforms.current->translate(
- fixedToFloat(x), fixedToFloat(y), fixedToFloat(z));
- c->transforms.invalidate();
-}
-
-void glScissor(GLint x, GLint y, GLsizei w, GLsizei h)
-{
- ogles_context_t* c = ogles_context_t::get();
- ogles_scissor(c, x, y, w, h);
-}
-
-void glViewport(GLint x, GLint y, GLsizei w, GLsizei h)
-{
- ogles_context_t* c = ogles_context_t::get();
- ogles_viewport(c, x, y, w, h);
-}
-
-void glDepthRangef(GLclampf zNear, GLclampf zFar)
-{
- ogles_context_t* c = ogles_context_t::get();
- depthRangef(zNear, zFar, c);
-}
-
-void glDepthRangex(GLclampx zNear, GLclampx zFar)
-{
- ogles_context_t* c = ogles_context_t::get();
- depthRangef(fixedToFloat(zNear), fixedToFloat(zFar), c);
-}
-
-void glPolygonOffsetx(GLfixed factor, GLfixed units)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->polygonOffset.factor = factor;
- c->polygonOffset.units = units;
-}
-
-void glPolygonOffset(GLfloat factor, GLfloat units)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->polygonOffset.factor = gglFloatToFixed(factor);
- c->polygonOffset.units = gglFloatToFixed(units);
-}
-
-GLbitfield glQueryMatrixxOES(GLfixed* m, GLint* e)
-{
- ogles_context_t* c = ogles_context_t::get();
- GLbitfield status = 0;
- GLfloat const* f = c->transforms.current->top().elements();
- for (int i=0 ; i<16 ; i++) {
- if (isnan(f[i]) || isinf(f[i])) {
- status |= 1<<i;
- continue;
- }
- e[i] = exponent(f[i]) - 7;
- m[i] = mantissa(f[i]);
- }
- return status;
-}
diff --git a/opengl/libagl/matrix.h b/opengl/libagl/matrix.h
deleted file mode 100644
index cafc119..0000000
--- a/opengl/libagl/matrix.h
+++ /dev/null
@@ -1,399 +0,0 @@
-/* libs/opengles/matrix.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_MATRIX_H
-#define ANDROID_OPENGLES_MATRIX_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-#include <utils/Log.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include <GLES/gl.h>
-
-namespace android {
-
-const int OGLES_MODELVIEW_STACK_DEPTH = 16;
-const int OGLES_PROJECTION_STACK_DEPTH = 2;
-const int OGLES_TEXTURE_STACK_DEPTH = 2;
-
-void ogles_init_matrix(ogles_context_t*);
-void ogles_uninit_matrix(ogles_context_t*);
-void ogles_invalidate_perspective(ogles_context_t* c);
-void ogles_validate_transform_impl(ogles_context_t* c, uint32_t want);
-
-int ogles_surfaceport(ogles_context_t* c, GLint x, GLint y);
-
-void ogles_scissor(ogles_context_t* c,
- GLint x, GLint y, GLsizei w, GLsizei h);
-
-void ogles_viewport(ogles_context_t* c,
- GLint x, GLint y, GLsizei w, GLsizei h);
-
-inline void ogles_validate_transform(
- ogles_context_t* c, uint32_t want)
-{
- if (c->transforms.dirty & want)
- ogles_validate_transform_impl(c, want);
-}
-
-// ----------------------------------------------------------------------------
-
-inline
-GLfixed vsquare3(GLfixed a, GLfixed b, GLfixed c)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- int32_t t;
- asm(
- "smull %0, %1, %2, %2 \n"
- "smlal %0, %1, %3, %3 \n"
- "smlal %0, %1, %4, %4 \n"
- "movs %0, %0, lsr #16 \n"
- "adc %0, %0, %1, lsl #16 \n"
- : "=&r"(r), "=&r"(t)
- : "%r"(a), "r"(b), "r"(c)
- : "cc"
- );
- return r;
-
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-
- GLfixed res;
- int32_t t1,t2,t3;
- asm(
- "mult %[a], %[a] \r\n"
- "li %[res],0x8000 \r\n"
- "madd %[b],%[b] \r\n"
- "move %[t3],$zero \r\n"
- "madd %[c],%[c] \r\n"
- "mflo %[t1]\r\n"
- "mfhi %[t2]\r\n"
- "addu %[t1],%[res],%[t1]\r\n" /*add 0x8000*/
- "sltu %[t3],%[t1],%[res]\r\n"
- "addu %[t2],%[t2],%[t3]\r\n"
- "srl %[res],%[t1],16\r\n"
- "sll %[t2],%[t2],16\r\n"
- "or %[res],%[res],%[t2]\r\n"
- : [res]"=&r"(res),[t1]"=&r"(t1),[t2]"=&r"(t2),[t3]"=&r"(t3)
- : [a] "r" (a),[b] "r" (b),[c] "r" (c)
- : "%hi","%lo"
- );
- return res;
-
-#else
-
- return (( int64_t(a)*a +
- int64_t(b)*b +
- int64_t(c)*c + 0x8000)>>16);
-
-#endif
-}
-
-static inline GLfixed mla2a( GLfixed a0, GLfixed b0,
- GLfixed a1, GLfixed b1,
- GLfixed c)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- int32_t t;
- asm(
- "smull %0, %1, %2, %3 \n"
- "smlal %0, %1, %4, %5 \n"
- "add %0, %6, %0, lsr #16 \n"
- "add %0, %0, %1, lsl #16 \n"
- : "=&r"(r), "=&r"(t)
- : "%r"(a0), "r"(b0),
- "%r"(a1), "r"(b1),
- "r"(c)
- :
- );
- return r;
-
-#else
-
- return (( int64_t(a0)*b0 +
- int64_t(a1)*b1)>>16) + c;
-
-#endif
-}
-
-static inline GLfixed mla3a( GLfixed a0, GLfixed b0,
- GLfixed a1, GLfixed b1,
- GLfixed a2, GLfixed b2,
- GLfixed c)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- int32_t t;
- asm(
- "smull %0, %1, %2, %3 \n"
- "smlal %0, %1, %4, %5 \n"
- "smlal %0, %1, %6, %7 \n"
- "add %0, %8, %0, lsr #16 \n"
- "add %0, %0, %1, lsl #16 \n"
- : "=&r"(r), "=&r"(t)
- : "%r"(a0), "r"(b0),
- "%r"(a1), "r"(b1),
- "%r"(a2), "r"(b2),
- "r"(c)
- :
- );
- return r;
-
-#elif defined(__mips__) && !defined(__LP64__) && __mips_isa_rev < 6
-
- GLfixed res;
- int32_t t1,t2;
- asm(
- "mult %[a0],%[b0] \r\n"
- "madd %[a1],%[b1] \r\n"
- "madd %[a2],%[b2] \r\n"
- "mflo %[t2]\r\n"
- "mfhi %[t1]\r\n"
- "srl %[t2],%[t2],16\r\n"
- "sll %[t1],%[t1],16\r\n"
- "or %[t2],%[t2],%[t1]\r\n"
- "addu %[res],%[t2],%[c]"
- : [res]"=&r"(res),[t1]"=&r"(t1),[t2]"=&r"(t2)
- : [a0] "r" (a0),[b0] "r" (b0),[a1] "r" (a1),[b1] "r" (b1),[a2] "r" (a2),[b2] "r" (b2),[c] "r" (c)
- : "%hi","%lo"
- );
- return res;
-
-#else
-
- return (( int64_t(a0)*b0 +
- int64_t(a1)*b1 +
- int64_t(a2)*b2)>>16) + c;
-
-#endif
-}
-
-// b0, b1, b2 are signed 16-bit quanities
-// that have been shifted right by 'shift' bits relative to normal
-// S16.16 fixed point
-static inline GLfixed mla3a16( GLfixed a0, int32_t b1b0,
- GLfixed a1,
- GLfixed a2, int32_t b2,
- GLint shift,
- GLfixed c)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- asm(
- "smulwb %0, %1, %2 \n"
- "smlawt %0, %3, %2, %0 \n"
- "smlawb %0, %4, %5, %0 \n"
- "add %0, %7, %0, lsl %6 \n"
- : "=&r"(r)
- : "r"(a0), "r"(b1b0),
- "r"(a1),
- "r"(a2), "r"(b2),
- "r"(shift),
- "r"(c)
- :
- );
- return r;
-
-#else
-
- int32_t accum;
- int16_t b0 = b1b0 & 0xffff;
- int16_t b1 = (b1b0 >> 16) & 0xffff;
- accum = int64_t(a0)*int16_t(b0) >> 16;
- accum += int64_t(a1)*int16_t(b1) >> 16;
- accum += int64_t(a2)*int16_t(b2) >> 16;
- accum = (accum << shift) + c;
- return accum;
-
-#endif
-}
-
-
-static inline GLfixed mla3a16_btb( GLfixed a0,
- GLfixed a1,
- GLfixed a2,
- int32_t b1b0, int32_t xxb2,
- GLint shift,
- GLfixed c)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- asm(
- "smulwb %0, %1, %4 \n"
- "smlawt %0, %2, %4, %0 \n"
- "smlawb %0, %3, %5, %0 \n"
- "add %0, %7, %0, lsl %6 \n"
- : "=&r"(r)
- : "r"(a0),
- "r"(a1),
- "r"(a2),
- "r"(b1b0), "r"(xxb2),
- "r"(shift),
- "r"(c)
- :
- );
- return r;
-
-#else
-
- int32_t accum;
- int16_t b0 = b1b0 & 0xffff;
- int16_t b1 = (b1b0 >> 16) & 0xffff;
- int16_t b2 = xxb2 & 0xffff;
- accum = int64_t(a0)*int16_t(b0) >> 16;
- accum += int64_t(a1)*int16_t(b1) >> 16;
- accum += int64_t(a2)*int16_t(b2) >> 16;
- accum = (accum << shift) + c;
- return accum;
-
-#endif
-}
-
-static inline GLfixed mla3a16_btt( GLfixed a0,
- GLfixed a1,
- GLfixed a2,
- int32_t b1b0, int32_t b2xx,
- GLint shift,
- GLfixed c)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- asm(
- "smulwb %0, %1, %4 \n"
- "smlawt %0, %2, %4, %0 \n"
- "smlawt %0, %3, %5, %0 \n"
- "add %0, %7, %0, lsl %6 \n"
- : "=&r"(r)
- : "r"(a0),
- "r"(a1),
- "r"(a2),
- "r"(b1b0), "r"(b2xx),
- "r"(shift),
- "r"(c)
- :
- );
- return r;
-
-#else
-
- int32_t accum;
- int16_t b0 = b1b0 & 0xffff;
- int16_t b1 = (b1b0 >> 16) & 0xffff;
- int16_t b2 = (b2xx >> 16) & 0xffff;
- accum = int64_t(a0)*int16_t(b0) >> 16;
- accum += int64_t(a1)*int16_t(b1) >> 16;
- accum += int64_t(a2)*int16_t(b2) >> 16;
- accum = (accum << shift) + c;
- return accum;
-
-#endif
-}
-
-static inline GLfixed mla3( GLfixed a0, GLfixed b0,
- GLfixed a1, GLfixed b1,
- GLfixed a2, GLfixed b2)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- int32_t t;
- asm(
- "smull %0, %1, %2, %3 \n"
- "smlal %0, %1, %4, %5 \n"
- "smlal %0, %1, %6, %7 \n"
- "movs %0, %0, lsr #16 \n"
- "adc %0, %0, %1, lsl #16 \n"
- : "=&r"(r), "=&r"(t)
- : "%r"(a0), "r"(b0),
- "%r"(a1), "r"(b1),
- "%r"(a2), "r"(b2)
- : "cc"
- );
- return r;
-
-#else
-
- return (( int64_t(a0)*b0 +
- int64_t(a1)*b1 +
- int64_t(a2)*b2 + 0x8000)>>16);
-
-#endif
-}
-
-static inline GLfixed mla4( GLfixed a0, GLfixed b0,
- GLfixed a1, GLfixed b1,
- GLfixed a2, GLfixed b2,
- GLfixed a3, GLfixed b3)
-{
-#if defined(__arm__) && !defined(__thumb__)
-
- GLfixed r;
- int32_t t;
- asm(
- "smull %0, %1, %2, %3 \n"
- "smlal %0, %1, %4, %5 \n"
- "smlal %0, %1, %6, %7 \n"
- "smlal %0, %1, %8, %9 \n"
- "movs %0, %0, lsr #16 \n"
- "adc %0, %0, %1, lsl #16 \n"
- : "=&r"(r), "=&r"(t)
- : "%r"(a0), "r"(b0),
- "%r"(a1), "r"(b1),
- "%r"(a2), "r"(b2),
- "%r"(a3), "r"(b3)
- : "cc"
- );
- return r;
-
-#else
-
- return (( int64_t(a0)*b0 +
- int64_t(a1)*b1 +
- int64_t(a2)*b2 +
- int64_t(a3)*b3 + 0x8000)>>16);
-
-#endif
-}
-
-inline
-GLfixed dot4(const GLfixed* a, const GLfixed* b)
-{
- return mla4(a[0], b[0], a[1], b[1], a[2], b[2], a[3], b[3]);
-}
-
-
-inline
-GLfixed dot3(const GLfixed* a, const GLfixed* b)
-{
- return mla3(a[0], b[0], a[1], b[1], a[2], b[2]);
-}
-
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_MATRIX_H
-
diff --git a/opengl/libagl/mipmap.cpp b/opengl/libagl/mipmap.cpp
deleted file mode 100644
index e142a58..0000000
--- a/opengl/libagl/mipmap.cpp
+++ /dev/null
@@ -1,192 +0,0 @@
-/* libs/opengles/mipmap.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "context.h"
-#include "state.h"
-#include "texture.h"
-#include "TextureObjectManager.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex)
-{
- int level = 0;
- const GGLSurface* base = &tex->surface;
- const GGLFormat& pixelFormat(c->rasterizer.formats[base->format]);
-
- int w = base->width;
- int h = base->height;
- if ((w&h) == 1)
- return NO_ERROR;
-
- w = (w>>1) ? : 1;
- h = (h>>1) ? : 1;
-
- while(true) {
- ++level;
- const int bpr = w * pixelFormat.size;
- if (tex->reallocate(level, w, h, w,
- base->format, base->compressedFormat, bpr) != NO_ERROR) {
- return NO_MEMORY;
- }
-
- int stride = w;
- int bs = base->stride;
- GGLSurface& cur = tex->editMip(level);
-
- if (base->format == GGL_PIXEL_FORMAT_RGB_565)
- {
- uint16_t const * src = (uint16_t const *)base->data;
- uint16_t* dst = (uint16_t*)cur.data;
- const uint32_t mask = 0x07E0F81F;
- for (int y=0 ; y<h ; y++) {
- size_t offset = (y*2) * bs;
- for (int x=0 ; x<w ; x++) {
- uint32_t p00 = src[offset];
- uint32_t p10 = src[offset+1];
- uint32_t p01 = src[offset+bs];
- uint32_t p11 = src[offset+bs+1];
- p00 = (p00 | (p00 << 16)) & mask;
- p01 = (p01 | (p01 << 16)) & mask;
- p10 = (p10 | (p10 << 16)) & mask;
- p11 = (p11 | (p11 << 16)) & mask;
- uint32_t grb = ((p00 + p10 + p01 + p11) >> 2) & mask;
- uint32_t rgb = (grb & 0xFFFF) | (grb >> 16);
- dst[x + y*stride] = rgb;
- offset += 2;
- }
- }
- }
- else if (base->format == GGL_PIXEL_FORMAT_RGBA_5551)
- {
- uint16_t const * src = (uint16_t const *)base->data;
- uint16_t* dst = (uint16_t*)cur.data;
- for (int y=0 ; y<h ; y++) {
- size_t offset = (y*2) * bs;
- for (int x=0 ; x<w ; x++) {
- uint32_t p00 = src[offset];
- uint32_t p10 = src[offset+1];
- uint32_t p01 = src[offset+bs];
- uint32_t p11 = src[offset+bs+1];
- uint32_t r = ((p00>>11)+(p10>>11)+(p01>>11)+(p11>>11)+2)>>2;
- uint32_t g = (((p00>>6)+(p10>>6)+(p01>>6)+(p11>>6)+2)>>2)&0x3F;
- uint32_t b = ((p00&0x3E)+(p10&0x3E)+(p01&0x3E)+(p11&0x3E)+4)>>3;
- uint32_t a = ((p00&1)+(p10&1)+(p01&1)+(p11&1)+2)>>2;
- dst[x + y*stride] = (r<<11)|(g<<6)|(b<<1)|a;
- offset += 2;
- }
- }
- }
- else if (base->format == GGL_PIXEL_FORMAT_RGBA_8888)
- {
- uint32_t const * src = (uint32_t const *)base->data;
- uint32_t* dst = (uint32_t*)cur.data;
- for (int y=0 ; y<h ; y++) {
- size_t offset = (y*2) * bs;
- for (int x=0 ; x<w ; x++) {
- uint32_t p00 = src[offset];
- uint32_t p10 = src[offset+1];
- uint32_t p01 = src[offset+bs];
- uint32_t p11 = src[offset+bs+1];
- uint32_t rb00 = p00 & 0x00FF00FF;
- uint32_t rb01 = p01 & 0x00FF00FF;
- uint32_t rb10 = p10 & 0x00FF00FF;
- uint32_t rb11 = p11 & 0x00FF00FF;
- uint32_t ga00 = (p00 >> 8) & 0x00FF00FF;
- uint32_t ga01 = (p01 >> 8) & 0x00FF00FF;
- uint32_t ga10 = (p10 >> 8) & 0x00FF00FF;
- uint32_t ga11 = (p11 >> 8) & 0x00FF00FF;
- uint32_t rb = (rb00 + rb01 + rb10 + rb11)>>2;
- uint32_t ga = (ga00 + ga01 + ga10 + ga11)>>2;
- uint32_t rgba = (rb & 0x00FF00FF) | ((ga & 0x00FF00FF)<<8);
- dst[x + y*stride] = rgba;
- offset += 2;
- }
- }
- }
- else if ((base->format == GGL_PIXEL_FORMAT_RGB_888) ||
- (base->format == GGL_PIXEL_FORMAT_LA_88) ||
- (base->format == GGL_PIXEL_FORMAT_A_8) ||
- (base->format == GGL_PIXEL_FORMAT_L_8))
- {
- int skip;
- switch (base->format) {
- case GGL_PIXEL_FORMAT_RGB_888: skip = 3; break;
- case GGL_PIXEL_FORMAT_LA_88: skip = 2; break;
- default: skip = 1; break;
- }
- uint8_t const * src = (uint8_t const *)base->data;
- uint8_t* dst = (uint8_t*)cur.data;
- bs *= skip;
- stride *= skip;
- for (int y=0 ; y<h ; y++) {
- size_t offset = (y*2) * bs;
- for (int x=0 ; x<w ; x++) {
- for (int c=0 ; c<skip ; c++) {
- uint32_t p00 = src[c+offset];
- uint32_t p10 = src[c+offset+skip];
- uint32_t p01 = src[c+offset+bs];
- uint32_t p11 = src[c+offset+bs+skip];
- dst[x + y*stride + c] = (p00 + p10 + p01 + p11) >> 2;
- }
- offset += 2*skip;
- }
- }
- }
- else if (base->format == GGL_PIXEL_FORMAT_RGBA_4444)
- {
- uint16_t const * src = (uint16_t const *)base->data;
- uint16_t* dst = (uint16_t*)cur.data;
- for (int y=0 ; y<h ; y++) {
- size_t offset = (y*2) * bs;
- for (int x=0 ; x<w ; x++) {
- uint32_t p00 = src[offset];
- uint32_t p10 = src[offset+1];
- uint32_t p01 = src[offset+bs];
- uint32_t p11 = src[offset+bs+1];
- p00 = ((p00 << 12) & 0x0F0F0000) | (p00 & 0x0F0F);
- p10 = ((p10 << 12) & 0x0F0F0000) | (p10 & 0x0F0F);
- p01 = ((p01 << 12) & 0x0F0F0000) | (p01 & 0x0F0F);
- p11 = ((p11 << 12) & 0x0F0F0000) | (p11 & 0x0F0F);
- uint32_t rbga = (p00 + p10 + p01 + p11) >> 2;
- uint32_t rgba = (rbga & 0x0F0F) | ((rbga>>12) & 0xF0F0);
- dst[x + y*stride] = rgba;
- offset += 2;
- }
- }
- } else {
- ALOGE("Unsupported format (%d)", base->format);
- return BAD_TYPE;
- }
-
- // exit condition: we just processed the 1x1 LODs
- if ((w&h) == 1)
- break;
-
- base = &cur;
- w = (w>>1) ? : 1;
- h = (h>>1) ? : 1;
- }
- return NO_ERROR;
-}
-
-}; // namespace android
diff --git a/opengl/libagl/primitives.cpp b/opengl/libagl/primitives.cpp
deleted file mode 100644
index d3b19e8..0000000
--- a/opengl/libagl/primitives.cpp
+++ /dev/null
@@ -1,1112 +0,0 @@
-/* libs/opengles/primitives.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "context.h"
-#include "primitives.h"
-#include "light.h"
-#include "matrix.h"
-#include "vertex.h"
-#include "fp.h"
-#include "TextureObjectManager.h"
-
-extern "C" void iterators0032(const void* that,
- int32_t* it, int32_t c0, int32_t c1, int32_t c2);
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static void primitive_point(ogles_context_t* c, vertex_t* v);
-static void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
-static void primitive_clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static void primitive_nop_point(ogles_context_t* c, vertex_t* v);
-static void primitive_nop_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1);
-static void primitive_nop_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static inline bool cull_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static void lerp_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static void lerp_texcoords(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static void lerp_texcoords_w(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static void triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static void clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2);
-
-static unsigned int clip_line(ogles_context_t* c,
- vertex_t* s, vertex_t* p);
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-static void lightTriangleDarkSmooth(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- if (!(v0->flags & vertex_t::LIT)) {
- v0->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v0->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v0->color.v, cp);
- }
- if (!(v1->flags & vertex_t::LIT)) {
- v1->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v1->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v1->color.v, cp);
- }
- if(!(v2->flags & vertex_t::LIT)) {
- v2->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v2->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v2->color.v, cp);
- }
-}
-
-static void lightTriangleDarkFlat(ogles_context_t* c,
- vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2)
-{
- if (!(v2->flags & vertex_t::LIT)) {
- v2->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v2->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v2->color.v, cp);
- }
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
-}
-
-static void lightTriangleSmooth(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- if (!(v0->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v0);
- if (!(v1->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v1);
- if(!(v2->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v2);
-}
-
-static void lightTriangleFlat(ogles_context_t* c,
- vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* v2)
-{
- if (!(v2->flags & vertex_t::LIT))
- c->lighting.lightVertex(c, v2);
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
-}
-
-// The fog versions...
-
-static inline
-void lightVertexDarkSmoothFog(ogles_context_t* c, vertex_t* v)
-{
- if (!(v->flags & vertex_t::LIT)) {
- v->flags |= vertex_t::LIT;
- v->fog = c->fog.fog(c, v->eye.z);
- const GLvoid* cp = c->arrays.color.element(
- v->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v->color.v, cp);
- }
-}
-static inline
-void lightVertexDarkFlatFog(ogles_context_t* c, vertex_t* v)
-{
- if (!(v->flags & vertex_t::LIT)) {
- v->flags |= vertex_t::LIT;
- v->fog = c->fog.fog(c, v->eye.z);
- }
-}
-static inline
-void lightVertexSmoothFog(ogles_context_t* c, vertex_t* v)
-{
- if (!(v->flags & vertex_t::LIT)) {
- v->fog = c->fog.fog(c, v->eye.z);
- c->lighting.lightVertex(c, v);
- }
-}
-
-static void lightTriangleDarkSmoothFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- lightVertexDarkSmoothFog(c, v0);
- lightVertexDarkSmoothFog(c, v1);
- lightVertexDarkSmoothFog(c, v2);
-}
-
-static void lightTriangleDarkFlatFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- lightVertexDarkFlatFog(c, v0);
- lightVertexDarkFlatFog(c, v1);
- lightVertexDarkSmoothFog(c, v2);
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
-}
-
-static void lightTriangleSmoothFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- lightVertexSmoothFog(c, v0);
- lightVertexSmoothFog(c, v1);
- lightVertexSmoothFog(c, v2);
-}
-
-static void lightTriangleFlatFog(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- lightVertexDarkFlatFog(c, v0);
- lightVertexDarkFlatFog(c, v1);
- lightVertexSmoothFog(c, v2);
- // configure the rasterizer here, before we clip
- c->rasterizer.procs.color4xv(c, v2->color.v);
-}
-
-
-
-typedef void (*light_primitive_t)(ogles_context_t*,
- vertex_t*, vertex_t*, vertex_t*);
-
-// fog 0x4, light 0x2, smooth 0x1
-static const light_primitive_t lightPrimitive[8] = {
- lightTriangleDarkFlat, // no fog | dark | flat
- lightTriangleDarkSmooth, // no fog | dark | smooth
- lightTriangleFlat, // no fog | light | flat
- lightTriangleSmooth, // no fog | light | smooth
- lightTriangleDarkFlatFog, // fog | dark | flat
- lightTriangleDarkSmoothFog, // fog | dark | smooth
- lightTriangleFlatFog, // fog | light | flat
- lightTriangleSmoothFog // fog | light | smooth
-};
-
-void ogles_validate_primitives(ogles_context_t* c)
-{
- const uint32_t enables = c->rasterizer.state.enables;
-
- // set up the lighting/shading/smoothing/fogging function
- int index = enables & GGL_ENABLE_SMOOTH ? 0x1 : 0;
- index |= c->lighting.enable ? 0x2 : 0;
- index |= enables & GGL_ENABLE_FOG ? 0x4 : 0;
- c->lighting.lightTriangle = lightPrimitive[index];
-
- // set up the primitive renderers
- if (ggl_likely(c->arrays.vertex.enable)) {
- c->prims.renderPoint = primitive_point;
- c->prims.renderLine = primitive_line;
- c->prims.renderTriangle = primitive_clip_triangle;
- } else {
- c->prims.renderPoint = primitive_nop_point;
- c->prims.renderLine = primitive_nop_line;
- c->prims.renderTriangle = primitive_nop_triangle;
- }
-}
-
-// ----------------------------------------------------------------------------
-
-void compute_iterators_t::initTriangle(
- vertex_t const* v0, vertex_t const* v1, vertex_t const* v2)
-{
- m_dx01 = v1->window.x - v0->window.x;
- m_dy10 = v0->window.y - v1->window.y;
- m_dx20 = v0->window.x - v2->window.x;
- m_dy02 = v2->window.y - v0->window.y;
- m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
- (void)m_reserved; // suppress unused warning
-}
-
-void compute_iterators_t::initLine(
- vertex_t const* v0, vertex_t const* v1)
-{
- m_dx01 = m_dy02 = v1->window.x - v0->window.x;
- m_dy10 = m_dx20 = v0->window.y - v1->window.y;
- m_area = m_dx01*m_dy02 + (-m_dy10)*m_dx20;
-}
-
-void compute_iterators_t::initLerp(vertex_t const* v0, uint32_t enables)
-{
- m_x0 = v0->window.x;
- m_y0 = v0->window.y;
- const GGLcoord area = (m_area + TRI_HALF) >> TRI_FRACTION_BITS;
- const GGLcoord minArea = 2; // cannot be inverted
- // triangles with an area smaller than 1.0 are not smooth-shaded
-
- int q=0, s=0, d=0;
- if (abs(area) >= minArea) {
- // Here we do some voodoo magic, to compute a suitable scale
- // factor for deltas/area:
-
- // First compute the 1/area with full 32-bits precision,
- // gglRecipQNormalized returns a number [-0.5, 0.5[ and an exponent.
- d = gglRecipQNormalized(area, &q);
-
- // Then compute the minimum left-shift to not overflow the muls
- // below.
- s = 32 - gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
-
- // We'll keep 16-bits of precision for deltas/area. So we need
- // to shift everything left an extra 15 bits.
- s += 15;
-
- // make sure all final shifts are not > 32, because gglMulx
- // can't handle it.
- if (s < q) s = q;
- if (s > 32) {
- d >>= 32-s;
- s = 32;
- }
- }
-
- m_dx01 = gglMulx(m_dx01, d, s);
- m_dy10 = gglMulx(m_dy10, d, s);
- m_dx20 = gglMulx(m_dx20, d, s);
- m_dy02 = gglMulx(m_dy02, d, s);
- m_area_scale = 32 + q - s;
- m_scale = 0;
-
- if (enables & GGL_ENABLE_TMUS) {
- const int A = gglClz(abs(m_dy02)|abs(m_dy10)|abs(m_dx01)|abs(m_dx20));
- const int B = gglClz(abs(m_x0)|abs(m_y0));
- m_scale = max(0, 32 - (A + 16)) +
- max(0, 32 - (B + TRI_FRACTION_BITS)) + 1;
- }
-}
-
-int compute_iterators_t::iteratorsScale(GGLfixed* it,
- int32_t c0, int32_t c1, int32_t c2) const
-{
- int32_t dc01 = c1 - c0;
- int32_t dc02 = c2 - c0;
- const int A = gglClz(abs(c0));
- const int B = gglClz(abs(dc01)|abs(dc02));
- const int scale = min(A, B - m_scale) - 2;
- if (scale >= 0) {
- c0 <<= scale;
- dc01 <<= scale;
- dc02 <<= scale;
- } else {
- c0 >>= -scale;
- dc01 >>= -scale;
- dc02 >>= -scale;
- }
- const int s = m_area_scale;
- int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
- int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
- int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
- gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
- it[0] = c;
- it[1] = dcdx;
- it[2] = dcdy;
- return scale;
-}
-
-void compute_iterators_t::iterators1616(GGLfixed* it,
- GGLfixed c0, GGLfixed c1, GGLfixed c2) const
-{
- const GGLfixed dc01 = c1 - c0;
- const GGLfixed dc02 = c2 - c0;
- // 16.16 x 16.16 == 32.32 --> 16.16
- const int s = m_area_scale;
- int32_t dcdx = gglMulAddx(dc01, m_dy02, gglMulx(dc02, m_dy10, s), s);
- int32_t dcdy = gglMulAddx(dc02, m_dx01, gglMulx(dc01, m_dx20, s), s);
- int32_t c = c0 - (gglMulAddx(dcdx, m_x0,
- gglMulx(dcdy, m_y0, TRI_FRACTION_BITS), TRI_FRACTION_BITS));
- it[0] = c;
- it[1] = dcdx;
- it[2] = dcdy;
-}
-
-void compute_iterators_t::iterators0032(int64_t* it,
- int32_t c0, int32_t c1, int32_t c2) const
-{
- const int s = m_area_scale - 16;
- int32_t dc01 = (c1 - c0)>>s;
- int32_t dc02 = (c2 - c0)>>s;
- // 16.16 x 16.16 == 32.32
- int64_t dcdx = gglMulii(dc01, m_dy02) + gglMulii(dc02, m_dy10);
- int64_t dcdy = gglMulii(dc02, m_dx01) + gglMulii(dc01, m_dx20);
- it[ 0] = (c0<<16) - ((dcdx*m_x0 + dcdy*m_y0)>>4);
- it[ 1] = dcdx;
- it[ 2] = dcdy;
-}
-
-#if defined(__arm__) && !defined(__thumb__)
-inline void compute_iterators_t::iterators0032(int32_t* it,
- int32_t c0, int32_t c1, int32_t c2) const
-{
- ::iterators0032(this, it, c0, c1, c2);
-}
-#else
-void compute_iterators_t::iterators0032(int32_t* it,
- int32_t c0, int32_t c1, int32_t c2) const
-{
- int64_t it64[3];
- iterators0032(it64, c0, c1, c2);
- it[0] = it64[0];
- it[1] = it64[1];
- it[2] = it64[2];
-}
-#endif
-
-// ----------------------------------------------------------------------------
-
-static inline int32_t clampZ(GLfixed z) CONST;
-int32_t clampZ(GLfixed z) {
- z = (z & ~(z>>31));
- if (z >= 0x10000)
- z = 0xFFFF;
- return z;
-}
-
-static __attribute__((noinline))
-void fetch_texcoord_impl(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- vertex_t* const vtx[3] = { v0, v1, v2 };
- array_t const * const texcoordArray = c->arrays.texture;
-
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (!(c->rasterizer.state.texture[i].enable))
- continue;
-
- for (int j=0 ; j<3 ; j++) {
- vertex_t* const v = vtx[j];
- if (v->flags & vertex_t::TT)
- continue;
-
- // NOTE: here we could compute automatic texgen
- // such as sphere/cube maps, instead of fetching them
- // from the textcoord array.
-
- vec4_t& coords = v->texture[i];
- const GLubyte* tp = texcoordArray[i].element(
- v->index & vertex_cache_t::INDEX_MASK);
- texcoordArray[i].fetch(c, coords.v, tp);
-
- // transform texture coordinates...
- coords.Q = 0x10000;
- const transform_t& tr = c->transforms.texture[i].transform;
- if (ggl_unlikely(tr.ops)) {
- c->arrays.tex_transform[i](&tr, &coords, &coords);
- }
-
- // divide by Q
- const GGLfixed q = coords.Q;
- if (ggl_unlikely(q != 0x10000)) {
- const int32_t qinv = gglRecip28(q);
- coords.S = gglMulx(coords.S, qinv, 28);
- coords.T = gglMulx(coords.T, qinv, 28);
- }
- }
- }
- v0->flags |= vertex_t::TT;
- v1->flags |= vertex_t::TT;
- v2->flags |= vertex_t::TT;
-}
-
-inline void fetch_texcoord(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- const uint32_t enables = c->rasterizer.state.enables;
- if (!(enables & GGL_ENABLE_TMUS))
- return;
-
- // Fetch & transform texture coordinates...
- if (ggl_likely(v0->flags & v1->flags & v2->flags & vertex_t::TT)) {
- // already done for all three vertices, bail...
- return;
- }
- fetch_texcoord_impl(c, v0, v1, v2);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Point
-#endif
-
-void primitive_nop_point(ogles_context_t*, vertex_t*) {
-}
-
-void primitive_point(ogles_context_t* c, vertex_t* v)
-{
- // lighting & clamping...
- const uint32_t enables = c->rasterizer.state.enables;
-
- if (ggl_unlikely(!(v->flags & vertex_t::LIT))) {
- if (c->lighting.enable) {
- c->lighting.lightVertex(c, v);
- } else {
- v->flags |= vertex_t::LIT;
- const GLvoid* cp = c->arrays.color.element(
- v->index & vertex_cache_t::INDEX_MASK);
- c->arrays.color.fetch(c, v->color.v, cp);
- }
- if (enables & GGL_ENABLE_FOG) {
- v->fog = c->fog.fog(c, v->eye.z);
- }
- }
-
- // XXX: we don't need to do that each-time
- // if color array and lighting not enabled
- c->rasterizer.procs.color4xv(c, v->color.v);
-
- // XXX: look into ES point-sprite extension
- if (enables & GGL_ENABLE_TMUS) {
- fetch_texcoord(c, v,v,v);
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (!c->rasterizer.state.texture[i].enable)
- continue;
- int32_t itt[8];
- itt[1] = itt[2] = itt[4] = itt[5] = 0;
- itt[6] = itt[7] = 16; // XXX: check that
- if (c->rasterizer.state.texture[i].s_wrap == GGL_CLAMP) {
- int width = c->textures.tmu[i].texture->surface.width;
- itt[0] = v->texture[i].S * width;
- itt[6] = 0;
- }
- if (c->rasterizer.state.texture[i].t_wrap == GGL_CLAMP) {
- int height = c->textures.tmu[i].texture->surface.height;
- itt[3] = v->texture[i].T * height;
- itt[7] = 0;
- }
- c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
- }
- }
-
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- int32_t itz[3];
- itz[0] = clampZ(v->window.z) * 0x00010001;
- itz[1] = itz[2] = 0;
- c->rasterizer.procs.zGrad3xv(c, itz);
- }
-
- if (enables & GGL_ENABLE_FOG) {
- GLfixed itf[3];
- itf[0] = v->fog;
- itf[1] = itf[2] = 0;
- c->rasterizer.procs.fogGrad3xv(c, itf);
- }
-
- // Render our point...
- c->rasterizer.procs.pointx(c, v->window.v, c->point.size);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Line
-#endif
-
-void primitive_nop_line(ogles_context_t*, vertex_t*, vertex_t*) {
-}
-
-void primitive_line(ogles_context_t* c, vertex_t* v0, vertex_t* v1)
-{
- // get texture coordinates
- fetch_texcoord(c, v0, v1, v1);
-
- // light/shade the vertices first (they're copied below)
- c->lighting.lightTriangle(c, v0, v1, v1);
-
- // clip the line if needed
- if (ggl_unlikely((v0->flags | v1->flags) & vertex_t::CLIP_ALL)) {
- unsigned int count = clip_line(c, v0, v1);
- if (ggl_unlikely(count == 0))
- return;
- }
-
- // compute iterators...
- const uint32_t enables = c->rasterizer.state.enables;
- const uint32_t mask = GGL_ENABLE_TMUS |
- GGL_ENABLE_SMOOTH |
- GGL_ENABLE_W |
- GGL_ENABLE_FOG |
- GGL_ENABLE_DEPTH_TEST;
-
- if (ggl_unlikely(enables & mask)) {
- c->lerp.initLine(v0, v1);
- lerp_triangle(c, v0, v1, v0);
- }
-
- // render our line
- c->rasterizer.procs.linex(c, v0->window.v, v1->window.v, c->line.width);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Triangle
-#endif
-
-void primitive_nop_triangle(ogles_context_t* /*c*/,
- vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/) {
-}
-
-void primitive_clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- uint32_t cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
- if (ggl_likely(!cc)) {
- // code below must be as optimized as possible, this is the
- // common code path.
-
- // This triangle is not clipped, test if it's culled
- // unclipped triangle...
- c->lerp.initTriangle(v0, v1, v2);
- if (cull_triangle(c, v0, v1, v2))
- return; // culled!
-
- // Fetch all texture coordinates if needed
- fetch_texcoord(c, v0, v1, v2);
-
- // light (or shade) our triangle!
- c->lighting.lightTriangle(c, v0, v1, v2);
-
- triangle(c, v0, v1, v2);
- return;
- }
-
- // The assumption here is that we're not going to clip very often,
- // and even more rarely will we clip a triangle that ends up
- // being culled out. So it's okay to light the vertices here, even though
- // in a few cases we won't render the triangle (if culled).
-
- // Fetch texture coordinates...
- fetch_texcoord(c, v0, v1, v2);
-
- // light (or shade) our triangle!
- c->lighting.lightTriangle(c, v0, v1, v2);
-
- clip_triangle(c, v0, v1, v2);
-}
-
-// -----------------------------------------------------------------------
-
-void triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- // compute iterators...
- const uint32_t enables = c->rasterizer.state.enables;
- const uint32_t mask = GGL_ENABLE_TMUS |
- GGL_ENABLE_SMOOTH |
- GGL_ENABLE_W |
- GGL_ENABLE_FOG |
- GGL_ENABLE_DEPTH_TEST;
-
- if (ggl_likely(enables & mask))
- lerp_triangle(c, v0, v1, v2);
-
- c->rasterizer.procs.trianglex(c, v0->window.v, v1->window.v, v2->window.v);
-}
-
-void lerp_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- const uint32_t enables = c->rasterizer.state.enables;
- c->lerp.initLerp(v0, enables);
-
- // set up texture iterators
- if (enables & GGL_ENABLE_TMUS) {
- if (enables & GGL_ENABLE_W) {
- lerp_texcoords_w(c, v0, v1, v2);
- } else {
- lerp_texcoords(c, v0, v1, v2);
- }
- }
-
- // set up the color iterators
- const compute_iterators_t& lerp = c->lerp;
- if (enables & GGL_ENABLE_SMOOTH) {
- GLfixed itc[12];
- for (int i=0 ; i<4 ; i++) {
- const GGLcolor c0 = v0->color.v[i] * 255;
- const GGLcolor c1 = v1->color.v[i] * 255;
- const GGLcolor c2 = v2->color.v[i] * 255;
- lerp.iterators1616(&itc[i*3], c0, c1, c2);
- }
- c->rasterizer.procs.colorGrad12xv(c, itc);
- }
-
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- int32_t itz[3];
- const int32_t v0z = clampZ(v0->window.z);
- const int32_t v1z = clampZ(v1->window.z);
- const int32_t v2z = clampZ(v2->window.z);
- if (ggl_unlikely(c->polygonOffset.enable)) {
- const int32_t units = (c->polygonOffset.units << 16);
- const GLfixed factor = c->polygonOffset.factor;
- if (factor) {
- int64_t itz64[3];
- lerp.iterators0032(itz64, v0z, v1z, v2z);
- int64_t maxDepthSlope = max(itz64[1], itz64[2]);
- itz[0] = uint32_t(itz64[0])
- + uint32_t((maxDepthSlope*factor)>>16) + units;
- itz[1] = uint32_t(itz64[1]);
- itz[2] = uint32_t(itz64[2]);
- } else {
- lerp.iterators0032(itz, v0z, v1z, v2z);
- itz[0] += units;
- }
- } else {
- lerp.iterators0032(itz, v0z, v1z, v2z);
- }
- c->rasterizer.procs.zGrad3xv(c, itz);
- }
-
- if (ggl_unlikely(enables & GGL_ENABLE_FOG)) {
- GLfixed itf[3];
- lerp.iterators1616(itf, v0->fog, v1->fog, v2->fog);
- c->rasterizer.procs.fogGrad3xv(c, itf);
- }
-}
-
-
-static inline
-int compute_lod(ogles_context_t* c, int i,
- int32_t s0, int32_t t0, int32_t s1, int32_t t1, int32_t s2, int32_t t2)
-{
- // Compute mipmap level / primitive
- // rho = sqrt( texelArea / area )
- // lod = log2( rho )
- // lod = log2( texelArea / area ) / 2
- // lod = (log2( texelArea ) - log2( area )) / 2
- const compute_iterators_t& lerp = c->lerp;
- const GGLcoord area = abs(lerp.area());
- const int w = c->textures.tmu[i].texture->surface.width;
- const int h = c->textures.tmu[i].texture->surface.height;
- const int shift = 16 + (16 - TRI_FRACTION_BITS);
- int32_t texelArea = abs( gglMulx(s1-s0, t2-t0, shift) -
- gglMulx(s2-s0, t1-t0, shift) )*w*h;
- int log2TArea = (32-TRI_FRACTION_BITS -1) - gglClz(texelArea);
- int log2Area = (32-TRI_FRACTION_BITS*2-1) - gglClz(area);
- int lod = (log2TArea - log2Area + 1) >> 1;
- return lod;
-}
-
-void lerp_texcoords(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- const compute_iterators_t& lerp = c->lerp;
- int32_t itt[8] __attribute__((aligned(16)));
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- const texture_t& tmu = c->rasterizer.state.texture[i];
- if (!tmu.enable)
- continue;
-
- // compute the jacobians using block floating-point
- int32_t s0 = v0->texture[i].S;
- int32_t t0 = v0->texture[i].T;
- int32_t s1 = v1->texture[i].S;
- int32_t t1 = v1->texture[i].T;
- int32_t s2 = v2->texture[i].S;
- int32_t t2 = v2->texture[i].T;
-
- const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
- if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
- int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
- c->rasterizer.procs.bindTextureLod(c, i,
- &c->textures.tmu[i].texture->mip(lod));
- }
-
- // premultiply (s,t) when clampling
- if (tmu.s_wrap == GGL_CLAMP) {
- const int width = tmu.surface.width;
- s0 *= width;
- s1 *= width;
- s2 *= width;
- }
- if (tmu.t_wrap == GGL_CLAMP) {
- const int height = tmu.surface.height;
- t0 *= height;
- t1 *= height;
- t2 *= height;
- }
- itt[6] = -lerp.iteratorsScale(itt+0, s0, s1, s2);
- itt[7] = -lerp.iteratorsScale(itt+3, t0, t1, t2);
- c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
- }
-}
-
-void lerp_texcoords_w(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- const compute_iterators_t& lerp = c->lerp;
- int32_t itt[8] __attribute__((aligned(16)));
- int32_t itw[3];
-
- // compute W's scale to 2.30
- int32_t w0 = v0->window.w;
- int32_t w1 = v1->window.w;
- int32_t w2 = v2->window.w;
- int wscale = 32 - gglClz(w0|w1|w2);
-
- // compute the jacobian using block floating-point
- int sc = lerp.iteratorsScale(itw, w0, w1, w2);
- sc += wscale - 16;
- c->rasterizer.procs.wGrad3xv(c, itw);
-
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- const texture_t& tmu = c->rasterizer.state.texture[i];
- if (!tmu.enable)
- continue;
-
- // compute the jacobians using block floating-point
- int32_t s0 = v0->texture[i].S;
- int32_t t0 = v0->texture[i].T;
- int32_t s1 = v1->texture[i].S;
- int32_t t1 = v1->texture[i].T;
- int32_t s2 = v2->texture[i].S;
- int32_t t2 = v2->texture[i].T;
-
- const GLenum min_filter = c->textures.tmu[i].texture->min_filter;
- if (ggl_unlikely(min_filter >= GL_NEAREST_MIPMAP_NEAREST)) {
- int lod = compute_lod(c, i, s0, t0, s1, t1, s2, t2);
- c->rasterizer.procs.bindTextureLod(c, i,
- &c->textures.tmu[i].texture->mip(lod));
- }
-
- // premultiply (s,t) when clampling
- if (tmu.s_wrap == GGL_CLAMP) {
- const int width = tmu.surface.width;
- s0 *= width;
- s1 *= width;
- s2 *= width;
- }
- if (tmu.t_wrap == GGL_CLAMP) {
- const int height = tmu.surface.height;
- t0 *= height;
- t1 *= height;
- t2 *= height;
- }
-
- s0 = gglMulx(s0, w0, wscale);
- t0 = gglMulx(t0, w0, wscale);
- s1 = gglMulx(s1, w1, wscale);
- t1 = gglMulx(t1, w1, wscale);
- s2 = gglMulx(s2, w2, wscale);
- t2 = gglMulx(t2, w2, wscale);
-
- itt[6] = sc - lerp.iteratorsScale(itt+0, s0, s1, s2);
- itt[7] = sc - lerp.iteratorsScale(itt+3, t0, t1, t2);
- c->rasterizer.procs.texCoordGradScale8xv(c, i, itt);
- }
-}
-
-
-static inline
-bool cull_triangle(ogles_context_t* c, vertex_t* /*v0*/, vertex_t* /*v1*/, vertex_t* /*v2*/)
-{
- if (ggl_likely(c->cull.enable)) {
- const GLenum winding = (c->lerp.area() > 0) ? GL_CW : GL_CCW;
- const GLenum face = (winding == c->cull.frontFace) ? GL_FRONT : GL_BACK;
- if (face == c->cull.cullFace)
- return true; // culled!
- }
- return false;
-}
-
-static inline
-GLfixed frustumPlaneDist(int plane, const vec4_t& s)
-{
- const GLfixed d = s.v[ plane >> 1 ];
- return ((plane & 1) ? (s.w - d) : (s.w + d));
-}
-
-static inline
-int32_t clipDivide(GLfixed a, GLfixed b) {
- // returns a 4.28 fixed-point
- return gglMulDivi(1LU<<28, a, b);
-}
-
-void clip_triangle(ogles_context_t* c,
- vertex_t* v0, vertex_t* v1, vertex_t* v2)
-{
- uint32_t all_cc = (v0->flags | v1->flags | v2->flags) & vertex_t::CLIP_ALL;
-
- vertex_t *p0, *p1, *p2;
- const int MAX_CLIPPING_PLANES = 6 + OGLES_MAX_CLIP_PLANES;
- const int MAX_VERTICES = 3;
-
- // Temporary buffer to hold the new vertices. Each plane can add up to
- // two new vertices (because the polygon is convex).
- // We need one extra element, to handle an overflow case when
- // the polygon degenerates into something non convex.
- vertex_t buffer[MAX_CLIPPING_PLANES * 2 + 1]; // ~3KB
- vertex_t* buf = buffer;
-
- // original list of vertices (polygon to clip, in fact this
- // function works with an arbitrary polygon).
- vertex_t* in[3] = { v0, v1, v2 };
-
- // output lists (we need 2, which we use back and forth)
- // (maximum outpout list's size is MAX_CLIPPING_PLANES + MAX_VERTICES)
- // 2 more elements for overflow when non convex polygons.
- vertex_t* out[2][MAX_CLIPPING_PLANES + MAX_VERTICES + 2];
- unsigned int outi = 0;
-
- // current input list
- vertex_t** ivl = in;
-
- // 3 input vertices, 0 in the output list, first plane
- unsigned int ic = 3;
-
- // User clip-planes first, the clipping is always done in eye-coordinate
- // this is basically the same algorithm than for the view-volume
- // clipping, except for the computation of the distance (vertex, plane)
- // and the fact that we need to compute the eye-coordinates of each
- // new vertex we create.
-
- if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
- {
- unsigned int plane = 0;
- uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
- do {
- if (cc & 1) {
- // pointers to our output list (head and current)
- vertex_t** const ovl = &out[outi][0];
- vertex_t** output = ovl;
- unsigned int oc = 0;
- unsigned int sentinel = 0;
- // previous vertex, compute distance to the plane
- vertex_t* s = ivl[ic-1];
- const vec4_t& equation = c->clipPlanes.plane[plane].equation;
- GLfixed sd = dot4(equation.v, s->eye.v);
- // clip each vertex against this plane...
- for (unsigned int i=0 ; i<ic ; i++) {
- vertex_t* p = ivl[i];
- const GLfixed pd = dot4(equation.v, p->eye.v);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- *output++ = p;
- oc++;
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipEye(c, buf, t, p, s);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipEye(c, buf, t, s, p);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- *output++ = p;
- oc++;
- } else {
- // both outside
- }
- }
- s = p;
- sd = pd;
- }
- // output list become the new input list
- if (oc<3)
- return; // less than 3 vertices left? we're done!
- ivl = ovl;
- ic = oc;
- outi = 1-outi;
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
-
- // frustum clip-planes
- if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
- {
- unsigned int plane = 0;
- uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
- do {
- if (cc & 1) {
- // pointers to our output list (head and current)
- vertex_t** const ovl = &out[outi][0];
- vertex_t** output = ovl;
- unsigned int oc = 0;
- unsigned int sentinel = 0;
- // previous vertex, compute distance to the plane
- vertex_t* s = ivl[ic-1];
- GLfixed sd = frustumPlaneDist(plane, s->clip);
- // clip each vertex against this plane...
- for (unsigned int i=0 ; i<ic ; i++) {
- vertex_t* p = ivl[i];
- const GLfixed pd = frustumPlaneDist(plane, p->clip);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- *output++ = p;
- oc++;
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipVertex(c, buf, t, p, s);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipVertex(c, buf, t, s, p);
- *output++ = buf++;
- oc++;
- if (++sentinel >= 3)
- return; // non-convex polygon!
- }
- *output++ = p;
- oc++;
- } else {
- // both outside
- }
- }
- s = p;
- sd = pd;
- }
- // output list become the new input list
- if (oc<3)
- return; // less than 3 vertices left? we're done!
- ivl = ovl;
- ic = oc;
- outi = 1-outi;
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
-
- // finally we can render our triangles...
- p0 = ivl[0];
- p1 = ivl[1];
- for (unsigned int i=2 ; i<ic ; i++) {
- p2 = ivl[i];
- c->lerp.initTriangle(p0, p1, p2);
- if (cull_triangle(c, p0, p1, p2)) {
- p1 = p2;
- continue; // culled!
- }
- triangle(c, p0, p1, p2);
- p1 = p2;
- }
-}
-
-unsigned int clip_line(ogles_context_t* c, vertex_t* s, vertex_t* p)
-{
- const uint32_t all_cc = (s->flags | p->flags) & vertex_t::CLIP_ALL;
-
- if (ggl_unlikely(all_cc & vertex_t::USER_CLIP_ALL))
- {
- unsigned int plane = 0;
- uint32_t cc = (all_cc & vertex_t::USER_CLIP_ALL) >> 8;
- do {
- if (cc & 1) {
- const vec4_t& equation = c->clipPlanes.plane[plane].equation;
- const GLfixed sd = dot4(equation.v, s->eye.v);
- const GLfixed pd = dot4(equation.v, p->eye.v);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipEye(c, p, t, p, s);
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipEye(c, s, t, s, p);
- }
- } else {
- // both outside
- return 0;
- }
- }
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
-
- // frustum clip-planes
- if (all_cc & vertex_t::FRUSTUM_CLIP_ALL)
- {
- unsigned int plane = 0;
- uint32_t cc = all_cc & vertex_t::FRUSTUM_CLIP_ALL;
- do {
- if (cc & 1) {
- const GLfixed sd = frustumPlaneDist(plane, s->clip);
- const GLfixed pd = frustumPlaneDist(plane, p->clip);
- if (sd >= 0) {
- if (pd >= 0) {
- // both inside
- } else {
- // s inside, p outside (exiting)
- const GLfixed t = clipDivide(sd, sd-pd);
- c->arrays.clipVertex(c, p, t, p, s);
- }
- } else {
- if (pd >= 0) {
- // s outside (entering)
- if (pd) {
- const GLfixed t = clipDivide(pd, pd-sd);
- c->arrays.clipVertex(c, s, t, s, p);
- }
- } else {
- // both outside
- return 0;
- }
- }
- }
- cc >>= 1;
- plane++;
- } while (cc);
- }
-
- return 2;
-}
-
-
-}; // namespace android
diff --git a/opengl/libagl/primitives.h b/opengl/libagl/primitives.h
deleted file mode 100644
index 1bef604..0000000
--- a/opengl/libagl/primitives.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/* libs/opengles/primitives.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_PRIMITIVES_H
-#define ANDROID_OPENGLES_PRIMITIVES_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-
-namespace android {
-
-namespace gl {
-struct ogles_context_t;
-};
-
-void ogles_validate_primitives(ogles_context_t* c);
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_PRIMITIVES_H
-
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
deleted file mode 100644
index 8bb7e83..0000000
--- a/opengl/libagl/state.cpp
+++ /dev/null
@@ -1,598 +0,0 @@
-/* libs/opengles/state.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdlib.h>
-
-#include "context.h"
-#include "fp.h"
-#include "state.h"
-#include "array.h"
-#include "matrix.h"
-#include "vertex.h"
-#include "light.h"
-#include "texture.h"
-#include "BufferObjectManager.h"
-#include "TextureObjectManager.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static char const * const gVendorString = "Android";
-static char const * const gRendererString = "Android PixelFlinger 1.4";
-static char const * const gVersionString = "OpenGL ES-CM 1.0";
-static char const * const gExtensionsString =
- "GL_OES_byte_coordinates " // OK
- "GL_OES_fixed_point " // OK
- "GL_OES_single_precision " // OK
- "GL_OES_read_format " // OK
- "GL_OES_compressed_paletted_texture " // OK
- "GL_OES_draw_texture " // OK
- "GL_OES_matrix_get " // OK
- "GL_OES_query_matrix " // OK
- // "GL_OES_point_size_array " // TODO
- // "GL_OES_point_sprite " // TODO
- "GL_OES_EGL_image " // OK
- "GL_OES_EGL_sync " // OK
-#ifdef GL_OES_compressed_ETC1_RGB8_texture
- "GL_OES_compressed_ETC1_RGB8_texture " // OK
-#endif
- "GL_ARB_texture_compression " // OK
- "GL_ARB_texture_non_power_of_two " // OK
- "GL_ANDROID_user_clip_plane " // OK
- "GL_ANDROID_vertex_buffer_object " // OK
- "GL_ANDROID_generate_mipmap " // OK
- ;
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-ogles_context_t *ogles_init(size_t extra)
-{
- void* const base = malloc(extra + sizeof(ogles_context_t) + 32);
- if (!base) return 0;
-
- ogles_context_t *c =
- (ogles_context_t *)((ptrdiff_t(base) + extra + 31) & ~0x1FL);
- memset(c, 0, sizeof(ogles_context_t));
- ggl_init_context(&(c->rasterizer));
-
- // XXX: this should be passed as an argument
- sp<EGLSurfaceManager> smgr(new EGLSurfaceManager());
- c->surfaceManager = smgr.get();
- c->surfaceManager->incStrong(c);
-
- sp<EGLBufferObjectManager> bomgr(new EGLBufferObjectManager());
- c->bufferObjectManager = bomgr.get();
- c->bufferObjectManager->incStrong(c);
-
- ogles_init_array(c);
- ogles_init_matrix(c);
- ogles_init_vertex(c);
- ogles_init_light(c);
- ogles_init_texture(c);
-
- c->rasterizer.base = base;
- c->point.size = TRI_ONE;
- c->line.width = TRI_ONE;
-
- // in OpenGL, writing to the depth buffer is enabled by default.
- c->rasterizer.procs.depthMask(c, 1);
-
- // OpenGL enables dithering by default
- c->rasterizer.procs.enable(c, GL_DITHER);
-
- return c;
-}
-
-void ogles_uninit(ogles_context_t* c)
-{
- ogles_uninit_array(c);
- ogles_uninit_matrix(c);
- ogles_uninit_vertex(c);
- ogles_uninit_light(c);
- ogles_uninit_texture(c);
- c->surfaceManager->decStrong(c);
- c->bufferObjectManager->decStrong(c);
- ggl_uninit_context(&(c->rasterizer));
- free(c->rasterizer.base);
-}
-
-void _ogles_error(ogles_context_t* c, GLenum error)
-{
- if (c->error == GL_NO_ERROR)
- c->error = error;
-}
-
-static bool stencilop_valid(GLenum op) {
- switch (op) {
- case GL_KEEP:
- case GL_ZERO:
- case GL_REPLACE:
- case GL_INCR:
- case GL_DECR:
- case GL_INVERT:
- return true;
- }
- return false;
-}
-
-static void enable_disable(ogles_context_t* c, GLenum cap, int enabled)
-{
- if ((cap >= GL_LIGHT0) && (cap<GL_LIGHT0+OGLES_MAX_LIGHTS)) {
- c->lighting.lights[cap-GL_LIGHT0].enable = enabled;
- c->lighting.enabledLights &= ~(1<<(cap-GL_LIGHT0));
- c->lighting.enabledLights |= (enabled<<(cap-GL_LIGHT0));
- return;
- }
-
- switch (cap) {
- case GL_POINT_SMOOTH:
- c->point.smooth = enabled;
- break;
- case GL_LINE_SMOOTH:
- c->line.smooth = enabled;
- break;
- case GL_POLYGON_OFFSET_FILL:
- c->polygonOffset.enable = enabled;
- break;
- case GL_CULL_FACE:
- c->cull.enable = enabled;
- break;
- case GL_LIGHTING:
- c->lighting.enable = enabled;
- break;
- case GL_COLOR_MATERIAL:
- c->lighting.colorMaterial.enable = enabled;
- break;
- case GL_NORMALIZE:
- case GL_RESCALE_NORMAL:
- c->transforms.rescaleNormals = enabled ? cap : 0;
- // XXX: invalidate mvit
- break;
-
- case GL_CLIP_PLANE0:
- case GL_CLIP_PLANE1:
- case GL_CLIP_PLANE2:
- case GL_CLIP_PLANE3:
- case GL_CLIP_PLANE4:
- case GL_CLIP_PLANE5:
- c->clipPlanes.enable &= ~(1<<(cap-GL_CLIP_PLANE0));
- c->clipPlanes.enable |= (enabled<<(cap-GL_CLIP_PLANE0));
- ogles_invalidate_perspective(c);
- break;
-
- case GL_FOG:
- case GL_DEPTH_TEST:
- ogles_invalidate_perspective(c);
- [[fallthrough]];
- case GL_BLEND:
- case GL_SCISSOR_TEST:
- case GL_ALPHA_TEST:
- case GL_COLOR_LOGIC_OP:
- case GL_DITHER:
- case GL_STENCIL_TEST:
- case GL_TEXTURE_2D:
- // these need to fall through into the rasterizer
- c->rasterizer.procs.enableDisable(c, cap, enabled);
- break;
- case GL_TEXTURE_EXTERNAL_OES:
- c->rasterizer.procs.enableDisable(c, GL_TEXTURE_2D, enabled);
- break;
-
- case GL_MULTISAMPLE:
- case GL_SAMPLE_ALPHA_TO_COVERAGE:
- case GL_SAMPLE_ALPHA_TO_ONE:
- case GL_SAMPLE_COVERAGE:
- // not supported in this implementation
- break;
-
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-using namespace android;
-
-#if 0
-#pragma mark -
-#endif
-
-// These ones are super-easy, we're not supporting those features!
-void glSampleCoverage(GLclampf /*value*/, GLboolean /*invert*/) {
-}
-void glSampleCoveragex(GLclampx /*value*/, GLboolean /*invert*/) {
-}
-void glStencilFunc(GLenum func, GLint /*ref*/, GLuint /*mask*/) {
- ogles_context_t* c = ogles_context_t::get();
- if (func < GL_NEVER || func > GL_ALWAYS) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- // from OpenGL|ES 1.0 sepcification:
- // If there is no stencil buffer, no stencil modification can occur
- // and it is as if the stencil test always passes.
-}
-
-void glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
- ogles_context_t* c = ogles_context_t::get();
- if ((stencilop_valid(fail) &
- stencilop_valid(zfail) &
- stencilop_valid(zpass)) == 0) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-}
-
-// ----------------------------------------------------------------------------
-
-void glAlphaFunc(GLenum func, GLclampf ref)
-{
- glAlphaFuncx(func, gglFloatToFixed(ref));
-}
-
-void glCullFace(GLenum mode)
-{
- ogles_context_t* c = ogles_context_t::get();
- switch (mode) {
- case GL_FRONT:
- case GL_BACK:
- case GL_FRONT_AND_BACK:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- }
- c->cull.cullFace = mode;
-}
-
-void glFrontFace(GLenum mode)
-{
- ogles_context_t* c = ogles_context_t::get();
- switch (mode) {
- case GL_CW:
- case GL_CCW:
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->cull.frontFace = mode;
-}
-
-void glHint(GLenum target, GLenum mode)
-{
- ogles_context_t* c = ogles_context_t::get();
- switch (target) {
- case GL_FOG_HINT:
- case GL_GENERATE_MIPMAP_HINT:
- case GL_LINE_SMOOTH_HINT:
- break;
- case GL_POINT_SMOOTH_HINT:
- c->rasterizer.procs.enableDisable(c,
- GGL_POINT_SMOOTH_NICE, mode==GL_NICEST);
- break;
- case GL_PERSPECTIVE_CORRECTION_HINT:
- c->perspective = (mode == GL_NICEST) ? 1 : 0;
- break;
- default:
- ogles_error(c, GL_INVALID_ENUM);
- }
-}
-
-void glEnable(GLenum cap) {
- ogles_context_t* c = ogles_context_t::get();
- enable_disable(c, cap, 1);
-}
-void glDisable(GLenum cap) {
- ogles_context_t* c = ogles_context_t::get();
- enable_disable(c, cap, 0);
-}
-
-void glFinish()
-{ // nothing to do for our software implementation
-}
-
-void glFlush()
-{ // nothing to do for our software implementation
-}
-
-GLenum glGetError()
-{
- // From OpenGL|ES 1.0 specification:
- // If more than one flag has recorded an error, glGetError returns
- // and clears an arbitrary error flag value. Thus, glGetError should
- // always be called in a loop, until it returns GL_NO_ERROR,
- // if all error flags are to be reset.
-
- ogles_context_t* c = ogles_context_t::get();
- if (c->error) {
- const GLenum ret(c->error);
- c->error = 0;
- return ret;
- }
-
- if (c->rasterizer.error) {
- const GLenum ret(c->rasterizer.error);
- c->rasterizer.error = 0;
- return ret;
- }
-
- return GL_NO_ERROR;
-}
-
-const GLubyte* glGetString(GLenum string)
-{
- switch (string) {
- case GL_VENDOR: return (const GLubyte*)gVendorString;
- case GL_RENDERER: return (const GLubyte*)gRendererString;
- case GL_VERSION: return (const GLubyte*)gVersionString;
- case GL_EXTENSIONS: return (const GLubyte*)gExtensionsString;
- }
- ogles_context_t* c = ogles_context_t::get();
- ogles_error(c, GL_INVALID_ENUM);
- return 0;
-}
-
-void glGetIntegerv(GLenum pname, GLint *params)
-{
- int i;
- ogles_context_t* c = ogles_context_t::get();
- switch (pname) {
- case GL_ALIASED_POINT_SIZE_RANGE:
- params[0] = 0;
- params[1] = GGL_MAX_ALIASED_POINT_SIZE;
- break;
- case GL_ALIASED_LINE_WIDTH_RANGE:
- params[0] = 0;
- params[1] = GGL_MAX_ALIASED_POINT_SIZE;
- break;
- case GL_ALPHA_BITS: {
- int index = c->rasterizer.state.buffers.color.format;
- GGLFormat const * formats = gglGetPixelFormatTable();
- params[0] = formats[index].ah - formats[index].al;
- break;
- }
- case GL_RED_BITS: {
- int index = c->rasterizer.state.buffers.color.format;
- GGLFormat const * formats = gglGetPixelFormatTable();
- params[0] = formats[index].rh - formats[index].rl;
- break;
- }
- case GL_GREEN_BITS: {
- int index = c->rasterizer.state.buffers.color.format;
- GGLFormat const * formats = gglGetPixelFormatTable();
- params[0] = formats[index].gh - formats[index].gl;
- break;
- }
- case GL_BLUE_BITS: {
- int index = c->rasterizer.state.buffers.color.format;
- GGLFormat const * formats = gglGetPixelFormatTable();
- params[0] = formats[index].bh - formats[index].bl;
- break;
- }
- case GL_COMPRESSED_TEXTURE_FORMATS:
- params[ 0] = GL_PALETTE4_RGB8_OES;
- params[ 1] = GL_PALETTE4_RGBA8_OES;
- params[ 2] = GL_PALETTE4_R5_G6_B5_OES;
- params[ 3] = GL_PALETTE4_RGBA4_OES;
- params[ 4] = GL_PALETTE4_RGB5_A1_OES;
- params[ 5] = GL_PALETTE8_RGB8_OES;
- params[ 6] = GL_PALETTE8_RGBA8_OES;
- params[ 7] = GL_PALETTE8_R5_G6_B5_OES;
- params[ 8] = GL_PALETTE8_RGBA4_OES;
- params[ 9] = GL_PALETTE8_RGB5_A1_OES;
- i = 10;
-#ifdef GL_OES_compressed_ETC1_RGB8_texture
- params[i++] = GL_ETC1_RGB8_OES;
-#endif
- break;
- case GL_DEPTH_BITS:
- params[0] = c->rasterizer.state.buffers.depth.format ? 0 : 16;
- break;
- case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
- params[0] = GL_RGB;
- break;
- case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
- params[0] = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case GL_MAX_LIGHTS:
- params[0] = OGLES_MAX_LIGHTS;
- break;
- case GL_MAX_CLIP_PLANES:
- params[0] = OGLES_MAX_CLIP_PLANES;
- break;
- case GL_MAX_MODELVIEW_STACK_DEPTH:
- params[0] = OGLES_MODELVIEW_STACK_DEPTH;
- break;
- case GL_MAX_PROJECTION_STACK_DEPTH:
- params[0] = OGLES_PROJECTION_STACK_DEPTH;
- break;
- case GL_MAX_TEXTURE_STACK_DEPTH:
- params[0] = OGLES_TEXTURE_STACK_DEPTH;
- break;
- case GL_MAX_TEXTURE_SIZE:
- params[0] = GGL_MAX_TEXTURE_SIZE;
- break;
- case GL_MAX_TEXTURE_UNITS:
- params[0] = GGL_TEXTURE_UNIT_COUNT;
- break;
- case GL_MAX_VIEWPORT_DIMS:
- params[0] = GGL_MAX_VIEWPORT_DIMS;
- params[1] = GGL_MAX_VIEWPORT_DIMS;
- break;
- case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
- params[0] = OGLES_NUM_COMPRESSED_TEXTURE_FORMATS;
- break;
- case GL_SMOOTH_LINE_WIDTH_RANGE:
- params[0] = 0;
- params[1] = GGL_MAX_SMOOTH_LINE_WIDTH;
- break;
- case GL_SMOOTH_POINT_SIZE_RANGE:
- params[0] = 0;
- params[1] = GGL_MAX_SMOOTH_POINT_SIZE;
- break;
- case GL_STENCIL_BITS:
- params[0] = 0;
- break;
- case GL_SUBPIXEL_BITS:
- params[0] = GGL_SUBPIXEL_BITS;
- break;
-
- case GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES:
- memcpy( params,
- c->transforms.modelview.top().elements(),
- 16*sizeof(GLint));
- break;
- case GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES:
- memcpy( params,
- c->transforms.projection.top().elements(),
- 16*sizeof(GLint));
- break;
- case GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES:
- memcpy( params,
- c->transforms.texture[c->textures.active].top().elements(),
- 16*sizeof(GLint));
- break;
-
- default:
- ogles_error(c, GL_INVALID_ENUM);
- break;
- }
-}
-
-// ----------------------------------------------------------------------------
-
-void glPointSize(GLfloat size)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (size <= 0) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->point.size = TRI_FROM_FIXED(gglFloatToFixed(size));
-}
-
-void glPointSizex(GLfixed size)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (size <= 0) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->point.size = TRI_FROM_FIXED(size);
-}
-
-// ----------------------------------------------------------------------------
-
-void glLineWidth(GLfloat width)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (width <= 0) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->line.width = TRI_FROM_FIXED(gglFloatToFixed(width));
-}
-
-void glLineWidthx(GLfixed width)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (width <= 0) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->line.width = TRI_FROM_FIXED(width);
-}
-
-// ----------------------------------------------------------------------------
-
-void glColorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.colorMask(c, r, g, b, a);
-}
-
-void glDepthMask(GLboolean flag) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.depthMask(c, flag);
-}
-
-void glStencilMask(GLuint mask) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.stencilMask(c, mask);
-}
-
-void glDepthFunc(GLenum func) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.depthFunc(c, func);
-}
-
-void glLogicOp(GLenum opcode) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.logicOp(c, opcode);
-}
-
-void glAlphaFuncx(GLenum func, GLclampx ref) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.alphaFuncx(c, func, ref);
-}
-
-void glBlendFunc(GLenum sfactor, GLenum dfactor) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.blendFunc(c, sfactor, dfactor);
-}
-
-void glClear(GLbitfield mask) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.clear(c, mask);
-}
-
-void glClearColorx(GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.clearColorx(c, red, green, blue, alpha);
-}
-
-void glClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.clearColorx(c,
- gglFloatToFixed(r),
- gglFloatToFixed(g),
- gglFloatToFixed(b),
- gglFloatToFixed(a));
-}
-
-void glClearDepthx(GLclampx depth) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.clearDepthx(c, depth);
-}
-
-void glClearDepthf(GLclampf depth)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.clearDepthx(c, gglFloatToFixed(depth));
-}
-
-void glClearStencil(GLint s) {
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.clearStencil(c, s);
-}
diff --git a/opengl/libagl/state.h b/opengl/libagl/state.h
deleted file mode 100644
index 55a5ccb..0000000
--- a/opengl/libagl/state.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* libs/opengles/state.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_STATE_H
-#define ANDROID_OPENGLES_STATE_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include <GLES/gl.h>
-
-#include <stdio.h>
-
-namespace android {
-
-ogles_context_t *ogles_init(size_t extra);
-void ogles_uninit(ogles_context_t* c);
-void _ogles_error(ogles_context_t* c, GLenum error);
-
-#ifndef TRACE_GL_ERRORS
-#define TRACE_GL_ERRORS 0
-#endif
-
-#if TRACE_GL_ERRORS
-#define ogles_error(c, error) \
-do { \
- printf("ogles_error at file %s line %d\n", __FILE__, __LINE__); \
- _ogles_error(c, error); \
-} while (0)
-#else /* !TRACE_GL_ERRORS */
-#define ogles_error(c, error) _ogles_error((c), (error))
-#endif
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_STATE_H
-
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
deleted file mode 100644
index 4c5f3e9..0000000
--- a/opengl/libagl/texture.cpp
+++ /dev/null
@@ -1,1643 +0,0 @@
-/* libs/opengles/texture.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "context.h"
-#include "fp.h"
-#include "state.h"
-#include "texture.h"
-#include "TextureObjectManager.h"
-
-#include <ETC1/etc1.h>
-
-#include <ui/GraphicBufferMapper.h>
-#include <ui/Rect.h>
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-static void bindTextureTmu(
- ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex);
-
-static __attribute__((noinline))
-void generateMipmap(ogles_context_t* c, GLint level);
-
-// ----------------------------------------------------------------------------
-
-#if 0
-#pragma mark -
-#pragma mark Init
-#endif
-
-void ogles_init_texture(ogles_context_t* c)
-{
- c->textures.packAlignment = 4;
- c->textures.unpackAlignment = 4;
-
- // each context has a default named (0) texture (not shared)
- c->textures.defaultTexture = new EGLTextureObject();
- c->textures.defaultTexture->incStrong(c);
-
- // bind the default texture to each texture unit
- for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- bindTextureTmu(c, i, 0, c->textures.defaultTexture);
- memset(c->current.texture[i].v, 0, sizeof(vec4_t));
- c->current.texture[i].Q = 0x10000;
- }
-}
-
-void ogles_uninit_texture(ogles_context_t* c)
-{
- if (c->textures.ggl)
- gglUninit(c->textures.ggl);
- c->textures.defaultTexture->decStrong(c);
- for (int i=0; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (c->textures.tmu[i].texture)
- c->textures.tmu[i].texture->decStrong(c);
- }
-}
-
-static __attribute__((noinline))
-void validate_tmu(ogles_context_t* c, int i)
-{
- texture_unit_t& u(c->textures.tmu[i]);
- if (u.dirty) {
- u.dirty = 0;
- c->rasterizer.procs.activeTexture(c, i);
- c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
- c->rasterizer.procs.texGeni(c, GGL_S,
- GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
- c->rasterizer.procs.texGeni(c, GGL_T,
- GGL_TEXTURE_GEN_MODE, GGL_AUTOMATIC);
- c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
- GGL_TEXTURE_WRAP_S, u.texture->wraps);
- c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
- GGL_TEXTURE_WRAP_T, u.texture->wrapt);
- c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
- GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
- c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
- GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
-
- // disable this texture unit if it's not complete
- if (!u.texture->isComplete()) {
- c->rasterizer.procs.disable(c, GGL_TEXTURE_2D);
- }
- }
-}
-
-void ogles_validate_texture(ogles_context_t* c)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (c->rasterizer.state.texture[i].enable)
- validate_tmu(c, i);
- }
- c->rasterizer.procs.activeTexture(c, c->textures.active);
-}
-
-static
-void invalidate_texture(ogles_context_t* c, int tmu, uint8_t flags = 0xFF) {
- c->textures.tmu[tmu].dirty = flags;
-}
-
-/*
- * If the active textures are EGLImage, they need to be locked before
- * they can be used.
- *
- * FIXME: code below is far from being optimal
- *
- */
-
-void ogles_lock_textures(ogles_context_t* c)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (c->rasterizer.state.texture[i].enable) {
- texture_unit_t& u(c->textures.tmu[i]);
- ANativeWindowBuffer* native_buffer = u.texture->buffer;
- if (native_buffer) {
- c->rasterizer.procs.activeTexture(c, i);
-
- auto& mapper = GraphicBufferMapper::get();
- void* vaddr;
- mapper.lock(native_buffer->handle, GRALLOC_USAGE_SW_READ_OFTEN,
- Rect(native_buffer->width, native_buffer->height),
- &vaddr);
-
- u.texture->setImageBits(vaddr);
- c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
- }
- }
- }
-}
-
-void ogles_unlock_textures(ogles_context_t* c)
-{
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (c->rasterizer.state.texture[i].enable) {
- texture_unit_t& u(c->textures.tmu[i]);
- ANativeWindowBuffer* native_buffer = u.texture->buffer;
- if (native_buffer) {
- c->rasterizer.procs.activeTexture(c, i);
-
- auto& mapper = GraphicBufferMapper::get();
- mapper.unlock(native_buffer->handle);
-
- u.texture->setImageBits(NULL);
- c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
- }
- }
- }
- c->rasterizer.procs.activeTexture(c, c->textures.active);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Format conversion
-#endif
-
-static uint32_t gl2format_table[6][4] = {
- // BYTE, 565, 4444, 5551
- { GGL_PIXEL_FORMAT_A_8,
- 0, 0, 0 }, // GL_ALPHA
- { GGL_PIXEL_FORMAT_RGB_888,
- GGL_PIXEL_FORMAT_RGB_565,
- 0, 0 }, // GL_RGB
- { GGL_PIXEL_FORMAT_RGBA_8888,
- 0,
- GGL_PIXEL_FORMAT_RGBA_4444,
- GGL_PIXEL_FORMAT_RGBA_5551 }, // GL_RGBA
- { GGL_PIXEL_FORMAT_L_8,
- 0, 0, 0 }, // GL_LUMINANCE
- { GGL_PIXEL_FORMAT_LA_88,
- 0, 0, 0 }, // GL_LUMINANCE_ALPHA
-};
-
-static int32_t convertGLPixelFormat(GLint format, GLenum type)
-{
- int32_t fi = -1;
- int32_t ti = -1;
- switch (format) {
- case GL_ALPHA: fi = 0; break;
- case GL_RGB: fi = 1; break;
- case GL_RGBA: fi = 2; break;
- case GL_LUMINANCE: fi = 3; break;
- case GL_LUMINANCE_ALPHA: fi = 4; break;
- }
- switch (type) {
- case GL_UNSIGNED_BYTE: ti = 0; break;
- case GL_UNSIGNED_SHORT_5_6_5: ti = 1; break;
- case GL_UNSIGNED_SHORT_4_4_4_4: ti = 2; break;
- case GL_UNSIGNED_SHORT_5_5_5_1: ti = 3; break;
- }
- if (fi==-1 || ti==-1)
- return 0;
- return gl2format_table[fi][ti];
-}
-
-// ----------------------------------------------------------------------------
-
-static GLenum validFormatType(ogles_context_t* c, GLenum format, GLenum type)
-{
- GLenum error = 0;
- if (format<GL_ALPHA || format>GL_LUMINANCE_ALPHA) {
- error = GL_INVALID_ENUM;
- }
- if (type != GL_UNSIGNED_BYTE && type != GL_UNSIGNED_SHORT_4_4_4_4 &&
- type != GL_UNSIGNED_SHORT_5_5_5_1 && type != GL_UNSIGNED_SHORT_5_6_5) {
- error = GL_INVALID_ENUM;
- }
- if (type == GL_UNSIGNED_SHORT_5_6_5 && format != GL_RGB) {
- error = GL_INVALID_OPERATION;
- }
- if ((type == GL_UNSIGNED_SHORT_4_4_4_4 ||
- type == GL_UNSIGNED_SHORT_5_5_5_1) && format != GL_RGBA) {
- error = GL_INVALID_OPERATION;
- }
- if (error) {
- ogles_error(c, error);
- }
- return error;
-}
-
-// ----------------------------------------------------------------------------
-
-GGLContext* getRasterizer(ogles_context_t* c)
-{
- GGLContext* ggl = c->textures.ggl;
- if (ggl_unlikely(!ggl)) {
- // this is quite heavy the first time...
- gglInit(&ggl);
- if (!ggl) {
- return 0;
- }
- GGLfixed colors[4] = { 0, 0, 0, 0x10000 };
- c->textures.ggl = ggl;
- ggl->activeTexture(ggl, 0);
- ggl->enable(ggl, GGL_TEXTURE_2D);
- ggl->texEnvi(ggl, GGL_TEXTURE_ENV, GGL_TEXTURE_ENV_MODE, GGL_REPLACE);
- ggl->disable(ggl, GGL_DITHER);
- ggl->shadeModel(ggl, GGL_FLAT);
- ggl->color4xv(ggl, colors);
- }
- return ggl;
-}
-
-static __attribute__((noinline))
-int copyPixels(
- ogles_context_t* c,
- const GGLSurface& dst,
- GLint xoffset, GLint yoffset,
- const GGLSurface& src,
- GLint x, GLint y, GLsizei w, GLsizei h)
-{
- if ((dst.format == src.format) &&
- (dst.stride == src.stride) &&
- (dst.width == src.width) &&
- (dst.height == src.height) &&
- (dst.stride > 0) &&
- ((x|y) == 0) &&
- ((xoffset|yoffset) == 0))
- {
- // this is a common case...
- const GGLFormat& pixelFormat(c->rasterizer.formats[src.format]);
- const size_t size = src.height * src.stride * pixelFormat.size;
- memcpy(dst.data, src.data, size);
- return 0;
- }
-
- // use pixel-flinger to handle all the conversions
- GGLContext* ggl = getRasterizer(c);
- if (!ggl) {
- // the only reason this would fail is because we ran out of memory
- return GL_OUT_OF_MEMORY;
- }
-
- ggl->colorBuffer(ggl, &dst);
- ggl->bindTexture(ggl, &src);
- ggl->texCoord2i(ggl, x-xoffset, y-yoffset);
- ggl->recti(ggl, xoffset, yoffset, xoffset+w, yoffset+h);
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-
-static __attribute__((noinline))
-sp<EGLTextureObject> getAndBindActiveTextureObject(ogles_context_t* c)
-{
- sp<EGLTextureObject> tex;
- const int active = c->textures.active;
- const GLuint name = c->textures.tmu[active].name;
-
- // free the reference to the previously bound object
- texture_unit_t& u(c->textures.tmu[active]);
- if (u.texture)
- u.texture->decStrong(c);
-
- if (name == 0) {
- // 0 is our local texture object, not shared with anyone.
- // But it affects all bound TMUs immediately.
- // (we need to invalidate all units bound to this texture object)
- tex = c->textures.defaultTexture;
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (c->textures.tmu[i].texture == tex.get())
- invalidate_texture(c, i);
- }
- } else {
- // get a new texture object for that name
- tex = c->surfaceManager->replaceTexture(name);
- }
-
- // bind this texture to the current active texture unit
- // and add a reference to this texture object
- u.texture = tex.get();
- u.texture->incStrong(c);
- u.name = name;
- invalidate_texture(c, active);
- return tex;
-}
-
-void bindTextureTmu(
- ogles_context_t* c, int tmu, GLuint texture, const sp<EGLTextureObject>& tex)
-{
- if (tex.get() == c->textures.tmu[tmu].texture)
- return;
-
- // free the reference to the previously bound object
- texture_unit_t& u(c->textures.tmu[tmu]);
- if (u.texture)
- u.texture->decStrong(c);
-
- // bind this texture to the current active texture unit
- // and add a reference to this texture object
- u.texture = tex.get();
- u.texture->incStrong(c);
- u.name = texture;
- invalidate_texture(c, tmu);
-}
-
-int createTextureSurface(ogles_context_t* c,
- GGLSurface** outSurface, int32_t* outSize, GLint level,
- GLenum format, GLenum type, GLsizei width, GLsizei height,
- GLenum compressedFormat = 0)
-{
- // convert the pixelformat to one we can handle
- const int32_t formatIdx = convertGLPixelFormat(format, type);
- if (formatIdx == 0) { // we don't know what to do with this
- return GL_INVALID_OPERATION;
- }
-
- // figure out the size we need as well as the stride
- const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
- const int32_t align = c->textures.unpackAlignment-1;
- const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
- const size_t size = bpr * height;
- const int32_t stride = bpr / pixelFormat.size;
-
- if (level > 0) {
- const int active = c->textures.active;
- EGLTextureObject* tex = c->textures.tmu[active].texture;
- status_t err = tex->reallocate(level,
- width, height, stride, formatIdx, compressedFormat, bpr);
- if (err != NO_ERROR)
- return GL_OUT_OF_MEMORY;
- GGLSurface& surface = tex->editMip(level);
- *outSurface = &surface;
- *outSize = size;
- return 0;
- }
-
- sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
- status_t err = tex->reallocate(level,
- width, height, stride, formatIdx, compressedFormat, bpr);
- if (err != NO_ERROR)
- return GL_OUT_OF_MEMORY;
-
- tex->internalformat = format;
- *outSurface = &tex->surface;
- *outSize = size;
- return 0;
-}
-
-static GLsizei dataSizePalette4(int numLevels, int width, int height, int format)
-{
- int indexBits = 8;
- int entrySize = 0;
- switch (format) {
- case GL_PALETTE4_RGB8_OES:
- indexBits = 4;
- [[fallthrough]];
- case GL_PALETTE8_RGB8_OES:
- entrySize = 3;
- break;
-
- case GL_PALETTE4_RGBA8_OES:
- indexBits = 4;
- [[fallthrough]];
- case GL_PALETTE8_RGBA8_OES:
- entrySize = 4;
- break;
-
- case GL_PALETTE4_R5_G6_B5_OES:
- case GL_PALETTE4_RGBA4_OES:
- case GL_PALETTE4_RGB5_A1_OES:
- indexBits = 4;
- [[fallthrough]];
- case GL_PALETTE8_R5_G6_B5_OES:
- case GL_PALETTE8_RGBA4_OES:
- case GL_PALETTE8_RGB5_A1_OES:
- entrySize = 2;
- break;
- }
-
- size_t size = (1 << indexBits) * entrySize; // palette size
-
- for (int i=0 ; i< numLevels ; i++) {
- int w = (width >> i) ? : 1;
- int h = (height >> i) ? : 1;
- int levelSize = h * ((w * indexBits) / 8) ? : 1;
- size += levelSize;
- }
-
- return size;
-}
-
-static void decodePalette4(const GLvoid *data, int level, int width, int height,
- void *surface, int stride, int format)
-
-{
- int indexBits = 8;
- int entrySize = 0;
- switch (format) {
- case GL_PALETTE4_RGB8_OES:
- indexBits = 4;
- [[fallthrough]];
- case GL_PALETTE8_RGB8_OES:
- entrySize = 3;
- break;
-
- case GL_PALETTE4_RGBA8_OES:
- indexBits = 4;
- [[fallthrough]];
- case GL_PALETTE8_RGBA8_OES:
- entrySize = 4;
- break;
-
- case GL_PALETTE4_R5_G6_B5_OES:
- case GL_PALETTE4_RGBA4_OES:
- case GL_PALETTE4_RGB5_A1_OES:
- indexBits = 4;
- [[fallthrough]];
- case GL_PALETTE8_R5_G6_B5_OES:
- case GL_PALETTE8_RGBA4_OES:
- case GL_PALETTE8_RGB5_A1_OES:
- entrySize = 2;
- break;
- }
-
- const int paletteSize = (1 << indexBits) * entrySize;
-
- uint8_t const* pixels = (uint8_t *)data + paletteSize;
- for (int i=0 ; i<level ; i++) {
- int w = (width >> i) ? : 1;
- int h = (height >> i) ? : 1;
- pixels += h * ((w * indexBits) / 8);
- }
- width = (width >> level) ? : 1;
- height = (height >> level) ? : 1;
-
- if (entrySize == 2) {
- uint8_t const* const palette = (uint8_t*)data;
- for (int y=0 ; y<height ; y++) {
- uint8_t* p = (uint8_t*)surface + y*stride*2;
- if (indexBits == 8) {
- for (int x=0 ; x<width ; x++) {
- int index = 2 * (*pixels++);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- }
- } else {
- for (int x=0 ; x<width ; x+=2) {
- int v = *pixels++;
- int index = 2 * (v >> 4);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- if (x+1 < width) {
- index = 2 * (v & 0xF);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- }
- }
- }
- }
- } else if (entrySize == 3) {
- uint8_t const* const palette = (uint8_t*)data;
- for (int y=0 ; y<height ; y++) {
- uint8_t* p = (uint8_t*)surface + y*stride*3;
- if (indexBits == 8) {
- for (int x=0 ; x<width ; x++) {
- int index = 3 * (*pixels++);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- *p++ = palette[index + 2];
- }
- } else {
- for (int x=0 ; x<width ; x+=2) {
- int v = *pixels++;
- int index = 3 * (v >> 4);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- *p++ = palette[index + 2];
- if (x+1 < width) {
- index = 3 * (v & 0xF);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- *p++ = palette[index + 2];
- }
- }
- }
- }
- } else if (entrySize == 4) {
- uint8_t const* const palette = (uint8_t*)data;
- for (int y=0 ; y<height ; y++) {
- uint8_t* p = (uint8_t*)surface + y*stride*4;
- if (indexBits == 8) {
- for (int x=0 ; x<width ; x++) {
- int index = 4 * (*pixels++);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- *p++ = palette[index + 2];
- *p++ = palette[index + 3];
- }
- } else {
- for (int x=0 ; x<width ; x+=2) {
- int v = *pixels++;
- int index = 4 * (v >> 4);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- *p++ = palette[index + 2];
- *p++ = palette[index + 3];
- if (x+1 < width) {
- index = 4 * (v & 0xF);
- *p++ = palette[index + 0];
- *p++ = palette[index + 1];
- *p++ = palette[index + 2];
- *p++ = palette[index + 3];
- }
- }
- }
- }
- }
-}
-
-
-
-static __attribute__((noinline))
-void set_depth_and_fog(ogles_context_t* c, GGLfixed z)
-{
- const uint32_t enables = c->rasterizer.state.enables;
- // we need to compute Zw
- int32_t iterators[3];
- iterators[1] = iterators[2] = 0;
- GGLfixed Zw;
- GGLfixed n = gglFloatToFixed(c->transforms.vpt.zNear);
- GGLfixed f = gglFloatToFixed(c->transforms.vpt.zFar);
- if (z<=0) Zw = n;
- else if (z>=0x10000) Zw = f;
- else Zw = gglMulAddx(z, (f-n), n);
- if (enables & GGL_ENABLE_FOG) {
- // set up fog if needed...
- iterators[0] = c->fog.fog(c, Zw);
- c->rasterizer.procs.fogGrad3xv(c, iterators);
- }
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- // set up z-test if needed...
- int32_t z = (Zw & ~(Zw>>31));
- if (z >= 0x10000)
- z = 0xFFFF;
- iterators[0] = (z << 16) | z;
- c->rasterizer.procs.zGrad3xv(c, iterators);
- }
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark Generate mimaps
-#endif
-
-extern status_t buildAPyramid(ogles_context_t* c, EGLTextureObject* tex);
-
-void generateMipmap(ogles_context_t* c, GLint level)
-{
- if (level == 0) {
- const int active = c->textures.active;
- EGLTextureObject* tex = c->textures.tmu[active].texture;
- if (tex->generate_mipmap) {
- if (buildAPyramid(c, tex) != NO_ERROR) {
- ogles_error(c, GL_OUT_OF_MEMORY);
- return;
- }
- }
- }
-}
-
-
-static void texParameterx(
- GLenum target, GLenum pname, GLfixed param, ogles_context_t* c)
-{
- if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
- switch (pname) {
- case GL_TEXTURE_WRAP_S:
- if ((param == GL_REPEAT) ||
- (param == GL_CLAMP_TO_EDGE)) {
- textureObject->wraps = param;
- } else {
- goto invalid_enum;
- }
- break;
- case GL_TEXTURE_WRAP_T:
- if ((param == GL_REPEAT) ||
- (param == GL_CLAMP_TO_EDGE)) {
- textureObject->wrapt = param;
- } else {
- goto invalid_enum;
- }
- break;
- case GL_TEXTURE_MIN_FILTER:
- if ((param == GL_NEAREST) ||
- (param == GL_LINEAR) ||
- (param == GL_NEAREST_MIPMAP_NEAREST) ||
- (param == GL_LINEAR_MIPMAP_NEAREST) ||
- (param == GL_NEAREST_MIPMAP_LINEAR) ||
- (param == GL_LINEAR_MIPMAP_LINEAR)) {
- textureObject->min_filter = param;
- } else {
- goto invalid_enum;
- }
- break;
- case GL_TEXTURE_MAG_FILTER:
- if ((param == GL_NEAREST) ||
- (param == GL_LINEAR)) {
- textureObject->mag_filter = param;
- } else {
- goto invalid_enum;
- }
- break;
- case GL_GENERATE_MIPMAP:
- textureObject->generate_mipmap = param;
- break;
- default:
-invalid_enum:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- invalidate_texture(c, c->textures.active);
-}
-
-
-
-static void drawTexxOESImp(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
- ogles_context_t* c)
-{
- ogles_lock_textures(c);
-
- const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
- y = gglIntToFixed(cbSurface.height) - (y + h);
- w >>= FIXED_BITS;
- h >>= FIXED_BITS;
-
- // set up all texture units
- for (int i=0 ; i<GGL_TEXTURE_UNIT_COUNT ; i++) {
- if (!c->rasterizer.state.texture[i].enable)
- continue;
-
- int32_t texcoords[8];
- texture_unit_t& u(c->textures.tmu[i]);
-
- // validate this tmu (bind, wrap, filter)
- validate_tmu(c, i);
- // we CLAMP here, which works with premultiplied (s,t)
- c->rasterizer.procs.texParameteri(c,
- GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_S, GGL_CLAMP);
- c->rasterizer.procs.texParameteri(c,
- GGL_TEXTURE_2D, GGL_TEXTURE_WRAP_T, GGL_CLAMP);
- u.dirty = 0xFF; // XXX: should be more subtle
-
- EGLTextureObject* textureObject = u.texture;
- const GLint Ucr = textureObject->crop_rect[0] << 16;
- const GLint Vcr = textureObject->crop_rect[1] << 16;
- const GLint Wcr = textureObject->crop_rect[2] << 16;
- const GLint Hcr = textureObject->crop_rect[3] << 16;
-
- // computes texture coordinates (pre-multiplied)
- int32_t dsdx = Wcr / w; // dsdx = ((Wcr/w)/Wt)*Wt
- int32_t dtdy =-Hcr / h; // dtdy = -((Hcr/h)/Ht)*Ht
- int32_t s0 = Ucr - gglMulx(dsdx, x); // s0 = Ucr - x * dsdx
- int32_t t0 = (Vcr+Hcr) - gglMulx(dtdy, y); // t0 = (Vcr+Hcr) - y*dtdy
- texcoords[0] = s0;
- texcoords[1] = dsdx;
- texcoords[2] = 0;
- texcoords[3] = t0;
- texcoords[4] = 0;
- texcoords[5] = dtdy;
- texcoords[6] = 0;
- texcoords[7] = 0;
- c->rasterizer.procs.texCoordGradScale8xv(c, i, texcoords);
- }
-
- const uint32_t enables = c->rasterizer.state.enables;
- if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
- set_depth_and_fog(c, z);
-
- c->rasterizer.procs.activeTexture(c, c->textures.active);
- c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
- c->rasterizer.procs.disable(c, GGL_W_LERP);
- c->rasterizer.procs.disable(c, GGL_AA);
- c->rasterizer.procs.shadeModel(c, GL_FLAT);
- c->rasterizer.procs.recti(c,
- gglFixedToIntRound(x),
- gglFixedToIntRound(y),
- gglFixedToIntRound(x)+w,
- gglFixedToIntRound(y)+h);
-
- ogles_unlock_textures(c);
-}
-
-static void drawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h,
- ogles_context_t* c)
-{
- // quickly reject empty rects
- if ((w|h) <= 0)
- return;
-
- drawTexxOESImp(x, y, z, w, h, c);
-}
-
-static void drawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h, ogles_context_t* c)
-{
- // All coordinates are integer, so if we have only one
- // texture unit active and no scaling is required
- // THEN, we can use our special 1:1 mapping
- // which is a lot faster.
-
- if (ggl_likely(c->rasterizer.state.enabled_tmu == 1)) {
- const int tmu = 0;
- texture_unit_t& u(c->textures.tmu[tmu]);
- EGLTextureObject* textureObject = u.texture;
- const GLint Wcr = textureObject->crop_rect[2];
- const GLint Hcr = textureObject->crop_rect[3];
-
- if ((w == Wcr) && (h == -Hcr)) {
- if ((w|h) <= 0) return; // quickly reject empty rects
-
- if (u.dirty) {
- c->rasterizer.procs.activeTexture(c, tmu);
- c->rasterizer.procs.bindTexture(c, &(u.texture->surface));
- c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
- GGL_TEXTURE_MIN_FILTER, u.texture->min_filter);
- c->rasterizer.procs.texParameteri(c, GGL_TEXTURE_2D,
- GGL_TEXTURE_MAG_FILTER, u.texture->mag_filter);
- }
- c->rasterizer.procs.texGeni(c, GGL_S,
- GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
- c->rasterizer.procs.texGeni(c, GGL_T,
- GGL_TEXTURE_GEN_MODE, GGL_ONE_TO_ONE);
- u.dirty = 0xFF; // XXX: should be more subtle
- c->rasterizer.procs.activeTexture(c, c->textures.active);
-
- const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
- y = cbSurface.height - (y + h);
- const GLint Ucr = textureObject->crop_rect[0];
- const GLint Vcr = textureObject->crop_rect[1];
- const GLint s0 = Ucr - x;
- const GLint t0 = (Vcr + Hcr) - y;
-
- const GLuint tw = textureObject->surface.width;
- const GLuint th = textureObject->surface.height;
- if ((uint32_t(s0+x+w) > tw) || (uint32_t(t0+y+h) > th)) {
- // The GL spec is unclear about what should happen
- // in this case, so we just use the slow case, which
- // at least won't crash
- goto slow_case;
- }
-
- ogles_lock_textures(c);
-
- c->rasterizer.procs.texCoord2i(c, s0, t0);
- const uint32_t enables = c->rasterizer.state.enables;
- if (ggl_unlikely(enables & (GGL_ENABLE_DEPTH_TEST|GGL_ENABLE_FOG)))
- set_depth_and_fog(c, gglIntToFixed(z));
-
- c->rasterizer.procs.color4xv(c, c->currentColorClamped.v);
- c->rasterizer.procs.disable(c, GGL_W_LERP);
- c->rasterizer.procs.disable(c, GGL_AA);
- c->rasterizer.procs.shadeModel(c, GL_FLAT);
- c->rasterizer.procs.recti(c, x, y, x+w, y+h);
-
- ogles_unlock_textures(c);
-
- return;
- }
- }
-
-slow_case:
- drawTexxOESImp(
- gglIntToFixed(x), gglIntToFixed(y), gglIntToFixed(z),
- gglIntToFixed(w), gglIntToFixed(h),
- c);
-}
-
-
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-
-#if 0
-#pragma mark -
-#pragma mark Texture API
-#endif
-
-void glActiveTexture(GLenum texture)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (uint32_t(texture-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- c->textures.active = texture - GL_TEXTURE0;
- c->rasterizer.procs.activeTexture(c, c->textures.active);
-}
-
-void glBindTexture(GLenum target, GLuint texture)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- // Bind or create a texture
- sp<EGLTextureObject> tex;
- if (texture == 0) {
- // 0 is our local texture object
- tex = c->textures.defaultTexture;
- } else {
- tex = c->surfaceManager->texture(texture);
- if (ggl_unlikely(tex == 0)) {
- tex = c->surfaceManager->createTexture(texture);
- if (tex == 0) {
- ogles_error(c, GL_OUT_OF_MEMORY);
- return;
- }
- }
- }
- bindTextureTmu(c, c->textures.active, texture, tex);
-}
-
-void glGenTextures(GLsizei n, GLuint *textures)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (n<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- // generate unique (shared) texture names
- c->surfaceManager->getToken(n, textures);
-}
-
-void glDeleteTextures(GLsizei n, const GLuint *textures)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (n<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- // If deleting a bound texture, bind this unit to 0
- for (int t=0 ; t<GGL_TEXTURE_UNIT_COUNT ; t++) {
- if (c->textures.tmu[t].name == 0)
- continue;
- for (int i=0 ; i<n ; i++) {
- if (textures[i] && (textures[i] == c->textures.tmu[t].name)) {
- // bind this tmu to texture 0
- sp<EGLTextureObject> tex(c->textures.defaultTexture);
- bindTextureTmu(c, t, 0, tex);
- }
- }
- }
- c->surfaceManager->deleteTextures(n, textures);
- c->surfaceManager->recycleTokens(n, textures);
-}
-
-void glMultiTexCoord4f(
- GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- const int tmu = target-GL_TEXTURE0;
- c->current.texture[tmu].S = gglFloatToFixed(s);
- c->current.texture[tmu].T = gglFloatToFixed(t);
- c->current.texture[tmu].R = gglFloatToFixed(r);
- c->current.texture[tmu].Q = gglFloatToFixed(q);
-}
-
-void glMultiTexCoord4x(
- GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (uint32_t(target-GL_TEXTURE0) > uint32_t(GGL_TEXTURE_UNIT_COUNT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- const int tmu = target-GL_TEXTURE0;
- c->current.texture[tmu].S = s;
- c->current.texture[tmu].T = t;
- c->current.texture[tmu].R = r;
- c->current.texture[tmu].Q = q;
-}
-
-void glPixelStorei(GLenum pname, GLint param)
-{
- ogles_context_t* c = ogles_context_t::get();
- if ((pname != GL_PACK_ALIGNMENT) && (pname != GL_UNPACK_ALIGNMENT)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if ((param<=0 || param>8) || (param & (param-1))) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (pname == GL_PACK_ALIGNMENT)
- c->textures.packAlignment = param;
- if (pname == GL_UNPACK_ALIGNMENT)
- c->textures.unpackAlignment = param;
-}
-
-void glTexEnvf(GLenum target, GLenum pname, GLfloat param)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.texEnvi(c, target, pname, GLint(param));
-}
-
-void glTexEnvfv(
- GLenum target, GLenum pname, const GLfloat *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (pname == GL_TEXTURE_ENV_MODE) {
- c->rasterizer.procs.texEnvi(c, target, pname, GLint(*params));
- return;
- }
- if (pname == GL_TEXTURE_ENV_COLOR) {
- GGLfixed fixed[4];
- for (int i=0 ; i<4 ; i++)
- fixed[i] = gglFloatToFixed(params[i]);
- c->rasterizer.procs.texEnvxv(c, target, pname, fixed);
- return;
- }
- ogles_error(c, GL_INVALID_ENUM);
-}
-
-void glTexEnvx(GLenum target, GLenum pname, GLfixed param)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.texEnvi(c, target, pname, param);
-}
-
-void glTexEnvxv(
- GLenum target, GLenum pname, const GLfixed *params)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->rasterizer.procs.texEnvxv(c, target, pname, params);
-}
-
-void glTexParameteriv(
- GLenum target, GLenum pname, const GLint* params)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- EGLTextureObject* textureObject = c->textures.tmu[c->textures.active].texture;
- switch (pname) {
- case GL_TEXTURE_CROP_RECT_OES:
- memcpy(textureObject->crop_rect, params, 4*sizeof(GLint));
- break;
- default:
- texParameterx(target, pname, GLfixed(params[0]), c);
- return;
- }
-}
-
-void glTexParameterf(
- GLenum target, GLenum pname, GLfloat param)
-{
- ogles_context_t* c = ogles_context_t::get();
- texParameterx(target, pname, GLfixed(param), c);
-}
-
-void glTexParameterx(
- GLenum target, GLenum pname, GLfixed param)
-{
- ogles_context_t* c = ogles_context_t::get();
- texParameterx(target, pname, param, c);
-}
-
-void glTexParameteri(
- GLenum target, GLenum pname, GLint param)
-{
- ogles_context_t* c = ogles_context_t::get();
- texParameterx(target, pname, GLfixed(param), c);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#endif
-
-void glCompressedTexImage2D(
- GLenum target, GLint level, GLenum internalformat,
- GLsizei width, GLsizei height, GLint border,
- GLsizei imageSize, const GLvoid *data)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (width<0 || height<0 || border!=0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- // "uncompress" the texture since pixelflinger doesn't support
- // any compressed texture format natively.
- GLenum format;
- GLenum type;
- switch (internalformat) {
- case GL_PALETTE8_RGB8_OES:
- case GL_PALETTE4_RGB8_OES:
- format = GL_RGB;
- type = GL_UNSIGNED_BYTE;
- break;
- case GL_PALETTE8_RGBA8_OES:
- case GL_PALETTE4_RGBA8_OES:
- format = GL_RGBA;
- type = GL_UNSIGNED_BYTE;
- break;
- case GL_PALETTE8_R5_G6_B5_OES:
- case GL_PALETTE4_R5_G6_B5_OES:
- format = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case GL_PALETTE8_RGBA4_OES:
- case GL_PALETTE4_RGBA4_OES:
- format = GL_RGBA;
- type = GL_UNSIGNED_SHORT_4_4_4_4;
- break;
- case GL_PALETTE8_RGB5_A1_OES:
- case GL_PALETTE4_RGB5_A1_OES:
- format = GL_RGBA;
- type = GL_UNSIGNED_SHORT_5_5_5_1;
- break;
-#ifdef GL_OES_compressed_ETC1_RGB8_texture
- case GL_ETC1_RGB8_OES:
- format = GL_RGB;
- type = GL_UNSIGNED_BYTE;
- break;
-#endif
- default:
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- if (!data || !width || !height) {
- // unclear if this is an error or not...
- return;
- }
-
- int32_t size;
- GGLSurface* surface;
-
-#ifdef GL_OES_compressed_ETC1_RGB8_texture
- if (internalformat == GL_ETC1_RGB8_OES) {
- GLsizei compressedSize = etc1_get_encoded_data_size(width, height);
- if (compressedSize > imageSize) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- int error = createTextureSurface(c, &surface, &size,
- level, format, type, width, height);
- if (error) {
- ogles_error(c, error);
- return;
- }
- if (etc1_decode_image(
- (const etc1_byte*)data,
- (etc1_byte*)surface->data,
- width, height, 3, surface->stride*3) != 0) {
- ogles_error(c, GL_INVALID_OPERATION);
- }
- return;
- }
-#endif
-
- // all mipmap levels are specified at once.
- const int numLevels = level<0 ? -level : 1;
-
- if (dataSizePalette4(numLevels, width, height, format) > imageSize) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- for (int i=0 ; i<numLevels ; i++) {
- int lod_w = (width >> i) ? : 1;
- int lod_h = (height >> i) ? : 1;
- int error = createTextureSurface(c, &surface, &size,
- i, format, type, lod_w, lod_h);
- if (error) {
- ogles_error(c, error);
- return;
- }
- decodePalette4(data, i, width, height,
- surface->data, surface->stride, internalformat);
- }
-}
-
-
-void glTexImage2D(
- GLenum target, GLint level, GLint internalformat,
- GLsizei width, GLsizei height, GLint border,
- GLenum format, GLenum type, const GLvoid *pixels)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (width<0 || height<0 || border!=0 || level < 0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (format != (GLenum)internalformat) {
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
- if (validFormatType(c, format, type)) {
- return;
- }
-
- int32_t size = 0;
- GGLSurface* surface = 0;
- int error = createTextureSurface(c, &surface, &size,
- level, format, type, width, height);
- if (error) {
- ogles_error(c, error);
- return;
- }
-
- if (pixels) {
- const int32_t formatIdx = convertGLPixelFormat(format, type);
- const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
- const int32_t align = c->textures.unpackAlignment-1;
- const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
- const int32_t stride = bpr / pixelFormat.size;
-
- GGLSurface userSurface;
- userSurface.version = sizeof(userSurface);
- userSurface.width = width;
- userSurface.height = height;
- userSurface.stride = stride;
- userSurface.format = formatIdx;
- userSurface.compressedFormat = 0;
- userSurface.data = (GLubyte*)pixels;
-
- int err = copyPixels(c, *surface, 0, 0, userSurface, 0, 0, width, height);
- if (err) {
- ogles_error(c, err);
- return;
- }
- generateMipmap(c, level);
- }
-}
-
-// ----------------------------------------------------------------------------
-
-void glCompressedTexSubImage2D(
- GLenum /*target*/, GLint /*level*/, GLint /*xoffset*/,
- GLint /*yoffset*/, GLsizei /*width*/, GLsizei /*height*/,
- GLenum /*format*/, GLsizei /*imageSize*/,
- const GLvoid* /*data*/)
-{
- ogles_context_t* c = ogles_context_t::get();
- ogles_error(c, GL_INVALID_ENUM);
-}
-
-void glTexSubImage2D(
- GLenum target, GLint level, GLint xoffset,
- GLint yoffset, GLsizei width, GLsizei height,
- GLenum format, GLenum type, const GLvoid *pixels)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (validFormatType(c, format, type)) {
- return;
- }
-
- // find out which texture is bound to the current unit
- const int active = c->textures.active;
- EGLTextureObject* tex = c->textures.tmu[active].texture;
- const GGLSurface& surface(tex->mip(level));
-
- if (!tex->internalformat || tex->direct) {
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
-
- if (format != tex->internalformat) {
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
- if ((xoffset + width > GLsizei(surface.width)) ||
- (yoffset + height > GLsizei(surface.height))) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (!width || !height) {
- return; // okay, but no-op.
- }
-
- // figure out the size we need as well as the stride
- const int32_t formatIdx = convertGLPixelFormat(format, type);
- if (formatIdx == 0) { // we don't know what to do with this
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
-
- const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
- const int32_t align = c->textures.unpackAlignment-1;
- const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
- const int32_t stride = bpr / pixelFormat.size;
- GGLSurface userSurface;
- userSurface.version = sizeof(userSurface);
- userSurface.width = width;
- userSurface.height = height;
- userSurface.stride = stride;
- userSurface.format = formatIdx;
- userSurface.compressedFormat = 0;
- userSurface.data = (GLubyte*)pixels;
-
- int err = copyPixels(c,
- surface, xoffset, yoffset,
- userSurface, 0, 0, width, height);
- if (err) {
- ogles_error(c, err);
- return;
- }
-
- generateMipmap(c, level);
-
- // since we only changed the content of the texture, we don't need
- // to call bindTexture on the main rasterizer.
-}
-
-// ----------------------------------------------------------------------------
-
-void glCopyTexImage2D(
- GLenum target, GLint level, GLenum internalformat,
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLint border)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (internalformat<GL_ALPHA || internalformat>GL_LUMINANCE_ALPHA) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (width<0 || height<0 || border!=0 || level<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- GLenum format = 0;
- GLenum type = GL_UNSIGNED_BYTE;
- const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
- const int cbFormatIdx = cbSurface.format;
- switch (cbFormatIdx) {
- case GGL_PIXEL_FORMAT_RGB_565:
- type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case GGL_PIXEL_FORMAT_RGBA_5551:
- type = GL_UNSIGNED_SHORT_5_5_5_1;
- break;
- case GGL_PIXEL_FORMAT_RGBA_4444:
- type = GL_UNSIGNED_SHORT_4_4_4_4;
- break;
- }
- switch (internalformat) {
- case GL_ALPHA:
- case GL_LUMINANCE_ALPHA:
- case GL_LUMINANCE:
- type = GL_UNSIGNED_BYTE;
- break;
- }
-
- // figure out the format to use for the new texture
- switch (cbFormatIdx) {
- case GGL_PIXEL_FORMAT_RGBA_8888:
- case GGL_PIXEL_FORMAT_A_8:
- case GGL_PIXEL_FORMAT_RGBA_5551:
- case GGL_PIXEL_FORMAT_RGBA_4444:
- format = internalformat;
- break;
- case GGL_PIXEL_FORMAT_RGBX_8888:
- case GGL_PIXEL_FORMAT_RGB_888:
- case GGL_PIXEL_FORMAT_RGB_565:
- case GGL_PIXEL_FORMAT_L_8:
- switch (internalformat) {
- case GL_LUMINANCE:
- case GL_RGB:
- format = internalformat;
- break;
- }
- break;
- }
-
- if (format == 0) {
- // invalid combination
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- // create the new texture...
- int32_t size;
- GGLSurface* surface;
- int error = createTextureSurface(c, &surface, &size,
- level, format, type, width, height);
- if (error) {
- ogles_error(c, error);
- return;
- }
-
- // The bottom row is stored first in textures
- GGLSurface txSurface(*surface);
- txSurface.stride = -txSurface.stride;
-
- // (x,y) is the lower-left corner of colorBuffer
- y = cbSurface.height - (y + height);
-
- /* The GLES spec says:
- * If any of the pixels within the specified rectangle are outside
- * the framebuffer associated with the current rendering context,
- * then the values obtained for those pixels are undefined.
- */
- if (x+width > GLint(cbSurface.width))
- width = cbSurface.width - x;
-
- if (y+height > GLint(cbSurface.height))
- height = cbSurface.height - y;
-
- int err = copyPixels(c,
- txSurface, 0, 0,
- cbSurface, x, y, width, height);
- if (err) {
- ogles_error(c, err);
- }
-
- generateMipmap(c, level);
-}
-
-void glCopyTexSubImage2D(
- GLenum target, GLint level, GLint xoffset, GLint yoffset,
- GLint x, GLint y, GLsizei width, GLsizei height)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (xoffset<0 || yoffset<0 || width<0 || height<0 || level<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (!width || !height) {
- return; // okay, but no-op.
- }
-
- // find out which texture is bound to the current unit
- const int active = c->textures.active;
- EGLTextureObject* tex = c->textures.tmu[active].texture;
- const GGLSurface& surface(tex->mip(level));
-
- if (!tex->internalformat) {
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
- if ((xoffset + width > GLsizei(surface.width)) ||
- (yoffset + height > GLsizei(surface.height))) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- // The bottom row is stored first in textures
- GGLSurface txSurface(surface);
- txSurface.stride = -txSurface.stride;
-
- // (x,y) is the lower-left corner of colorBuffer
- const GGLSurface& cbSurface = c->rasterizer.state.buffers.color.s;
- y = cbSurface.height - (y + height);
-
- /* The GLES spec says:
- * If any of the pixels within the specified rectangle are outside
- * the framebuffer associated with the current rendering context,
- * then the values obtained for those pixels are undefined.
- */
- if (x+width > GLint(cbSurface.width))
- width = cbSurface.width - x;
-
- if (y+height > GLint(cbSurface.height))
- height = cbSurface.height - y;
-
- int err = copyPixels(c,
- txSurface, xoffset, yoffset,
- cbSurface, x, y, width, height);
- if (err) {
- ogles_error(c, err);
- return;
- }
-
- generateMipmap(c, level);
-}
-
-void glReadPixels(
- GLint x, GLint y, GLsizei width, GLsizei height,
- GLenum format, GLenum type, GLvoid *pixels)
-{
- ogles_context_t* c = ogles_context_t::get();
- if ((format != GL_RGBA) && (format != GL_RGB)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if ((type != GL_UNSIGNED_BYTE) && (type != GL_UNSIGNED_SHORT_5_6_5)) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
- if (width<0 || height<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (x<0 || y<0) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- int32_t formatIdx = GGL_PIXEL_FORMAT_NONE;
- if ((format == GL_RGBA) && (type == GL_UNSIGNED_BYTE)) {
- formatIdx = GGL_PIXEL_FORMAT_RGBA_8888;
- } else if ((format == GL_RGB) && (type == GL_UNSIGNED_SHORT_5_6_5)) {
- formatIdx = GGL_PIXEL_FORMAT_RGB_565;
- } else {
- ogles_error(c, GL_INVALID_OPERATION);
- return;
- }
-
- const GGLSurface& readSurface = c->rasterizer.state.buffers.read.s;
- if ((x+width > GLint(readSurface.width)) ||
- (y+height > GLint(readSurface.height))) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- const GGLFormat& pixelFormat(c->rasterizer.formats[formatIdx]);
- const int32_t align = c->textures.packAlignment-1;
- const int32_t bpr = ((width * pixelFormat.size) + align) & ~align;
- const int32_t stride = bpr / pixelFormat.size;
-
- GGLSurface userSurface;
- userSurface.version = sizeof(userSurface);
- userSurface.width = width;
- userSurface.height = height;
- userSurface.stride = -stride; // bottom row is transfered first
- userSurface.format = formatIdx;
- userSurface.compressedFormat = 0;
- userSurface.data = (GLubyte*)pixels;
-
- // use pixel-flinger to handle all the conversions
- GGLContext* ggl = getRasterizer(c);
- if (!ggl) {
- // the only reason this would fail is because we ran out of memory
- ogles_error(c, GL_OUT_OF_MEMORY);
- return;
- }
-
- ggl->colorBuffer(ggl, &userSurface); // destination is user buffer
- ggl->bindTexture(ggl, &readSurface); // source is read-buffer
- ggl->texCoord2i(ggl, x, readSurface.height - (y + height));
- ggl->recti(ggl, 0, 0, width, height);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark DrawTexture Extension
-#endif
-
-void glDrawTexsvOES(const GLshort* coords) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
-}
-void glDrawTexivOES(const GLint* coords) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexiOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
-}
-void glDrawTexsOES(GLshort x , GLshort y, GLshort z, GLshort w, GLshort h) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexiOES(x, y, z, w, h, c);
-}
-void glDrawTexiOES(GLint x, GLint y, GLint z, GLint w, GLint h) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexiOES(x, y, z, w, h, c);
-}
-
-void glDrawTexfvOES(const GLfloat* coords) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexxOES(
- gglFloatToFixed(coords[0]),
- gglFloatToFixed(coords[1]),
- gglFloatToFixed(coords[2]),
- gglFloatToFixed(coords[3]),
- gglFloatToFixed(coords[4]),
- c);
-}
-void glDrawTexxvOES(const GLfixed* coords) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexxOES(coords[0], coords[1], coords[2], coords[3], coords[4], c);
-}
-void glDrawTexfOES(GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h){
- ogles_context_t* c = ogles_context_t::get();
- drawTexxOES(
- gglFloatToFixed(x), gglFloatToFixed(y), gglFloatToFixed(z),
- gglFloatToFixed(w), gglFloatToFixed(h),
- c);
-}
-void glDrawTexxOES(GLfixed x, GLfixed y, GLfixed z, GLfixed w, GLfixed h) {
- ogles_context_t* c = ogles_context_t::get();
- drawTexxOES(x, y, z, w, h, c);
-}
-
-// ----------------------------------------------------------------------------
-#if 0
-#pragma mark -
-#pragma mark EGL Image Extension
-#endif
-
-void glEGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- if (image == EGL_NO_IMAGE_KHR) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
- if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- // bind it to the texture unit
- sp<EGLTextureObject> tex = getAndBindActiveTextureObject(c);
- tex->setImage(native_buffer);
-}
-
-void glEGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
-{
- ogles_context_t* c = ogles_context_t::get();
- if (target != GL_RENDERBUFFER_OES) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- if (image == EGL_NO_IMAGE_KHR) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)image;
- if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
- if (native_buffer->common.version != sizeof(ANativeWindowBuffer)) {
- ogles_error(c, GL_INVALID_VALUE);
- return;
- }
-
- // well, we're not supporting this extension anyways
-}
diff --git a/opengl/libagl/texture.h b/opengl/libagl/texture.h
deleted file mode 100644
index 98f7550..0000000
--- a/opengl/libagl/texture.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* libs/opengles/texture.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_TEXTURE_H
-#define ANDROID_OPENGLES_TEXTURE_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-#include <private/pixelflinger/ggl_context.h>
-
-#include <GLES/gl.h>
-
-#include "context.h"
-
-namespace android {
-
-void ogles_init_texture(ogles_context_t* c);
-void ogles_uninit_texture(ogles_context_t* c);
-void ogles_validate_texture(ogles_context_t* c);
-void ogles_lock_textures(ogles_context_t* c);
-void ogles_unlock_textures(ogles_context_t* c);
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_TEXTURE_H
diff --git a/opengl/libagl/vertex.cpp b/opengl/libagl/vertex.cpp
deleted file mode 100644
index 9aacdb3..0000000
--- a/opengl/libagl/vertex.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/* libs/opengles/vertex.cpp
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "context.h"
-#include "fp.h"
-#include "vertex.h"
-#include "state.h"
-#include "matrix.h"
-
-namespace android {
-
-// ----------------------------------------------------------------------------
-
-void ogles_init_vertex(ogles_context_t* c)
-{
- c->cull.enable = GL_FALSE;
- c->cull.cullFace = GL_BACK;
- c->cull.frontFace = GL_CCW;
-
- c->current.color.r = 0x10000;
- c->current.color.g = 0x10000;
- c->current.color.b = 0x10000;
- c->current.color.a = 0x10000;
-
- c->currentNormal.z = 0x10000;
-}
-
-void ogles_uninit_vertex(ogles_context_t* /*c*/)
-{
-}
-
-// ----------------------------------------------------------------------------
-// vertex processing
-// ----------------------------------------------------------------------------
-
-// Divides a vertex clip coordinates by W
-static inline
-void perspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
-{
- // [x,y,z]window = vpt * ([x,y,z]clip / clip.w)
- // [w]window = 1/w
-
- // With a regular projection generated by glFrustum(),
- // we have w=-z, therefore, w is in [zNear, zFar].
- // Also, zNear and zFar are stricly positive,
- // and 1/w (window.w) is in [1/zFar, 1/zNear], usually this
- // means ]0, +inf[ -- however, it is always recommended
- // to use as large values as possible for zNear.
- // All in all, w is usually smaller than 1.0 (assuming
- // zNear is at least 1.0); and even if zNear is smaller than 1.0
- // values of w won't be too big.
-
- const int32_t rw = gglRecip28(v->clip.w);
- const GLfixed* const m = c->transforms.vpt.transform.matrix.m;
- v->window.w = rw;
- v->window.x = gglMulAddx(gglMulx(v->clip.x, rw, 16), m[ 0], m[12], 28);
- v->window.y = gglMulAddx(gglMulx(v->clip.y, rw, 16), m[ 5], m[13], 28);
- v->window.x = TRI_FROM_FIXED(v->window.x);
- v->window.y = TRI_FROM_FIXED(v->window.y);
- if (enables & GGL_ENABLE_DEPTH_TEST) {
- v->window.z = gglMulAddx(gglMulx(v->clip.z, rw, 16), m[10], m[14], 28);
- }
-}
-
-// frustum clipping and W-divide
-static inline
-void clipFrustumPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
-{
- // ndc = clip / W
- // window = ncd * viewport
-
- // clip to the view-volume
- uint32_t clip = v->flags & vertex_t::CLIP_ALL;
- const GLfixed w = v->clip.w;
- if (v->clip.x < -w) clip |= vertex_t::CLIP_L;
- if (v->clip.x > w) clip |= vertex_t::CLIP_R;
- if (v->clip.y < -w) clip |= vertex_t::CLIP_B;
- if (v->clip.y > w) clip |= vertex_t::CLIP_T;
- if (v->clip.z < -w) clip |= vertex_t::CLIP_N;
- if (v->clip.z > w) clip |= vertex_t::CLIP_F;
-
- v->flags |= clip;
- c->arrays.cull &= clip;
-
- if (ggl_likely(!clip)) {
- // if the vertex is clipped, we don't do the perspective
- // divide, since we don't need its window coordinates.
- perspective(c, v, enables);
- }
-}
-
-// frustum clipping, user clipping and W-divide
-static inline
-void clipAllPerspective(ogles_context_t* c, vertex_t* v, uint32_t enables)
-{
- // compute eye coordinates
- c->arrays.mv_transform(
- &c->transforms.modelview.transform, &v->eye, &v->obj);
- v->flags |= vertex_t::EYE;
-
- // clip this vertex against each user clip plane
- uint32_t clip = 0;
- int planes = c->clipPlanes.enable;
- while (planes) {
- const int i = 31 - gglClz(planes);
- planes &= ~(1<<i);
- // XXX: we should have a special dot() for 2,3,4 coords vertices
- GLfixed d = dot4(c->clipPlanes.plane[i].equation.v, v->eye.v);
- if (d < 0) {
- clip |= 0x100<<i;
- }
- }
- v->flags |= clip;
-
- clipFrustumPerspective(c, v, enables);
-}
-
-// ----------------------------------------------------------------------------
-
-void ogles_vertex_project(ogles_context_t* c, vertex_t* v) {
- perspective(c, v, c->rasterizer.state.enables);
-}
-
-void ogles_vertex_perspective2D(ogles_context_t* c, vertex_t* v)
-{
- // here we assume w=1.0 and the viewport transformation
- // has been applied already.
- c->arrays.cull = 0;
- v->window.x = TRI_FROM_FIXED(v->clip.x);
- v->window.y = TRI_FROM_FIXED(v->clip.y);
- v->window.z = v->clip.z;
- v->window.w = v->clip.w << 12;
-}
-
-void ogles_vertex_perspective3DZ(ogles_context_t* c, vertex_t* v) {
- clipFrustumPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
-}
-void ogles_vertex_perspective3D(ogles_context_t* c, vertex_t* v) {
- clipFrustumPerspective(c, v, 0);
-}
-void ogles_vertex_clipAllPerspective3DZ(ogles_context_t* c, vertex_t* v) {
- clipAllPerspective(c, v, GGL_ENABLE_DEPTH_TEST);
-}
-void ogles_vertex_clipAllPerspective3D(ogles_context_t* c, vertex_t* v) {
- clipAllPerspective(c, v, 0);
-}
-
-static void clipPlanex(GLenum plane, const GLfixed* equ, ogles_context_t* c)
-{
- const int p = plane - GL_CLIP_PLANE0;
- if (ggl_unlikely(uint32_t(p) > (GL_CLIP_PLANE5 - GL_CLIP_PLANE0))) {
- ogles_error(c, GL_INVALID_ENUM);
- return;
- }
-
- vec4_t& equation = c->clipPlanes.plane[p].equation;
- memcpy(equation.v, equ, sizeof(vec4_t));
-
- ogles_validate_transform(c, transform_state_t::MVIT);
- transform_t& mvit = c->transforms.mvit4;
- mvit.point4(&mvit, &equation, &equation);
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-
-void glColor4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->current.color.r = gglFloatToFixed(r);
- c->currentColorClamped.r = gglClampx(c->current.color.r);
- c->current.color.g = gglFloatToFixed(g);
- c->currentColorClamped.g = gglClampx(c->current.color.g);
- c->current.color.b = gglFloatToFixed(b);
- c->currentColorClamped.b = gglClampx(c->current.color.b);
- c->current.color.a = gglFloatToFixed(a);
- c->currentColorClamped.a = gglClampx(c->current.color.a);
-}
-
-void glColor4x(GLfixed r, GLfixed g, GLfixed b, GLfixed a)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->current.color.r = r;
- c->current.color.g = g;
- c->current.color.b = b;
- c->current.color.a = a;
- c->currentColorClamped.r = gglClampx(r);
- c->currentColorClamped.g = gglClampx(g);
- c->currentColorClamped.b = gglClampx(b);
- c->currentColorClamped.a = gglClampx(a);
-}
-
-void glNormal3f(GLfloat x, GLfloat y, GLfloat z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->currentNormal.x = gglFloatToFixed(x);
- c->currentNormal.y = gglFloatToFixed(y);
- c->currentNormal.z = gglFloatToFixed(z);
-}
-
-void glNormal3x(GLfixed x, GLfixed y, GLfixed z)
-{
- ogles_context_t* c = ogles_context_t::get();
- c->currentNormal.x = x;
- c->currentNormal.y = y;
- c->currentNormal.z = z;
-}
-
-// ----------------------------------------------------------------------------
-
-void glClipPlanef(GLenum plane, const GLfloat* equ)
-{
- const GLfixed equx[4] = {
- gglFloatToFixed(equ[0]),
- gglFloatToFixed(equ[1]),
- gglFloatToFixed(equ[2]),
- gglFloatToFixed(equ[3])
- };
- ogles_context_t* c = ogles_context_t::get();
- clipPlanex(plane, equx, c);
-}
-
-void glClipPlanex(GLenum plane, const GLfixed* equ)
-{
- ogles_context_t* c = ogles_context_t::get();
- clipPlanex(plane, equ, c);
-}
diff --git a/opengl/libagl/vertex.h b/opengl/libagl/vertex.h
deleted file mode 100644
index 55e6213..0000000
--- a/opengl/libagl/vertex.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/* libs/opengles/vertex.h
-**
-** Copyright 2006, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
-
-#ifndef ANDROID_OPENGLES_VERTEX_H
-#define ANDROID_OPENGLES_VERTEX_H
-
-#include <stdint.h>
-#include <stddef.h>
-#include <sys/types.h>
-
-namespace android {
-
-namespace gl {
-struct vertex_t;
-struct ogles_context_t;
-};
-
-void ogles_init_vertex(ogles_context_t* c);
-void ogles_uninit_vertex(ogles_context_t* c);
-
-void ogles_vertex_perspective2D(ogles_context_t*, vertex_t*);
-
-void ogles_vertex_perspective3D(ogles_context_t*, vertex_t*);
-void ogles_vertex_perspective3DZ(ogles_context_t*, vertex_t*);
-void ogles_vertex_clipAllPerspective3D(ogles_context_t*, vertex_t*);
-void ogles_vertex_clipAllPerspective3DZ(ogles_context_t*, vertex_t*);
-
-
-void ogles_vertex_project(ogles_context_t* c, vertex_t*);
-
-}; // namespace android
-
-#endif // ANDROID_OPENGLES_VERTEX_H
-
diff --git a/opengl/libs/Android.bp b/opengl/libs/Android.bp
index eb90c8b..48a68af 100644
--- a/opengl/libs/Android.bp
+++ b/opengl/libs/Android.bp
@@ -159,7 +159,7 @@
"libEGL_getProcAddress",
"libEGL_blobCache",
],
- ldflags: ["-Wl,--exclude-libs=ALL"],
+ ldflags: ["-Wl,--exclude-libs=ALL,--Bsymbolic-functions"],
export_include_dirs: ["EGL/include"],
}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 038a432..e143260 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -51,12 +51,6 @@
* /vendor/lib/egl/libGLESv1_CM.so
* /vendor/lib/egl/libGLESv2.so
*
- * The software renderer for the emulator must be provided as a single
- * library at:
- *
- * /system/lib/egl/libGLES_android.so
- *
- *
* For backward compatibility and to facilitate the transition to
* this new naming scheme, the loader will additionally look for:
*
@@ -146,38 +140,6 @@
#endif
#endif
-static void setEmulatorGlesValue(void) {
- char prop[PROPERTY_VALUE_MAX];
- property_get("ro.kernel.qemu", prop, "0");
- if (atoi(prop) != 1) return;
-
- property_get("ro.kernel.qemu.gles",prop,"0");
- if (atoi(prop) == 1) {
- ALOGD("Emulator has host GPU support, qemu.gles is set to 1.");
- property_set("qemu.gles", "1");
- return;
- }
-
- // for now, checking the following
- // directory is good enough for emulator system images
- const char* vendor_lib_path =
-#if defined(__LP64__)
- "/vendor/lib64/egl";
-#else
- "/vendor/lib/egl";
-#endif
-
- const bool has_vendor_lib = (access(vendor_lib_path, R_OK) == 0);
- if (has_vendor_lib) {
- ALOGD("Emulator has vendor provided software renderer, qemu.gles is set to 2.");
- property_set("qemu.gles", "2");
- } else {
- ALOGD("Emulator without GPU support detected. "
- "Fallback to legacy software renderer, qemu.gles is set to 0.");
- property_set("qemu.gles", "0");
- }
-}
-
static const char* DRIVER_SUFFIX_PROPERTY = "ro.hardware.egl";
static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
@@ -260,8 +222,6 @@
return cnx->dso;
}
- setEmulatorGlesValue();
-
// Check if we should use ANGLE early, so loading each driver doesn't require repeated queries.
if (android::GraphicsEnv::getInstance().shouldUseAngle()) {
cnx->shouldUseAngle = true;
@@ -311,7 +271,7 @@
}
if (!hnd) {
- android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
+ android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
false, systemTime() - openTime);
}
@@ -330,7 +290,7 @@
}
if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
- android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
+ android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
false, systemTime() - openTime);
}
@@ -340,7 +300,7 @@
LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
"couldn't load system OpenGL ES wrapper libraries");
- android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL, true,
+ android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true,
systemTime() - openTime);
return (void*)hnd;
@@ -637,7 +597,7 @@
return nullptr;
}
- android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::ANGLE);
+ android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::ANGLE);
driver_t* hnd = nullptr;
// ANGLE doesn't ship with GLES library, and thus we skip GLES driver.
@@ -666,7 +626,7 @@
}
ALOGD("Load updated gl driver.");
- android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED);
+ android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL_UPDATED);
driver_t* hnd = nullptr;
void* dso = load_updated_driver("GLES", ns);
if (dso) {
@@ -697,7 +657,7 @@
Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
const bool exact) {
ATRACE_CALL();
- android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL);
+ android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
driver_t* hnd = nullptr;
void* dso = load_system_driver("GLES", suffix, exact);
if (dso) {
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index e996be6..d1b4a4e 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -1379,6 +1379,9 @@
if (!_s.get())
return setError(EGL_BAD_SURFACE, (EGLBoolean)EGL_FALSE);
+ if (n_rects < 0 || (n_rects > 0 && rects == NULL))
+ return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
+
egl_surface_t* const s = get_surface(draw);
if (CC_UNLIKELY(dp->traceGpuCompletion)) {
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index c8253e0..55a0c0a 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -28,7 +28,12 @@
#include <utils/String8.h>
#include <utils/Trace.h>
+#include <array>
+#include <fstream>
+#include <sstream>
+#include <sys/types.h>
#include <vkjson.h>
+#include <unistd.h>
#include "gpustats/GpuStats.h"
@@ -40,6 +45,7 @@
status_t cmdHelp(int out);
status_t cmdVkjson(int out, int err);
void dumpGameDriverInfo(std::string* result);
+void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid);
} // namespace
const String16 sDump("android.permission.DUMP");
@@ -51,7 +57,7 @@
void GpuService::setGpuStats(const std::string& driverPackageName,
const std::string& driverVersionName, uint64_t driverVersionCode,
int64_t driverBuildTime, const std::string& appPackageName,
- const int32_t vulkanVersion, GraphicsEnv::Driver driver,
+ const int32_t vulkanVersion, GpuStatsInfo::Driver driver,
bool isDriverLoaded, int64_t driverLoadingTime) {
mGpuStats->insert(driverPackageName, driverVersionName, driverVersionCode, driverBuildTime,
appPackageName, vulkanVersion, driver, isDriverLoaded, driverLoadingTime);
@@ -68,10 +74,151 @@
}
void GpuService::setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
- const GraphicsEnv::Stats stats, const uint64_t value) {
+ const GpuStatsInfo::Stats stats, const uint64_t value) {
mGpuStats->insertTargetStats(appPackageName, driverVersionCode, stats, value);
}
+bool isExpectedFormat(const char* str) {
+ // Should match in order:
+ // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
+ std::istringstream iss;
+ iss.str(str);
+
+ std::string word;
+ iss >> word;
+ if (word != "gpuaddr") { return false; }
+ iss >> word;
+ if (word != "useraddr") { return false; }
+ iss >> word;
+ if (word != "size") { return false; }
+ iss >> word;
+ if (word != "id") { return false; }
+ iss >> word;
+ if (word != "flags") { return false; }
+ iss >> word;
+ if (word != "type") { return false; }
+ iss >> word;
+ if (word != "usage") { return false; }
+ iss >> word;
+ if (word != "sglen") { return false; }
+ iss >> word;
+ if (word != "mapsize") { return false; }
+ iss >> word;
+ if (word != "eglsrf") { return false; }
+ iss >> word;
+ if (word != "eglimg") { return false; }
+ return true;
+}
+
+
+// Queries gpu memory via Qualcomm's /d/kgsl/proc/*/mem interface.
+status_t GpuService::getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const {
+ const std::string kDirectoryPath = "/d/kgsl/proc";
+ DIR* directory = opendir(kDirectoryPath.c_str());
+ if (!directory) { return PERMISSION_DENIED; }
+
+ // File Format:
+ // gpuaddr useraddr size id flags type usage sglen mapsize eglsrf eglimg
+ // 0000000000000000 0000000000000000 8359936 23 --w--pY-- gpumem VK/others( 38) 0 0 0 0
+ // 0000000000000000 0000000000000000 16293888 24 --wL--N-- ion surface 41 0 0 1
+
+ const bool dumpAll = dumpPid == 0;
+ static constexpr size_t kMaxLineLength = 1024;
+ static char line[kMaxLineLength];
+ while(dirent* subdir = readdir(directory)) {
+ // Skip "." and ".." in directory.
+ if (strcmp(subdir->d_name, ".") == 0 || strcmp(subdir->d_name, "..") == 0 ) { continue; }
+
+ std::string pid_str(subdir->d_name);
+ const uint32_t pid(stoi(pid_str));
+
+ if (!dumpAll && dumpPid != pid) {
+ continue;
+ }
+
+ std::string filepath(kDirectoryPath + "/" + pid_str + "/mem");
+ std::ifstream file(filepath);
+
+ // Check first line
+ file.getline(line, kMaxLineLength);
+ if (!isExpectedFormat(line)) {
+ continue;
+ }
+
+ if (result) {
+ StringAppendF(result, "%d:\n%s\n", pid, line);
+ }
+
+ while( file.getline(line, kMaxLineLength) ) {
+ if (result) {
+ StringAppendF(result, "%s\n", line);
+ }
+
+ std::istringstream iss;
+ iss.str(line);
+
+ // Skip gpuaddr, useraddr.
+ const char delimiter = ' ';
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+
+ // Get size.
+ int64_t memsize;
+ iss >> memsize;
+
+ // Skip id, flags.
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+
+ // Get type, usage.
+ std::string memtype;
+ std::string usage;
+ iss >> memtype >> usage;
+
+ // Adjust for the space in VK/others( #)
+ if (usage == "VK/others(") {
+ std::string vkTypeEnd;
+ iss >> vkTypeEnd;
+ usage.append(vkTypeEnd);
+ }
+
+ // Skip sglen.
+ iss >> std::ws;
+ iss.ignore(kMaxLineLength, delimiter);
+
+ // Get mapsize.
+ int64_t mapsize;
+ iss >> mapsize;
+
+ if (memsize == 0 && mapsize == 0) {
+ continue;
+ }
+
+ if (memtype == "gpumem") {
+ (*memories)[pid][usage].gpuMemory += memsize;
+ } else {
+ (*memories)[pid][usage].ionMemory += memsize;
+ }
+
+ if (mapsize > 0) {
+ (*memories)[pid][usage].mappedMemory += mapsize;
+ }
+ }
+
+ if (result) {
+ StringAppendF(result, "\n");
+ }
+ }
+
+ closedir(directory);
+
+ return OK;
+}
+
status_t GpuService::shellCommand(int /*in*/, int out, int err, std::vector<String16>& args) {
ATRACE_CALL();
@@ -99,24 +246,44 @@
StringAppendF(&result, "Permission Denial: can't dump gpu from pid=%d, uid=%d\n", pid, uid);
} else {
bool dumpAll = true;
- size_t index = 0;
+ bool dumpDriverInfo = false;
+ bool dumpStats = false;
+ bool dumpMemory = false;
size_t numArgs = args.size();
+ int32_t pid = 0;
if (numArgs) {
- if ((index < numArgs) && (args[index] == String16("--gpustats"))) {
- index++;
- mGpuStats->dump(args, &result);
- dumpAll = false;
+ dumpAll = false;
+ for (size_t index = 0; index < numArgs; ++index) {
+ if (args[index] == String16("--gpustats")) {
+ dumpStats = true;
+ } else if (args[index] == String16("--gpudriverinfo")) {
+ dumpDriverInfo = true;
+ } else if (args[index] == String16("--gpumem")) {
+ dumpMemory = true;
+ } else if (args[index].startsWith(String16("--gpumem="))) {
+ dumpMemory = true;
+ pid = atoi(String8(&args[index][9]));
+ }
}
}
- if (dumpAll) {
+ if (dumpAll || dumpDriverInfo) {
dumpGameDriverInfo(&result);
result.append("\n");
-
- mGpuStats->dump(Vector<String16>(), &result);
+ }
+ if (dumpAll || dumpStats) {
+ mGpuStats->dump(args, &result);
result.append("\n");
}
+ if (dumpAll || dumpMemory) {
+ GpuMemoryMap memories;
+ // Currently only queries Qualcomm gpu memory. More will be added later.
+ if (getQCommGpuMemoryInfo(&memories, &result, pid) == OK) {
+ dumpMemoryInfo(&result, memories, pid);
+ result.append("\n");
+ }
+ }
}
write(fd, result.c_str(), result.size());
@@ -168,6 +335,34 @@
StringAppendF(result, "Pre-release Game Driver: %s\n", preReleaseGameDriver);
}
+// Read and print all memory info for each process from /d/kgsl/proc/<pid>/mem.
+void dumpMemoryInfo(std::string* result, const GpuMemoryMap& memories, uint32_t pid) {
+ if (!result) return;
+
+ // Write results.
+ StringAppendF(result, "GPU Memory Summary:\n");
+ for(auto& mem : memories) {
+ uint32_t process = mem.first;
+ if (pid != 0 && pid != process) {
+ continue;
+ }
+
+ StringAppendF(result, "%d:\n", process);
+ for(auto& memStruct : mem.second) {
+ StringAppendF(result, " %s", memStruct.first.c_str());
+
+ if(memStruct.second.gpuMemory > 0)
+ StringAppendF(result, ", GPU memory = %" PRId64, memStruct.second.gpuMemory);
+ if(memStruct.second.mappedMemory > 0)
+ StringAppendF(result, ", Mapped memory = %" PRId64, memStruct.second.mappedMemory);
+ if(memStruct.second.ionMemory > 0)
+ StringAppendF(result, ", Ion memory = %" PRId64, memStruct.second.ionMemory);
+
+ StringAppendF(result, "\n");
+ }
+ }
+}
+
} // anonymous namespace
} // namespace android
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 7d44a35..b3dc2e2 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -25,11 +25,22 @@
#include <mutex>
#include <vector>
+#include <unordered_map>
namespace android {
class GpuStats;
+struct MemoryStruct {
+ int64_t gpuMemory;
+ int64_t mappedMemory;
+ int64_t ionMemory;
+};
+
+// A map that keeps track of how much memory of each type is allocated by every process.
+// Format: map[pid][memoryType] = MemoryStruct()'
+using GpuMemoryMap = std::unordered_map<int32_t, std::unordered_map<std::string, MemoryStruct>>;
+
class GpuService : public BnGpuService, public PriorityDumper {
public:
static const char* const SERVICE_NAME ANDROID_API;
@@ -46,12 +57,12 @@
void setGpuStats(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
const std::string& appPackageName, const int32_t vulkanVersion,
- GraphicsEnv::Driver driver, bool isDriverLoaded,
+ GpuStatsInfo::Driver driver, bool isDriverLoaded,
int64_t driverLoadingTime) override;
status_t getGpuStatsGlobalInfo(std::vector<GpuStatsGlobalInfo>* outStats) const override;
status_t getGpuStatsAppInfo(std::vector<GpuStatsAppInfo>* outStats) const override;
void setTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
- const GraphicsEnv::Stats stats, const uint64_t value) override;
+ const GpuStatsInfo::Stats stats, const uint64_t value) override;
/*
* IBinder interface
@@ -71,6 +82,8 @@
status_t doDump(int fd, const Vector<String16>& args, bool asProto);
+ status_t getQCommGpuMemoryInfo(GpuMemoryMap* memories, std::string* result, int32_t dumpPid) const;
+
/*
* Attributes
*/
diff --git a/services/gpuservice/gpustats/GpuStats.cpp b/services/gpuservice/gpustats/GpuStats.cpp
index 5d27e72..67babd4 100644
--- a/services/gpuservice/gpustats/GpuStats.cpp
+++ b/services/gpuservice/gpustats/GpuStats.cpp
@@ -27,20 +27,20 @@
namespace android {
-static void addLoadingCount(GraphicsEnv::Driver driver, bool isDriverLoaded,
+static void addLoadingCount(GpuStatsInfo::Driver driver, bool isDriverLoaded,
GpuStatsGlobalInfo* const outGlobalInfo) {
switch (driver) {
- case GraphicsEnv::Driver::GL:
- case GraphicsEnv::Driver::GL_UPDATED:
+ case GpuStatsInfo::Driver::GL:
+ case GpuStatsInfo::Driver::GL_UPDATED:
outGlobalInfo->glLoadingCount++;
if (!isDriverLoaded) outGlobalInfo->glLoadingFailureCount++;
break;
- case GraphicsEnv::Driver::VULKAN:
- case GraphicsEnv::Driver::VULKAN_UPDATED:
+ case GpuStatsInfo::Driver::VULKAN:
+ case GpuStatsInfo::Driver::VULKAN_UPDATED:
outGlobalInfo->vkLoadingCount++;
if (!isDriverLoaded) outGlobalInfo->vkLoadingFailureCount++;
break;
- case GraphicsEnv::Driver::ANGLE:
+ case GpuStatsInfo::Driver::ANGLE:
outGlobalInfo->angleLoadingCount++;
if (!isDriverLoaded) outGlobalInfo->angleLoadingFailureCount++;
break;
@@ -49,22 +49,22 @@
}
}
-static void addLoadingTime(GraphicsEnv::Driver driver, int64_t driverLoadingTime,
+static void addLoadingTime(GpuStatsInfo::Driver driver, int64_t driverLoadingTime,
GpuStatsAppInfo* const outAppInfo) {
switch (driver) {
- case GraphicsEnv::Driver::GL:
- case GraphicsEnv::Driver::GL_UPDATED:
+ case GpuStatsInfo::Driver::GL:
+ case GpuStatsInfo::Driver::GL_UPDATED:
if (outAppInfo->glDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
outAppInfo->glDriverLoadingTime.emplace_back(driverLoadingTime);
}
break;
- case GraphicsEnv::Driver::VULKAN:
- case GraphicsEnv::Driver::VULKAN_UPDATED:
+ case GpuStatsInfo::Driver::VULKAN:
+ case GpuStatsInfo::Driver::VULKAN_UPDATED:
if (outAppInfo->vkDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
outAppInfo->vkDriverLoadingTime.emplace_back(driverLoadingTime);
}
break;
- case GraphicsEnv::Driver::ANGLE:
+ case GpuStatsInfo::Driver::ANGLE:
if (outAppInfo->angleDriverLoadingTime.size() < GpuStats::MAX_NUM_LOADING_TIMES) {
outAppInfo->angleDriverLoadingTime.emplace_back(driverLoadingTime);
}
@@ -77,7 +77,7 @@
void GpuStats::insert(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
const std::string& appPackageName, const int32_t vulkanVersion,
- GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
+ GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime) {
ATRACE_CALL();
std::lock_guard<std::mutex> lock(mLock);
@@ -127,7 +127,7 @@
}
void GpuStats::insertTargetStats(const std::string& appPackageName,
- const uint64_t driverVersionCode, const GraphicsEnv::Stats stats,
+ const uint64_t driverVersionCode, const GpuStatsInfo::Stats stats,
const uint64_t /*value*/) {
ATRACE_CALL();
@@ -139,9 +139,12 @@
}
switch (stats) {
- case GraphicsEnv::Stats::CPU_VULKAN_IN_USE:
+ case GpuStatsInfo::Stats::CPU_VULKAN_IN_USE:
mAppStats[appStatsKey].cpuVulkanInUse = true;
break;
+ case GpuStatsInfo::Stats::FALSE_PREROTATION:
+ mAppStats[appStatsKey].falsePrerotation = true;
+ break;
default:
break;
}
diff --git a/services/gpuservice/gpustats/GpuStats.h b/services/gpuservice/gpustats/GpuStats.h
index 378f7f4..656b181 100644
--- a/services/gpuservice/gpustats/GpuStats.h
+++ b/services/gpuservice/gpustats/GpuStats.h
@@ -36,10 +36,10 @@
void insert(const std::string& driverPackageName, const std::string& driverVersionName,
uint64_t driverVersionCode, int64_t driverBuildTime,
const std::string& appPackageName, const int32_t vulkanVersion,
- GraphicsEnv::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
+ GpuStatsInfo::Driver driver, bool isDriverLoaded, int64_t driverLoadingTime);
// Insert target stats into app stats or potentially global stats as well.
void insertTargetStats(const std::string& appPackageName, const uint64_t driverVersionCode,
- const GraphicsEnv::Stats stats, const uint64_t value);
+ const GpuStatsInfo::Stats stats, const uint64_t value);
// dumpsys interface
void dump(const Vector<String16>& args, std::string* result);
// Pull gpu global stats
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 11578c3..f6b5935 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -44,6 +44,7 @@
"libhidlbase",
"libinput",
"liblog",
+ "libstatslog",
"libutils",
"libui",
"server_configurable_flags",
diff --git a/services/inputflinger/InputClassifier.cpp b/services/inputflinger/InputClassifier.cpp
index 6a7f279..7c061c5 100644
--- a/services/inputflinger/InputClassifier.cpp
+++ b/services/inputflinger/InputClassifier.cpp
@@ -276,7 +276,7 @@
bool eventAdded = mEvents.push(std::move(event));
if (!eventAdded) {
// If the queue is full, suspect the HAL is slow in processing the events.
- ALOGE("Dropped event with eventTime %" PRId64, event.args->eventTime);
+ ALOGE("Could not add the event to the queue. Resetting");
reset();
}
}
diff --git a/services/inputflinger/InputClassifierConverter.cpp b/services/inputflinger/InputClassifierConverter.cpp
index f82c8ef..fc8c7c3 100644
--- a/services/inputflinger/InputClassifierConverter.cpp
+++ b/services/inputflinger/InputClassifierConverter.cpp
@@ -358,6 +358,7 @@
event.displayId = args.displayId;
event.downTime = args.downTime;
event.eventTime = args.eventTime;
+ event.deviceTimestamp = 0;
event.action = getAction(args.action & AMOTION_EVENT_ACTION_MASK);
event.actionIndex = getActionIndex(args.action);
event.actionButton = getActionButton(args.actionButton);
@@ -375,7 +376,6 @@
event.pointerProperties = pointerProperties;
event.pointerCoords = pointerCoords;
- event.deviceTimestamp = args.deviceTimestamp;
event.frames = convertVideoFrames(args.videoFrames);
return event;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 423b69c..de63977 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -21,6 +21,7 @@
#include "InputListener.h"
#include <android/log.h>
+#include <math.h>
namespace android {
@@ -87,21 +88,32 @@
// --- NotifyMotionArgs ---
-NotifyMotionArgs::NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId,
- uint32_t source, int32_t displayId, uint32_t policyFlags,
- int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
- int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xPrecision, float yPrecision, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames) :
- NotifyArgs(sequenceNum, eventTime), deviceId(deviceId), source(source),
- displayId(displayId), policyFlags(policyFlags),
- action(action), actionButton(actionButton),
- flags(flags), metaState(metaState), buttonState(buttonState),
- classification(classification), edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
+NotifyMotionArgs::NotifyMotionArgs(
+ uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
+ int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState, MotionClassification classification,
+ int32_t edgeFlags, uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, float xPrecision, float yPrecision,
+ float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+ const std::vector<TouchVideoFrame>& videoFrames)
+ : NotifyArgs(sequenceNum, eventTime),
+ deviceId(deviceId),
+ source(source),
+ displayId(displayId),
+ policyFlags(policyFlags),
+ action(action),
+ actionButton(actionButton),
+ flags(flags),
+ metaState(metaState),
+ buttonState(buttonState),
+ classification(classification),
+ edgeFlags(edgeFlags),
pointerCount(pointerCount),
- xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime),
+ xPrecision(xPrecision),
+ yPrecision(yPrecision),
+ xCursorPosition(xCursorPosition),
+ yCursorPosition(yCursorPosition),
+ downTime(downTime),
videoFrames(videoFrames) {
for (uint32_t i = 0; i < pointerCount; i++) {
this->pointerProperties[i].copyFrom(pointerProperties[i]);
@@ -109,14 +121,25 @@
}
}
-NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
- NotifyArgs(other.sequenceNum, other.eventTime), deviceId(other.deviceId),
- source(other.source), displayId(other.displayId), policyFlags(other.policyFlags),
- action(other.action), actionButton(other.actionButton), flags(other.flags),
- metaState(other.metaState), buttonState(other.buttonState),
- classification(other.classification), edgeFlags(other.edgeFlags),
- deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
- xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime),
+NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other)
+ : NotifyArgs(other.sequenceNum, other.eventTime),
+ deviceId(other.deviceId),
+ source(other.source),
+ displayId(other.displayId),
+ policyFlags(other.policyFlags),
+ action(other.action),
+ actionButton(other.actionButton),
+ flags(other.flags),
+ metaState(other.metaState),
+ buttonState(other.buttonState),
+ classification(other.classification),
+ edgeFlags(other.edgeFlags),
+ pointerCount(other.pointerCount),
+ xPrecision(other.xPrecision),
+ yPrecision(other.yPrecision),
+ xCursorPosition(other.xCursorPosition),
+ yCursorPosition(other.yCursorPosition),
+ downTime(other.downTime),
videoFrames(other.videoFrames) {
for (uint32_t i = 0; i < pointerCount; i++) {
pointerProperties[i].copyFrom(other.pointerProperties[i]);
@@ -124,28 +147,23 @@
}
}
+static inline bool isCursorPositionEqual(float lhs, float rhs) {
+ return (isnan(lhs) && isnan(rhs)) || lhs == rhs;
+}
+
bool NotifyMotionArgs::operator==(const NotifyMotionArgs& rhs) const {
- bool equal =
- sequenceNum == rhs.sequenceNum
- && eventTime == rhs.eventTime
- && deviceId == rhs.deviceId
- && source == rhs.source
- && displayId == rhs.displayId
- && policyFlags == rhs.policyFlags
- && action == rhs.action
- && actionButton == rhs.actionButton
- && flags == rhs.flags
- && metaState == rhs.metaState
- && buttonState == rhs.buttonState
- && classification == rhs.classification
- && edgeFlags == rhs.edgeFlags
- && deviceTimestamp == rhs.deviceTimestamp
- && pointerCount == rhs.pointerCount
+ bool equal = sequenceNum == rhs.sequenceNum && eventTime == rhs.eventTime &&
+ deviceId == rhs.deviceId && source == rhs.source && displayId == rhs.displayId &&
+ policyFlags == rhs.policyFlags && action == rhs.action &&
+ actionButton == rhs.actionButton && flags == rhs.flags && metaState == rhs.metaState &&
+ buttonState == rhs.buttonState && classification == rhs.classification &&
+ edgeFlags == rhs.edgeFlags &&
+ pointerCount == rhs.pointerCount
// PointerProperties and PointerCoords are compared separately below
- && xPrecision == rhs.xPrecision
- && yPrecision == rhs.yPrecision
- && downTime == rhs.downTime
- && videoFrames == rhs.videoFrames;
+ && xPrecision == rhs.xPrecision && yPrecision == rhs.yPrecision &&
+ isCursorPositionEqual(xCursorPosition, rhs.xCursorPosition) &&
+ isCursorPositionEqual(yCursorPosition, rhs.yCursorPosition) &&
+ downTime == rhs.downTime && videoFrames == rhs.videoFrames;
if (!equal) {
return false;
}
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 359325f..7d30672 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -119,10 +119,6 @@
}
}
-void InputManager::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
- mDispatcher->transferTouchFocus(fromToken, toToken);
-}
-
// Used by tests only.
void InputManager::registerInputChannel(const sp<InputChannel>& channel) {
IPCThreadState* ipc = IPCThreadState::self();
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index f3da324..40f66d8 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -96,7 +96,6 @@
virtual void setInputWindows(const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener);
- virtual void transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken);
virtual void registerInputChannel(const sp<InputChannel>& channel);
virtual void unregisterInputChannel(const sp<InputChannel>& channel);
diff --git a/services/inputflinger/InputReaderBase.cpp b/services/inputflinger/InputReaderBase.cpp
index f48a645..0422d83 100644
--- a/services/inputflinger/InputReaderBase.cpp
+++ b/services/inputflinger/InputReaderBase.cpp
@@ -49,6 +49,44 @@
// --- InputReaderConfiguration ---
+std::string InputReaderConfiguration::changesToString(uint32_t changes) {
+ if (changes == 0) {
+ return "<none>";
+ }
+ std::string result;
+ if (changes & CHANGE_POINTER_SPEED) {
+ result += "POINTER_SPEED | ";
+ }
+ if (changes & CHANGE_POINTER_GESTURE_ENABLEMENT) {
+ result += "POINTER_GESTURE_ENABLEMENT | ";
+ }
+ if (changes & CHANGE_DISPLAY_INFO) {
+ result += "DISPLAY_INFO | ";
+ }
+ if (changes & CHANGE_SHOW_TOUCHES) {
+ result += "SHOW_TOUCHES | ";
+ }
+ if (changes & CHANGE_KEYBOARD_LAYOUTS) {
+ result += "KEYBOARD_LAYOUTS | ";
+ }
+ if (changes & CHANGE_DEVICE_ALIAS) {
+ result += "DEVICE_ALIAS | ";
+ }
+ if (changes & CHANGE_TOUCH_AFFINE_TRANSFORMATION) {
+ result += "TOUCH_AFFINE_TRANSFORMATION | ";
+ }
+ if (changes & CHANGE_EXTERNAL_STYLUS_PRESENCE) {
+ result += "EXTERNAL_STYLUS_PRESENCE | ";
+ }
+ if (changes & CHANGE_ENABLED_STATE) {
+ result += "ENABLED_STATE | ";
+ }
+ if (changes & CHANGE_MUST_REOPEN) {
+ result += "MUST_REOPEN | ";
+ }
+ return result;
+}
+
std::optional<DisplayViewport> InputReaderConfiguration::getDisplayViewportByUniqueId(
const std::string& uniqueDisplayId) const {
if (uniqueDisplayId.empty()) {
@@ -76,8 +114,10 @@
std::optional<DisplayViewport> result = std::nullopt;
for (const DisplayViewport& currentViewport : mDisplays) {
// Return the first match
- if (currentViewport.type == type && !result) {
- result = std::make_optional(currentViewport);
+ if (currentViewport.type == type) {
+ if (!result) {
+ result = std::make_optional(currentViewport);
+ }
count++;
}
}
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index b8c3a80..9185e00 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -34,6 +34,7 @@
"libinputreporter",
"libinputflinger_base",
"liblog",
+ "libstatslog",
"libui",
"libutils",
],
diff --git a/services/inputflinger/dispatcher/Connection.cpp b/services/inputflinger/dispatcher/Connection.cpp
index ef7f650..6f82f4f 100644
--- a/services/inputflinger/dispatcher/Connection.cpp
+++ b/services/inputflinger/dispatcher/Connection.cpp
@@ -52,13 +52,13 @@
}
}
-DispatchEntry* Connection::findWaitQueueEntry(uint32_t seq) {
- for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) {
- if (entry->seq == seq) {
- return entry;
+std::deque<DispatchEntry*>::iterator Connection::findWaitQueueEntry(uint32_t seq) {
+ for (std::deque<DispatchEntry*>::iterator it = waitQueue.begin(); it != waitQueue.end(); it++) {
+ if ((*it)->seq == seq) {
+ return it;
}
}
- return nullptr;
+ return waitQueue.end();
}
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Connection.h b/services/inputflinger/dispatcher/Connection.h
index ed4eebd..8423010 100644
--- a/services/inputflinger/dispatcher/Connection.h
+++ b/services/inputflinger/dispatcher/Connection.h
@@ -18,7 +18,6 @@
#define _UI_INPUT_INPUTDISPATCHER_CONNECTION_H
#include "InputState.h"
-#include "Queue.h"
#include <input/InputTransport.h>
#include <deque>
@@ -53,11 +52,11 @@
bool inputPublisherBlocked;
// Queue of events that need to be published to the connection.
- Queue<DispatchEntry> outboundQueue;
+ std::deque<DispatchEntry*> outboundQueue;
// Queue of events that have been published to the connection but that have not
// yet received a "finished" response from the application.
- Queue<DispatchEntry> waitQueue;
+ std::deque<DispatchEntry*> waitQueue;
explicit Connection(const sp<InputChannel>& inputChannel, bool monitor);
@@ -66,7 +65,7 @@
const std::string getWindowName() const;
const char* getStatusLabel() const;
- DispatchEntry* findWaitQueueEntry(uint32_t seq);
+ std::deque<DispatchEntry*>::iterator findWaitQueueEntry(uint32_t seq);
};
} // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 8d05640..640a69a 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -155,7 +155,8 @@
int32_t displayId, uint32_t policyFlags, int32_t action,
int32_t actionButton, int32_t flags, int32_t metaState,
int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, float xPrecision, float yPrecision, nsecs_t downTime,
+ int32_t edgeFlags, float xPrecision, float yPrecision,
+ float xCursorPosition, float yCursorPosition, nsecs_t downTime,
uint32_t pointerCount, const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords, float xOffset, float yOffset)
: EventEntry(sequenceNum, TYPE_MOTION, eventTime, policyFlags),
@@ -172,6 +173,8 @@
edgeFlags(edgeFlags),
xPrecision(xPrecision),
yPrecision(yPrecision),
+ xCursorPosition(xCursorPosition),
+ yCursorPosition(yCursorPosition),
downTime(downTime),
pointerCount(pointerCount) {
for (uint32_t i = 0; i < pointerCount; i++) {
@@ -190,11 +193,11 @@
", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, "
"buttonState=0x%08x, "
"classification=%s, edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, "
- "pointers=[",
+ "xCursorPosition=%0.1f, yCursorPosition=%0.1f, pointers=[",
deviceId, source, displayId, motionActionToString(action).c_str(),
actionButton, flags, metaState, buttonState,
motionClassificationToString(classification), edgeFlags, xPrecision,
- yPrecision);
+ yPrecision, xCursorPosition, yCursorPosition);
for (uint32_t i = 0; i < pointerCount; i++) {
if (i) {
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index b904caf..28c2799 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -29,16 +29,10 @@
namespace android::inputdispatcher {
-template <typename T>
-struct Link {
- T* next;
- T* prev;
+// Sequence number for synthesized or injected events.
+constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
-protected:
- inline Link() : next(nullptr), prev(nullptr) {}
-};
-
-struct EventEntry : Link<EventEntry> {
+struct EventEntry {
enum { TYPE_CONFIGURATION_CHANGED, TYPE_DEVICE_RESET, TYPE_KEY, TYPE_MOTION };
uint32_t sequenceNum;
@@ -50,8 +44,23 @@
bool dispatchInProgress; // initially false, set to true while dispatching
+ /**
+ * Injected keys are events from an external (probably untrusted) application
+ * and are not related to real hardware state. They come in via
+ * InputDispatcher::injectInputEvent, which sets policy flag POLICY_FLAG_INJECTED.
+ */
inline bool isInjected() const { return injectionState != nullptr; }
+ /**
+ * Synthesized events are either injected events, or events that come
+ * from real hardware, but aren't directly attributable to a specific hardware event.
+ * Key repeat is a synthesized event, because it is related to an actual hardware state
+ * (a key is currently pressed), but the repeat itself is generated by the framework.
+ */
+ inline bool isSynthesized() const {
+ return isInjected() || sequenceNum == SYNTHESIZED_EVENT_SEQUENCE_NUM;
+ }
+
void release();
virtual void appendDescription(std::string& msg) const = 0;
@@ -128,6 +137,8 @@
int32_t edgeFlags;
float xPrecision;
float yPrecision;
+ float xCursorPosition;
+ float yCursorPosition;
nsecs_t downTime;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
@@ -137,9 +148,9 @@
int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
int32_t flags, int32_t metaState, int32_t buttonState,
MotionClassification classification, int32_t edgeFlags, float xPrecision,
- float yPrecision, nsecs_t downTime, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xOffset, float yOffset);
+ float yPrecision, float xCursorPosition, float yCursorPosition, nsecs_t downTime,
+ uint32_t pointerCount, const PointerProperties* pointerProperties,
+ const PointerCoords* pointerCoords, float xOffset, float yOffset);
virtual void appendDescription(std::string& msg) const;
protected:
@@ -147,7 +158,7 @@
};
// Tracks the progress of dispatching a particular event to a particular connection.
-struct DispatchEntry : Link<DispatchEntry> {
+struct DispatchEntry {
const uint32_t seq; // unique sequence number, never 0
EventEntry* eventEntry; // the event to dispatch
@@ -195,10 +206,10 @@
//
// Commands are implicitly 'LockedInterruptible'.
struct CommandEntry;
-typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry);
+typedef std::function<void(InputDispatcher&, CommandEntry*)> Command;
class Connection;
-struct CommandEntry : Link<CommandEntry> {
+struct CommandEntry {
explicit CommandEntry(Command command);
~CommandEntry();
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 4410008..4db9ae2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -35,7 +35,7 @@
#define DEBUG_INJECTION 0
// Log debug messages about input focus tracking.
-#define DEBUG_FOCUS 0
+static constexpr bool DEBUG_FOCUS = false;
// Log debug messages about the app switch latency optimization.
#define DEBUG_APP_SWITCH 0
@@ -50,9 +50,11 @@
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
+#include <statslog.h>
#include <stddef.h>
#include <time.h>
#include <unistd.h>
+#include <queue>
#include <sstream>
#include <android-base/chrono_utils.h>
@@ -203,10 +205,39 @@
}
}
-template <typename T, typename U>
-static T getValueByKey(std::unordered_map<U, T>& map, U key) {
- typename std::unordered_map<U, T>::const_iterator it = map.find(key);
- return it != map.end() ? it->second : T{};
+/**
+ * Find the entry in std::unordered_map by key, and return it.
+ * If the entry is not found, return a default constructed entry.
+ *
+ * Useful when the entries are vectors, since an empty vector will be returned
+ * if the entry is not found.
+ * Also useful when the entries are sp<>. If an entry is not found, nullptr is returned.
+ */
+template <typename K, typename V>
+static V getValueByKey(const std::unordered_map<K, V>& map, K key) {
+ auto it = map.find(key);
+ return it != map.end() ? it->second : V{};
+}
+
+/**
+ * Find the entry in std::unordered_map by value, and remove it.
+ * If more than one entry has the same value, then all matching
+ * key-value pairs will be removed.
+ *
+ * Return true if at least one value has been removed.
+ */
+template <typename K, typename V>
+static bool removeByValue(std::unordered_map<K, V>& map, const V& value) {
+ bool removed = false;
+ for (auto it = map.begin(); it != map.end();) {
+ if (it->second == value) {
+ it = map.erase(it);
+ removed = true;
+ } else {
+ it++;
+ }
+ }
+ return removed;
}
// --- InputDispatcher ---
@@ -240,8 +271,9 @@
drainInboundQueueLocked();
}
- while (mConnectionsByFd.size() != 0) {
- unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel);
+ while (!mConnectionsByFd.empty()) {
+ sp<Connection> connection = mConnectionsByFd.begin()->second;
+ unregisterInputChannel(connection->inputChannel);
}
}
@@ -282,9 +314,9 @@
// If dispatching is frozen, do not process timeouts or try to deliver any new events.
if (mDispatchFrozen) {
-#if DEBUG_FOCUS
- ALOGD("Dispatch frozen. Waiting some more.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Dispatch frozen. Waiting some more.");
+ }
return;
}
@@ -299,7 +331,7 @@
// Ready to start a new event.
// If we don't already have a pending event, go grab one.
if (!mPendingEvent) {
- if (mInboundQueue.isEmpty()) {
+ if (mInboundQueue.empty()) {
if (isAppSwitchDue) {
// The inbound queue is empty so the app switch key we were waiting
// for will never arrive. Stop waiting for it.
@@ -324,7 +356,8 @@
}
} else {
// Inbound queue has at least one entry.
- mPendingEvent = mInboundQueue.dequeueAtHead();
+ mPendingEvent = mInboundQueue.front();
+ mInboundQueue.pop_front();
traceInboundQueueLengthLocked();
}
@@ -420,8 +453,8 @@
}
bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) {
- bool needWake = mInboundQueue.isEmpty();
- mInboundQueue.enqueueAtTail(entry);
+ bool needWake = mInboundQueue.empty();
+ mInboundQueue.push_back(entry);
traceInboundQueueLengthLocked();
switch (entry->type) {
@@ -482,9 +515,10 @@
void InputDispatcher::addRecentEventLocked(EventEntry* entry) {
entry->refCount += 1;
- mRecentQueue.enqueueAtTail(entry);
- if (mRecentQueue.count() > RECENT_QUEUE_MAX_SIZE) {
- mRecentQueue.dequeueAtHead()->release();
+ mRecentQueue.push_back(entry);
+ if (mRecentQueue.size() > RECENT_QUEUE_MAX_SIZE) {
+ mRecentQueue.front()->release();
+ mRecentQueue.pop_front();
}
}
@@ -643,35 +677,33 @@
}
bool InputDispatcher::haveCommandsLocked() const {
- return !mCommandQueue.isEmpty();
+ return !mCommandQueue.empty();
}
bool InputDispatcher::runCommandsLockedInterruptible() {
- if (mCommandQueue.isEmpty()) {
+ if (mCommandQueue.empty()) {
return false;
}
do {
- CommandEntry* commandEntry = mCommandQueue.dequeueAtHead();
-
+ std::unique_ptr<CommandEntry> commandEntry = std::move(mCommandQueue.front());
+ mCommandQueue.pop_front();
Command command = commandEntry->command;
- (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible'
+ command(*this, commandEntry.get()); // commands are implicitly 'LockedInterruptible'
commandEntry->connection.clear();
- delete commandEntry;
- } while (!mCommandQueue.isEmpty());
+ } while (!mCommandQueue.empty());
return true;
}
-CommandEntry* InputDispatcher::postCommandLocked(Command command) {
- CommandEntry* commandEntry = new CommandEntry(command);
- mCommandQueue.enqueueAtTail(commandEntry);
- return commandEntry;
+void InputDispatcher::postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) {
+ mCommandQueue.push_back(std::move(commandEntry));
}
void InputDispatcher::drainInboundQueueLocked() {
- while (!mInboundQueue.isEmpty()) {
- EventEntry* entry = mInboundQueue.dequeueAtHead();
+ while (!mInboundQueue.empty()) {
+ EventEntry* entry = mInboundQueue.front();
+ mInboundQueue.pop_front();
releaseInboundEventLocked(entry);
}
traceInboundQueueLengthLocked();
@@ -750,9 +782,10 @@
resetKeyRepeatLocked();
// Enqueue a command to run outside the lock to tell the policy that the configuration changed.
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doNotifyConfigurationChangedLockedInterruptible);
commandEntry->eventTime = entry->eventTime;
+ postCommandLocked(std::move(commandEntry));
return true;
}
@@ -821,7 +854,7 @@
// Give the policy a chance to intercept the key.
if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) {
if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
- CommandEntry* commandEntry = postCommandLocked(
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
&InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
sp<InputWindowHandle> focusedWindowHandle =
getValueByKey(mFocusedWindowHandlesByDisplay, getTargetDisplayId(entry));
@@ -829,6 +862,7 @@
commandEntry->inputChannel = getInputChannelLocked(focusedWindowHandle->getToken());
}
commandEntry->keyEntry = entry;
+ postCommandLocked(std::move(commandEntry));
entry->refCount += 1;
return false; // wait for the command to run
} else {
@@ -1004,16 +1038,15 @@
pokeUserActivityLocked(eventEntry);
for (const InputTarget& inputTarget : inputTargets) {
- ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel);
- if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
+ sp<Connection> connection = getConnectionLocked(inputTarget.inputChannel);
+ if (connection != nullptr) {
prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget);
} else {
-#if DEBUG_FOCUS
- ALOGD("Dropping event delivery to target with channel '%s' because it "
- "is no longer registered with the input dispatcher.",
- inputTarget.inputChannel->getName().c_str());
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Dropping event delivery to target with channel '%s' because it "
+ "is no longer registered with the input dispatcher.",
+ inputTarget.inputChannel->getName().c_str());
+ }
}
}
}
@@ -1024,9 +1057,9 @@
const sp<InputWindowHandle>& windowHandle, nsecs_t* nextWakeupTime, const char* reason) {
if (applicationHandle == nullptr && windowHandle == nullptr) {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
-#if DEBUG_FOCUS
- ALOGD("Waiting for system to become ready for input. Reason: %s", reason);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Waiting for system to become ready for input. Reason: %s", reason);
+ }
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY;
mInputTargetWaitStartTime = currentTime;
mInputTargetWaitTimeoutTime = LONG_LONG_MAX;
@@ -1035,10 +1068,10 @@
}
} else {
if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
-#if DEBUG_FOCUS
- ALOGD("Waiting for application to become ready for input: %s. Reason: %s",
- getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Waiting for application to become ready for input: %s. Reason: %s",
+ getApplicationWindowLabel(applicationHandle, windowHandle).c_str(), reason);
+ }
nsecs_t timeout;
if (windowHandle != nullptr) {
timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
@@ -1102,21 +1135,18 @@
mInputTargetWaitTimeoutExpired = true;
// Input state will not be realistic. Mark it out of sync.
- if (inputChannel.get()) {
- ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
- if (connectionIndex >= 0) {
- sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
- sp<IBinder> token = connection->inputChannel->getToken();
+ sp<Connection> connection = getConnectionLocked(inputChannel);
+ if (connection != nullptr) {
+ sp<IBinder> token = connection->inputChannel->getToken();
- if (token != nullptr) {
- removeWindowByTokenLocked(token);
- }
+ if (token != nullptr) {
+ removeWindowByTokenLocked(token);
+ }
- if (connection->status == Connection::STATUS_NORMAL) {
- CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
- "application not responding");
- synthesizeCancelationEventsForConnectionLocked(connection, options);
- }
+ if (connection->status == Connection::STATUS_NORMAL) {
+ CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS,
+ "application not responding");
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
}
}
}
@@ -1130,9 +1160,9 @@
}
void InputDispatcher::resetANRTimeoutsLocked() {
-#if DEBUG_FOCUS
- ALOGD("Resetting ANR timeouts.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Resetting ANR timeouts.");
+ }
// Reset input target wait timeout.
mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE;
@@ -1186,10 +1216,8 @@
handleTargetsNotReadyLocked(currentTime, entry, focusedApplicationHandle,
nullptr, nextWakeupTime,
"Waiting because no window has focus but there is "
- "a "
- "focused application that may eventually add a "
- "window "
- "when it finishes starting up.");
+ "a focused application that may eventually add a "
+ "window when it finishes starting up.");
goto Unresponsive;
}
@@ -1226,11 +1254,11 @@
Unresponsive:
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
-#if DEBUG_FOCUS
- ALOGD("findFocusedWindow finished: injectionResult=%d, "
- "timeSpentWaitingForApplication=%0.1fms",
- injectionResult, timeSpentWaitingForApplication / 1000000.0);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("findFocusedWindow finished: injectionResult=%d, "
+ "timeSpentWaitingForApplication=%0.1fms",
+ injectionResult, timeSpentWaitingForApplication / 1000000.0);
+ }
return injectionResult;
}
@@ -1276,15 +1304,16 @@
maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT);
bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN ||
maskedAction == AMOTION_EVENT_ACTION_SCROLL || isHoverAction);
+ const bool isFromMouse = entry->source == AINPUT_SOURCE_MOUSE;
bool wrongDevice = false;
if (newGesture) {
bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN;
if (switchedDevice && mTempTouchState.down && !down && !isHoverAction) {
-#if DEBUG_FOCUS
- ALOGD("Dropping event because a pointer for a different device is already down "
- "in display %" PRId32,
- displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Dropping event because a pointer for a different device is already down "
+ "in display %" PRId32,
+ displayId);
+ }
// TODO: test multiple simultaneous input streams.
injectionResult = INPUT_EVENT_INJECTION_FAILED;
switchedDevice = false;
@@ -1298,11 +1327,11 @@
mTempTouchState.displayId = displayId;
isSplit = false;
} else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {
-#if DEBUG_FOCUS
- ALOGI("Dropping move event because a pointer for a different device is already active "
- "in display %" PRId32,
- displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGI("Dropping move event because a pointer for a different device is already active "
+ "in display %" PRId32,
+ displayId);
+ }
// TODO: test multiple simultaneous input streams.
injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED;
switchedDevice = false;
@@ -1313,9 +1342,17 @@
if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) {
/* Case 1: New splittable pointer going down, or need target for hover or scroll. */
+ int32_t x;
+ int32_t y;
int32_t pointerIndex = getMotionEventActionPointerIndex(action);
- int32_t x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
- int32_t y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ // Always dispatch mouse events to cursor position.
+ if (isFromMouse) {
+ x = int32_t(entry->xCursorPosition);
+ y = int32_t(entry->yCursorPosition);
+ } else {
+ x = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
+ y = int32_t(entry->pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
+ }
bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
sp<InputWindowHandle> newTouchedWindowHandle =
findTouchedWindowAtLocked(displayId, x, y, isDown /*addOutsideTargets*/,
@@ -1328,8 +1365,8 @@
// Figure out whether splitting will be allowed for this window.
if (newTouchedWindowHandle != nullptr &&
newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
- // New window supports splitting.
- isSplit = true;
+ // New window supports splitting, but we should never split mouse events.
+ isSplit = !isFromMouse;
} else if (isSplit) {
// New window does not support splitting but we have already split events.
// Ignore the new window.
@@ -1384,11 +1421,11 @@
// If the pointer is not currently down, then ignore the event.
if (!mTempTouchState.down) {
-#if DEBUG_FOCUS
- ALOGD("Dropping event because the pointer is not down or we previously "
- "dropped the pointer down event in display %" PRId32,
- displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Dropping event because the pointer is not down or we previously "
+ "dropped the pointer down event in display %" PRId32,
+ displayId);
+ }
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1405,11 +1442,11 @@
findTouchedWindowAtLocked(displayId, x, y);
if (oldTouchedWindowHandle != newTouchedWindowHandle &&
oldTouchedWindowHandle != nullptr && newTouchedWindowHandle != nullptr) {
-#if DEBUG_FOCUS
- ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
- oldTouchedWindowHandle->getName().c_str(),
- newTouchedWindowHandle->getName().c_str(), displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Touch is slipping out of window %s into window %s in display %" PRId32,
+ oldTouchedWindowHandle->getName().c_str(),
+ newTouchedWindowHandle->getName().c_str(), displayId);
+ }
// Make a slippery exit from the old window.
mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT,
@@ -1478,11 +1515,11 @@
}
bool hasGestureMonitor = !mTempTouchState.gestureMonitors.empty();
if (!haveForegroundWindow && !hasGestureMonitor) {
-#if DEBUG_FOCUS
- ALOGD("Dropping event because there is no touched foreground window in display %" PRId32
- " or gesture monitor to receive it.",
- displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Dropping event because there is no touched foreground window in display "
+ "%" PRId32 " or gesture monitor to receive it.",
+ displayId);
+ }
injectionResult = INPUT_EVENT_INJECTION_FAILED;
goto Failed;
}
@@ -1586,18 +1623,19 @@
if (injectionPermission == INJECTION_PERMISSION_GRANTED) {
if (!wrongDevice) {
if (switchedDevice) {
-#if DEBUG_FOCUS
- ALOGD("Conflicting pointer actions: Switched to a different device.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Conflicting pointer actions: Switched to a different device.");
+ }
*outConflictingPointerActions = true;
}
if (isHoverAction) {
// Started hovering, therefore no longer down.
if (oldState && oldState->down) {
-#if DEBUG_FOCUS
- ALOGD("Conflicting pointer actions: Hover received while pointer was down.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Conflicting pointer actions: Hover received while pointer was "
+ "down.");
+ }
*outConflictingPointerActions = true;
}
mTempTouchState.reset();
@@ -1614,9 +1652,9 @@
} else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) {
// First pointer went down.
if (oldState && oldState->down) {
-#if DEBUG_FOCUS
- ALOGD("Conflicting pointer actions: Down received while already down.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Conflicting pointer actions: Down received while already down.");
+ }
*outConflictingPointerActions = true;
}
} else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) {
@@ -1657,9 +1695,9 @@
mLastHoverWindowHandle = newHoverWindowHandle;
}
} else {
-#if DEBUG_FOCUS
- ALOGD("Not updating touch focus because injection was denied.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Not updating touch focus because injection was denied.");
+ }
}
Unresponsive:
@@ -1668,11 +1706,11 @@
nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime);
updateDispatchStatistics(currentTime, entry, injectionResult, timeSpentWaitingForApplication);
-#if DEBUG_FOCUS
- ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
- "timeSpentWaitingForApplication=%0.1fms",
- injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, "
+ "timeSpentWaitingForApplication=%0.1fms",
+ injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0);
+ }
return injectionResult;
}
@@ -1790,18 +1828,16 @@
}
// If the window's connection is not registered then keep waiting.
- ssize_t connectionIndex =
- getConnectionIndexLocked(getInputChannelLocked(windowHandle->getToken()));
- if (connectionIndex < 0) {
+ sp<Connection> connection =
+ getConnectionLocked(getInputChannelLocked(windowHandle->getToken()));
+ if (connection == nullptr) {
return StringPrintf("Waiting because the %s window's input channel is not "
"registered with the input dispatcher. The window may be in the "
- "process "
- "of being removed.",
+ "process of being removed.",
targetType);
}
// If the connection is dead then keep waiting.
- sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
if (connection->status != Connection::STATUS_NORMAL) {
return StringPrintf("Waiting because the %s window's input connection is %s."
"The window may be in the process of being removed.",
@@ -1811,9 +1847,9 @@
// If the connection is backed up then keep waiting.
if (connection->inputPublisherBlocked) {
return StringPrintf("Waiting because the %s window's input channel is full. "
- "Outbound queue length: %d. Wait queue length: %d.",
- targetType, connection->outboundQueue.count(),
- connection->waitQueue.count());
+ "Outbound queue length: %zu. Wait queue length: %zu.",
+ targetType, connection->outboundQueue.size(),
+ connection->waitQueue.size());
}
// Ensure that the dispatch queues aren't too far backed up for this event.
@@ -1829,13 +1865,13 @@
// often anticipate pending UI changes when typing on a keyboard.
// To obtain this behavior, we must serialize key events with respect to all
// prior input events.
- if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
+ if (!connection->outboundQueue.empty() || !connection->waitQueue.empty()) {
return StringPrintf("Waiting to send key event because the %s window has not "
"finished processing all of the input events that were previously "
- "delivered to it. Outbound queue length: %d. Wait queue length: "
- "%d.",
- targetType, connection->outboundQueue.count(),
- connection->waitQueue.count());
+ "delivered to it. Outbound queue length: %zu. Wait queue length: "
+ "%zu.",
+ targetType, connection->outboundQueue.size(),
+ connection->waitQueue.size());
}
} else {
// Touch events can always be sent to a window immediately because the user intended
@@ -1853,16 +1889,17 @@
// The one case where we pause input event delivery is when the wait queue is piling
// up with lots of events because the application is not responding.
// This condition ensures that ANRs are detected reliably.
- if (!connection->waitQueue.isEmpty() &&
- currentTime >= connection->waitQueue.head->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) {
+ if (!connection->waitQueue.empty() &&
+ currentTime >=
+ connection->waitQueue.front()->deliveryTime + STREAM_AHEAD_EVENT_TIMEOUT) {
return StringPrintf("Waiting to send non-key event because the %s window has not "
"finished processing certain input events that were delivered to "
"it over "
- "%0.1fms ago. Wait queue length: %d. Wait queue head age: "
+ "%0.1fms ago. Wait queue length: %zu. Wait queue head age: "
"%0.1fms.",
targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
- connection->waitQueue.count(),
- (currentTime - connection->waitQueue.head->deliveryTime) *
+ connection->waitQueue.size(),
+ (currentTime - connection->waitQueue.front()->deliveryTime) *
0.000001f);
}
}
@@ -1925,10 +1962,11 @@
}
}
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doPokeUserActivityLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry =
+ std::make_unique<CommandEntry>(&InputDispatcher::doPokeUserActivityLockedInterruptible);
commandEntry->eventTime = eventEntry->eventTime;
commandEntry->userActivityEventType = eventType;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime,
@@ -1971,10 +2009,11 @@
if (!splitMotionEntry) {
return; // split event was dropped
}
-#if DEBUG_FOCUS
- ALOGD("channel '%s' ~ Split motion event.", connection->getInputChannelName().c_str());
- logOutboundMotionDetails(" ", splitMotionEntry);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("channel '%s' ~ Split motion event.",
+ connection->getInputChannelName().c_str());
+ logOutboundMotionDetails(" ", splitMotionEntry);
+ }
enqueueDispatchEntriesLocked(currentTime, connection, splitMotionEntry, inputTarget);
splitMotionEntry->release();
return;
@@ -1997,7 +2036,7 @@
ATRACE_NAME(message.c_str());
}
- bool wasEmpty = connection->outboundQueue.isEmpty();
+ bool wasEmpty = connection->outboundQueue.empty();
// Enqueue dispatch entries for the requested modes.
enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
@@ -2014,7 +2053,7 @@
InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
// If the outbound queue was previously empty, start the dispatch cycle going.
- if (wasEmpty && !connection->outboundQueue.isEmpty()) {
+ if (wasEmpty && !connection->outboundQueue.empty()) {
startDispatchCycleLocked(currentTime, connection);
}
}
@@ -2120,7 +2159,7 @@
}
// Enqueue the dispatch entry.
- connection->outboundQueue.enqueueAtTail(dispatchEntry);
+ connection->outboundQueue.push_back(dispatchEntry);
traceOutboundQueueLength(connection);
}
@@ -2146,9 +2185,10 @@
return;
}
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
commandEntry->newToken = newToken;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2162,9 +2202,8 @@
ALOGD("channel '%s' ~ startDispatchCycle", connection->getInputChannelName().c_str());
#endif
- while (connection->status == Connection::STATUS_NORMAL &&
- !connection->outboundQueue.isEmpty()) {
- DispatchEntry* dispatchEntry = connection->outboundQueue.head;
+ while (connection->status == Connection::STATUS_NORMAL && !connection->outboundQueue.empty()) {
+ DispatchEntry* dispatchEntry = connection->outboundQueue.front();
dispatchEntry->deliveryTime = currentTime;
// Publish the event.
@@ -2232,10 +2271,13 @@
motionEntry->buttonState,
motionEntry->classification, xOffset, yOffset,
motionEntry->xPrecision,
- motionEntry->yPrecision, motionEntry->downTime,
- motionEntry->eventTime,
+ motionEntry->yPrecision,
+ motionEntry->xCursorPosition,
+ motionEntry->yCursorPosition,
+ motionEntry->downTime, motionEntry->eventTime,
motionEntry->pointerCount,
motionEntry->pointerProperties, usingCoords);
+ reportTouchEventForStatistics(*motionEntry);
break;
}
@@ -2247,7 +2289,7 @@
// Check the result.
if (status) {
if (status == WOULD_BLOCK) {
- if (connection->waitQueue.isEmpty()) {
+ if (connection->waitQueue.empty()) {
ALOGE("channel '%s' ~ Could not publish event because the pipe is full. "
"This is unexpected because the wait queue is empty, so the pipe "
"should be empty and we shouldn't have any problems writing an "
@@ -2274,9 +2316,11 @@
}
// Re-enqueue the event on the wait queue.
- connection->outboundQueue.dequeue(dispatchEntry);
+ connection->outboundQueue.erase(std::remove(connection->outboundQueue.begin(),
+ connection->outboundQueue.end(),
+ dispatchEntry));
traceOutboundQueueLength(connection);
- connection->waitQueue.enqueueAtTail(dispatchEntry);
+ connection->waitQueue.push_back(dispatchEntry);
traceWaitQueueLength(connection);
}
}
@@ -2309,9 +2353,9 @@
#endif
// Clear the dispatch queues.
- drainDispatchQueue(&connection->outboundQueue);
+ drainDispatchQueue(connection->outboundQueue);
traceOutboundQueueLength(connection);
- drainDispatchQueue(&connection->waitQueue);
+ drainDispatchQueue(connection->waitQueue);
traceWaitQueueLength(connection);
// The connection appears to be unrecoverably broken.
@@ -2326,9 +2370,10 @@
}
}
-void InputDispatcher::drainDispatchQueue(Queue<DispatchEntry>* queue) {
- while (!queue->isEmpty()) {
- DispatchEntry* dispatchEntry = queue->dequeueAtHead();
+void InputDispatcher::drainDispatchQueue(std::deque<DispatchEntry*>& queue) {
+ while (!queue.empty()) {
+ DispatchEntry* dispatchEntry = queue.front();
+ queue.pop_front();
releaseDispatchEntry(dispatchEntry);
}
}
@@ -2346,8 +2391,7 @@
{ // acquire lock
std::scoped_lock _l(d->mLock);
- ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd);
- if (connectionIndex < 0) {
+ if (d->mConnectionsByFd.find(fd) == d->mConnectionsByFd.end()) {
ALOGE("Received spurious receive callback for unknown input channel. "
"fd=%d, events=0x%x",
fd, events);
@@ -2355,7 +2399,7 @@
}
bool notify;
- sp<Connection> connection = d->mConnectionsByFd.valueAt(connectionIndex);
+ sp<Connection> connection = d->mConnectionsByFd[fd];
if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) {
if (!(events & ALOOPER_EVENT_INPUT)) {
ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. "
@@ -2409,8 +2453,8 @@
void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked(
const CancelationOptions& options) {
- for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
- synthesizeCancelationEventsForConnectionLocked(mConnectionsByFd.valueAt(i), options);
+ for (const auto& pair : mConnectionsByFd) {
+ synthesizeCancelationEventsForConnectionLocked(pair.second, options);
}
}
@@ -2433,10 +2477,12 @@
void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked(
const sp<InputChannel>& channel, const CancelationOptions& options) {
- ssize_t index = getConnectionIndexLocked(channel);
- if (index >= 0) {
- synthesizeCancelationEventsForConnectionLocked(mConnectionsByFd.valueAt(index), options);
+ sp<Connection> connection = getConnectionLocked(channel);
+ if (connection == nullptr) {
+ return;
}
+
+ synthesizeCancelationEventsForConnectionLocked(connection, options);
}
void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
@@ -2573,8 +2619,9 @@
originalMotionEntry->metaState, originalMotionEntry->buttonState,
originalMotionEntry->classification, originalMotionEntry->edgeFlags,
originalMotionEntry->xPrecision, originalMotionEntry->yPrecision,
- originalMotionEntry->downTime, splitPointerCount,
- splitPointerProperties, splitPointerCoords, 0, 0);
+ originalMotionEntry->xCursorPosition,
+ originalMotionEntry->yCursorPosition, originalMotionEntry->downTime,
+ splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
if (originalMotionEntry->injectionState) {
splitMotionEntry->injectionState = originalMotionEntry->injectionState;
@@ -2720,11 +2767,13 @@
#if DEBUG_INBOUND_EVENT_DETAILS
ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
", policyFlags=0x%x, "
- "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
- "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
+ "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, "
+ "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, xCursorPosition=%f, "
+ "yCursorPosition=%f, downTime=%" PRId64,
args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
- args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
+ args->edgeFlags, args->xPrecision, args->yPrecision, args->xCursorPosition,
+ args->yCursorPosition, args->downTime);
for (uint32_t i = 0; i < args->pointerCount; i++) {
ALOGD(" Pointer %d: id=%d, toolType=%d, "
"x=%f, y=%f, pressure=%f, size=%f, "
@@ -2768,7 +2817,8 @@
event.initialize(args->deviceId, args->source, args->displayId, args->action,
args->actionButton, args->flags, args->edgeFlags, args->metaState,
args->buttonState, args->classification, 0, 0, args->xPrecision,
- args->yPrecision, args->downTime, args->eventTime, args->pointerCount,
+ args->yPrecision, args->xCursorPosition, args->yCursorPosition,
+ args->downTime, args->eventTime, args->pointerCount,
args->pointerProperties, args->pointerCoords);
policyFlags |= POLICY_FLAG_FILTERED;
@@ -2785,8 +2835,9 @@
args->displayId, policyFlags, args->action, args->actionButton,
args->flags, args->metaState, args->buttonState,
args->classification, args->edgeFlags, args->xPrecision,
- args->yPrecision, args->downTime, args->pointerCount,
- args->pointerProperties, args->pointerCoords, 0, 0);
+ args->yPrecision, args->xCursorPosition, args->yCursorPosition,
+ args->downTime, args->pointerCount, args->pointerProperties,
+ args->pointerCoords, 0, 0);
needWake = enqueueInboundEventLocked(newEntry);
mLock.unlock();
@@ -2849,8 +2900,7 @@
policyFlags |= POLICY_FLAG_TRUSTED;
}
- EventEntry* firstInjectedEntry;
- EventEntry* lastInjectedEntry;
+ std::queue<EventEntry*> injectedEntries;
switch (event->getType()) {
case AINPUT_EVENT_TYPE_KEY: {
KeyEvent keyEvent;
@@ -2884,13 +2934,14 @@
}
mLock.lock();
- firstInjectedEntry = new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM,
- keyEvent.getEventTime(), keyEvent.getDeviceId(),
- keyEvent.getSource(), keyEvent.getDisplayId(),
- policyFlags, action, flags, keyEvent.getKeyCode(),
- keyEvent.getScanCode(), keyEvent.getMetaState(),
- keyEvent.getRepeatCount(), keyEvent.getDownTime());
- lastInjectedEntry = firstInjectedEntry;
+ KeyEntry* injectedEntry =
+ new KeyEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, keyEvent.getEventTime(),
+ keyEvent.getDeviceId(), keyEvent.getSource(),
+ keyEvent.getDisplayId(), policyFlags, action, flags,
+ keyEvent.getKeyCode(), keyEvent.getScanCode(),
+ keyEvent.getMetaState(), keyEvent.getRepeatCount(),
+ keyEvent.getDownTime());
+ injectedEntries.push(injectedEntry);
break;
}
@@ -2918,17 +2969,20 @@
mLock.lock();
const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
- firstInjectedEntry =
+ MotionEntry* injectedEntry =
new MotionEntry(SYNTHESIZED_EVENT_SEQUENCE_NUM, *sampleEventTimes,
motionEvent->getDeviceId(), motionEvent->getSource(),
motionEvent->getDisplayId(), policyFlags, action, actionButton,
motionEvent->getFlags(), motionEvent->getMetaState(),
motionEvent->getButtonState(), motionEvent->getClassification(),
motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
- motionEvent->getYPrecision(), motionEvent->getDownTime(),
- uint32_t(pointerCount), pointerProperties, samplePointerCoords,
+ motionEvent->getYPrecision(),
+ motionEvent->getRawXCursorPosition(),
+ motionEvent->getRawYCursorPosition(),
+ motionEvent->getDownTime(), uint32_t(pointerCount),
+ pointerProperties, samplePointerCoords,
motionEvent->getXOffset(), motionEvent->getYOffset());
- lastInjectedEntry = firstInjectedEntry;
+ injectedEntries.push(injectedEntry);
for (size_t i = motionEvent->getHistorySize(); i > 0; i--) {
sampleEventTimes += 1;
samplePointerCoords += pointerCount;
@@ -2940,12 +2994,13 @@
motionEvent->getMetaState(), motionEvent->getButtonState(),
motionEvent->getClassification(),
motionEvent->getEdgeFlags(), motionEvent->getXPrecision(),
- motionEvent->getYPrecision(), motionEvent->getDownTime(),
- uint32_t(pointerCount), pointerProperties,
- samplePointerCoords, motionEvent->getXOffset(),
- motionEvent->getYOffset());
- lastInjectedEntry->next = nextInjectedEntry;
- lastInjectedEntry = nextInjectedEntry;
+ motionEvent->getYPrecision(),
+ motionEvent->getRawXCursorPosition(),
+ motionEvent->getRawYCursorPosition(),
+ motionEvent->getDownTime(), uint32_t(pointerCount),
+ pointerProperties, samplePointerCoords,
+ motionEvent->getXOffset(), motionEvent->getYOffset());
+ injectedEntries.push(nextInjectedEntry);
}
break;
}
@@ -2961,13 +3016,12 @@
}
injectionState->refCount += 1;
- lastInjectedEntry->injectionState = injectionState;
+ injectedEntries.back()->injectionState = injectionState;
bool needWake = false;
- for (EventEntry* entry = firstInjectedEntry; entry != nullptr;) {
- EventEntry* nextEntry = entry->next;
- needWake |= enqueueInboundEventLocked(entry);
- entry = nextEntry;
+ while (!injectedEntries.empty()) {
+ needWake |= enqueueInboundEventLocked(injectedEntries.front());
+ injectedEntries.pop();
}
mLock.unlock();
@@ -3093,14 +3147,7 @@
std::vector<sp<InputWindowHandle>> InputDispatcher::getWindowHandlesLocked(
int32_t displayId) const {
- std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>::const_iterator it =
- mWindowHandlesByDisplay.find(displayId);
- if (it != mWindowHandlesByDisplay.end()) {
- return it->second;
- }
-
- // Return an empty one if nothing found.
- return std::vector<sp<InputWindowHandle>>();
+ return getValueByKey(mWindowHandlesByDisplay, displayId);
}
sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
@@ -3142,6 +3189,63 @@
return mInputChannelsByToken.at(token);
}
+void InputDispatcher::updateWindowHandlesForDisplayLocked(
+ const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId) {
+ if (inputWindowHandles.empty()) {
+ // Remove all handles on a display if there are no windows left.
+ mWindowHandlesByDisplay.erase(displayId);
+ return;
+ }
+
+ // Since we compare the pointer of input window handles across window updates, we need
+ // to make sure the handle object for the same window stays unchanged across updates.
+ const std::vector<sp<InputWindowHandle>>& oldHandles = getWindowHandlesLocked(displayId);
+ std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
+ for (const sp<InputWindowHandle>& handle : oldHandles) {
+ oldHandlesByTokens[handle->getToken()] = handle;
+ }
+
+ std::vector<sp<InputWindowHandle>> newHandles;
+ for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
+ if (!handle->updateInfo()) {
+ // handle no longer valid
+ continue;
+ }
+
+ const InputWindowInfo* info = handle->getInfo();
+ if ((getInputChannelLocked(handle->getToken()) == nullptr &&
+ info->portalToDisplayId == ADISPLAY_ID_NONE)) {
+ const bool noInputChannel =
+ info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
+ const bool canReceiveInput =
+ !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
+ !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
+ if (canReceiveInput && !noInputChannel) {
+ ALOGE("Window handle %s has no registered input channel",
+ handle->getName().c_str());
+ }
+ continue;
+ }
+
+ if (info->displayId != displayId) {
+ ALOGE("Window %s updated by wrong display %d, should belong to display %d",
+ handle->getName().c_str(), displayId, info->displayId);
+ continue;
+ }
+
+ if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
+ const sp<InputWindowHandle> oldHandle = oldHandlesByTokens.at(handle->getToken());
+ oldHandle->updateFrom(handle);
+ newHandles.push_back(oldHandle);
+ } else {
+ newHandles.push_back(handle);
+ }
+ }
+
+ // Insert or replace
+ mWindowHandlesByDisplay[displayId] = newHandles;
+}
+
/**
* Called from InputManagerService, update window handle list by displayId that can receive input.
* A window handle contains information about InputChannel, Touch Region, Types, Focused,...
@@ -3152,9 +3256,13 @@
void InputDispatcher::setInputWindows(const std::vector<sp<InputWindowHandle>>& inputWindowHandles,
int32_t displayId,
const sp<ISetInputWindowsListener>& setInputWindowsListener) {
-#if DEBUG_FOCUS
- ALOGD("setInputWindows displayId=%" PRId32, displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ std::string windowList;
+ for (const sp<InputWindowHandle>& iwh : inputWindowHandles) {
+ windowList += iwh->getName() + " ";
+ }
+ ALOGD("setInputWindows displayId=%" PRId32 " %s", displayId, windowList.c_str());
+ }
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3162,73 +3270,19 @@
const std::vector<sp<InputWindowHandle>> oldWindowHandles =
getWindowHandlesLocked(displayId);
+ updateWindowHandlesForDisplayLocked(inputWindowHandles, displayId);
+
sp<InputWindowHandle> newFocusedWindowHandle = nullptr;
bool foundHoveredWindow = false;
-
- if (inputWindowHandles.empty()) {
- // Remove all handles on a display if there are no windows left.
- mWindowHandlesByDisplay.erase(displayId);
- } else {
- // Since we compare the pointer of input window handles across window updates, we need
- // to make sure the handle object for the same window stays unchanged across updates.
- const std::vector<sp<InputWindowHandle>>& oldHandles =
- mWindowHandlesByDisplay[displayId];
- std::unordered_map<sp<IBinder>, sp<InputWindowHandle>, IBinderHash> oldHandlesByTokens;
- for (const sp<InputWindowHandle>& handle : oldHandles) {
- oldHandlesByTokens[handle->getToken()] = handle;
+ for (const sp<InputWindowHandle>& windowHandle : getWindowHandlesLocked(displayId)) {
+ // Set newFocusedWindowHandle to the top most focused window instead of the last one
+ if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus &&
+ windowHandle->getInfo()->visible) {
+ newFocusedWindowHandle = windowHandle;
}
-
- std::vector<sp<InputWindowHandle>> newHandles;
- for (const sp<InputWindowHandle>& handle : inputWindowHandles) {
- if (!handle->updateInfo()) {
- // handle no longer valid
- continue;
- }
- const InputWindowInfo* info = handle->getInfo();
-
- if ((getInputChannelLocked(handle->getToken()) == nullptr &&
- info->portalToDisplayId == ADISPLAY_ID_NONE)) {
- const bool noInputChannel =
- info->inputFeatures & InputWindowInfo::INPUT_FEATURE_NO_INPUT_CHANNEL;
- const bool canReceiveInput =
- !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_TOUCHABLE) ||
- !(info->layoutParamsFlags & InputWindowInfo::FLAG_NOT_FOCUSABLE);
- if (canReceiveInput && !noInputChannel) {
- ALOGE("Window handle %s has no registered input channel",
- handle->getName().c_str());
- }
- continue;
- }
-
- if (info->displayId != displayId) {
- ALOGE("Window %s updated by wrong display %d, should belong to display %d",
- handle->getName().c_str(), displayId, info->displayId);
- continue;
- }
-
- if (oldHandlesByTokens.find(handle->getToken()) != oldHandlesByTokens.end()) {
- const sp<InputWindowHandle> oldHandle =
- oldHandlesByTokens.at(handle->getToken());
- oldHandle->updateFrom(handle);
- newHandles.push_back(oldHandle);
- } else {
- newHandles.push_back(handle);
- }
+ if (windowHandle == mLastHoverWindowHandle) {
+ foundHoveredWindow = true;
}
-
- for (const sp<InputWindowHandle>& windowHandle : newHandles) {
- // Set newFocusedWindowHandle to the top most focused window instead of the last one
- if (!newFocusedWindowHandle && windowHandle->getInfo()->hasFocus &&
- windowHandle->getInfo()->visible) {
- newFocusedWindowHandle = windowHandle;
- }
- if (windowHandle == mLastHoverWindowHandle) {
- foundHoveredWindow = true;
- }
- }
-
- // Insert or replace
- mWindowHandlesByDisplay[displayId] = newHandles;
}
if (!foundHoveredWindow) {
@@ -3240,10 +3294,10 @@
if (oldFocusedWindowHandle != newFocusedWindowHandle) {
if (oldFocusedWindowHandle != nullptr) {
-#if DEBUG_FOCUS
- ALOGD("Focus left window: %s in display %" PRId32,
- oldFocusedWindowHandle->getName().c_str(), displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Focus left window: %s in display %" PRId32,
+ oldFocusedWindowHandle->getName().c_str(), displayId);
+ }
sp<InputChannel> focusedInputChannel =
getInputChannelLocked(oldFocusedWindowHandle->getToken());
if (focusedInputChannel != nullptr) {
@@ -3254,10 +3308,10 @@
mFocusedWindowHandlesByDisplay.erase(displayId);
}
if (newFocusedWindowHandle != nullptr) {
-#if DEBUG_FOCUS
- ALOGD("Focus entered window: %s in display %" PRId32,
- newFocusedWindowHandle->getName().c_str(), displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Focus entered window: %s in display %" PRId32,
+ newFocusedWindowHandle->getName().c_str(), displayId);
+ }
mFocusedWindowHandlesByDisplay[displayId] = newFocusedWindowHandle;
}
@@ -3272,10 +3326,10 @@
for (size_t i = 0; i < state.windows.size();) {
TouchedWindow& touchedWindow = state.windows[i];
if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
-#if DEBUG_FOCUS
- ALOGD("Touched window was removed: %s in display %" PRId32,
- touchedWindow.windowHandle->getName().c_str(), displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Touched window was removed: %s in display %" PRId32,
+ touchedWindow.windowHandle->getName().c_str(), displayId);
+ }
sp<InputChannel> touchedInputChannel =
getInputChannelLocked(touchedWindow.windowHandle->getToken());
if (touchedInputChannel != nullptr) {
@@ -3297,9 +3351,9 @@
// which might not happen until the next GC.
for (const sp<InputWindowHandle>& oldWindowHandle : oldWindowHandles) {
if (!hasWindowHandleLocked(oldWindowHandle)) {
-#if DEBUG_FOCUS
- ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
+ }
oldWindowHandle->releaseChannel();
}
}
@@ -3315,9 +3369,10 @@
void InputDispatcher::setFocusedApplication(
int32_t displayId, const sp<InputApplicationHandle>& inputApplicationHandle) {
-#if DEBUG_FOCUS
- ALOGD("setFocusedApplication displayId=%" PRId32, displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("setFocusedApplication displayId=%" PRId32 " %s", displayId,
+ inputApplicationHandle ? inputApplicationHandle->getName().c_str() : "<nullptr>");
+ }
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3335,10 +3390,6 @@
oldFocusedApplicationHandle.clear();
mFocusedApplicationHandlesByDisplay.erase(displayId);
}
-
-#if DEBUG_FOCUS
- // logDispatchStateLocked();
-#endif
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -3355,9 +3406,9 @@
* display. The display-specified events won't be affected.
*/
void InputDispatcher::setFocusedDisplay(int32_t displayId) {
-#if DEBUG_FOCUS
- ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("setFocusedDisplay displayId=%" PRId32, displayId);
+ }
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3396,9 +3447,9 @@
}
}
-#if DEBUG_FOCUS
- logDispatchStateLocked();
-#endif
+ if (DEBUG_FOCUS) {
+ logDispatchStateLocked();
+ }
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -3406,9 +3457,9 @@
}
void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) {
-#if DEBUG_FOCUS
- ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen);
+ }
bool changed;
{ // acquire lock
@@ -3430,9 +3481,9 @@
changed = false;
}
-#if DEBUG_FOCUS
- logDispatchStateLocked();
-#endif
+ if (DEBUG_FOCUS) {
+ logDispatchStateLocked();
+ }
} // release lock
if (changed) {
@@ -3442,9 +3493,9 @@
}
void InputDispatcher::setInputFilterEnabled(bool enabled) {
-#if DEBUG_FOCUS
- ALOGD("setInputFilterEnabled: enabled=%d", enabled);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("setInputFilterEnabled: enabled=%d", enabled);
+ }
{ // acquire lock
std::scoped_lock _l(mLock);
@@ -3463,9 +3514,9 @@
bool InputDispatcher::transferTouchFocus(const sp<IBinder>& fromToken, const sp<IBinder>& toToken) {
if (fromToken == toToken) {
-#if DEBUG_FOCUS
- ALOGD("Trivial transfer to same window.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Trivial transfer to same window.");
+ }
return true;
}
@@ -3478,14 +3529,14 @@
ALOGW("Cannot transfer focus because from or to window not found.");
return false;
}
-#if DEBUG_FOCUS
- ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
- fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("transferTouchFocus: fromWindowHandle=%s, toWindowHandle=%s",
+ fromWindowHandle->getName().c_str(), toWindowHandle->getName().c_str());
+ }
if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) {
-#if DEBUG_FOCUS
- ALOGD("Cannot transfer focus because windows are on different displays.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Cannot transfer focus because windows are on different displays.");
+ }
return false;
}
@@ -3513,20 +3564,17 @@
Found:
if (!found) {
-#if DEBUG_FOCUS
- ALOGD("Focus transfer failed because from window did not have focus.");
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Focus transfer failed because from window did not have focus.");
+ }
return false;
}
sp<InputChannel> fromChannel = getInputChannelLocked(fromToken);
sp<InputChannel> toChannel = getInputChannelLocked(toToken);
- ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel);
- ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel);
- if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) {
- sp<Connection> fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex);
- sp<Connection> toConnection = mConnectionsByFd.valueAt(toConnectionIndex);
-
+ sp<Connection> fromConnection = getConnectionLocked(fromChannel);
+ sp<Connection> toConnection = getConnectionLocked(toChannel);
+ if (fromConnection != nullptr && toConnection != nullptr) {
fromConnection->inputState.copyPointerStateTo(toConnection->inputState);
CancelationOptions
options(CancelationOptions::CANCEL_POINTER_EVENTS,
@@ -3534,9 +3582,9 @@
synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
}
-#if DEBUG_FOCUS
- logDispatchStateLocked();
-#endif
+ if (DEBUG_FOCUS) {
+ logDispatchStateLocked();
+ }
} // release lock
// Wake up poll loop since it may need to make new input dispatching choices.
@@ -3545,9 +3593,9 @@
}
void InputDispatcher::resetAndDropEverythingLocked(const char* reason) {
-#if DEBUG_FOCUS
- ALOGD("Resetting and dropping all events (%s).", reason);
-#endif
+ if (DEBUG_FOCUS) {
+ ALOGD("Resetting and dropping all events (%s).", reason);
+ }
CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason);
synthesizeCancelationEventsForAllConnectionsLocked(options);
@@ -3703,9 +3751,9 @@
nsecs_t currentTime = now();
// Dump recently dispatched or dropped events from oldest to newest.
- if (!mRecentQueue.isEmpty()) {
- dump += StringPrintf(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
- for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
+ if (!mRecentQueue.empty()) {
+ dump += StringPrintf(INDENT "RecentQueue: length=%zu\n", mRecentQueue.size());
+ for (EventEntry* entry : mRecentQueue) {
dump += INDENT2;
entry->appendDescription(dump);
dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f);
@@ -3726,9 +3774,9 @@
}
// Dump inbound events from oldest to newest.
- if (!mInboundQueue.isEmpty()) {
- dump += StringPrintf(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
- for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
+ if (!mInboundQueue.empty()) {
+ dump += StringPrintf(INDENT "InboundQueue: length=%zu\n", mInboundQueue.size());
+ for (EventEntry* entry : mInboundQueue) {
dump += INDENT2;
entry->appendDescription(dump);
dump += StringPrintf(", age=%0.1fms\n", (currentTime - entry->eventTime) * 0.000001f);
@@ -3749,22 +3797,21 @@
dump += INDENT "ReplacedKeys: <empty>\n";
}
- if (!mConnectionsByFd.isEmpty()) {
+ if (!mConnectionsByFd.empty()) {
dump += INDENT "Connections:\n";
- for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
- const sp<Connection>& connection = mConnectionsByFd.valueAt(i);
- dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', "
+ for (const auto& pair : mConnectionsByFd) {
+ const sp<Connection>& connection = pair.second;
+ dump += StringPrintf(INDENT2 "%i: channelName='%s', windowName='%s', "
"status=%s, monitor=%s, inputPublisherBlocked=%s\n",
- i, connection->getInputChannelName().c_str(),
+ pair.first, connection->getInputChannelName().c_str(),
connection->getWindowName().c_str(), connection->getStatusLabel(),
toString(connection->monitor),
toString(connection->inputPublisherBlocked));
- if (!connection->outboundQueue.isEmpty()) {
- dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n",
- connection->outboundQueue.count());
- for (DispatchEntry* entry = connection->outboundQueue.head; entry;
- entry = entry->next) {
+ if (!connection->outboundQueue.empty()) {
+ dump += StringPrintf(INDENT3 "OutboundQueue: length=%zu\n",
+ connection->outboundQueue.size());
+ for (DispatchEntry* entry : connection->outboundQueue) {
dump.append(INDENT4);
entry->eventEntry->appendDescription(dump);
dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
@@ -3775,11 +3822,10 @@
dump += INDENT3 "OutboundQueue: <empty>\n";
}
- if (!connection->waitQueue.isEmpty()) {
- dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n",
- connection->waitQueue.count());
- for (DispatchEntry* entry = connection->waitQueue.head; entry;
- entry = entry->next) {
+ if (!connection->waitQueue.empty()) {
+ dump += StringPrintf(INDENT3 "WaitQueue: length=%zu\n",
+ connection->waitQueue.size());
+ for (DispatchEntry* entry : connection->waitQueue) {
dump += INDENT4;
entry->eventEntry->appendDescription(dump);
dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
@@ -3828,8 +3874,8 @@
{ // acquire lock
std::scoped_lock _l(mLock);
-
- if (getConnectionIndexLocked(inputChannel) >= 0) {
+ sp<Connection> existingConnection = getConnectionLocked(inputChannel);
+ if (existingConnection != nullptr) {
ALOGW("Attempted to register already registered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
@@ -3838,7 +3884,7 @@
sp<Connection> connection = new Connection(inputChannel, false /*monitor*/);
int fd = inputChannel->getFd();
- mConnectionsByFd.add(fd, connection);
+ mConnectionsByFd[fd] = connection;
mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
@@ -3867,7 +3913,7 @@
sp<Connection> connection = new Connection(inputChannel, true /*monitor*/);
const int fd = inputChannel->getFd();
- mConnectionsByFd.add(fd, connection);
+ mConnectionsByFd[fd] = connection;
mInputChannelsByToken[inputChannel->getToken()] = inputChannel;
auto& monitorsByDisplay =
@@ -3903,16 +3949,15 @@
status_t InputDispatcher::unregisterInputChannelLocked(const sp<InputChannel>& inputChannel,
bool notify) {
- ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
- if (connectionIndex < 0) {
+ sp<Connection> connection = getConnectionLocked(inputChannel);
+ if (connection == nullptr) {
ALOGW("Attempted to unregister already unregistered input channel '%s'",
inputChannel->getName().c_str());
return BAD_VALUE;
}
- sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
- mConnectionsByFd.removeItemsAt(connectionIndex);
-
+ const bool removed = removeByValue(mConnectionsByFd, connection);
+ ALOG_ASSERT(removed);
mInputChannelsByToken.erase(inputChannel->getToken());
if (connection->monitor) {
@@ -4012,30 +4057,31 @@
return std::nullopt;
}
-ssize_t InputDispatcher::getConnectionIndexLocked(const sp<InputChannel>& inputChannel) {
+sp<Connection> InputDispatcher::getConnectionLocked(const sp<InputChannel>& inputChannel) {
if (inputChannel == nullptr) {
- return -1;
+ return nullptr;
}
- for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
- sp<Connection> connection = mConnectionsByFd.valueAt(i);
+ for (const auto& pair : mConnectionsByFd) {
+ sp<Connection> connection = pair.second;
if (connection->inputChannel->getToken() == inputChannel->getToken()) {
- return i;
+ return connection;
}
}
- return -1;
+ return nullptr;
}
void InputDispatcher::onDispatchCycleFinishedLocked(nsecs_t currentTime,
const sp<Connection>& connection, uint32_t seq,
bool handled) {
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doDispatchCycleFinishedLockedInterruptible);
commandEntry->connection = connection;
commandEntry->eventTime = currentTime;
commandEntry->seq = seq;
commandEntry->handled = handled;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::onDispatchCycleBrokenLocked(nsecs_t currentTime,
@@ -4043,19 +4089,21 @@
ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!",
connection->getInputChannelName().c_str());
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible);
commandEntry->connection = connection;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::onFocusChangedLocked(const sp<InputWindowHandle>& oldFocus,
const sp<InputWindowHandle>& newFocus) {
sp<IBinder> oldToken = oldFocus != nullptr ? oldFocus->getToken() : nullptr;
sp<IBinder> newToken = newFocus != nullptr ? newFocus->getToken() : nullptr;
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyFocusChangedLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+ &InputDispatcher::doNotifyFocusChangedLockedInterruptible);
commandEntry->oldToken = oldToken;
commandEntry->newToken = newToken;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::onANRLocked(nsecs_t currentTime,
@@ -4086,12 +4134,13 @@
mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
dumpDispatchStateLocked(mLastANRState);
- CommandEntry* commandEntry =
- postCommandLocked(&InputDispatcher::doNotifyANRLockedInterruptible);
+ std::unique_ptr<CommandEntry> commandEntry =
+ std::make_unique<CommandEntry>(&InputDispatcher::doNotifyANRLockedInterruptible);
commandEntry->inputApplicationHandle = applicationHandle;
commandEntry->inputChannel =
windowHandle != nullptr ? getInputChannelLocked(windowHandle->getToken()) : nullptr;
commandEntry->reason = reason;
+ postCommandLocked(std::move(commandEntry));
}
void InputDispatcher::doNotifyConfigurationChangedLockedInterruptible(CommandEntry* commandEntry) {
@@ -4176,53 +4225,58 @@
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
- nsecs_t finishTime = commandEntry->eventTime;
+ const nsecs_t finishTime = commandEntry->eventTime;
uint32_t seq = commandEntry->seq;
- bool handled = commandEntry->handled;
+ const bool handled = commandEntry->handled;
// Handle post-event policy actions.
- DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
- if (dispatchEntry) {
- nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
- if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- std::string msg =
- StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
- connection->getWindowName().c_str(), eventDuration * 0.000001f);
- dispatchEntry->eventEntry->appendDescription(msg);
- ALOGI("%s", msg.c_str());
- }
-
- bool restartEvent;
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- restartEvent =
- afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry,
- motionEntry, handled);
- } else {
- restartEvent = false;
- }
-
- // Dequeue the event and start the next cycle.
- // Note that because the lock might have been released, it is possible that the
- // contents of the wait queue to have been drained, so we need to double-check
- // a few things.
- if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
- connection->waitQueue.dequeue(dispatchEntry);
- traceWaitQueueLength(connection);
- if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.enqueueAtHead(dispatchEntry);
- traceOutboundQueueLength(connection);
- } else {
- releaseDispatchEntry(dispatchEntry);
- }
- }
-
- // Start the next dispatch cycle for this connection.
- startDispatchCycleLocked(now(), connection);
+ std::deque<DispatchEntry*>::iterator dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt == connection->waitQueue.end()) {
+ return;
}
+ DispatchEntry* dispatchEntry = *dispatchEntryIt;
+
+ nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
+ if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+ std::string msg =
+ StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
+ connection->getWindowName().c_str(), eventDuration * 0.000001f);
+ dispatchEntry->eventEntry->appendDescription(msg);
+ ALOGI("%s", msg.c_str());
+ }
+
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ restartEvent =
+ afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
+ handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Note that because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ dispatchEntryIt = connection->findWaitQueueEntry(seq);
+ if (dispatchEntryIt != connection->waitQueue.end()) {
+ dispatchEntry = *dispatchEntryIt;
+ connection->waitQueue.erase(dispatchEntryIt);
+ traceWaitQueueLength(connection);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.push_front(dispatchEntry);
+ traceOutboundQueueLength(connection);
+ } else {
+ releaseDispatchEntry(dispatchEntry);
+ }
+ }
+
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
@@ -4429,9 +4483,37 @@
// TODO Write some statistics about how long we spend waiting.
}
+/**
+ * Report the touch event latency to the statsd server.
+ * Input events are reported for statistics if:
+ * - This is a touchscreen event
+ * - InputFilter is not enabled
+ * - Event is not injected or synthesized
+ *
+ * Statistics should be reported before calling addValue, to prevent a fresh new sample
+ * from getting aggregated with the "old" data.
+ */
+void InputDispatcher::reportTouchEventForStatistics(const MotionEntry& motionEntry)
+ REQUIRES(mLock) {
+ const bool reportForStatistics = (motionEntry.source == AINPUT_SOURCE_TOUCHSCREEN) &&
+ !(motionEntry.isSynthesized()) && !mInputFilterEnabled;
+ if (!reportForStatistics) {
+ return;
+ }
+
+ if (mTouchStatistics.shouldReport()) {
+ android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mTouchStatistics.getMin(),
+ mTouchStatistics.getMax(), mTouchStatistics.getMean(),
+ mTouchStatistics.getStDev(), mTouchStatistics.getCount());
+ mTouchStatistics.reset();
+ }
+ const float latencyMicros = nanoseconds_to_microseconds(now() - motionEntry.eventTime);
+ mTouchStatistics.addValue(latencyMicros);
+}
+
void InputDispatcher::traceInboundQueueLengthLocked() {
if (ATRACE_ENABLED()) {
- ATRACE_INT("iq", mInboundQueue.count());
+ ATRACE_INT("iq", mInboundQueue.size());
}
}
@@ -4439,7 +4521,7 @@
if (ATRACE_ENABLED()) {
char counterName[40];
snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName().c_str());
- ATRACE_INT(counterName, connection->outboundQueue.count());
+ ATRACE_INT(counterName, connection->outboundQueue.size());
}
}
@@ -4447,7 +4529,7 @@
if (ATRACE_ENABLED()) {
char counterName[40];
snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName().c_str());
- ATRACE_INT(counterName, connection->waitQueue.count());
+ ATRACE_INT(counterName, connection->waitQueue.size());
}
}
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 67bf199..0d9d6b0 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -26,15 +26,14 @@
#include "InputState.h"
#include "InputTarget.h"
#include "Monitor.h"
-#include "Queue.h"
#include "TouchState.h"
#include "TouchedWindow.h"
-#include <cutils/atomic.h>
#include <input/Input.h>
#include <input/InputApplication.h>
#include <input/InputTransport.h>
#include <input/InputWindow.h>
+#include <input/LatencyStatistics.h>
#include <limits.h>
#include <stddef.h>
#include <ui/Region.h>
@@ -135,9 +134,9 @@
sp<Looper> mLooper;
EventEntry* mPendingEvent GUARDED_BY(mLock);
- Queue<EventEntry> mInboundQueue GUARDED_BY(mLock);
- Queue<EventEntry> mRecentQueue GUARDED_BY(mLock);
- Queue<CommandEntry> mCommandQueue GUARDED_BY(mLock);
+ std::deque<EventEntry*> mInboundQueue GUARDED_BY(mLock);
+ std::deque<EventEntry*> mRecentQueue GUARDED_BY(mLock);
+ std::deque<std::unique_ptr<CommandEntry>> mCommandQueue GUARDED_BY(mLock);
DropReason mLastDropReason GUARDED_BY(mLock);
@@ -172,7 +171,7 @@
bool addPortalWindows = false) REQUIRES(mLock);
// All registered connections mapped by channel file descriptor.
- KeyedVector<int, sp<Connection>> mConnectionsByFd GUARDED_BY(mLock);
+ std::unordered_map<int, sp<Connection>> mConnectionsByFd GUARDED_BY(mLock);
struct IBinderHash {
std::size_t operator()(const sp<IBinder>& b) const {
@@ -186,7 +185,7 @@
std::optional<int32_t> findGestureMonitorDisplayByTokenLocked(const sp<IBinder>& token)
REQUIRES(mLock);
- ssize_t getConnectionIndexLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
+ sp<Connection> getConnectionLocked(const sp<InputChannel>& inputChannel) REQUIRES(mLock);
// Input channels that will receive a copy of all input events sent to the provided display.
std::unordered_map<int32_t, std::vector<Monitor>> mGlobalMonitorsByDisplay GUARDED_BY(mLock);
@@ -235,7 +234,7 @@
// Deferred command processing.
bool haveCommandsLocked() const REQUIRES(mLock);
bool runCommandsLockedInterruptible() REQUIRES(mLock);
- CommandEntry* postCommandLocked(Command command) REQUIRES(mLock);
+ void postCommandLocked(std::unique_ptr<CommandEntry> commandEntry) REQUIRES(mLock);
// Input filter processing.
bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) REQUIRES(mLock);
@@ -261,6 +260,13 @@
sp<InputChannel> getInputChannelLocked(const sp<IBinder>& windowToken) const REQUIRES(mLock);
bool hasWindowHandleLocked(const sp<InputWindowHandle>& windowHandle) const REQUIRES(mLock);
+ /*
+ * Validate and update InputWindowHandles for a given display.
+ */
+ void updateWindowHandlesForDisplayLocked(
+ const std::vector<sp<InputWindowHandle>>& inputWindowHandles, int32_t displayId)
+ REQUIRES(mLock);
+
// Focus tracking for keys, trackball, etc.
std::unordered_map<int32_t, sp<InputWindowHandle>> mFocusedWindowHandlesByDisplay
GUARDED_BY(mLock);
@@ -379,7 +385,7 @@
uint32_t seq, bool handled) REQUIRES(mLock);
void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
bool notify) REQUIRES(mLock);
- void drainDispatchQueue(Queue<DispatchEntry>* queue);
+ void drainDispatchQueue(std::deque<DispatchEntry*>& queue);
void releaseDispatchEntry(DispatchEntry* dispatchEntry);
static int handleReceiveCallback(int fd, int events, void* data);
// The action sent should only be of type AMOTION_EVENT_*
@@ -450,6 +456,10 @@
void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
// Statistics gathering.
+ static constexpr std::chrono::duration TOUCH_STATS_REPORT_PERIOD = 5min;
+ LatencyStatistics mTouchStatistics{TOUCH_STATS_REPORT_PERIOD};
+
+ void reportTouchEventForStatistics(const MotionEntry& entry);
void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
int32_t injectionResult, nsecs_t timeSpentWaitingForApplication);
void traceInboundQueueLengthLocked() REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/InputState.cpp b/services/inputflinger/dispatcher/InputState.cpp
index 7d9b03a..c60700e 100644
--- a/services/inputflinger/dispatcher/InputState.cpp
+++ b/services/inputflinger/dispatcher/InputState.cpp
@@ -232,6 +232,8 @@
memento.flags = flags;
memento.xPrecision = entry->xPrecision;
memento.yPrecision = entry->yPrecision;
+ memento.xCursorPosition = entry->xCursorPosition;
+ memento.yCursorPosition = entry->yCursorPosition;
memento.downTime = entry->downTime;
memento.setPointers(entry);
memento.hovering = hovering;
@@ -271,7 +273,8 @@
0 /*actionButton*/, memento.flags, AMETA_NONE,
0 /*buttonState*/, MotionClassification::NONE,
AMOTION_EVENT_EDGE_FLAG_NONE, memento.xPrecision,
- memento.yPrecision, memento.downTime, memento.pointerCount,
+ memento.yPrecision, memento.xCursorPosition,
+ memento.yCursorPosition, memento.downTime, memento.pointerCount,
memento.pointerProperties, memento.pointerCoords, 0 /*xOffset*/,
0 /*yOffset*/));
}
diff --git a/services/inputflinger/dispatcher/InputState.h b/services/inputflinger/dispatcher/InputState.h
index 205b647..47e9b36 100644
--- a/services/inputflinger/dispatcher/InputState.h
+++ b/services/inputflinger/dispatcher/InputState.h
@@ -24,9 +24,6 @@
namespace android::inputdispatcher {
-// Sequence number for synthesized or injected events.
-constexpr uint32_t SYNTHESIZED_EVENT_SEQUENCE_NUM = 0;
-
/* Tracks dispatched key and motion event state so that cancellation events can be
* synthesized when events are dropped. */
class InputState {
@@ -94,6 +91,8 @@
int32_t flags;
float xPrecision;
float yPrecision;
+ float xCursorPosition;
+ float yCursorPosition;
nsecs_t downTime;
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
diff --git a/services/inputflinger/dispatcher/Queue.h b/services/inputflinger/dispatcher/Queue.h
deleted file mode 100644
index 0e75821..0000000
--- a/services/inputflinger/dispatcher/Queue.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_INPUT_INPUTDISPATCHER_QUEUE_H
-#define _UI_INPUT_INPUTDISPATCHER_QUEUE_H
-
-namespace android::inputdispatcher {
-
-// Generic queue implementation.
-template <typename T>
-struct Queue {
- T* head;
- T* tail;
- uint32_t entryCount;
-
- inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {}
-
- inline bool isEmpty() const { return !head; }
-
- inline void enqueueAtTail(T* entry) {
- entryCount++;
- entry->prev = tail;
- if (tail) {
- tail->next = entry;
- } else {
- head = entry;
- }
- entry->next = nullptr;
- tail = entry;
- }
-
- inline void enqueueAtHead(T* entry) {
- entryCount++;
- entry->next = head;
- if (head) {
- head->prev = entry;
- } else {
- tail = entry;
- }
- entry->prev = nullptr;
- head = entry;
- }
-
- inline void dequeue(T* entry) {
- entryCount--;
- if (entry->prev) {
- entry->prev->next = entry->next;
- } else {
- head = entry->next;
- }
- if (entry->next) {
- entry->next->prev = entry->prev;
- } else {
- tail = entry->prev;
- }
- }
-
- inline T* dequeueAtHead() {
- entryCount--;
- T* entry = head;
- head = entry->next;
- if (head) {
- head->prev = nullptr;
- } else {
- tail = nullptr;
- }
- return entry;
- }
-
- uint32_t count() const { return entryCount; }
-};
-
-} // namespace android::inputdispatcher
-
-#endif // _UI_INPUT_INPUTDISPATCHER_QUEUE_H
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index d8b352c..973b4f9 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -42,7 +42,6 @@
virtual status_t dump(int fd, const Vector<String16>& args);
void setInputWindows(const std::vector<InputWindowInfo>&,
const sp<ISetInputWindowsListener>&) {}
- void transferTouchFocus(const sp<IBinder>&, const sp<IBinder>&) {}
void registerInputChannel(const sp<InputChannel>&) {}
void unregisterInputChannel(const sp<InputChannel>&) {}
diff --git a/services/inputflinger/include/InputListener.h b/services/inputflinger/include/InputListener.h
index b51dcb6..0dcd2f9 100644
--- a/services/inputflinger/include/InputListener.h
+++ b/services/inputflinger/include/InputListener.h
@@ -107,31 +107,32 @@
*/
MotionClassification classification;
int32_t edgeFlags;
- /**
- * A timestamp in the input device's time base, not the platform's.
- * The units are microseconds since the last reset.
- * This can only be compared to other device timestamps from the same device.
- * This value will overflow after a little over an hour.
- */
- uint32_t deviceTimestamp;
+
uint32_t pointerCount;
PointerProperties pointerProperties[MAX_POINTERS];
PointerCoords pointerCoords[MAX_POINTERS];
float xPrecision;
float yPrecision;
+ /**
+ * Mouse cursor position when this event is reported relative to the origin of the specified
+ * display. Only valid if this is a mouse event (originates from a mouse or from a trackpad in
+ * gestures enabled mode.
+ */
+ float xCursorPosition;
+ float yCursorPosition;
nsecs_t downTime;
std::vector<TouchVideoFrame> videoFrames;
inline NotifyMotionArgs() { }
NotifyMotionArgs(uint32_t sequenceNum, nsecs_t eventTime, int32_t deviceId, uint32_t source,
- int32_t displayId, uint32_t policyFlags,
- int32_t action, int32_t actionButton, int32_t flags,
- int32_t metaState, int32_t buttonState, MotionClassification classification,
- int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
- const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
- float xPrecision, float yPrecision, nsecs_t downTime,
- const std::vector<TouchVideoFrame>& videoFrames);
+ int32_t displayId, uint32_t policyFlags, int32_t action, int32_t actionButton,
+ int32_t flags, int32_t metaState, int32_t buttonState,
+ MotionClassification classification, int32_t edgeFlags, uint32_t pointerCount,
+ const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
+ float xPrecision, float yPrecision, float xCursorPosition,
+ float yCursorPosition, nsecs_t downTime,
+ const std::vector<TouchVideoFrame>& videoFrames);
NotifyMotionArgs(const NotifyMotionArgs& other);
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index 8ad5dd0..5d576b9 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -24,14 +24,13 @@
#include <input/DisplayViewport.h>
#include <input/VelocityControl.h>
#include <input/VelocityTracker.h>
-#include <utils/KeyedVector.h>
#include <utils/Thread.h>
#include <utils/RefBase.h>
-#include <utils/SortedVector.h>
-#include <optional>
#include <stddef.h>
#include <unistd.h>
+#include <optional>
+#include <set>
#include <unordered_map>
#include <vector>
@@ -250,7 +249,7 @@
bool pointerCapture;
// The set of currently disabled input devices.
- SortedVector<int32_t> disabledDevices;
+ std::set<int32_t> disabledDevices;
InputReaderConfiguration() :
virtualKeyQuietTime(0),
@@ -270,6 +269,8 @@
pointerGestureZoomSpeedRatio(0.3f),
showTouches(false), pointerCapture(false) { }
+ static std::string changesToString(uint32_t changes);
+
std::optional<DisplayViewport> getDisplayViewportByType(ViewportType type) const;
std::optional<DisplayViewport> getDisplayViewportByUniqueId(const std::string& uniqueDisplayId)
const;
diff --git a/services/inputflinger/reader/Android.bp b/services/inputflinger/reader/Android.bp
index 4e97397..a64f4dd 100644
--- a/services/inputflinger/reader/Android.bp
+++ b/services/inputflinger/reader/Android.bp
@@ -58,7 +58,6 @@
"libui",
"libutils",
"libhardware_legacy",
- "libstatslog",
],
header_libs: [
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index a5e5415..efe3809 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -28,7 +28,6 @@
#include <sys/inotify.h>
#include <sys/ioctl.h>
#include <sys/limits.h>
-#include <sys/utsname.h>
#include <unistd.h>
#define LOG_TAG "EventHub"
@@ -94,14 +93,6 @@
return out;
}
-static void getLinuxRelease(int* major, int* minor) {
- struct utsname info;
- if (uname(&info) || sscanf(info.release, "%d.%d", major, minor) <= 0) {
- *major = 0, *minor = 0;
- ALOGE("Could not get linux version: %s", strerror(errno));
- }
-}
-
/**
* Return true if name matches "v4l-touch*"
*/
@@ -280,9 +271,8 @@
ALOGI("Video device scanning disabled");
}
- struct epoll_event eventItem;
- memset(&eventItem, 0, sizeof(eventItem));
- eventItem.events = EPOLLIN;
+ struct epoll_event eventItem = {};
+ eventItem.events = EPOLLIN | EPOLLWAKEUP;
eventItem.data.fd = mINotifyFd;
int result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno);
@@ -306,11 +296,6 @@
result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem);
LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d",
errno);
-
- int major, minor;
- getLinuxRelease(&major, &minor);
- // EPOLLWAKEUP was introduced in kernel 3.5
- mUsingEpollWakeup = major > 3 || (major == 3 && minor >= 5);
}
EventHub::~EventHub(void) {
@@ -1491,27 +1476,13 @@
}
}
- std::string wakeMechanism = "EPOLLWAKEUP";
- if (!mUsingEpollWakeup) {
-#ifndef EVIOCSSUSPENDBLOCK
- // uapi headers don't include EVIOCSSUSPENDBLOCK, and future kernels
- // will use an epoll flag instead, so as long as we want to support
- // this feature, we need to be prepared to define the ioctl ourselves.
-#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int)
-#endif
- if (ioctl(device->fd, EVIOCSSUSPENDBLOCK, 1)) {
- wakeMechanism = "<none>";
- } else {
- wakeMechanism = "EVIOCSSUSPENDBLOCK";
- }
- }
// Tell the kernel that we want to use the monotonic clock for reporting timestamps
// associated with input events. This is important because the input system
// uses the timestamps extensively and assumes they were recorded using the monotonic
// clock.
int clockId = CLOCK_MONOTONIC;
bool usingClockIoctl = !ioctl(device->fd, EVIOCSCLOCKID, &clockId);
- ALOGI("wakeMechanism=%s, usingClockIoctl=%s", wakeMechanism.c_str(), toString(usingClockIoctl));
+ ALOGI("usingClockIoctl=%s", toString(usingClockIoctl));
}
void EventHub::openVideoDeviceLocked(const std::string& devicePath) {
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index d0613b0..7fed61f 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -49,6 +49,13 @@
}
void InputDevice::setEnabled(bool enabled, nsecs_t when) {
+ if (enabled && mAssociatedDisplayPort && !mAssociatedViewport) {
+ ALOGW("Cannot enable input device %s because it is associated with port %" PRIu8 ", "
+ "but the corresponding viewport is not found",
+ getName().c_str(), *mAssociatedDisplayPort);
+ enabled = false;
+ }
+
if (isEnabled() == enabled) {
return;
}
@@ -144,14 +151,15 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_ENABLED_STATE)) {
- ssize_t index = config->disabledDevices.indexOf(mId);
- bool enabled = index < 0;
+ auto it = config->disabledDevices.find(mId);
+ bool enabled = it == config->disabledDevices.end();
setEnabled(enabled, when);
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
// In most situations, no port will be specified.
mAssociatedDisplayPort = std::nullopt;
+ mAssociatedViewport = std::nullopt;
// Find the display port that corresponds to the current input port.
const std::string& inputPort = mIdentifier.location;
if (!inputPort.empty()) {
@@ -161,12 +169,40 @@
mAssociatedDisplayPort = std::make_optional(displayPort->second);
}
}
+
+ // If the device was explicitly disabled by the user, it would be present in the
+ // "disabledDevices" list. If it is associated with a specific display, and it was not
+ // explicitly disabled, then enable/disable the device based on whether we can find the
+ // corresponding viewport.
+ bool enabled = (config->disabledDevices.find(mId) == config->disabledDevices.end());
+ if (mAssociatedDisplayPort) {
+ mAssociatedViewport = config->getDisplayViewportByPort(*mAssociatedDisplayPort);
+ if (!mAssociatedViewport) {
+ ALOGW("Input device %s should be associated with display on port %" PRIu8 ", "
+ "but the corresponding viewport is not found.",
+ getName().c_str(), *mAssociatedDisplayPort);
+ enabled = false;
+ }
+ }
+
+ if (changes) {
+ // For first-time configuration, only allow device to be disabled after mappers have
+ // finished configuring. This is because we need to read some of the properties from
+ // the device's open fd.
+ setEnabled(enabled, when);
+ }
}
for (InputMapper* mapper : mMappers) {
mapper->configure(when, config, changes);
mSources |= mapper->getSources();
}
+
+ // If a device is just plugged but it might be disabled, we need to update some info like
+ // axis range of touch from each InputMapper first, then disable it.
+ if (!changes) {
+ setEnabled(config->disabledDevices.find(mId) == config->disabledDevices.end(), when);
+ }
}
}
@@ -324,9 +360,15 @@
mContext->getListener()->notifyDeviceReset(&args);
}
-std::optional<int32_t> InputDevice::getAssociatedDisplay() {
+std::optional<int32_t> InputDevice::getAssociatedDisplayId() {
+ // Check if we had associated to the specific display.
+ if (mAssociatedViewport) {
+ return mAssociatedViewport->displayId;
+ }
+
+ // No associated display port, check if some InputMapper is associated.
for (InputMapper* mapper : mMappers) {
- std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplay();
+ std::optional<int32_t> associatedDisplayId = mapper->getAssociatedDisplayId();
if (associatedDisplayId) {
return associatedDisplayId;
}
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 27cbf19..e57604c 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -48,7 +48,7 @@
namespace android {
-InputReader::InputReader(const sp<EventHubInterface>& eventHub,
+InputReader::InputReader(std::shared_ptr<EventHubInterface> eventHub,
const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener)
: mContext(this),
@@ -353,7 +353,8 @@
mEventHub->setExcludedDevices(mConfig.excludedDeviceNames);
if (changes) {
- ALOGI("Reconfiguring input devices. changes=0x%08x", changes);
+ ALOGI("Reconfiguring input devices, changes=%s",
+ InputReaderConfiguration::changesToString(changes).c_str());
nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) {
@@ -607,14 +608,19 @@
}
InputDevice* device = mDevices.valueAt(deviceIndex);
- std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplay();
+ if (!device->isEnabled()) {
+ ALOGW("Ignoring disabled device %s", device->getName().c_str());
+ return false;
+ }
+
+ std::optional<int32_t> associatedDisplayId = device->getAssociatedDisplayId();
// No associated display. By default, can dispatch to all displays.
if (!associatedDisplayId) {
return true;
}
if (*associatedDisplayId == ADISPLAY_ID_NONE) {
- ALOGW("Device has associated, but no associated display id.");
+ ALOGW("Device %s is associated with display ADISPLAY_ID_NONE.", device->getName().c_str());
return true;
}
diff --git a/services/inputflinger/reader/InputReaderFactory.cpp b/services/inputflinger/reader/InputReaderFactory.cpp
index 9f73680..a897141 100644
--- a/services/inputflinger/reader/InputReaderFactory.cpp
+++ b/services/inputflinger/reader/InputReaderFactory.cpp
@@ -22,7 +22,7 @@
sp<InputReaderInterface> createInputReader(const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener) {
- return new InputReader(new EventHub(), policy, listener);
+ return new InputReader(std::make_unique<EventHub>(), policy, listener);
}
} // namespace android
\ No newline at end of file
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index 794396a..c17f3a1 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -145,12 +145,11 @@
* which keys are currently down. Finally, the event hub keeps track of the capabilities of
* individual input devices, such as their class and the set of key codes that they support.
*/
-class EventHubInterface : public virtual RefBase {
-protected:
+class EventHubInterface {
+public:
EventHubInterface() {}
virtual ~EventHubInterface() {}
-public:
// Synthetic raw event type codes produced when devices are added or removed.
enum {
// Sent when a device is added.
@@ -261,62 +260,64 @@
public:
EventHub();
- virtual uint32_t getDeviceClasses(int32_t deviceId) const;
+ virtual uint32_t getDeviceClasses(int32_t deviceId) const override;
- virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const;
+ virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const override;
- virtual int32_t getDeviceControllerNumber(int32_t deviceId) const;
+ virtual int32_t getDeviceControllerNumber(int32_t deviceId) const override;
- virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const;
+ virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const override;
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
- RawAbsoluteAxisInfo* outAxisInfo) const;
+ RawAbsoluteAxisInfo* outAxisInfo) const override;
- virtual bool hasRelativeAxis(int32_t deviceId, int axis) const;
+ virtual bool hasRelativeAxis(int32_t deviceId, int axis) const override;
- virtual bool hasInputProperty(int32_t deviceId, int property) const;
+ virtual bool hasInputProperty(int32_t deviceId, int property) const override;
virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
int32_t metaState, int32_t* outKeycode, int32_t* outMetaState,
- uint32_t* outFlags) const;
+ uint32_t* outFlags) const override;
- virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const;
+ virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
+ AxisInfo* outAxisInfo) const override;
- virtual void setExcludedDevices(const std::vector<std::string>& devices);
+ virtual void setExcludedDevices(const std::vector<std::string>& devices) override;
- virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const;
- virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const;
- virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const;
- virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const;
+ virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const override;
+ virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const override;
+ virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const override;
+ virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis,
+ int32_t* outValue) const override;
virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
- uint8_t* outFlags) const;
+ uint8_t* outFlags) const override;
- virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize);
- virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId);
+ virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) override;
+ virtual std::vector<TouchVideoFrame> getVideoFrames(int32_t deviceId) override;
- virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const;
- virtual bool hasLed(int32_t deviceId, int32_t led) const;
- virtual void setLedState(int32_t deviceId, int32_t led, bool on);
+ virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const override;
+ virtual bool hasLed(int32_t deviceId, int32_t led) const override;
+ virtual void setLedState(int32_t deviceId, int32_t led, bool on) override;
- virtual void getVirtualKeyDefinitions(int32_t deviceId,
- std::vector<VirtualKeyDefinition>& outVirtualKeys) const;
+ virtual void getVirtualKeyDefinitions(
+ int32_t deviceId, std::vector<VirtualKeyDefinition>& outVirtualKeys) const override;
- virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const;
- virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp<KeyCharacterMap>& map);
+ virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t deviceId) const override;
+ virtual bool setKeyboardLayoutOverlay(int32_t deviceId,
+ const sp<KeyCharacterMap>& map) override;
- virtual void vibrate(int32_t deviceId, nsecs_t duration);
- virtual void cancelVibrate(int32_t deviceId);
+ virtual void vibrate(int32_t deviceId, nsecs_t duration) override;
+ virtual void cancelVibrate(int32_t deviceId) override;
- virtual void requestReopenDevices();
+ virtual void requestReopenDevices() override;
- virtual void wake();
+ virtual void wake() override;
- virtual void dump(std::string& dump);
- virtual void monitor();
+ virtual void dump(std::string& dump) override;
+ virtual void monitor() override;
-protected:
- virtual ~EventHub();
+ virtual ~EventHub() override;
private:
struct Device {
@@ -385,9 +386,9 @@
void configureFd(Device* device);
- bool isDeviceEnabled(int32_t deviceId);
- status_t enableDevice(int32_t deviceId);
- status_t disableDevice(int32_t deviceId);
+ bool isDeviceEnabled(int32_t deviceId) override;
+ status_t enableDevice(int32_t deviceId) override;
+ status_t disableDevice(int32_t deviceId) override;
status_t registerFdForEpoll(int fd);
status_t unregisterFdFromEpoll(int fd);
status_t registerDeviceForEpollLocked(Device* device);
@@ -475,8 +476,6 @@
size_t mPendingEventCount;
size_t mPendingEventIndex;
bool mPendingINotify;
-
- bool mUsingEpollWakeup;
};
}; // namespace android
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 57f0b31..882407d 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -55,7 +55,9 @@
inline std::optional<uint8_t> getAssociatedDisplayPort() const {
return mAssociatedDisplayPort;
}
-
+ inline std::optional<DisplayViewport> getAssociatedViewport() const {
+ return mAssociatedViewport;
+ }
inline void setMic(bool hasMic) { mHasMic = hasMic; }
inline bool hasMic() const { return mHasMic; }
@@ -112,7 +114,7 @@
return value;
}
- std::optional<int32_t> getAssociatedDisplay();
+ std::optional<int32_t> getAssociatedDisplayId();
private:
InputReaderContext* mContext;
@@ -128,6 +130,7 @@
uint32_t mSources;
bool mIsExternal;
std::optional<uint8_t> mAssociatedDisplayPort;
+ std::optional<DisplayViewport> mAssociatedViewport;
bool mHasMic;
bool mDropUntilNextSync;
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index e29c8f2..7b4321e 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -22,11 +22,9 @@
#include "InputReaderBase.h"
#include "InputReaderContext.h"
-#include <utils/BitSet.h>
#include <utils/Condition.h>
#include <utils/KeyedVector.h>
#include <utils/Mutex.h>
-#include <utils/Timers.h>
#include <vector>
@@ -49,35 +47,39 @@
*/
class InputReader : public InputReaderInterface {
public:
- InputReader(const sp<EventHubInterface>& eventHub, const sp<InputReaderPolicyInterface>& policy,
+ InputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
const sp<InputListenerInterface>& listener);
virtual ~InputReader();
- virtual void dump(std::string& dump);
- virtual void monitor();
+ virtual void dump(std::string& dump) override;
+ virtual void monitor() override;
- virtual void loopOnce();
+ virtual void loopOnce() override;
- virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices);
+ virtual void getInputDevices(std::vector<InputDeviceInfo>& outInputDevices) override;
- virtual bool isInputDeviceEnabled(int32_t deviceId);
+ virtual bool isInputDeviceEnabled(int32_t deviceId) override;
- virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode);
- virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode);
- virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw);
+ virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t scanCode) override;
+ virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask,
+ int32_t keyCode) override;
+ virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t sw) override;
- virtual void toggleCapsLockState(int32_t deviceId);
+ virtual void toggleCapsLockState(int32_t deviceId) override;
virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
- const int32_t* keyCodes, uint8_t* outFlags);
+ const int32_t* keyCodes, uint8_t* outFlags) override;
- virtual void requestRefreshConfiguration(uint32_t changes);
+ virtual void requestRefreshConfiguration(uint32_t changes) override;
virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize,
- ssize_t repeat, int32_t token);
- virtual void cancelVibrate(int32_t deviceId, int32_t token);
+ ssize_t repeat, int32_t token) override;
+ virtual void cancelVibrate(int32_t deviceId, int32_t token) override;
- virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId);
+ virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) override;
+
protected:
// These members are protected so they can be instrumented by test cases.
virtual InputDevice* createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
@@ -90,20 +92,20 @@
public:
explicit ContextImpl(InputReader* reader);
- virtual void updateGlobalMetaState();
- virtual int32_t getGlobalMetaState();
- virtual void disableVirtualKeysUntil(nsecs_t time);
+ virtual void updateGlobalMetaState() override;
+ virtual int32_t getGlobalMetaState() override;
+ virtual void disableVirtualKeysUntil(nsecs_t time) override;
virtual bool shouldDropVirtualKey(nsecs_t now, InputDevice* device, int32_t keyCode,
- int32_t scanCode);
- virtual void fadePointer();
- virtual void requestTimeoutAtTime(nsecs_t when);
- virtual int32_t bumpGeneration();
- virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices);
- virtual void dispatchExternalStylusState(const StylusState& outState);
- virtual InputReaderPolicyInterface* getPolicy();
- virtual InputListenerInterface* getListener();
- virtual EventHubInterface* getEventHub();
- virtual uint32_t getNextSequenceNum();
+ int32_t scanCode) override;
+ virtual void fadePointer() override;
+ virtual void requestTimeoutAtTime(nsecs_t when) override;
+ virtual int32_t bumpGeneration() override;
+ virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override;
+ virtual void dispatchExternalStylusState(const StylusState& outState) override;
+ virtual InputReaderPolicyInterface* getPolicy() override;
+ virtual InputListenerInterface* getListener() override;
+ virtual EventHubInterface* getEventHub() override;
+ virtual uint32_t getNextSequenceNum() override;
} mContext;
friend class ContextImpl;
@@ -113,7 +115,10 @@
Condition mReaderIsAliveCondition;
- sp<EventHubInterface> mEventHub;
+ // This could be unique_ptr, but due to the way InputReader tests are written,
+ // it is made shared_ptr here. In the tests, an EventHub reference is retained by the test
+ // in parallel to passing it to the InputReader.
+ std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<QueuedInputListener> mQueuedListener;
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.cpp b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
index da85fda..f69138e 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.cpp
@@ -313,6 +313,8 @@
mPointerVelocityControl.move(when, &deltaX, &deltaY);
int32_t displayId;
+ float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+ float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
if (mSource == AINPUT_SOURCE_MOUSE) {
if (moved || scrolled || buttonsChanged) {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
@@ -328,10 +330,9 @@
mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
}
- float x, y;
- mPointerController->getPosition(&x, &y);
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
- pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
+ mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);
+ pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);
pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);
displayId = mPointerController->getDisplayId();
@@ -378,9 +379,9 @@
mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, downTime,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
/* videoFrames */ {});
getListener()->notifyMotion(&releaseArgs);
}
@@ -389,9 +390,9 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, motionEventAction, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- mXPrecision, mYPrecision, downTime, /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
+ mXPrecision, mYPrecision, xCursorPosition, yCursorPosition, downTime,
+ /* videoFrames */ {});
getListener()->notifyMotion(&args);
if (buttonsPressed) {
@@ -403,9 +404,9 @@
mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, downTime,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision,
+ xCursorPosition, yCursorPosition, downTime,
/* videoFrames */ {});
getListener()->notifyMotion(&pressArgs);
}
@@ -418,10 +419,9 @@
NotifyMotionArgs hoverArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,
0, metaState, currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, downTime,
- /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+ yCursorPosition, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&hoverArgs);
}
@@ -434,10 +434,9 @@
mSource, displayId, policyFlags,
AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
currentButtonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties,
- &pointerCoords, mXPrecision, mYPrecision, downTime,
- /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, mXPrecision, mYPrecision, xCursorPosition,
+ yCursorPosition, downTime, /* videoFrames */ {});
getListener()->notifyMotion(&scrollArgs);
}
}
@@ -464,7 +463,7 @@
}
}
-std::optional<int32_t> CursorInputMapper::getAssociatedDisplay() {
+std::optional<int32_t> CursorInputMapper::getAssociatedDisplayId() {
if (mParameters.hasAssociatedDisplay) {
if (mParameters.mode == Parameters::MODE_POINTER) {
return std::make_optional(mPointerController->getDisplayId());
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index eb2ad54..77d122a 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -56,18 +56,19 @@
explicit CursorInputMapper(InputDevice* device);
virtual ~CursorInputMapper();
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void dump(std::string& dump) override;
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
- virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
- virtual void fadePointer();
+ virtual void fadePointer() override;
- virtual std::optional<int32_t> getAssociatedDisplay();
+ virtual std::optional<int32_t> getAssociatedDisplayId() override;
private:
// Amount that trackball needs to move in order to generate a key event.
diff --git a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
index 9764fbb..34f339a 100644
--- a/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
+++ b/services/inputflinger/reader/mapper/ExternalStylusInputMapper.h
@@ -30,13 +30,13 @@
explicit ExternalStylusInputMapper(InputDevice* device);
virtual ~ExternalStylusInputMapper() = default;
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
- virtual void sync(nsecs_t when);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void dump(std::string& dump) override;
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
private:
SingleTouchMotionAccumulator mSingleTouchMotionAccumulator;
@@ -44,6 +44,8 @@
TouchButtonAccumulator mTouchButtonAccumulator;
StylusState mStylusState;
+
+ void sync(nsecs_t when);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index cfd207c..a559ef8 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -73,7 +73,7 @@
virtual void updateExternalStylusState(const StylusState& state);
virtual void fadePointer();
- virtual std::optional<int32_t> getAssociatedDisplay() { return std::nullopt; }
+ virtual std::optional<int32_t> getAssociatedDisplayId() { return std::nullopt; }
protected:
InputDevice* mDevice;
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index b493e83..50adf73 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -334,9 +334,10 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(),
AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE, policyFlags,
AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0, 0,
- /* videoFrames */ {});
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &pointerProperties, &pointerCoords, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index 1b071d0..b46d27d 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -26,12 +26,13 @@
explicit JoystickInputMapper(InputDevice* device);
virtual ~JoystickInputMapper();
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void dump(std::string& dump) override;
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
private:
struct Axis {
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
index 0e91c0e..f51d4a0 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp
@@ -127,6 +127,22 @@
dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
}
+std::optional<DisplayViewport> KeyboardInputMapper::findViewport(
+ nsecs_t when, const InputReaderConfiguration* config) {
+ const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
+ if (displayPort) {
+ // Find the viewport that contains the same port
+ return mDevice->getAssociatedViewport();
+ }
+
+ // No associated display defined, try to find default display if orientationAware.
+ if (mParameters.orientationAware) {
+ return config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ }
+
+ return std::nullopt;
+}
+
void KeyboardInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,
uint32_t changes) {
InputMapper::configure(when, config, changes);
@@ -137,9 +153,7 @@
}
if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
- if (mParameters.orientationAware) {
- mViewport = config->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
- }
+ mViewport = findViewport(when, config);
}
}
@@ -409,4 +423,11 @@
}
}
+std::optional<int32_t> KeyboardInputMapper::getAssociatedDisplayId() {
+ if (mViewport) {
+ return std::make_optional(mViewport->displayId);
+ }
+ return std::nullopt;
+}
+
} // namespace android
diff --git a/services/inputflinger/reader/mapper/KeyboardInputMapper.h b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
index 7a68fc3..de2a377 100644
--- a/services/inputflinger/reader/mapper/KeyboardInputMapper.h
+++ b/services/inputflinger/reader/mapper/KeyboardInputMapper.h
@@ -26,20 +26,22 @@
KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType);
virtual ~KeyboardInputMapper();
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void dump(std::string& dump) override;
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
- virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
- virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
+ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
- const int32_t* keyCodes, uint8_t* outFlags);
+ const int32_t* keyCodes, uint8_t* outFlags) override;
- virtual int32_t getMetaState();
- virtual void updateMetaState(int32_t keyCode);
+ virtual int32_t getMetaState() override;
+ virtual void updateMetaState(int32_t keyCode) override;
+ virtual std::optional<int32_t> getAssociatedDisplayId() override;
private:
// The current viewport.
@@ -92,6 +94,8 @@
void initializeLedState(LedState& ledState, int32_t led);
void updateLedState(bool reset);
void updateLedStateForModifier(LedState& ledState, int32_t led, int32_t modifier, bool reset);
+ std::optional<DisplayViewport> findViewport(nsecs_t when,
+ const InputReaderConfiguration* config);
};
} // namespace android
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index 7460a31..c567c8b 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -72,7 +72,6 @@
} else {
clearSlots(-1);
}
- mDeviceTimestamp = 0;
}
void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) {
@@ -166,8 +165,6 @@
} else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) {
// MultiTouch Sync: The driver has returned all data for *one* of the pointers.
mCurrentSlot += 1;
- } else if (rawEvent->type == EV_MSC && rawEvent->code == MSC_TIMESTAMP) {
- mDeviceTimestamp = rawEvent->value;
}
}
@@ -316,7 +313,6 @@
outCount += 1;
}
- outState->deviceTimestamp = mMultiTouchMotionAccumulator.getDeviceTimestamp();
outState->rawPointerData.pointerCount = outCount;
mPointerIdBits = newPointerIdBits;
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
index 873dda1..a45c3cb 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.h
@@ -78,7 +78,6 @@
inline size_t getSlotCount() const { return mSlotCount; }
inline const Slot* getSlot(size_t index) const { return &mSlots[index]; }
- inline uint32_t getDeviceTimestamp() const { return mDeviceTimestamp; }
private:
int32_t mCurrentSlot;
@@ -86,7 +85,6 @@
size_t mSlotCount;
bool mUsingSlotsProtocol;
bool mHaveStylus;
- uint32_t mDeviceTimestamp;
void clearSlots(int32_t initialSlot);
};
@@ -96,8 +94,8 @@
explicit MultiTouchInputMapper(InputDevice* device);
virtual ~MultiTouchInputMapper();
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
protected:
virtual void syncTouch(nsecs_t when, RawState* outState);
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
index 803fdf3..e113cca 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.cpp
@@ -122,9 +122,9 @@
NotifyMotionArgs scrollArgs(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,
metaState, /* buttonState */ 0, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
- 0, 0, 0, /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,
+ &pointerCoords, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, 0, /* videoFrames */ {});
getListener()->notifyMotion(&scrollArgs);
}
diff --git a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
index 2648837..38c7258 100644
--- a/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
+++ b/services/inputflinger/reader/mapper/RotaryEncoderInputMapper.h
@@ -27,12 +27,13 @@
explicit RotaryEncoderInputMapper(InputDevice* device);
virtual ~RotaryEncoderInputMapper();
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void dump(std::string& dump) override;
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
private:
CursorScrollAccumulator mRotaryEncoderScrollAccumulator;
diff --git a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
index d6b1455..8438eee 100644
--- a/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SingleTouchInputMapper.h
@@ -27,8 +27,8 @@
explicit SingleTouchInputMapper(InputDevice* device);
virtual ~SingleTouchInputMapper();
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
protected:
virtual void syncTouch(nsecs_t when, RawState* outState);
diff --git a/services/inputflinger/reader/mapper/SwitchInputMapper.h b/services/inputflinger/reader/mapper/SwitchInputMapper.h
index dd4bb9e..e65d4e2 100644
--- a/services/inputflinger/reader/mapper/SwitchInputMapper.h
+++ b/services/inputflinger/reader/mapper/SwitchInputMapper.h
@@ -26,11 +26,11 @@
explicit SwitchInputMapper(InputDevice* device);
virtual ~SwitchInputMapper();
- virtual uint32_t getSources();
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void process(const RawEvent* rawEvent) override;
- virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
- virtual void dump(std::string& dump);
+ virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode) override;
+ virtual void dump(std::string& dump) override;
private:
uint32_t mSwitchValues;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 32ed97b..34603b9 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -23,11 +23,6 @@
#include "TouchButtonAccumulator.h"
#include "TouchCursorInputMapperCommon.h"
-#include <statslog.h>
-
-// How often to report input event statistics
-static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60);
-
namespace android {
// --- Constants ---
@@ -566,15 +561,10 @@
const std::optional<uint8_t> displayPort = mDevice->getAssociatedDisplayPort();
if (displayPort) {
// Find the viewport that contains the same port
- std::optional<DisplayViewport> v = mConfig.getDisplayViewportByPort(*displayPort);
- if (!v) {
- ALOGW("Input device %s should be associated with display on port %" PRIu8 ", "
- "but the corresponding viewport is not found.",
- getDeviceName().c_str(), *displayPort);
- }
- return v;
+ return mDevice->getAssociatedViewport();
}
+ // Check if uniqueDisplayId is specified in idc file.
if (!mParameters.uniqueDisplayId.empty()) {
return mConfig.getDisplayViewportByUniqueId(mParameters.uniqueDisplayId);
}
@@ -598,6 +588,7 @@
return viewport;
}
+ // No associated display, return a non-display viewport.
DisplayViewport newViewport;
// Raw width and height in the natural orientation.
int32_t rawWidth = mRawPointerAxes.getRawWidth();
@@ -1395,26 +1386,12 @@
mExternalStylusFusionTimeout = LLONG_MAX;
}
-void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) {
- nsecs_t now = systemTime(CLOCK_MONOTONIC);
- nsecs_t latency = now - evdevTime;
- mStatistics.addValue(nanoseconds_to_microseconds(latency));
- nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime;
- if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) {
- android::util::stats_write(android::util::TOUCH_EVENT_REPORTED, mStatistics.min,
- mStatistics.max, mStatistics.mean(), mStatistics.stdev(),
- mStatistics.count);
- mStatistics.reset(now);
- }
-}
-
void TouchInputMapper::process(const RawEvent* rawEvent) {
mCursorButtonAccumulator.process(rawEvent);
mCursorScrollAccumulator.process(rawEvent);
mTouchButtonAccumulator.process(rawEvent);
if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
- reportEventForStatistics(rawEvent->when);
sync(rawEvent->when);
}
}
@@ -1848,7 +1825,6 @@
int32_t buttonState = mCurrentCookedState.buttonState;
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState,
buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
@@ -1869,7 +1845,6 @@
// The listener takes care of batching moves so we don't have to deal with that here.
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1,
@@ -1901,7 +1876,7 @@
uint32_t upId = upIdBits.clearFirstMarkedBit();
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
- metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp,
+ metaState, buttonState, 0,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId,
@@ -1915,8 +1890,7 @@
if (moveNeeded && !moveIdBits.isEmpty()) {
ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value);
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
- buttonState, 0, mCurrentCookedState.deviceTimestamp,
- mCurrentCookedState.cookedPointerData.pointerProperties,
+ buttonState, 0, mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1,
mOrientedXPrecision, mOrientedYPrecision, mDownTime);
@@ -1933,7 +1907,7 @@
}
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0,
- metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp,
+ metaState, buttonState, 0,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits,
@@ -1948,7 +1922,7 @@
!mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) {
int32_t metaState = getContext()->getGlobalMetaState();
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState,
- mLastCookedState.buttonState, 0, mLastCookedState.deviceTimestamp,
+ mLastCookedState.buttonState, 0,
mLastCookedState.cookedPointerData.pointerProperties,
mLastCookedState.cookedPointerData.pointerCoords,
mLastCookedState.cookedPointerData.idToIndex,
@@ -1965,7 +1939,6 @@
if (!mSentHoverEnter) {
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
metaState, mCurrentRawState.buttonState, 0,
- mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -1975,7 +1948,7 @@
}
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- mCurrentRawState.buttonState, 0, mCurrentCookedState.deviceTimestamp,
+ mCurrentRawState.buttonState, 0,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex,
@@ -1994,7 +1967,6 @@
buttonState &= ~actionButton;
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
actionButton, 0, metaState, buttonState, 0,
- mCurrentCookedState.deviceTimestamp,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
@@ -2011,7 +1983,7 @@
int32_t actionButton = BitSet32::valueForBit(pressedButtons.clearFirstMarkedBit());
buttonState |= actionButton;
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton,
- 0, metaState, buttonState, 0, mCurrentCookedState.deviceTimestamp,
+ 0, metaState, buttonState, 0,
mCurrentCookedState.cookedPointerData.pointerProperties,
mCurrentCookedState.cookedPointerData.pointerCoords,
mCurrentCookedState.cookedPointerData.idToIndex, idBits, -1,
@@ -2030,7 +2002,6 @@
uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount;
mCurrentCookedState.cookedPointerData.clear();
- mCurrentCookedState.deviceTimestamp = mCurrentRawState.deviceTimestamp;
mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount;
mCurrentCookedState.cookedPointerData.hoveringIdBits =
mCurrentRawState.rawPointerData.hoveringIdBits;
@@ -2428,7 +2399,7 @@
if (!dispatchedGestureIdBits.isEmpty()) {
if (cancelPreviousGesture) {
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState,
- buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
mPointerGesture.downTime);
@@ -2447,7 +2418,7 @@
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, 0,
metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, mPointerGesture.lastGestureProperties,
+ mPointerGesture.lastGestureProperties,
mPointerGesture.lastGestureCoords,
mPointerGesture.lastGestureIdToIndex, dispatchedGestureIdBits, id, 0,
0, mPointerGesture.downTime);
@@ -2460,7 +2431,7 @@
// Send motion events for all pointers that moved.
if (moveNeeded) {
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
- buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, -1, 0, 0,
@@ -2480,8 +2451,7 @@
}
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, 0,
- metaState, buttonState, 0,
- /* deviceTimestamp */ 0, mPointerGesture.currentGestureProperties,
+ metaState, buttonState, 0, mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex, dispatchedGestureIdBits, id, 0,
0, mPointerGesture.downTime);
@@ -2491,7 +2461,7 @@
// Send motion events for hover.
if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) {
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
- buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.currentGestureProperties,
mPointerGesture.currentGestureCoords,
mPointerGesture.currentGestureIdToIndex,
@@ -2518,9 +2488,8 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords, 0, 0,
- mPointerGesture.downTime, /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties, &pointerCoords,
+ 0, 0, x, y, mPointerGesture.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -2548,7 +2517,7 @@
int32_t metaState = getContext()->getGlobalMetaState();
int32_t buttonState = mCurrentRawState.buttonState;
dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, 0, metaState,
- buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0,
+ buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords,
mPointerGesture.lastGestureIdToIndex, mPointerGesture.lastGestureIdBits, -1,
0, 0, mPointerGesture.downTime);
@@ -3418,17 +3387,19 @@
int32_t metaState = getContext()->getGlobalMetaState();
int32_t displayId = mViewport.displayId;
- if (mPointerController != nullptr) {
- if (down || hovering) {
- mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
- mPointerController->clearSpots();
- mPointerController->setButtonState(mCurrentRawState.buttonState);
- mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
- } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
- mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
- }
- displayId = mPointerController->getDisplayId();
+ if (down || hovering) {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
+ mPointerController->clearSpots();
+ mPointerController->setButtonState(mCurrentRawState.buttonState);
+ mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
+ } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) {
+ mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
}
+ displayId = mPointerController->getDisplayId();
+
+ float xCursorPosition;
+ float yCursorPosition;
+ mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
if (mPointerSimple.down && !down) {
mPointerSimple.down = false;
@@ -3437,9 +3408,9 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_UP, 0, 0, metaState,
mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
- &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
- mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+ &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
/* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3451,9 +3422,9 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0,
metaState, mLastRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
- &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
- mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.lastProperties,
+ &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
/* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3467,11 +3438,10 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_DOWN, 0, 0,
metaState, mCurrentRawState.buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, mPointerSimple.downTime,
- /* videoFrames */ {});
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3479,10 +3449,10 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState,
mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime,
- /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3494,11 +3464,10 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0,
metaState, mCurrentRawState.buttonState,
- MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE,
- /* deviceTimestamp */ 0, 1, &mPointerSimple.currentProperties,
- &mPointerSimple.currentCoords, mOrientedXPrecision,
- mOrientedYPrecision, mPointerSimple.downTime,
- /* videoFrames */ {});
+ MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,
+ &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
+ mOrientedXPrecision, mOrientedYPrecision, xCursorPosition,
+ yCursorPosition, mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3506,10 +3475,10 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
metaState, mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
- &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
- mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime,
- /* videoFrames */ {});
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &mPointerSimple.currentCoords, mOrientedXPrecision,
+ mOrientedYPrecision, xCursorPosition, yCursorPosition,
+ mPointerSimple.downTime, /* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3528,9 +3497,9 @@
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, getDeviceId(), mSource,
displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState,
mCurrentRawState.buttonState, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1,
- &mPointerSimple.currentProperties, &pointerCoords,
- mOrientedXPrecision, mOrientedYPrecision, mPointerSimple.downTime,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, &mPointerSimple.currentProperties,
+ &pointerCoords, mOrientedXPrecision, mOrientedYPrecision,
+ xCursorPosition, yCursorPosition, mPointerSimple.downTime,
/* videoFrames */ {});
getListener()->notifyMotion(&args);
}
@@ -3554,7 +3523,7 @@
void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
int32_t action, int32_t actionButton, int32_t flags,
int32_t metaState, int32_t buttonState, int32_t edgeFlags,
- uint32_t deviceTimestamp, const PointerProperties* properties,
+ const PointerProperties* properties,
const PointerCoords* coords, const uint32_t* idToIndex,
BitSet32 idBits, int32_t changedId, float xPrecision,
float yPrecision, nsecs_t downTime) {
@@ -3589,16 +3558,21 @@
ALOG_ASSERT(false);
}
}
- const int32_t displayId = getAssociatedDisplay().value_or(ADISPLAY_ID_NONE);
+ float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+ float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;
+ if (mDeviceMode == DEVICE_MODE_POINTER) {
+ mPointerController->getPosition(&xCursorPosition, &yCursorPosition);
+ }
+ const int32_t displayId = getAssociatedDisplayId().value_or(ADISPLAY_ID_NONE);
const int32_t deviceId = getDeviceId();
std::vector<TouchVideoFrame> frames = mDevice->getEventHub()->getVideoFrames(deviceId);
std::for_each(frames.begin(), frames.end(),
[this](TouchVideoFrame& frame) { frame.rotate(this->mSurfaceOrientation); });
NotifyMotionArgs args(mContext->getNextSequenceNum(), when, deviceId, source, displayId,
policyFlags, action, actionButton, flags, metaState, buttonState,
- MotionClassification::NONE, edgeFlags, deviceTimestamp, pointerCount,
- pointerProperties, pointerCoords, xPrecision, yPrecision, downTime,
- std::move(frames));
+ MotionClassification::NONE, edgeFlags, pointerCount, pointerProperties,
+ pointerCoords, xPrecision, yPrecision, xCursorPosition, yCursorPosition,
+ downTime, std::move(frames));
getListener()->notifyMotion(&args);
}
@@ -3647,9 +3621,9 @@
const float scaledX = x * mXScale;
const float scaledY = y * mYScale;
return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue &&
- scaledX >= mPhysicalLeft && scaledX <= mPhysicalLeft + mPhysicalWidth &&
+ scaledX >= mSurfaceLeft && scaledX <= mSurfaceLeft + mSurfaceWidth &&
y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue &&
- scaledY >= mPhysicalTop && scaledY <= mPhysicalTop + mPhysicalHeight;
+ scaledY >= mSurfaceTop && scaledY <= mSurfaceTop + mSurfaceHeight;
}
const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit(int32_t x, int32_t y) {
@@ -3895,7 +3869,7 @@
return true;
}
-std::optional<int32_t> TouchInputMapper::getAssociatedDisplay() {
+std::optional<int32_t> TouchInputMapper::getAssociatedDisplayId() {
if (mParameters.hasAssociatedDisplay) {
if (mDeviceMode == DEVICE_MODE_POINTER) {
return std::make_optional(mPointerController->getDisplayId());
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index d14812a..89c017d 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -28,68 +28,6 @@
namespace android {
-/**
- * Basic statistics information.
- * Keep track of min, max, average, and standard deviation of the received samples.
- * Used to report latency information about input events.
- */
-struct LatencyStatistics {
- float min;
- float max;
- // Sum of all samples
- float sum;
- // Sum of squares of all samples
- float sum2;
- // The number of samples
- size_t count;
- // The last time statistics were reported.
- nsecs_t lastReportTime;
-
- LatencyStatistics() { reset(systemTime(SYSTEM_TIME_MONOTONIC)); }
-
- inline void addValue(float x) {
- if (x < min) {
- min = x;
- }
- if (x > max) {
- max = x;
- }
- sum += x;
- sum2 += x * x;
- count++;
- }
-
- // Get the average value. Should not be called if no samples have been added.
- inline float mean() {
- if (count == 0) {
- return 0;
- }
- return sum / count;
- }
-
- // Get the standard deviation. Should not be called if no samples have been added.
- inline float stdev() {
- if (count == 0) {
- return 0;
- }
- float average = mean();
- return sqrt(sum2 / count - average * average);
- }
-
- /**
- * Reset internal state. The variable 'when' is the time when the data collection started.
- * Call this to start a new data collection window.
- */
- inline void reset(nsecs_t when) {
- max = 0;
- min = std::numeric_limits<float>::max();
- sum = 0;
- sum2 = 0;
- count = 0;
- lastReportTime = when;
- }
-};
-
/* Raw axis information from the driver. */
struct RawPointerAxes {
RawAbsoluteAxisInfo x;
@@ -197,23 +135,24 @@
explicit TouchInputMapper(InputDevice* device);
virtual ~TouchInputMapper();
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void dump(std::string& dump);
- virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
- virtual void reset(nsecs_t when);
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void dump(std::string& dump) override;
+ virtual void configure(nsecs_t when, const InputReaderConfiguration* config,
+ uint32_t changes) override;
+ virtual void reset(nsecs_t when) override;
+ virtual void process(const RawEvent* rawEvent) override;
- virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode);
- virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode);
+ virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode) override;
+ virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode) override;
virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
- const int32_t* keyCodes, uint8_t* outFlags);
+ const int32_t* keyCodes, uint8_t* outFlags) override;
- virtual void fadePointer();
- virtual void cancelTouch(nsecs_t when);
- virtual void timeoutExpired(nsecs_t when);
- virtual void updateExternalStylusState(const StylusState& state);
- virtual std::optional<int32_t> getAssociatedDisplay();
+ virtual void fadePointer() override;
+ virtual void cancelTouch(nsecs_t when) override;
+ virtual void timeoutExpired(nsecs_t when) override;
+ virtual void updateExternalStylusState(const StylusState& state) override;
+ virtual std::optional<int32_t> getAssociatedDisplayId() override;
protected:
CursorButtonAccumulator mCursorButtonAccumulator;
@@ -358,7 +297,6 @@
struct RawState {
nsecs_t when;
- uint32_t deviceTimestamp;
// Raw pointer sample data.
RawPointerData rawPointerData;
@@ -371,7 +309,6 @@
void copyFrom(const RawState& other) {
when = other.when;
- deviceTimestamp = other.deviceTimestamp;
rawPointerData.copyFrom(other.rawPointerData);
buttonState = other.buttonState;
rawVScroll = other.rawVScroll;
@@ -380,7 +317,6 @@
void clear() {
when = 0;
- deviceTimestamp = 0;
rawPointerData.clear();
buttonState = 0;
rawVScroll = 0;
@@ -389,7 +325,6 @@
};
struct CookedState {
- uint32_t deviceTimestamp;
// Cooked pointer sample data.
CookedPointerData cookedPointerData;
@@ -401,7 +336,6 @@
int32_t buttonState;
void copyFrom(const CookedState& other) {
- deviceTimestamp = other.deviceTimestamp;
cookedPointerData.copyFrom(other.cookedPointerData);
fingerIdBits = other.fingerIdBits;
stylusIdBits = other.stylusIdBits;
@@ -410,7 +344,6 @@
}
void clear() {
- deviceTimestamp = 0;
cookedPointerData.clear();
fingerIdBits.clear();
stylusIdBits.clear();
@@ -759,9 +692,6 @@
VelocityControl mWheelXVelocityControl;
VelocityControl mWheelYVelocityControl;
- // Latency statistics for touch events
- struct LatencyStatistics mStatistics;
-
std::optional<DisplayViewport> findViewport();
void resetExternalStylus();
@@ -811,10 +741,9 @@
// it is the first / last pointer to go down / up.
void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, int32_t action,
int32_t actionButton, int32_t flags, int32_t metaState, int32_t buttonState,
- int32_t edgeFlags, uint32_t deviceTimestamp,
- const PointerProperties* properties, const PointerCoords* coords,
- const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
- float xPrecision, float yPrecision, nsecs_t downTime);
+ int32_t edgeFlags, const PointerProperties* properties,
+ const PointerCoords* coords, const uint32_t* idToIndex, BitSet32 idBits,
+ int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime);
// Updates pointer coords and properties for pointers with specified ids that have moved.
// Returns true if any of them changed.
@@ -828,11 +757,9 @@
static void assignPointerIds(const RawState* last, RawState* current);
- void reportEventForStatistics(nsecs_t evdevTime);
-
const char* modeToString(DeviceMode deviceMode);
};
} // namespace android
-#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
+#endif // _UI_INPUTREADER_TOUCH_INPUT_MAPPER_H
\ No newline at end of file
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index 6b33f48..dc67890 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -26,14 +26,15 @@
explicit VibratorInputMapper(InputDevice* device);
virtual ~VibratorInputMapper();
- virtual uint32_t getSources();
- virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
- virtual void process(const RawEvent* rawEvent);
+ virtual uint32_t getSources() override;
+ virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
+ virtual void process(const RawEvent* rawEvent) override;
- virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
- virtual void cancelVibrate(int32_t token);
- virtual void timeoutExpired(nsecs_t when);
- virtual void dump(std::string& dump);
+ virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
+ int32_t token) override;
+ virtual void cancelVibrate(int32_t token) override;
+ virtual void timeoutExpired(nsecs_t when) override;
+ virtual void dump(std::string& dump) override;
private:
bool mVibrating;
diff --git a/services/inputflinger/tests/InputClassifierConverter_test.cpp b/services/inputflinger/tests/InputClassifierConverter_test.cpp
index 813b69e..f58b628 100644
--- a/services/inputflinger/tests/InputClassifierConverter_test.cpp
+++ b/services/inputflinger/tests/InputClassifierConverter_test.cpp
@@ -38,12 +38,15 @@
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 2);
coords.setAxisValue(AMOTION_EVENT_AXIS_SIZE, 0.5);
static constexpr nsecs_t downTime = 2;
- NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
- AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
- 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
- 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/,
- downTime, {}/*videoFrames*/);
+ NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/,
+ AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/,
+ AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/,
+ AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1 /*pointerCount*/, &properties,
+ &coords, 0 /*xPrecision*/, 0 /*yPrecision*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime,
+ {} /*videoFrames*/);
return motionArgs;
}
diff --git a/services/inputflinger/tests/InputClassifier_test.cpp b/services/inputflinger/tests/InputClassifier_test.cpp
index 7cc17a2..40086ef 100644
--- a/services/inputflinger/tests/InputClassifier_test.cpp
+++ b/services/inputflinger/tests/InputClassifier_test.cpp
@@ -38,12 +38,15 @@
coords.setAxisValue(AMOTION_EVENT_AXIS_X, 1);
coords.setAxisValue(AMOTION_EVENT_AXIS_Y, 1);
static constexpr nsecs_t downTime = 2;
- NotifyMotionArgs motionArgs(1/*sequenceNum*/, downTime/*eventTime*/, 3/*deviceId*/,
- AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4/*policyFlags*/, AMOTION_EVENT_ACTION_DOWN,
- 0/*actionButton*/, 0/*flags*/, AMETA_NONE, 0/*buttonState*/, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, 5/*deviceTimestamp*/,
- 1/*pointerCount*/, &properties, &coords, 0/*xPrecision*/, 0/*yPrecision*/,
- downTime, {}/*videoFrames*/);
+ NotifyMotionArgs motionArgs(1 /*sequenceNum*/, downTime /*eventTime*/, 3 /*deviceId*/,
+ AINPUT_SOURCE_ANY, ADISPLAY_ID_DEFAULT, 4 /*policyFlags*/,
+ AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, 0 /*flags*/,
+ AMETA_NONE, 0 /*buttonState*/, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1 /*pointerCount*/, &properties,
+ &coords, 0 /*xPrecision*/, 0 /*yPrecision*/,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, downTime,
+ {} /*videoFrames*/);
return motionArgs;
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 551bee1..aa98ef7 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -251,8 +251,10 @@
// Rejects undefined motion actions.
event.initialize(DEVICE_ID, source, DISPLAY_ID,
- /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -260,18 +262,24 @@
// Rejects pointer down with invalid index.
event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer down index too large.";
event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ AMOTION_EVENT_ACTION_POINTER_DOWN |
+ (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -279,36 +287,45 @@
// Rejects pointer up with invalid index.
event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer up index too large.";
event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
- 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ AMOTION_EVENT_ACTION_POINTER_UP |
+ (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+ 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer up index too small.";
// Rejects motion events with invalid number of pointers.
- event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 0, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+ metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 0, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with 0 pointers.";
- event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME,
- /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+ metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -316,18 +333,22 @@
// Rejects motion events with invalid pointer ids.
pointerProperties[0].id = -1;
- event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+ metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
<< "Should reject motion events with pointer ids less than 0.";
pointerProperties[0].id = MAX_POINTER_ID + 1;
- event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 1, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+ metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -336,9 +357,11 @@
// Rejects motion events with duplicate pointer ids.
pointerProperties[0].id = 1;
pointerProperties[1].id = 1;
- event.initialize(DEVICE_ID, source, DISPLAY_ID,
- AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification, 0, 0, 0, 0,
- ARBITRARY_TIME, ARBITRARY_TIME, /*pointerCount*/ 2, pointerProperties, pointerCoords);
+ event.initialize(DEVICE_ID, source, DISPLAY_ID, AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags,
+ metaState, 0, classification, 0, 0, 0, 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ ARBITRARY_TIME, ARBITRARY_TIME,
+ /*pointerCount*/ 2, pointerProperties, pointerCoords);
ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
&event,
INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
@@ -465,6 +488,7 @@
mInfo.frameRight = mFrame.right;
mInfo.frameBottom = mFrame.bottom;
mInfo.globalScaleFactor = 1.0;
+ mInfo.touchableRegion.clear();
mInfo.addTouchableRegion(mFrame);
mInfo.visible = true;
mInfo.canReceiveKeys = true;
@@ -523,8 +547,10 @@
INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
}
-static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
- int32_t displayId, int32_t x = 100, int32_t y = 200) {
+static int32_t injectMotionEvent(const sp<InputDispatcher>& dispatcher, int32_t action,
+ int32_t source, int32_t displayId, int32_t x, int32_t y,
+ int32_t xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ int32_t yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION) {
MotionEvent event;
PointerProperties pointerProperties[1];
PointerCoords pointerCoords[1];
@@ -539,12 +565,11 @@
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid motion down event.
- event.initialize(DEVICE_ID, source, displayId,
- AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0,
- AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
- /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
- /* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
- pointerCoords);
+ event.initialize(DEVICE_ID, source, displayId, action, /* actionButton */ 0, /* flags */ 0,
+ /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+ /* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
+ /* yPrecision */ 0, xCursorPosition, yCursorPosition, currentTime, currentTime,
+ /*pointerCount*/ 1, pointerProperties, pointerCoords);
// Inject event until dispatch out.
return dispatcher->injectInputEvent(
@@ -553,6 +578,11 @@
INJECT_EVENT_TIMEOUT, POLICY_FLAG_FILTERED | POLICY_FLAG_PASS_TO_USER);
}
+static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
+ int32_t displayId, int32_t x = 100, int32_t y = 200) {
+ return injectMotionEvent(dispatcher, AMOTION_EVENT_ACTION_DOWN, source, displayId, x, y);
+}
+
static NotifyKeyArgs generateKeyArgs(int32_t action, int32_t displayId = ADISPLAY_ID_NONE) {
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid key event.
@@ -578,11 +608,12 @@
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid motion event.
NotifyMotionArgs args(/* sequenceNum */ 0, currentTime, DEVICE_ID, source, displayId,
- POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
- AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
- AMOTION_EVENT_EDGE_FLAG_NONE, /* deviceTimestamp */ 0, 1, pointerProperties,
- pointerCoords, /* xPrecision */ 0, /* yPrecision */ 0, currentTime,
- /* videoFrames */ {});
+ POLICY_FLAG_PASS_TO_USER, action, /* actionButton */ 0, /* flags */ 0,
+ AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
+ AMOTION_EVENT_EDGE_FLAG_NONE, 1, pointerProperties, pointerCoords,
+ /* xPrecision */ 0, /* yPrecision */ 0,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION,
+ AMOTION_EVENT_INVALID_CURSOR_POSITION, currentTime, /* videoFrames */ {});
return args;
}
@@ -706,6 +737,32 @@
windowSecond->consumeEvent(AINPUT_EVENT_TYPE_KEY, ADISPLAY_ID_NONE);
}
+TEST_F(InputDispatcherTest, DispatchMouseEventsUnderCursor) {
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+
+ sp<FakeWindowHandle> windowLeft =
+ new FakeWindowHandle(application, mDispatcher, "Left", ADISPLAY_ID_DEFAULT);
+ windowLeft->setFrame(Rect(0, 0, 600, 800));
+ windowLeft->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+ sp<FakeWindowHandle> windowRight =
+ new FakeWindowHandle(application, mDispatcher, "Right", ADISPLAY_ID_DEFAULT);
+ windowRight->setFrame(Rect(600, 0, 1200, 800));
+ windowRight->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+ std::vector<sp<InputWindowHandle>> inputWindowHandles{windowLeft, windowRight};
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+
+ // Inject an event with coordinate in the area of right window, with mouse cursor in the area of
+ // left window. This event should be dispatched to the left window.
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED,
+ injectMotionEvent(mDispatcher, AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_MOUSE,
+ ADISPLAY_ID_DEFAULT, 610, 400, 599, 400));
+ windowLeft->consumeEvent(AINPUT_EVENT_TYPE_MOTION, ADISPLAY_ID_DEFAULT);
+ windowRight->assertNoEvents();
+}
+
/* Test InputDispatcher for MultiDisplay */
class InputDispatcherFocusOnTwoDisplaysTest : public InputDispatcherTest {
public:
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index aeb4ad6..31b1652 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -202,6 +202,20 @@
mConfig.setDisplayViewports(mViewports);
}
+ bool updateViewport(const DisplayViewport& viewport) {
+ size_t count = mViewports.size();
+ for (size_t i = 0; i < count; i++) {
+ const DisplayViewport& currentViewport = mViewports[i];
+ if (currentViewport.displayId == viewport.displayId) {
+ mViewports[i] = viewport;
+ mConfig.setDisplayViewports(mViewports);
+ return true;
+ }
+ }
+ // no viewport found.
+ return false;
+ }
+
void addExcludedDeviceName(const std::string& deviceName) {
mConfig.excludedDeviceNames.push_back(deviceName);
}
@@ -210,21 +224,9 @@
mConfig.portAssociations.insert({inputPort, displayPort});
}
- void addDisabledDevice(int32_t deviceId) {
- ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
- bool currentlyEnabled = index < 0;
- if (currentlyEnabled) {
- mConfig.disabledDevices.add(deviceId);
- }
- }
+ void addDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.insert(deviceId); }
- void removeDisabledDevice(int32_t deviceId) {
- ssize_t index = mConfig.disabledDevices.indexOf(deviceId);
- bool currentlyEnabled = index < 0;
- if (!currentlyEnabled) {
- mConfig.disabledDevices.remove(deviceId);
- }
- }
+ void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
mPointerControllers.add(deviceId, controller);
@@ -345,14 +347,13 @@
List<RawEvent> mEvents;
std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
-protected:
+public:
virtual ~FakeEventHub() {
for (size_t i = 0; i < mDevices.size(); i++) {
delete mDevices.valueAt(i);
}
}
-public:
FakeEventHub() { }
void addDevice(int32_t deviceId, const std::string& name, uint32_t classes) {
@@ -548,7 +549,7 @@
virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis,
RawAbsoluteAxisInfo* outAxisInfo) const {
Device* device = getDevice(deviceId);
- if (device) {
+ if (device && device->enabled) {
ssize_t index = device->absoluteAxes.indexOfKey(axis);
if (index >= 0) {
*outAxisInfo = device->absoluteAxes.valueAt(index);
@@ -780,7 +781,7 @@
// --- FakeInputReaderContext ---
class FakeInputReaderContext : public InputReaderContext {
- sp<EventHubInterface> mEventHub;
+ std::shared_ptr<EventHubInterface> mEventHub;
sp<InputReaderPolicyInterface> mPolicy;
sp<InputListenerInterface> mListener;
int32_t mGlobalMetaState;
@@ -789,12 +790,14 @@
uint32_t mNextSequenceNum;
public:
- FakeInputReaderContext(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- mEventHub(eventHub), mPolicy(policy), mListener(listener),
- mGlobalMetaState(0), mNextSequenceNum(1) {
- }
+ FakeInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : mEventHub(eventHub),
+ mPolicy(policy),
+ mListener(listener),
+ mGlobalMetaState(0),
+ mNextSequenceNum(1) {}
virtual ~FakeInputReaderContext() { }
@@ -1019,12 +1022,10 @@
InputDevice* mNextDevice;
public:
- InstrumentedInputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
- InputReader(eventHub, policy, listener),
- mNextDevice(nullptr) {
- }
+ InstrumentedInputReader(std::shared_ptr<EventHubInterface> eventHub,
+ const sp<InputReaderPolicyInterface>& policy,
+ const sp<InputListenerInterface>& listener)
+ : InputReader(eventHub, policy, listener), mNextDevice(nullptr) {}
virtual ~InstrumentedInputReader() {
if (mNextDevice) {
@@ -1252,11 +1253,11 @@
protected:
sp<TestInputListener> mFakeListener;
sp<FakeInputReaderPolicy> mFakePolicy;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<InstrumentedInputReader> mReader;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
@@ -1268,7 +1269,6 @@
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
void addDevice(int32_t deviceId, const std::string& name, uint32_t classes,
@@ -1578,10 +1578,14 @@
mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
mReader->loopOnce();
- // Check device.
+ // Device should only dispatch to the specified display.
ASSERT_EQ(deviceId, device->getId());
ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, DISPLAY_ID));
ASSERT_TRUE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
+
+ // Can't dispatch event from a disabled device.
+ disableDevice(deviceId, device);
+ ASSERT_FALSE(mReader->canDispatchToDisplay(deviceId, SECONDARY_DISPLAY_ID));
}
@@ -1590,12 +1594,13 @@
class InputDeviceTest : public testing::Test {
protected:
static const char* DEVICE_NAME;
+ static const char* DEVICE_LOCATION;
static const int32_t DEVICE_ID;
static const int32_t DEVICE_GENERATION;
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
@@ -1603,7 +1608,7 @@
InputDevice* mDevice;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
@@ -1611,6 +1616,7 @@
mFakeEventHub->addDevice(DEVICE_ID, DEVICE_NAME, 0);
InputDeviceIdentifier identifier;
identifier.name = DEVICE_NAME;
+ identifier.location = DEVICE_LOCATION;
mDevice = new InputDevice(mFakeContext, DEVICE_ID, DEVICE_GENERATION,
DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
}
@@ -1621,11 +1627,11 @@
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
};
const char* InputDeviceTest::DEVICE_NAME = "device";
+const char* InputDeviceTest::DEVICE_LOCATION = "USB1";
const int32_t InputDeviceTest::DEVICE_ID = 1;
const int32_t InputDeviceTest::DEVICE_GENERATION = 2;
const int32_t InputDeviceTest::DEVICE_CONTROLLER_NUMBER = 0;
@@ -1778,6 +1784,49 @@
ASSERT_NO_FATAL_FAILURE(mapper2->assertProcessWasCalled());
}
+// A single input device is associated with a specific display. Check that:
+// 1. Device is disabled if the viewport corresponding to the associated display is not found
+// 2. Device is disabled when setEnabled API is called
+TEST_F(InputDeviceTest, Configure_AssignsDisplayPort) {
+ FakeInputMapper* mapper = new FakeInputMapper(mDevice, AINPUT_SOURCE_TOUCHSCREEN);
+ mDevice->addMapper(mapper);
+
+ // First Configuration.
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0);
+
+ // Device should be enabled by default.
+ ASSERT_TRUE(mDevice->isEnabled());
+
+ // Prepare associated info.
+ constexpr uint8_t hdmi = 1;
+ const std::string UNIQUE_ID = "local:1";
+
+ mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi);
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ // Device should be disabled because it is associated with a specific display via
+ // input port <-> display port association, but the corresponding display is not found
+ ASSERT_FALSE(mDevice->isEnabled());
+
+ // Prepare displays.
+ mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+ DISPLAY_ORIENTATION_0, UNIQUE_ID, hdmi,
+ ViewportType::VIEWPORT_INTERNAL);
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ ASSERT_TRUE(mDevice->isEnabled());
+
+ // Device should be disabled after set disable.
+ mFakePolicy->addDisabledDevice(mDevice->getId());
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_ENABLED_STATE);
+ ASSERT_FALSE(mDevice->isEnabled());
+
+ // Device should still be disabled even found the associated display.
+ mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ ASSERT_FALSE(mDevice->isEnabled());
+}
// --- InputMapperTest ---
@@ -1790,14 +1839,14 @@
static const int32_t DEVICE_CONTROLLER_NUMBER;
static const uint32_t DEVICE_CLASSES;
- sp<FakeEventHub> mFakeEventHub;
+ std::shared_ptr<FakeEventHub> mFakeEventHub;
sp<FakeInputReaderPolicy> mFakePolicy;
sp<TestInputListener> mFakeListener;
FakeInputReaderContext* mFakeContext;
InputDevice* mDevice;
virtual void SetUp() {
- mFakeEventHub = new FakeEventHub();
+ mFakeEventHub = std::make_unique<FakeEventHub>();
mFakePolicy = new FakeInputReaderPolicy();
mFakeListener = new TestInputListener();
mFakeContext = new FakeInputReaderContext(mFakeEventHub, mFakePolicy, mFakeListener);
@@ -1815,7 +1864,6 @@
delete mFakeContext;
mFakeListener.clear();
mFakePolicy.clear();
- mFakeEventHub.clear();
}
void addConfigurationProperty(const char* key, const char* value) {
@@ -1950,8 +1998,9 @@
void prepareDisplay(int32_t orientation);
- void testDPadKeyRotation(KeyboardInputMapper* mapper,
- int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode);
+ void testDPadKeyRotation(KeyboardInputMapper* mapper, int32_t originalScanCode,
+ int32_t originalKeyCode, int32_t rotatedKeyCode,
+ int32_t displayId = ADISPLAY_ID_NONE);
};
/* Similar to setDisplayInfoAndReconfigure, but pre-populates all parameters except for the
@@ -1963,7 +2012,8 @@
}
void KeyboardInputMapperTest::testDPadKeyRotation(KeyboardInputMapper* mapper,
- int32_t originalScanCode, int32_t originalKeyCode, int32_t rotatedKeyCode) {
+ int32_t originalScanCode, int32_t originalKeyCode,
+ int32_t rotatedKeyCode, int32_t displayId) {
NotifyKeyArgs args;
process(mapper, ARBITRARY_TIME, EV_KEY, originalScanCode, 1);
@@ -1971,15 +2021,16 @@
ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, args.action);
ASSERT_EQ(originalScanCode, args.scanCode);
ASSERT_EQ(rotatedKeyCode, args.keyCode);
+ ASSERT_EQ(displayId, args.displayId);
process(mapper, ARBITRARY_TIME, EV_KEY, originalScanCode, 0);
ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
ASSERT_EQ(AKEY_EVENT_ACTION_UP, args.action);
ASSERT_EQ(originalScanCode, args.scanCode);
ASSERT_EQ(rotatedKeyCode, args.keyCode);
+ ASSERT_EQ(displayId, args.displayId);
}
-
TEST_F(KeyboardInputMapperTest, GetSources) {
KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
@@ -2160,47 +2211,47 @@
addMapperAndConfigure(mapper);
prepareDisplay(DISPLAY_ORIENTATION_0);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_LEFT));
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_LEFT, DISPLAY_ID));
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_90);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN));
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_UP, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_DOWN, DISPLAY_ID));
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_180);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_LEFT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_UP));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_RIGHT));
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_UP, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
clearViewports();
prepareDisplay(DISPLAY_ORIENTATION_270);
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_RIGHT, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_DOWN));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_DOWN, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_LEFT));
- ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper,
- KEY_LEFT, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_UP));
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_UP, DISPLAY_ID));
// Special case: if orientation changes while key is down, we still emit the same keycode
// in the key up as we did in the key down.
@@ -2384,6 +2435,84 @@
ASSERT_EQ(AMETA_NONE, mapper->getMetaState());
}
+TEST_F(KeyboardInputMapperTest, Configure_AssignsDisplayPort) {
+ // keyboard 1.
+ mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+ mFakeEventHub->addKey(DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+
+ // keyboard 2.
+ const std::string USB2 = "USB2";
+ constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
+ InputDeviceIdentifier identifier;
+ identifier.name = "KEYBOARD2";
+ identifier.location = USB2;
+ std::unique_ptr<InputDevice> device2 =
+ std::make_unique<InputDevice>(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
+ DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
+ mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/);
+ mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+ mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_RIGHT, 0, AKEYCODE_DPAD_RIGHT, 0);
+ mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_DOWN, 0, AKEYCODE_DPAD_DOWN, 0);
+ mFakeEventHub->addKey(SECOND_DEVICE_ID, KEY_LEFT, 0, AKEYCODE_DPAD_LEFT, 0);
+
+ KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice, AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ addMapperAndConfigure(mapper);
+
+ KeyboardInputMapper* mapper2 = new KeyboardInputMapper(device2.get(), AINPUT_SOURCE_KEYBOARD,
+ AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+ device2->addMapper(mapper2);
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
+ device2->reset(ARBITRARY_TIME);
+
+ // Prepared displays and associated info.
+ constexpr uint8_t hdmi1 = 0;
+ constexpr uint8_t hdmi2 = 1;
+ const std::string SECONDARY_UNIQUE_ID = "local:1";
+
+ mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi1);
+ mFakePolicy->addInputPortAssociation(USB2, hdmi2);
+
+ // No associated display viewport found, should disable the device.
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+ ASSERT_FALSE(device2->isEnabled());
+
+ // Prepare second display.
+ constexpr int32_t newDisplayId = 2;
+ setDisplayInfoAndReconfigure(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
+ UNIQUE_ID, hdmi1, ViewportType::VIEWPORT_INTERNAL);
+ setDisplayInfoAndReconfigure(newDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0,
+ SECONDARY_UNIQUE_ID, hdmi2, ViewportType::VIEWPORT_EXTERNAL);
+ // Default device will reconfigure above, need additional reconfiguration for another device.
+ device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
+ InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+
+ // Device should be enabled after the associated display is found.
+ ASSERT_TRUE(mDevice->isEnabled());
+ ASSERT_TRUE(device2->isEnabled());
+
+ // Test pad key events
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_RIGHT, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_DOWN, DISPLAY_ID));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_LEFT, DISPLAY_ID));
+
+ ASSERT_NO_FATAL_FAILURE(
+ testDPadKeyRotation(mapper2, KEY_UP, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_UP, newDisplayId));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_RIGHT, AKEYCODE_DPAD_RIGHT,
+ AKEYCODE_DPAD_RIGHT, newDisplayId));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_DOWN, AKEYCODE_DPAD_DOWN,
+ AKEYCODE_DPAD_DOWN, newDisplayId));
+ ASSERT_NO_FATAL_FAILURE(testDPadKeyRotation(mapper2, KEY_LEFT, AKEYCODE_DPAD_LEFT,
+ AKEYCODE_DPAD_LEFT, newDisplayId));
+}
// --- CursorInputMapperTest ---
@@ -4696,7 +4825,6 @@
void processSlot(MultiTouchInputMapper* mapper, int32_t slot);
void processToolType(MultiTouchInputMapper* mapper, int32_t toolType);
void processKey(MultiTouchInputMapper* mapper, int32_t code, int32_t value);
- void processTimestamp(MultiTouchInputMapper* mapper, uint32_t value);
void processMTSync(MultiTouchInputMapper* mapper);
void processSync(MultiTouchInputMapper* mapper);
};
@@ -4812,10 +4940,6 @@
process(mapper, ARBITRARY_TIME, EV_KEY, code, value);
}
-void MultiTouchInputMapperTest::processTimestamp(MultiTouchInputMapper* mapper, uint32_t value) {
- process(mapper, ARBITRARY_TIME, EV_MSC, MSC_TIMESTAMP, value);
-}
-
void MultiTouchInputMapperTest::processMTSync(MultiTouchInputMapper* mapper) {
process(mapper, ARBITRARY_TIME, EV_SYN, SYN_MT_REPORT, 0);
}
@@ -6198,64 +6322,6 @@
toDisplayX(150), toDisplayY(250), 0, 0, 0, 0, 0, 0, 0, 0));
}
-TEST_F(MultiTouchInputMapperTest, Process_HandlesTimestamp) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(DISPLAY_ORIENTATION_0);
- prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
- NotifyMotionArgs args;
-
- // By default, deviceTimestamp should be zero
- processPosition(mapper, 100, 100);
- processMTSync(mapper);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(0U, args.deviceTimestamp);
-
- // Now the timestamp of 1000 is reported by evdev and should appear in MotionArgs
- processPosition(mapper, 0, 0);
- processTimestamp(mapper, 1000);
- processMTSync(mapper);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(1000U, args.deviceTimestamp);
-}
-
-TEST_F(MultiTouchInputMapperTest, WhenMapperIsReset_TimestampIsCleared) {
- MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
-
- addConfigurationProperty("touch.deviceType", "touchScreen");
- prepareDisplay(DISPLAY_ORIENTATION_0);
- prepareAxes(POSITION);
- addMapperAndConfigure(mapper);
- NotifyMotionArgs args;
-
- // Send a touch event with a timestamp
- processPosition(mapper, 100, 100);
- processTimestamp(mapper, 1);
- processMTSync(mapper);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(1U, args.deviceTimestamp);
-
- // Since the data accumulates, and new timestamp has not arrived, deviceTimestamp won't change
- processPosition(mapper, 100, 200);
- processMTSync(mapper);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(1U, args.deviceTimestamp);
-
- mapper->reset(/* when */ 0);
- // After the mapper is reset, deviceTimestamp should become zero again
- processPosition(mapper, 100, 300);
- processMTSync(mapper);
- processSync(mapper);
- ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
- ASSERT_EQ(0U, args.deviceTimestamp);
-}
-
/**
* Set the input device port <--> display port associations, and check that the
* events are routed to the display that matches the display port.
@@ -6363,12 +6429,13 @@
// Create the second touch screen device, and enable multi fingers.
const std::string USB2 = "USB2";
- const int32_t SECOND_DEVICE_ID = 2;
+ constexpr int32_t SECOND_DEVICE_ID = DEVICE_ID + 1;
InputDeviceIdentifier identifier;
- identifier.name = DEVICE_NAME;
+ identifier.name = "TOUCHSCREEN2";
identifier.location = USB2;
- InputDevice* device2 = new InputDevice(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
- DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
+ std::unique_ptr<InputDevice> device2 =
+ std::make_unique<InputDevice>(mFakeContext, SECOND_DEVICE_ID, DEVICE_GENERATION,
+ DEVICE_CONTROLLER_NUMBER, identifier, DEVICE_CLASSES);
mFakeEventHub->addDevice(SECOND_DEVICE_ID, DEVICE_NAME, 0 /*classes*/);
mFakeEventHub->addAbsoluteAxis(SECOND_DEVICE_ID, ABS_MT_POSITION_X, RAW_X_MIN, RAW_X_MAX,
0 /*flat*/, 0 /*fuzz*/);
@@ -6383,7 +6450,7 @@
String8("touchScreen"));
// Setup the second touch screen device.
- MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2);
+ MultiTouchInputMapper* mapper2 = new MultiTouchInputMapper(device2.get());
device2->addMapper(mapper2);
device2->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), 0 /*changes*/);
device2->reset(ARBITRARY_TIME);
@@ -6509,4 +6576,61 @@
ASSERT_EQ(frames, motionArgs.videoFrames);
}
+/**
+ * If we had defined port associations, but the viewport is not ready, the touch device would be
+ * expected to be disabled, and it should be enabled after the viewport has found.
+ */
+TEST_F(MultiTouchInputMapperTest, Configure_EnabledForAssociatedDisplay) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ constexpr uint8_t hdmi2 = 1;
+ const std::string secondaryUniqueId = "uniqueId2";
+ constexpr ViewportType type = ViewportType::VIEWPORT_EXTERNAL;
+
+ mFakePolicy->addInputPortAssociation(DEVICE_LOCATION, hdmi2);
+
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ ASSERT_EQ(mDevice->isEnabled(), false);
+
+ // Add display on hdmi2, the device should be enabled and can receive touch event.
+ prepareSecondaryDisplay(type, hdmi2);
+ ASSERT_EQ(mDevice->isEnabled(), true);
+
+ // Send a touch event.
+ processPosition(mapper, 100, 100);
+ processSync(mapper);
+
+ NotifyMotionArgs args;
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&args));
+ ASSERT_EQ(SECONDARY_DISPLAY_ID, args.displayId);
+}
+
+/**
+ * Test touch should not work if outside of surface.
+ */
+TEST_F(MultiTouchInputMapperTest, Viewports_SurfaceRange) {
+ MultiTouchInputMapper* mapper = new MultiTouchInputMapper(mDevice);
+ addConfigurationProperty("touch.deviceType", "touchScreen");
+ prepareDisplay(DISPLAY_ORIENTATION_0);
+ // Let surface be different from physical display.
+ std::optional<DisplayViewport> internalViewport =
+ mFakePolicy->getDisplayViewportByType(ViewportType::VIEWPORT_INTERNAL);
+ internalViewport->logicalLeft = internalViewport->physicalTop + 20;
+ internalViewport->logicalTop = internalViewport->physicalRight + 20;
+ internalViewport->logicalRight = internalViewport->physicalRight - 20;
+ internalViewport->logicalBottom = internalViewport->physicalBottom - 20;
+ mFakePolicy->updateViewport(internalViewport.value());
+
+ prepareAxes(POSITION);
+ addMapperAndConfigure(mapper);
+
+ int32_t rawX = 10;
+ int32_t rawY = 10;
+ processPosition(mapper, rawX, rawY);
+ processSync(mapper);
+ ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasNotCalled());
+}
+
} // namespace android
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 717f317..c7a8f5b 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -134,7 +134,12 @@
mActivationCount.add(list[i].sensorHandle, model);
- checkReturn(mSensors->activate(list[i].sensorHandle, 0 /* enabled */));
+ // Only disable all sensors on HAL 1.0 since HAL 2.0
+ // handles this in its initialize method
+ if (!mSensors->supportsMessageQueues()) {
+ checkReturn(mSensors->activate(list[i].sensorHandle,
+ 0 /* enabled */));
+ }
}
}));
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index cda982a..b404836 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -19,7 +19,7 @@
"-DEGL_EGLEXT_PROTOTYPES",
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.configstore-utils",
"android.hardware.configstore@1.0",
"android.hardware.configstore@1.1",
@@ -56,10 +56,20 @@
"libutils",
"libSurfaceFlingerProp",
],
+ // VrComposer is not used when building surfaceflinger for vendors
+ target: {
+ vendor: {
+ exclude_shared_libs: [
+ "android.frameworks.vr.composer@2.0",
+ ],
+ },
+ },
static_libs: [
"libcompositionengine",
+ "libperfetto_client_experimental",
"librenderengine",
"libserviceutils",
+ "libtimestats",
"libtrace_proto",
"libvr_manager",
"libvrflinger",
@@ -73,6 +83,7 @@
"libcompositionengine",
"librenderengine",
"libserviceutils",
+ "libtimestats",
],
export_shared_lib_headers: [
"android.hardware.graphics.allocator@2.0",
@@ -130,11 +141,11 @@
"DisplayHardware/VirtualDisplaySurface.cpp",
"Effects/Daltonizer.cpp",
"EventLog/EventLog.cpp",
+ "FrameTracer/FrameTracer.cpp",
"FrameTracker.cpp",
"Layer.cpp",
"LayerProtoHelper.cpp",
"LayerRejecter.cpp",
- "LayerStats.cpp",
"LayerVector.cpp",
"MonitoredProducer.cpp",
"NativeWindowSurface.cpp",
@@ -145,7 +156,7 @@
"Scheduler/DispSyncSource.cpp",
"Scheduler/EventControlThread.cpp",
"Scheduler/EventThread.cpp",
- "Scheduler/IdleTimer.cpp",
+ "Scheduler/OneShotTimer.cpp",
"Scheduler/LayerHistory.cpp",
"Scheduler/LayerInfo.cpp",
"Scheduler/MessageQueue.cpp",
@@ -157,7 +168,6 @@
"SurfaceFlinger.cpp",
"SurfaceInterceptor.cpp",
"SurfaceTracing.cpp",
- "TimeStats/TimeStats.cpp",
"TransactionCompletedThread.cpp",
],
}
@@ -174,6 +184,17 @@
// can be easily replaced.
"SurfaceFlingerFactory.cpp",
],
+ cflags: [
+ "-DUSE_VR_COMPOSER=1",
+ ],
+ // VrComposer is not used when building surfaceflinger for vendors
+ target: {
+ vendor: {
+ cflags: [
+ "-DUSE_VR_COMPOSER=0",
+ ],
+ },
+ },
logtags: ["EventLog/EventLogTags.logtags"],
}
@@ -226,7 +247,6 @@
subdirs = [
"layerproto",
- "TimeStats/timestatsproto",
"tests",
]
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index f51fbb4..b500ad3 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -22,17 +22,17 @@
#include "BufferLayer.h"
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <cutils/compiler.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <gui/BufferItem.h>
#include <gui/BufferQueue.h>
+#include <gui/GLConsumer.h>
#include <gui/LayerDebugInfo.h>
#include <gui/Surface.h>
#include <renderengine/RenderEngine.h>
@@ -50,6 +50,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerRejecter.h"
#include "TimeStats/TimeStats.h"
@@ -57,7 +58,7 @@
BufferLayer::BufferLayer(const LayerCreationArgs& args)
: Layer(args),
- mTextureName(args.flinger->getNewTexture()),
+ mTextureName(args.textureName),
mCompositionLayer{mFlinger->getCompositionEngine().createLayer(
compositionengine::LayerCreationArgs{this})} {
ALOGV("Creating Layer %s", args.name.string());
@@ -69,15 +70,23 @@
}
BufferLayer::~BufferLayer() {
- mFlinger->deleteTextureAsync(mTextureName);
- mFlinger->mTimeStats->onDestroy(getSequence());
+ if (!isClone()) {
+ // The original layer and the clone layer share the same texture. Therefore, only one of
+ // the layers, in this case the original layer, needs to handle the deletion. The original
+ // layer and the clone should be removed at the same time so there shouldn't be any issue
+ // with the clone layer trying to use the deleted texture.
+ mFlinger->deleteTextureAsync(mTextureName);
+ }
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void BufferLayer::useSurfaceDamage() {
if (mFlinger->mForceFullDamage) {
surfaceDamageRegion = Region::INVALID_REGION;
} else {
- surfaceDamageRegion = getDrawingSurfaceDamage();
+ surfaceDamageRegion = mBufferInfo.mSurfaceDamage;
}
}
@@ -88,7 +97,7 @@
bool BufferLayer::isOpaque(const Layer::State& s) const {
// if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
// layer's opaque flag.
- if ((mSidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
+ if ((mSidebandStream == nullptr) && (mBufferInfo.mBuffer == nullptr)) {
return false;
}
@@ -99,7 +108,7 @@
bool BufferLayer::isVisible() const {
bool visible = !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
- (mActiveBuffer != nullptr || mSidebandStream != nullptr);
+ (mBufferInfo.mBuffer != nullptr || mSidebandStream != nullptr);
mFlinger->mScheduler->setLayerVisibility(mSchedulerLayerHandle, visible);
return visible;
@@ -131,14 +140,16 @@
return inverse(tr);
}
-bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
+std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
- if (CC_UNLIKELY(mActiveBuffer == 0)) {
+
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+
+ if (CC_UNLIKELY(mBufferInfo.mBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
// SurfaceView because the WindowManager can't know when the client
@@ -155,33 +166,33 @@
finished = true;
return;
}
- under.orSelf(layer->visibleRegion);
+
+ under.orSelf(layer->getScreenBounds());
});
// if not everything below us is covered, we plug the holes!
- Region holes(clip.subtract(under));
+ Region holes(targetSettings.clip.subtract(under));
if (!holes.isEmpty()) {
- clearRegion.orSelf(holes);
+ targetSettings.clearRegion.orSelf(holes);
}
- return false;
+ return std::nullopt;
}
- bool blackOutLayer =
- (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
+ bool blackOutLayer = (isProtected() && !targetSettings.supportsProtectedContent) ||
+ (isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
+ auto& layer = *result;
if (!blackOutLayer) {
- layer.source.buffer.buffer = mActiveBuffer;
+ layer.source.buffer.buffer = mBufferInfo.mBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
- layer.source.buffer.fence = mActiveBufferFence;
+ layer.source.buffer.fence = mBufferInfo.mFence;
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.getDisplayDevice()) ||
- renderArea.needsFiltering() || isFixedSize();
+ const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
- setFilteringEnabled(useFiltering);
- getDrawingTransformMatrix(textureMatrix);
+ getDrawingTransformMatrix(useFiltering, textureMatrix);
if (getTransformToDisplayInverse()) {
/*
@@ -243,104 +254,34 @@
layer.alpha = 1.0;
}
- return true;
+ return result;
}
bool BufferLayer::isHdrY410() const {
// pixel format is HDR Y410 masquerading as RGBA_1010102
- return (mCurrentDataSpace == ui::Dataspace::BT2020_ITU_PQ &&
- getDrawingApi() == NATIVE_WINDOW_API_MEDIA &&
- mActiveBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
+ return (mBufferInfo.mDataspace == ui::Dataspace::BT2020_ITU_PQ &&
+ mBufferInfo.mApi == NATIVE_WINDOW_API_MEDIA &&
+ mBufferInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102);
}
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(displayDevice);
-
- // Apply this display's projection's viewport to the visible region
- // before giving it to the HWC HAL.
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
+void BufferLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
// Sideband layers
- if (layerCompositionState.sidebandStream.get()) {
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::SIDEBAND);
- ALOGV("[%s] Requesting Sideband composition", mName.string());
- error = hwcLayer->setSidebandStream(layerCompositionState.sidebandStream->handle());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
- layerCompositionState.sidebandStream->handle(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
- return;
- }
-
- // Device or Cursor layers
- if (mPotentialCursor) {
- ALOGV("[%s] Requesting Cursor composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CURSOR);
+ if (compositionState.sidebandStream.get()) {
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
} else {
- ALOGV("[%s] Requesting Device composition", mName.string());
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
+ // Normal buffer layers
+ compositionState.hdrMetadata = mBufferInfo.mHdrMetadata;
+ compositionState.compositionType = mPotentialCursor
+ ? Hwc2::IComposerClient::Composition::CURSOR
+ : Hwc2::IComposerClient::Composition::DEVICE;
}
-
- ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN
- ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- const HdrMetadata& metadata = getDrawingHdrMetadata();
- error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata, metadata);
- if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
- ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error == HWC2::Error::Unsupported) {
- // If per layer color transform is not supported, we use GPU composition.
- setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::CLIENT);
- } else if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.dataspace = mCurrentDataSpace;
- layerCompositionState.colorTransform = getColorTransform();
- layerCompositionState.hdrMetadata = metadata;
-
- setHwcLayerBuffer(displayDevice);
}
bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
- if (mBufferLatched) {
+ if (mBufferInfo.mBuffer != nullptr) {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
}
@@ -354,7 +295,7 @@
const CompositorTiming& compositorTiming) {
// mFrameLatencyNeeded is true when a new frame was latched for the
// composition.
- if (!mFrameLatencyNeeded) return false;
+ if (!mBufferInfo.mFrameLatencyNeeded) return false;
// Update mFrameEventHistory.
{
@@ -364,13 +305,13 @@
}
// Update mFrameTracker.
- nsecs_t desiredPresentTime = getDesiredPresentTime();
+ nsecs_t desiredPresentTime = mBufferInfo.mDesiredPresentTime;
mFrameTracker.setDesiredPresentTime(desiredPresentTime);
const int32_t layerID = getSequence();
mFlinger->mTimeStats->setDesiredTime(layerID, mCurrentFrameNumber, desiredPresentTime);
- std::shared_ptr<FenceTime> frameReadyFence = getCurrentFenceTime();
+ std::shared_ptr<FenceTime> frameReadyFence = mBufferInfo.mFenceTime;
if (frameReadyFence->isValid()) {
mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
} else {
@@ -381,21 +322,27 @@
if (presentFence->isValid()) {
mFlinger->mTimeStats->setPresentFence(layerID, mCurrentFrameNumber, presentFence);
+ mFlinger->mFrameTracer->traceFence(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
} else if (displayId && mFlinger->getHwComposer().isConnected(*displayId)) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
const nsecs_t actualPresentTime = mFlinger->getHwComposer().getRefreshTimestamp(*displayId);
mFlinger->mTimeStats->setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, getCurrentBufferId(), mCurrentFrameNumber,
+ actualPresentTime,
+ FrameTracer::FrameEvent::PRESENT_FENCE);
mFrameTracker.setActualPresentTime(actualPresentTime);
}
mFrameTracker.advanceFrame();
- mFrameLatencyNeeded = false;
+ mBufferInfo.mFrameLatencyNeeded = false;
return true;
}
-bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+bool BufferLayer::latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) {
ATRACE_CALL();
bool refreshRequired = latchSidebandStream(recomputeVisibleRegions);
@@ -428,14 +375,15 @@
// Capture the old state of the layer for comparisons later
const State& s(getDrawingState());
const bool oldOpacity = isOpaque(s);
- sp<GraphicBuffer> oldBuffer = mActiveBuffer;
- if (!allTransactionsSignaled()) {
+ BufferInfo oldBufferInfo = mBufferInfo;
+
+ if (!allTransactionsSignaled(expectedPresentTime)) {
mFlinger->setTransactionFlags(eTraversalNeeded);
return false;
}
- status_t err = updateTexImage(recomputeVisibleRegions, latchTime);
+ status_t err = updateTexImage(recomputeVisibleRegions, latchTime, expectedPresentTime);
if (err != NO_ERROR) {
return false;
}
@@ -445,65 +393,33 @@
return false;
}
- mBufferLatched = true;
-
err = updateFrameNumber(latchTime);
if (err != NO_ERROR) {
return false;
}
+ gatherBufferInfo();
+
mRefreshPending = true;
- mFrameLatencyNeeded = true;
- if (oldBuffer == nullptr) {
+ mBufferInfo.mFrameLatencyNeeded = true;
+ if (oldBufferInfo.mBuffer == nullptr) {
// the first time we receive a buffer, we need to trigger a
// geometry invalidation.
recomputeVisibleRegions = true;
}
- ui::Dataspace dataSpace = getDrawingDataSpace();
- // translate legacy dataspaces to modern dataspaces
- switch (dataSpace) {
- case ui::Dataspace::SRGB:
- dataSpace = ui::Dataspace::V0_SRGB;
- break;
- case ui::Dataspace::SRGB_LINEAR:
- dataSpace = ui::Dataspace::V0_SRGB_LINEAR;
- break;
- case ui::Dataspace::JFIF:
- dataSpace = ui::Dataspace::V0_JFIF;
- break;
- case ui::Dataspace::BT601_625:
- dataSpace = ui::Dataspace::V0_BT601_625;
- break;
- case ui::Dataspace::BT601_525:
- dataSpace = ui::Dataspace::V0_BT601_525;
- break;
- case ui::Dataspace::BT709:
- dataSpace = ui::Dataspace::V0_BT709;
- break;
- default:
- break;
- }
- mCurrentDataSpace = dataSpace;
-
- Rect crop(getDrawingCrop());
- const uint32_t transform(getDrawingTransform());
- const uint32_t scalingMode(getDrawingScalingMode());
- const bool transformToDisplayInverse(getTransformToDisplayInverse());
- if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
- (scalingMode != mCurrentScalingMode) ||
- (transformToDisplayInverse != mTransformToDisplayInverse)) {
- mCurrentCrop = crop;
- mCurrentTransform = transform;
- mCurrentScalingMode = scalingMode;
- mTransformToDisplayInverse = transformToDisplayInverse;
+ if ((mBufferInfo.mCrop != oldBufferInfo.mCrop) ||
+ (mBufferInfo.mTransform != oldBufferInfo.mTransform) ||
+ (mBufferInfo.mScaleMode != oldBufferInfo.mScaleMode) ||
+ (mBufferInfo.mTransformToDisplayInverse != oldBufferInfo.mTransformToDisplayInverse)) {
recomputeVisibleRegions = true;
}
- if (oldBuffer != nullptr) {
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
- if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
+ if (oldBufferInfo.mBuffer != nullptr) {
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
+ if (bufWidth != uint32_t(oldBufferInfo.mBuffer->width) ||
+ bufHeight != uint32_t(oldBufferInfo.mBuffer->height)) {
recomputeVisibleRegions = true;
}
}
@@ -540,10 +456,10 @@
}
// transaction
-void BufferLayer::notifyAvailableFrames() {
- const auto headFrameNumber = getHeadFrameNumber();
+void BufferLayer::notifyAvailableFrames(nsecs_t expectedPresentTime) {
+ const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
const bool headFenceSignaled = fenceHasSignaled();
- const bool presentTimeIsCurrent = framePresentTimeIsCurrent();
+ const bool presentTimeIsCurrent = framePresentTimeIsCurrent(expectedPresentTime);
Mutex::Autolock lock(mLocalSyncPointMutex);
for (auto& point : mLocalSyncPoints) {
if (headFrameNumber >= point->getFrameNumber() && headFenceSignaled &&
@@ -568,11 +484,11 @@
return mOverrideScalingMode;
}
- return mCurrentScalingMode;
+ return mBufferInfo.mScaleMode;
}
bool BufferLayer::isProtected() const {
- const sp<GraphicBuffer>& buffer(mActiveBuffer);
+ const sp<GraphicBuffer>& buffer(mBufferInfo.mBuffer);
return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
}
@@ -591,8 +507,8 @@
}
// h/w composer set-up
-bool BufferLayer::allTransactionsSignaled() {
- auto headFrameNumber = getHeadFrameNumber();
+bool BufferLayer::allTransactionsSignaled(nsecs_t expectedPresentTime) {
+ const auto headFrameNumber = getHeadFrameNumber(expectedPresentTime);
bool matchingFramesFound = false;
bool allTransactionsApplied = true;
Mutex::Autolock lock(mLocalSyncPointMutex);
@@ -640,27 +556,29 @@
}
bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
- // If we are not capturing based on the state of a known display device, we
- // only return mNeedsFiltering
+ // If we are not capturing based on the state of a known display device,
+ // just return false.
if (displayDevice == nullptr) {
- return mNeedsFiltering;
+ return false;
}
const auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (outputLayer == nullptr) {
- return mNeedsFiltering;
+ return false;
}
+ // We need filtering if the sourceCrop rectangle size does not match the
+ // displayframe rectangle size (not a 1:1 render)
const auto& compositionState = outputLayer->getState();
const auto displayFrame = compositionState.displayFrame;
const auto sourceCrop = compositionState.sourceCrop;
- return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
sourceCrop.getWidth() != displayFrame.getWidth();
}
-uint64_t BufferLayer::getHeadFrameNumber() const {
+uint64_t BufferLayer::getHeadFrameNumber(nsecs_t expectedPresentTime) const {
if (hasFrameUpdate()) {
- return getFrameNumber();
+ return getFrameNumber(expectedPresentTime);
} else {
return mCurrentFrameNumber;
}
@@ -674,15 +592,15 @@
return Rect(getActiveWidth(s), getActiveHeight(s));
}
- if (mActiveBuffer == nullptr) {
+ if (mBufferInfo.mBuffer == nullptr) {
return Rect::INVALID_RECT;
}
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
// Undo any transformations on the buffer and return the result.
- if (mCurrentTransform & ui::Transform::ROT_90) {
+ if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
@@ -710,15 +628,15 @@
return FloatRect(0, 0, getActiveWidth(s), getActiveHeight(s));
}
- if (mActiveBuffer == nullptr) {
+ if (mBufferInfo.mBuffer == nullptr) {
return parentBounds;
}
- uint32_t bufWidth = mActiveBuffer->getWidth();
- uint32_t bufHeight = mActiveBuffer->getHeight();
+ uint32_t bufWidth = mBufferInfo.mBuffer->getWidth();
+ uint32_t bufHeight = mBufferInfo.mBuffer->getHeight();
// Undo any transformations on the buffer and return the result.
- if (mCurrentTransform & ui::Transform::ROT_90) {
+ if (mBufferInfo.mTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
@@ -732,6 +650,122 @@
return FloatRect(0, 0, bufWidth, bufHeight);
}
+void BufferLayer::latchAndReleaseBuffer() {
+ mRefreshPending = false;
+ if (hasReadyFrame()) {
+ bool ignored = false;
+ latchBuffer(ignored, systemTime(), 0 /* expectedPresentTime */);
+ }
+ releasePendingBuffer(systemTime());
+}
+
+PixelFormat BufferLayer::getPixelFormat() const {
+ return mBufferInfo.mPixelFormat;
+}
+
+bool BufferLayer::getTransformToDisplayInverse() const {
+ return mBufferInfo.mTransformToDisplayInverse;
+}
+
+Rect BufferLayer::getBufferCrop() const {
+ // this is the crop rectangle that applies to the buffer
+ // itself (as opposed to the window)
+ if (!mBufferInfo.mCrop.isEmpty()) {
+ // if the buffer crop is defined, we use that
+ return mBufferInfo.mCrop;
+ } else if (mBufferInfo.mBuffer != nullptr) {
+ // otherwise we use the whole buffer
+ return mBufferInfo.mBuffer->getBounds();
+ } else {
+ // if we don't have a buffer yet, we use an empty/invalid crop
+ return Rect();
+ }
+}
+
+uint32_t BufferLayer::getBufferTransform() const {
+ return mBufferInfo.mTransform;
+}
+
+ui::Dataspace BufferLayer::getDataSpace() const {
+ return mBufferInfo.mDataspace;
+}
+
+ui::Dataspace BufferLayer::translateDataspace(ui::Dataspace dataspace) {
+ ui::Dataspace updatedDataspace = dataspace;
+ // translate legacy dataspaces to modern dataspaces
+ switch (dataspace) {
+ case ui::Dataspace::SRGB:
+ updatedDataspace = ui::Dataspace::V0_SRGB;
+ break;
+ case ui::Dataspace::SRGB_LINEAR:
+ updatedDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+ break;
+ case ui::Dataspace::JFIF:
+ updatedDataspace = ui::Dataspace::V0_JFIF;
+ break;
+ case ui::Dataspace::BT601_625:
+ updatedDataspace = ui::Dataspace::V0_BT601_625;
+ break;
+ case ui::Dataspace::BT601_525:
+ updatedDataspace = ui::Dataspace::V0_BT601_525;
+ break;
+ case ui::Dataspace::BT709:
+ updatedDataspace = ui::Dataspace::V0_BT709;
+ break;
+ default:
+ break;
+ }
+
+ return updatedDataspace;
+}
+
+sp<GraphicBuffer> BufferLayer::getBuffer() const {
+ return mBufferInfo.mBuffer;
+}
+
+void BufferLayer::getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]) {
+ GLConsumer::computeTransformMatrix(outMatrix, mBufferInfo.mBuffer, mBufferInfo.mCrop,
+ mBufferInfo.mTransform, filteringEnabled);
+}
+
+void BufferLayer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
+ Layer::setInitialValuesForClone(clonedFrom);
+
+ sp<BufferLayer> bufferClonedFrom = static_cast<BufferLayer*>(clonedFrom.get());
+ mPremultipliedAlpha = bufferClonedFrom->mPremultipliedAlpha;
+ mPotentialCursor = bufferClonedFrom->mPotentialCursor;
+ mProtectedByApp = bufferClonedFrom->mProtectedByApp;
+
+ updateCloneBufferInfo();
+}
+
+void BufferLayer::updateCloneBufferInfo() {
+ if (!isClone() || !isClonedFromAlive()) {
+ return;
+ }
+
+ sp<BufferLayer> clonedFrom = static_cast<BufferLayer*>(getClonedFrom().get());
+ mBufferInfo = clonedFrom->mBufferInfo;
+ mSidebandStream = clonedFrom->mSidebandStream;
+ surfaceDamageRegion = clonedFrom->surfaceDamageRegion;
+ mCurrentFrameNumber = clonedFrom->mCurrentFrameNumber.load();
+ mPreviousFrameNumber = clonedFrom->mPreviousFrameNumber;
+
+ // After buffer info is updated, the drawingState from the real layer needs to be copied into
+ // the cloned. This is because some properties of drawingState can change when latchBuffer is
+ // called. However, copying the drawingState would also overwrite the cloned layer's relatives.
+ // Therefore, temporarily store the relatives so they can be set in the cloned drawingState
+ // again.
+ wp<Layer> tmpZOrderRelativeOf = mDrawingState.zOrderRelativeOf;
+ SortedVector<wp<Layer>> tmpZOrderRelatives = mDrawingState.zOrderRelatives;
+ mDrawingState = clonedFrom->mDrawingState;
+ // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+ // InputWindows per client token yet.
+ mDrawingState.inputInfo.token = nullptr;
+ mDrawingState.zOrderRelativeOf = tmpZOrderRelativeOf;
+ mDrawingState.zOrderRelatives = tmpZOrderRelatives;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 46a62ed..656ba12 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -62,10 +62,6 @@
void useSurfaceDamage() override;
void useEmptyDamage() override;
- // getTypeId - Provide unique string for each class type in the Layer
- // hierarchy
- const char* getTypeId() const override { return "BufferLayer"; }
-
bool isOpaque(const Layer::State& s) const override;
// isVisible - true if this layer is visible, false otherwise
@@ -82,11 +78,6 @@
bool isHdrY410() const override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
-
- bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -96,17 +87,35 @@
// the visible regions need to be recomputed (this is a fairly heavy
// 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.
- bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ bool latchBuffer(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
bool isBufferLatched() const override { return mRefreshPending; }
- void notifyAvailableFrames() override;
+ void notifyAvailableFrames(nsecs_t expectedPresentTime) override;
bool hasReadyFrame() const override;
// Returns the current scaling mode, unless mOverrideScalingMode
// is set, in which case, it returns mOverrideScalingMode
uint32_t getEffectiveScalingMode() const override;
+
+ // Calls latchBuffer if the buffer has a frame queued and then releases the buffer.
+ // This is used if the buffer is just latched and releases to free up the buffer
+ // and will not be shown on screen.
+ // Should only be called on the main thread.
+ void latchAndReleaseBuffer() override;
+
+ bool getTransformToDisplayInverse() const override;
+
+ Rect getBufferCrop() const override;
+
+ uint32_t getBufferTransform() const override;
+
+ ui::Dataspace getDataSpace() const override;
+
+ sp<GraphicBuffer> getBuffer() const override;
+
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
@@ -114,22 +123,15 @@
// -----------------------------------------------------------------------
private:
virtual bool fenceHasSignaled() const = 0;
- virtual bool framePresentTimeIsCurrent() const = 0;
+ virtual bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const = 0;
- virtual nsecs_t getDesiredPresentTime() = 0;
- virtual std::shared_ptr<FenceTime> getCurrentFenceTime() const = 0;
+ PixelFormat getPixelFormat() const;
- virtual void getDrawingTransformMatrix(float *matrix) = 0;
- virtual uint32_t getDrawingTransform() const = 0;
- virtual ui::Dataspace getDrawingDataSpace() const = 0;
- virtual Rect getDrawingCrop() const = 0;
- virtual uint32_t getDrawingScalingMode() const = 0;
- virtual Region getDrawingSurfaceDamage() const = 0;
- virtual const HdrMetadata& getDrawingHdrMetadata() const = 0;
- virtual int getDrawingApi() const = 0;
- virtual PixelFormat getPixelFormat() const = 0;
+ // Computes the transform matrix using the setFilteringEnabled to determine whether the
+ // transform matrix should be computed for use with bilinear filtering.
+ void getDrawingTransformMatrix(bool filteringEnabled, float outMatrix[16]);
- virtual uint64_t getFrameNumber() const = 0;
+ virtual uint64_t getFrameNumber(nsecs_t expectedPresentTime) const = 0;
virtual bool getAutoRefresh() const = 0;
virtual bool getSidebandStreamChanged() const = 0;
@@ -139,24 +141,52 @@
virtual bool hasFrameUpdate() const = 0;
- virtual void setFilteringEnabled(bool enabled) = 0;
-
virtual status_t bindTextureImage() = 0;
- virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) = 0;
+ virtual status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) = 0;
virtual status_t updateActiveBuffer() = 0;
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
- virtual void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) = 0;
-
protected:
+ struct BufferInfo {
+ nsecs_t mDesiredPresentTime;
+ std::shared_ptr<FenceTime> mFenceTime;
+ sp<Fence> mFence;
+ uint32_t mTransform{0};
+ ui::Dataspace mDataspace{ui::Dataspace::UNKNOWN};
+ Rect mCrop;
+ uint32_t mScaleMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
+ Region mSurfaceDamage;
+ HdrMetadata mHdrMetadata;
+ int mApi;
+ PixelFormat mPixelFormat;
+ bool mTransformToDisplayInverse{false};
+
+ sp<GraphicBuffer> mBuffer;
+ int mBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
+
+ bool mFrameLatencyNeeded{false};
+ };
+
+ BufferInfo mBufferInfo;
+ virtual void gatherBufferInfo() = 0;
+
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ bool onPreComposition(nsecs_t) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
+
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
// Check all of the local sync points to ensure that all transactions
// which need to have been applied prior to the frame which is about to
// be latched have signaled
- bool allTransactionsSignaled();
+ bool allTransactionsSignaled(nsecs_t expectedPresentTime);
static bool getOpacityForFormat(uint32_t format);
@@ -165,24 +195,16 @@
bool mRefreshPending{false};
- // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
+ ui::Dataspace translateDataspace(ui::Dataspace dataspace);
+ void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+ void updateCloneBufferInfo() override;
+ uint64_t mPreviousFrameNumber = 0;
private:
// Returns true if this layer requires filtering
- bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
+ bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
- uint64_t getHeadFrameNumber() const;
-
- uint32_t mCurrentScalingMode{NATIVE_WINDOW_SCALING_MODE_FREEZE};
-
- bool mTransformToDisplayInverse{false};
-
- // main thread.
- bool mBufferLatched{false}; // TODO: Use mActiveBuffer?
+ uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
// BufferStateLayers can return Rect::INVALID_RECT if the layer does not have a display frame
// and its parent layer is not bounded
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 414814a..ea55795 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -428,30 +428,6 @@
return mCurrentFenceTime;
}
-status_t BufferLayerConsumer::doFenceWaitLocked() const {
- if (mCurrentFence->isValid()) {
- if (mRE.useWaitSync()) {
- base::unique_fd fenceFd(mCurrentFence->dup());
- if (fenceFd == -1) {
- BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
- return -errno;
- }
- if (!mRE.waitFence(std::move(fenceFd))) {
- BLC_LOGE("doFenceWait: failed to wait on fence fd");
- return UNKNOWN_ERROR;
- }
- } else {
- status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked");
- if (err != NO_ERROR) {
- BLC_LOGE("doFenceWait: error waiting for fence: %d", err);
- return err;
- }
- }
- }
-
- return NO_ERROR;
-}
-
void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
std::lock_guard<std::mutex> lock(mImagesMutex);
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index 617b1c2..39ed370 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -254,11 +254,6 @@
// mCurrentTextureImage must not be nullptr.
void computeCurrentTransformMatrixLocked();
- // doFenceWaitLocked inserts a wait command into the RenderEngine command
- // stream to ensure that it is safe for future RenderEngine commands to
- // access the current texture buffer.
- status_t doFenceWaitLocked() const;
-
// getCurrentCropLocked returns the cropping rectangle of the current buffer.
Rect getCurrentCropLocked() const;
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index cbb9d65..eb13f65 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -17,18 +17,17 @@
#undef LOG_TAG
#define LOG_TAG "BufferQueueLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-#include <compositionengine/Display.h>
+#include "BufferQueueLayer.h"
+
#include <compositionengine/Layer.h>
-#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/LayerCompositionState.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <gui/BufferQueueConsumer.h>
#include <system/window.h>
-#include "BufferQueueLayer.h"
#include "LayerRejecter.h"
#include "SurfaceInterceptor.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -45,6 +44,14 @@
void BufferQueueLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
mConsumer->setReleaseFence(releaseFence);
+
+ // Prevent tracing the same release multiple times.
+ if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
+ mPreviousReleasedFrameNumber = mPreviousFrameNumber;
+ }
}
void BufferQueueLayer::setTransformHint(uint32_t orientation) const {
@@ -61,10 +68,6 @@
return history;
}
-bool BufferQueueLayer::getTransformToDisplayInverse() const {
- return mConsumer->getTransformToDisplayInverse();
-}
-
void BufferQueueLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
if (!mConsumer->releasePendingBuffer()) {
return;
@@ -137,72 +140,20 @@
return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
}
-bool BufferQueueLayer::framePresentTimeIsCurrent() const {
+bool BufferQueueLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
Mutex::Autolock lock(mQueueItemLock);
- return mQueueItems[0].mTimestamp <= mFlinger->getExpectedPresentTime();
+ return mQueueItems[0].mTimestamp <= expectedPresentTime;
}
-nsecs_t BufferQueueLayer::getDesiredPresentTime() {
- return mConsumer->getTimestamp();
-}
-
-std::shared_ptr<FenceTime> BufferQueueLayer::getCurrentFenceTime() const {
- return mConsumer->getCurrentFenceTime();
-}
-
-void BufferQueueLayer::getDrawingTransformMatrix(float *matrix) {
- return mConsumer->getTransformMatrix(matrix);
-}
-
-// NOTE: SurfaceFlinger's definitions of "Current" and "Drawing" do not neatly map to BufferQueue's
-// These functions get the fields for the frame that is currently in SurfaceFlinger's Drawing state
-// so the functions start with "getDrawing". The data is retrieved from the BufferQueueConsumer's
-// current buffer so the consumer functions start with "getCurrent".
-//
-// This results in the rather confusing functions below.
-uint32_t BufferQueueLayer::getDrawingTransform() const {
- return mConsumer->getCurrentTransform();
-}
-
-ui::Dataspace BufferQueueLayer::getDrawingDataSpace() const {
- return mConsumer->getCurrentDataSpace();
-}
-
-Rect BufferQueueLayer::getDrawingCrop() const {
- return mConsumer->getCurrentCrop();
-}
-
-uint32_t BufferQueueLayer::getDrawingScalingMode() const {
- return mConsumer->getCurrentScalingMode();
-}
-
-Region BufferQueueLayer::getDrawingSurfaceDamage() const {
- return mConsumer->getSurfaceDamage();
-}
-
-const HdrMetadata& BufferQueueLayer::getDrawingHdrMetadata() const {
- return mConsumer->getCurrentHdrMetadata();
-}
-
-int BufferQueueLayer::getDrawingApi() const {
- return mConsumer->getCurrentApi();
-}
-
-PixelFormat BufferQueueLayer::getPixelFormat() const {
- return mFormat;
-}
-
-uint64_t BufferQueueLayer::getFrameNumber() const {
+uint64_t BufferQueueLayer::getFrameNumber(nsecs_t expectedPresentTime) const {
Mutex::Autolock lock(mQueueItemLock);
uint64_t frameNumber = mQueueItems[0].mFrameNumber;
// The head of the queue will be dropped if there are signaled and timely frames behind it
- nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
-
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
}
@@ -244,7 +195,7 @@
if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
// mSidebandStreamChanged was changed to false
mSidebandStream = mConsumer->getSidebandStream();
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
+ auto& layerCompositionState = getCompositionLayer()->editFEState();
layerCompositionState.sidebandStream = mSidebandStream;
if (layerCompositionState.sidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
@@ -261,15 +212,12 @@
return mQueuedFrames > 0;
}
-void BufferQueueLayer::setFilteringEnabled(bool enabled) {
- return mConsumer->setFilteringEnabled(enabled);
-}
-
status_t BufferQueueLayer::bindTextureImage() {
return mConsumer->bindTextureImage();
}
-status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) {
+status_t BufferQueueLayer::updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) {
// This boolean is used to make sure that SurfaceFlinger's shadow copy
// of the buffer queue isn't modified when the buffer queue is returning
// BufferItem's that weren't actually queued. This can happen in shared
@@ -278,9 +226,7 @@
const int32_t layerID = getSequence();
LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
- getTransformToDisplayInverse(), mFreezeGeometryUpdates);
-
- nsecs_t expectedPresentTime = mFlinger->getExpectedPresentTime();
+ getTransformToDisplayInverse());
if (isRemovedFromCurrentState()) {
expectedPresentTime = 0;
@@ -333,6 +279,7 @@
mQueueItems.clear();
mQueuedFrames = 0;
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
// Once we have hit this state, the shadow queue may no longer
@@ -359,9 +306,15 @@
mQueuedFrames--;
}
+ uint64_t bufferID = mQueueItems[0].mGraphicBuffer->getId();
mFlinger->mTimeStats->setAcquireFence(layerID, currentFrameNumber,
mQueueItems[0].mFenceTime);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, currentFrameNumber,
+ mQueueItems[0].mFenceTime,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
mFlinger->mTimeStats->setLatchTime(layerID, currentFrameNumber, latchTime);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, currentFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mQueueItems.removeAt(0);
}
@@ -377,12 +330,13 @@
status_t BufferQueueLayer::updateActiveBuffer() {
// update the active buffer
- mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot, &mActiveBufferFence);
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
+ mPreviousBufferId = getCurrentBufferId();
+ mBufferInfo.mBuffer =
+ mConsumer->getCurrentBuffer(&mBufferInfo.mBufferSlot, &mBufferInfo.mFence);
+ auto& layerCompositionState = getCompositionLayer()->editFEState();
+ layerCompositionState.buffer = mBufferInfo.mBuffer;
- if (mActiveBuffer == nullptr) {
+ if (mBufferInfo.mBuffer == nullptr) {
// this can only happen if the very first buffer was rejected.
return BAD_VALUE;
}
@@ -400,47 +354,30 @@
return NO_ERROR;
}
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState.hwc);
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- uint32_t hwcSlot = 0;
- sp<GraphicBuffer> hwcBuffer;
-
- // INVALID_BUFFER_SLOT is used to identify BufferStateLayers. Default to 0
- // for BufferQueueLayers
- int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
- (*outputLayer->editState().hwc)
- .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
-
- auto acquireFence = mConsumer->getCurrentFence();
- auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(), mActiveBuffer->handle,
- to_string(error).c_str(), static_cast<int32_t>(error));
+void BufferQueueLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
}
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.bufferSlot = mActiveBufferSlot;
- layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.acquireFence = acquireFence;
+ compositionState.buffer = mBufferInfo.mBuffer;
+ compositionState.bufferSlot = (mBufferInfo.mBufferSlot == BufferQueue::INVALID_BUFFER_SLOT)
+ ? 0
+ : mBufferInfo.mBufferSlot;
+ compositionState.acquireFence = mBufferInfo.mFence;
}
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
-void BufferQueueLayer::fakeVsync() {
- mRefreshPending = false;
- bool ignored = false;
- latchBuffer(ignored, systemTime());
- usleep(16000);
- releasePendingBuffer(systemTime());
-}
-
void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
+ const int32_t layerID = getSequence();
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, item.mGraphicBuffer->getId(), item.mFrameNumber,
+ systemTime(), FrameTracer::FrameEvent::POST);
+
ATRACE_CALL();
// Add this buffer from our internal queue tracker
{ // Autolock scope
@@ -476,13 +413,7 @@
mFlinger->mInterceptor->saveBufferUpdate(this, item.mGraphicBuffer->getWidth(),
item.mGraphicBuffer->getHeight(), item.mFrameNumber);
- // If this layer is orphaned, then we run a fake vsync pulse so that
- // dequeueBuffer doesn't block indefinitely.
- if (isRemovedFromCurrentState()) {
- fakeVsync();
- } else {
- mFlinger->signalLayerUpdate();
- }
+ mFlinger->signalLayerUpdate();
mConsumer->onBufferAvailable(item);
}
@@ -530,12 +461,7 @@
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer, true);
mProducer = new MonitoredProducer(producer, mFlinger, this);
- {
- // Grab the SF state lock during this since it's the only safe way to access RenderEngine
- Mutex::Autolock lock(mFlinger->mStateLock);
- mConsumer =
- new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
- }
+ mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
mConsumer->setContentsChangedListener(this);
mConsumer->setName(mName);
@@ -545,7 +471,7 @@
mProducer->setMaxDequeuedBufferCount(2);
}
- if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+ if (const auto display = mFlinger->getDefaultDisplayDeviceLocked()) {
updateTransformHint(display);
}
}
@@ -585,4 +511,30 @@
return static_cast<uint32_t>(producerStickyTransform);
}
+void BufferQueueLayer::gatherBufferInfo() {
+ mBufferInfo.mDesiredPresentTime = mConsumer->getTimestamp();
+ mBufferInfo.mFenceTime = mConsumer->getCurrentFenceTime();
+ mBufferInfo.mFence = mConsumer->getCurrentFence();
+ mBufferInfo.mTransform = mConsumer->getCurrentTransform();
+ mBufferInfo.mDataspace = translateDataspace(mConsumer->getCurrentDataSpace());
+ mBufferInfo.mCrop = mConsumer->getCurrentCrop();
+ mBufferInfo.mScaleMode = mConsumer->getCurrentScalingMode();
+ mBufferInfo.mSurfaceDamage = mConsumer->getSurfaceDamage();
+ mBufferInfo.mHdrMetadata = mConsumer->getCurrentHdrMetadata();
+ mBufferInfo.mApi = mConsumer->getCurrentApi();
+ mBufferInfo.mPixelFormat = mFormat;
+ mBufferInfo.mTransformToDisplayInverse = mConsumer->getTransformToDisplayInverse();
+}
+
+sp<Layer> BufferQueueLayer::createClone() {
+ const String8 name = mName + " (Mirror)";
+ LayerCreationArgs args =
+ LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
+ args.textureName = mTextureName;
+ sp<BufferQueueLayer> layer = new BufferQueueLayer(args);
+ layer->setInitialValuesForClone(this);
+
+ return layer;
+}
+
} // namespace android
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index 7def33a..f3e8a19 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -31,6 +31,7 @@
*/
class BufferQueueLayer : public BufferLayer, public BufferLayerConsumer::ContentsChangedListener {
public:
+ // Only call while mStateLock is held
explicit BufferQueueLayer(const LayerCreationArgs&);
~BufferQueueLayer() override;
@@ -38,14 +39,14 @@
// Interface implementation for Layer
// -----------------------------------------------------------------------
public:
+ const char* getType() const override { return "BufferQueueLayer"; }
+
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
void setTransformHint(uint32_t orientation) const override;
std::vector<OccupancyTracker::Segment> getOccupancyHistory(bool forceFlush) override;
- bool getTransformToDisplayInverse() const override;
-
// If a buffer was replaced this frame, release the former buffer
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
@@ -61,23 +62,10 @@
// -----------------------------------------------------------------------
public:
bool fenceHasSignaled() const override;
- bool framePresentTimeIsCurrent() const override;
+ bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
private:
- nsecs_t getDesiredPresentTime() override;
- std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
-
- void getDrawingTransformMatrix(float *matrix) override;
- uint32_t getDrawingTransform() const override;
- ui::Dataspace getDrawingDataSpace() const override;
- Rect getDrawingCrop() const override;
- uint32_t getDrawingScalingMode() const override;
- Region getDrawingSurfaceDamage() const override;
- const HdrMetadata& getDrawingHdrMetadata() const override;
- int getDrawingApi() const override;
- PixelFormat getPixelFormat() const override;
-
- uint64_t getFrameNumber() const override;
+ uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
@@ -86,20 +74,22 @@
bool hasFrameUpdate() const override;
- void setFilteringEnabled(bool enabled) override;
-
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& displayDevice) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ sp<Layer> createClone() override;
// -----------------------------------------------------------------------
// Interface implementation for BufferLayerConsumer::ContentsChangedListener
// -----------------------------------------------------------------------
protected:
+ void gatherBufferInfo() override;
+
void onFrameAvailable(const BufferItem& item) override;
void onFrameReplaced(const BufferItem& item) override;
void onSidebandStreamChanged() override;
@@ -121,10 +111,11 @@
PixelFormat mFormat{PIXEL_FORMAT_NONE};
- // Only accessed on the main thread.
- uint64_t mPreviousFrameNumber{0};
bool mUpdateTexImageFailed{false};
+ uint64_t mPreviousBufferId = 0;
+ uint64_t mPreviousReleasedFrameNumber = 0;
+
// Local copy of the queued contents of the incoming BufferQueue
mutable Mutex mQueueItemLock;
Condition mQueueItemCondition;
@@ -132,13 +123,10 @@
std::atomic<uint64_t> mLastFrameNumberReceived{0};
bool mAutoRefresh{false};
- int mActiveBufferSlot{BufferQueue::INVALID_BUFFER_SLOT};
// thread-safe
std::atomic<int32_t> mQueuedFrames{0};
std::atomic<bool> mSidebandStreamChanged{false};
-
- void fakeVsync();
};
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 63a07c3..fa4539a 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -19,19 +19,18 @@
#define LOG_TAG "BufferStateLayer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "BufferStateLayer.h"
+
#include <limits>
-#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
-#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/LayerCompositionState.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <gui/BufferQueue.h>
#include <private/gui/SyncFeatures.h>
#include <renderengine/Image.h>
-#include "BufferStateLayer.h"
#include "ColorLayer.h"
+#include "FrameTracer/FrameTracer.h"
#include "TimeStats/TimeStats.h"
namespace android {
@@ -49,15 +48,22 @@
: BufferLayer(args), mHwcSlotGenerator(new HwcSlotGenerator()) {
mOverrideScalingMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
mCurrentState.dataspace = ui::Dataspace::V0_SRGB;
+ if (const auto display = args.displayDevice) {
+ updateTransformHint(display);
+ }
}
BufferStateLayer::~BufferStateLayer() {
- if (mActiveBuffer != nullptr) {
- // Ensure that mActiveBuffer is uncached from RenderEngine here, as
+ // The original layer and the clone layer share the same texture and buffer. Therefore, only
+ // one of the layers, in this case the original layer, needs to handle the deletion. The
+ // original layer and the clone should be removed at the same time so there shouldn't be any
+ // issue with the clone layer trying to use the texture.
+ if (mBufferInfo.mBuffer != nullptr && !isClone()) {
+ // Ensure that mBuffer is uncached from RenderEngine here, as
// RenderEngine may have been using the buffer as an external texture
// after the client uncached the buffer.
auto& engine(mFlinger->getRenderEngine());
- engine.unbindExternalTextureBuffer(mActiveBuffer->getId());
+ engine.unbindExternalTextureBuffer(mBufferInfo.mBuffer->getId());
}
}
@@ -87,6 +93,14 @@
break;
}
}
+
+ // Prevent tracing the same release multiple times.
+ if (mPreviousFrameNumber != mPreviousReleasedFrameNumber) {
+ mFlinger->mFrameTracer->traceFence(getSequence(), mPreviousBufferId, mPreviousFrameNumber,
+ std::make_shared<FenceTime>(releaseFence),
+ FrameTracer::FrameEvent::RELEASE_FENCE);
+ mPreviousReleasedFrameNumber = mPreviousFrameNumber;
+ }
}
void BufferStateLayer::setTransformHint(uint32_t /*orientation*/) const {
@@ -95,7 +109,7 @@
}
void BufferStateLayer::releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) {
- mFlinger->getTransactionCompletedThread().addPresentedCallbackHandles(
+ mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
mDrawingState.callbackHandles);
mDrawingState.callbackHandles = {};
@@ -111,13 +125,10 @@
bool BufferStateLayer::willPresentCurrentTransaction() const {
// Returns true if the most recent Transaction applied to CurrentState will be presented.
- return getSidebandStreamChanged() || getAutoRefresh() ||
+ return (getSidebandStreamChanged() || getAutoRefresh() ||
(mCurrentState.modified &&
- (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr));
-}
-
-bool BufferStateLayer::getTransformToDisplayInverse() const {
- return mCurrentState.transformToDisplayInverse;
+ (mCurrentState.buffer != nullptr || mCurrentState.bgColorLayer != nullptr))) &&
+ !mLayerDetached;
}
void BufferStateLayer::pushPendingState() {
@@ -226,11 +237,15 @@
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
- mFlinger->mTimeStats->setPostTime(getSequence(), getFrameNumber(), getName().c_str(), postTime);
- mDesiredPresentTime = desiredPresentTime;
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->setPostTime(layerID, mFrameNumber, getName().c_str(), postTime);
+ mFlinger->mFrameTracer->traceNewLayer(layerID, getName().c_str());
+ mFlinger->mFrameTracer->traceTimestamp(layerID, buffer->getId(), mFrameNumber, postTime,
+ FrameTracer::FrameEvent::POST);
+ mCurrentState.desiredPresentTime = desiredPresentTime;
if (mFlinger->mUseSmart90ForVideo) {
- const nsecs_t presentTime = (mDesiredPresentTime == -1) ? 0 : mDesiredPresentTime;
+ const nsecs_t presentTime = (desiredPresentTime == -1) ? 0 : desiredPresentTime;
mFlinger->mScheduler->addLayerPresentTimeAndHDR(mSchedulerLayerHandle, presentTime,
mCurrentState.hdrMetadata.validTypes != 0);
}
@@ -320,7 +335,7 @@
} else { // If this layer will NOT need to be relatched and presented this frame
// Notify the transaction completed thread this handle is done
- mFlinger->getTransactionCompletedThread().addUnpresentedCallbackHandle(handle);
+ mFlinger->getTransactionCompletedThread().registerUnpresentedCallbackHandle(handle);
}
}
@@ -379,84 +394,15 @@
return getDrawingState().acquireFence->getStatus() == Fence::Status::Signaled;
}
-bool BufferStateLayer::framePresentTimeIsCurrent() const {
+bool BufferStateLayer::framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const {
if (!hasFrameUpdate() || isRemovedFromCurrentState()) {
return true;
}
- return mDesiredPresentTime <= mFlinger->getExpectedPresentTime();
+ return mCurrentState.desiredPresentTime <= expectedPresentTime;
}
-nsecs_t BufferStateLayer::getDesiredPresentTime() {
- return mDesiredPresentTime;
-}
-
-std::shared_ptr<FenceTime> BufferStateLayer::getCurrentFenceTime() const {
- return std::make_shared<FenceTime>(getDrawingState().acquireFence);
-}
-
-void BufferStateLayer::getDrawingTransformMatrix(float *matrix) {
- std::copy(std::begin(mTransformMatrix), std::end(mTransformMatrix), matrix);
-}
-
-uint32_t BufferStateLayer::getDrawingTransform() const {
- return getDrawingState().transform;
-}
-
-ui::Dataspace BufferStateLayer::getDrawingDataSpace() const {
- return getDrawingState().dataspace;
-}
-
-// Crop that applies to the buffer
-Rect BufferStateLayer::getDrawingCrop() const {
- const State& s(getDrawingState());
-
- if (s.crop.isEmpty() && s.buffer) {
- return s.buffer->getBounds();
- } else if (s.buffer) {
- Rect crop = s.crop;
- crop.left = std::max(crop.left, 0);
- crop.top = std::max(crop.top, 0);
- uint32_t bufferWidth = s.buffer->getWidth();
- uint32_t bufferHeight = s.buffer->getHeight();
- if (bufferHeight <= std::numeric_limits<int32_t>::max() &&
- bufferWidth <= std::numeric_limits<int32_t>::max()) {
- crop.right = std::min(crop.right, static_cast<int32_t>(bufferWidth));
- crop.bottom = std::min(crop.bottom, static_cast<int32_t>(bufferHeight));
- }
- if (!crop.isValid()) {
- // Crop rect is out of bounds, return whole buffer
- return s.buffer->getBounds();
- }
- return crop;
- }
- return s.crop;
-}
-
-uint32_t BufferStateLayer::getDrawingScalingMode() const {
- return NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
-}
-
-Region BufferStateLayer::getDrawingSurfaceDamage() const {
- return getDrawingState().surfaceDamageRegion;
-}
-
-const HdrMetadata& BufferStateLayer::getDrawingHdrMetadata() const {
- return getDrawingState().hdrMetadata;
-}
-
-int BufferStateLayer::getDrawingApi() const {
- return getDrawingState().api;
-}
-
-PixelFormat BufferStateLayer::getPixelFormat() const {
- if (!mActiveBuffer) {
- return PIXEL_FORMAT_NONE;
- }
- return mActiveBuffer->format;
-}
-
-uint64_t BufferStateLayer::getFrameNumber() const {
+uint64_t BufferStateLayer::getFrameNumber(nsecs_t /*expectedPresentTime*/) const {
return mFrameNumber;
}
@@ -475,7 +421,7 @@
// mSidebandStreamChanged was true
LOG_ALWAYS_FATAL_IF(!getCompositionLayer());
mSidebandStream = s.sidebandStream;
- getCompositionLayer()->editState().frontEnd.sidebandStream = mSidebandStream;
+ getCompositionLayer()->editFEState().sidebandStream = mSidebandStream;
if (mSidebandStream != nullptr) {
setTransactionFlags(eTransactionNeeded);
mFlinger->setTransactionFlags(eTraversalNeeded);
@@ -492,11 +438,6 @@
return mCurrentStateModified && (c.buffer != nullptr || c.bgColorLayer != nullptr);
}
-void BufferStateLayer::setFilteringEnabled(bool enabled) {
- GLConsumer::computeTransformMatrix(mTransformMatrix.data(), mActiveBuffer, mCurrentCrop,
- mCurrentTransform, enabled);
-}
-
status_t BufferStateLayer::bindTextureImage() {
const State& s(getDrawingState());
auto& engine(mFlinger->getRenderEngine());
@@ -504,7 +445,8 @@
return engine.bindExternalTextureBuffer(mTextureName, s.buffer, s.acquireFence);
}
-status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime) {
+status_t BufferStateLayer::updateTexImage(bool& /*recomputeVisibleRegions*/, nsecs_t latchTime,
+ nsecs_t /*expectedPresentTime*/) {
const State& s(getDrawingState());
if (!s.buffer) {
@@ -538,7 +480,7 @@
ALOGE("[%s] rejecting buffer: "
"bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
- mFlinger->mTimeStats->removeTimeRecord(layerID, getFrameNumber());
+ mFlinger->mTimeStats->removeTimeRecord(layerID, mFrameNumber);
return BAD_VALUE;
}
@@ -556,12 +498,18 @@
status_t err = bindTextureImage();
if (err != NO_ERROR) {
mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
return BAD_VALUE;
}
}
- mFlinger->mTimeStats->setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
- mFlinger->mTimeStats->setLatchTime(layerID, getFrameNumber(), latchTime);
+ const uint64_t bufferID = getCurrentBufferId();
+ mFlinger->mTimeStats->setAcquireFence(layerID, mFrameNumber, mBufferInfo.mFenceTime);
+ mFlinger->mFrameTracer->traceFence(layerID, bufferID, mFrameNumber, mBufferInfo.mFenceTime,
+ FrameTracer::FrameEvent::ACQUIRE_FENCE);
+ mFlinger->mTimeStats->setLatchTime(layerID, mFrameNumber, latchTime);
+ mFlinger->mFrameTracer->traceTimestamp(layerID, bufferID, mFrameNumber, latchTime,
+ FrameTracer::FrameEvent::LATCH);
mCurrentStateModified = false;
@@ -575,51 +523,36 @@
return BAD_VALUE;
}
- mActiveBuffer = s.buffer;
- mActiveBufferFence = s.acquireFence;
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.buffer = mActiveBuffer;
- layerCompositionState.bufferSlot = 0;
+ mPreviousBufferId = getCurrentBufferId();
+ mBufferInfo.mBuffer = s.buffer;
+ mBufferInfo.mFence = s.acquireFence;
+ auto& layerCompositionState = getCompositionLayer()->editFEState();
+ layerCompositionState.buffer = mBufferInfo.mBuffer;
return NO_ERROR;
}
status_t BufferStateLayer::updateFrameNumber(nsecs_t /*latchTime*/) {
// TODO(marissaw): support frame history events
+ mPreviousFrameNumber = mCurrentFrameNumber;
mCurrentFrameNumber = mFrameNumber;
return NO_ERROR;
}
-void BufferStateLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
- auto& hwcInfo = *outputLayer->editState().hwc;
- auto& hwcLayer = hwcInfo.hwcLayer;
-
- const State& s(getDrawingState());
-
- uint32_t hwcSlot;
- sp<GraphicBuffer> buffer;
- hwcInfo.hwcBufferCache.getHwcBuffer(mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId),
- s.buffer, &hwcSlot, &buffer);
-
- auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
- s.buffer->handle, to_string(error).c_str(), static_cast<int32_t>(error));
+void BufferStateLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ BufferLayer::latchPerFrameState(compositionState);
+ if (compositionState.compositionType == Hwc2::IComposerClient::Composition::SIDEBAND) {
+ return;
}
+ compositionState.buffer = mBufferInfo.mBuffer;
+ compositionState.bufferSlot = mBufferInfo.mBufferSlot;
+ compositionState.acquireFence = mBufferInfo.mFence;
+
mFrameNumber++;
}
-void BufferStateLayer::onFirstRef() {
- BufferLayer::onFirstRef();
-
- if (const auto display = mFlinger->getDefaultDisplayDevice()) {
- updateTransformHint(display);
- }
-}
-
void BufferStateLayer::HwcSlotGenerator::bufferErased(const client_cache_t& clientCacheId) {
std::lock_guard lock(mMutex);
if (!clientCacheId.isValid()) {
@@ -692,4 +625,57 @@
mFreeHwcCacheSlots.push(hwcCacheSlot);
mCachedBuffers.erase(clientCacheId);
}
+
+void BufferStateLayer::gatherBufferInfo() {
+ const State& s(getDrawingState());
+
+ mBufferInfo.mDesiredPresentTime = s.desiredPresentTime;
+ mBufferInfo.mFenceTime = std::make_shared<FenceTime>(s.acquireFence);
+ mBufferInfo.mFence = s.acquireFence;
+ mBufferInfo.mTransform = s.transform;
+ mBufferInfo.mDataspace = translateDataspace(s.dataspace);
+ mBufferInfo.mCrop = computeCrop(s);
+ mBufferInfo.mScaleMode = NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW;
+ mBufferInfo.mSurfaceDamage = s.surfaceDamageRegion;
+ mBufferInfo.mHdrMetadata = s.hdrMetadata;
+ mBufferInfo.mApi = s.api;
+ mBufferInfo.mPixelFormat =
+ !mBufferInfo.mBuffer ? PIXEL_FORMAT_NONE : mBufferInfo.mBuffer->format;
+ mBufferInfo.mTransformToDisplayInverse = s.transformToDisplayInverse;
+ mBufferInfo.mBufferSlot = mHwcSlotGenerator->getHwcCacheSlot(s.clientCacheId);
+}
+
+Rect BufferStateLayer::computeCrop(const State& s) {
+ if (s.crop.isEmpty() && s.buffer) {
+ return s.buffer->getBounds();
+ } else if (s.buffer) {
+ Rect crop = s.crop;
+ crop.left = std::max(crop.left, 0);
+ crop.top = std::max(crop.top, 0);
+ uint32_t bufferWidth = s.buffer->getWidth();
+ uint32_t bufferHeight = s.buffer->getHeight();
+ if (bufferHeight <= std::numeric_limits<int32_t>::max() &&
+ bufferWidth <= std::numeric_limits<int32_t>::max()) {
+ crop.right = std::min(crop.right, static_cast<int32_t>(bufferWidth));
+ crop.bottom = std::min(crop.bottom, static_cast<int32_t>(bufferHeight));
+ }
+ if (!crop.isValid()) {
+ // Crop rect is out of bounds, return whole buffer
+ return s.buffer->getBounds();
+ }
+ return crop;
+ }
+ return s.crop;
+}
+
+sp<Layer> BufferStateLayer::createClone() {
+ const String8 name = mName + " (Mirror)";
+ LayerCreationArgs args =
+ LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata());
+ args.textureName = mTextureName;
+ sp<BufferStateLayer> layer = new BufferStateLayer(args);
+ layer->mHwcSlotGenerator = mHwcSlotGenerator;
+ layer->setInitialValuesForClone(this);
+ return layer;
+}
} // namespace android
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 97e24cb..3dfe76c 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -19,7 +19,6 @@
#include "BufferLayer.h"
#include "Layer.h"
-#include <gui/GLConsumer.h>
#include <renderengine/Image.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
@@ -40,14 +39,14 @@
// -----------------------------------------------------------------------
// Interface implementation for Layer
// -----------------------------------------------------------------------
+ const char* getType() const override { return "BufferStateLayer"; }
+
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
void setTransformHint(uint32_t orientation) const override;
void releasePendingBuffer(nsecs_t dequeueReadyTime) override;
bool shouldPresentNow(nsecs_t expectedPresentTime) const override;
- bool getTransformToDisplayInverse() const override;
-
uint32_t doTransactionResize(uint32_t flags, Layer::State* /*stateToCommit*/) override {
return flags;
}
@@ -80,13 +79,13 @@
// Override to ignore legacy layer state properties that are not used by BufferStateLayer
bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
- bool setPosition(float /*x*/, float /*y*/, bool /*immediate*/) override { return false; }
+ bool setPosition(float /*x*/, float /*y*/) override { return false; }
bool setTransparentRegionHint(const Region& transparent) override;
bool setMatrix(const layer_state_t::matrix22_t& /*matrix*/,
bool /*allowNonRectPreservingTransforms*/) override {
return false;
}
- bool setCrop_legacy(const Rect& /*crop*/, bool /*immediate*/) override { return false; }
+ bool setCrop_legacy(const Rect& /*crop*/) override { return false; }
bool setOverrideScalingMode(int32_t /*overrideScalingMode*/) override { return false; }
void deferTransactionUntil_legacy(const sp<IBinder>& /*barrierHandle*/,
uint64_t /*frameNumber*/) override {}
@@ -102,23 +101,13 @@
// Interface implementation for BufferLayer
// -----------------------------------------------------------------------
bool fenceHasSignaled() const override;
- bool framePresentTimeIsCurrent() const override;
+ bool framePresentTimeIsCurrent(nsecs_t expectedPresentTime) const override;
+
+protected:
+ void gatherBufferInfo() override;
private:
- nsecs_t getDesiredPresentTime() override;
- std::shared_ptr<FenceTime> getCurrentFenceTime() const override;
-
- void getDrawingTransformMatrix(float *matrix) override;
- uint32_t getDrawingTransform() const override;
- ui::Dataspace getDrawingDataSpace() const override;
- Rect getDrawingCrop() const override;
- uint32_t getDrawingScalingMode() const override;
- Region getDrawingSurfaceDamage() const override;
- const HdrMetadata& getDrawingHdrMetadata() const override;
- int getDrawingApi() const override;
- PixelFormat getPixelFormat() const override;
-
- uint64_t getFrameNumber() const override;
+ uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
bool getAutoRefresh() const override;
bool getSidebandStreamChanged() const override;
@@ -127,39 +116,39 @@
bool hasFrameUpdate() const override;
- void setFilteringEnabled(bool enabled) override;
-
status_t bindTextureImage() override;
- status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime) override;
+ status_t updateTexImage(bool& recomputeVisibleRegions, nsecs_t latchTime,
+ nsecs_t expectedPresentTime) override;
status_t updateActiveBuffer() override;
status_t updateFrameNumber(nsecs_t latchTime) override;
- void setHwcLayerBuffer(const sp<const DisplayDevice>& display) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ sp<Layer> createClone() override;
+
+ // Crop that applies to the buffer
+ Rect computeCrop(const State& s);
private:
friend class SlotGenerationTest;
- void onFirstRef() override;
bool willPresentCurrentTransaction() const;
static const std::array<float, 16> IDENTITY_MATRIX;
std::unique_ptr<renderengine::Image> mTextureImage;
- std::array<float, 16> mTransformMatrix{IDENTITY_MATRIX};
-
std::atomic<bool> mSidebandStreamChanged{false};
- uint32_t mFrameNumber{0};
+ mutable uint32_t mFrameNumber{0};
sp<Fence> mPreviousReleaseFence;
+ uint64_t mPreviousBufferId = 0;
+ uint64_t mPreviousReleasedFrameNumber = 0;
- bool mCurrentStateModified = false;
+ mutable bool mCurrentStateModified = false;
bool mReleasePreviousBuffer = false;
nsecs_t mCallbackHandleAcquireTime = -1;
- nsecs_t mDesiredPresentTime = -1;
-
// TODO(marissaw): support sticky transform for LEGACY camera mode
class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp
index 6bfd302..c7ed9b0 100644
--- a/services/surfaceflinger/Client.cpp
+++ b/services/surfaceflinger/Client.cpp
@@ -106,6 +106,10 @@
nullptr, layer);
}
+status_t Client::mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* outHandle) {
+ return mFlinger->mirrorLayer(this, mirrorFromHandle, outHandle);
+}
+
status_t Client::clearLayerFrameStats(const sp<IBinder>& handle) const {
sp<Layer> layer = getLayerUser(handle);
if (layer == nullptr) {
diff --git a/services/surfaceflinger/Client.h b/services/surfaceflinger/Client.h
index 74e4818..7d7cef8 100644
--- a/services/surfaceflinger/Client.h
+++ b/services/surfaceflinger/Client.h
@@ -62,6 +62,8 @@
LayerMetadata metadata, sp<IBinder>* handle,
sp<IGraphicBufferProducer>* gbp);
+ status_t mirrorSurface(const sp<IBinder>& mirrorFromHandle, sp<IBinder>* handle);
+
virtual status_t clearLayerFrameStats(const sp<IBinder>& handle) const;
virtual status_t getLayerFrameStats(const sp<IBinder>& handle, FrameStats* outStats) const;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index fcc2d97..5b62054 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -18,23 +18,21 @@
#undef LOG_TAG
#define LOG_TAG "ColorLayer"
+#include "ColorLayer.h"
+
#include <stdint.h>
#include <stdlib.h>
#include <sys/types.h>
#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerCreationArgs.h>
-#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/LayerCompositionState.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <renderengine/RenderEngine.h>
#include <ui/GraphicBuffer.h>
#include <utils/Errors.h>
#include <utils/Log.h>
-#include "ColorLayer.h"
#include "DisplayDevice.h"
#include "SurfaceFlinger.h"
@@ -48,16 +46,14 @@
ColorLayer::~ColorLayer() = default;
-bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
- half4 color(getColor());
- half3 solidColor(color.r, color.g, color.b);
- layer.source.solidColor = solidColor;
- return true;
+std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+ result->source.solidColor = getColor().rgb;
+ return result;
}
bool ColorLayer::isVisible() const {
@@ -91,86 +87,34 @@
return true;
}
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t /* supportedPerFrameMetadata */,
- const ui::Dataspace targetDataspace) {
- RETURN_IF_NO_HWC_LAYER(display);
+void ColorLayer::latchPerFrameState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ Layer::latchPerFrameState(compositionState);
- Region visible = transform.transform(visibleRegion.intersect(viewport));
-
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer || !outputLayer->getState().hwc);
-
- auto& hwcLayer = (*outputLayer->getState().hwc).hwcLayer;
-
- auto error = hwcLayer->setVisibleRegion(visible);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- visible.dump(LOG_TAG);
- }
- outputLayer->editState().visibleRegion = visible;
-
- setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
-
- const ui::Dataspace dataspace =
- isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace
- : mCurrentDataSpace;
- error = hwcLayer->setDataspace(dataspace);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- auto& layerCompositionState = getCompositionLayer()->editState().frontEnd;
- layerCompositionState.dataspace = mCurrentDataSpace;
-
- half4 color = getColor();
- error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- layerCompositionState.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
- static_cast<uint8_t>(std::round(255.0f * color.g)),
- static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
-
- // Clear out the transform, because it doesn't make sense absent a source buffer
- error = hwcLayer->setTransform(HWC2::Transform::None);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
- outputLayer->editState().bufferTransform = static_cast<Hwc2::Transform>(0);
-
- error = hwcLayer->setColorTransform(getColorTransform());
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
- layerCompositionState.colorTransform = getColorTransform();
-
- error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
- if (error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- surfaceDamageRegion.dump(LOG_TAG);
- }
- layerCompositionState.surfaceDamage = surfaceDamageRegion;
-}
-
-void ColorLayer::commitTransaction(const State& stateToCommit) {
- Layer::commitTransaction(stateToCommit);
- mCurrentDataSpace = mDrawingState.dataspace;
+ compositionState.color = getColor();
+ compositionState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
}
std::shared_ptr<compositionengine::Layer> ColorLayer::getCompositionLayer() const {
return mCompositionLayer;
}
+bool ColorLayer::isOpaque(const Layer::State& s) const {
+ return (s.flags & layer_state_t::eLayerOpaque) != 0;
+}
+
+ui::Dataspace ColorLayer::getDataSpace() const {
+ return mDrawingState.dataspace;
+}
+
+sp<Layer> ColorLayer::createClone() {
+ String8 name = mName + " (Mirror)";
+ sp<ColorLayer> layer = new ColorLayer(
+ LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+ layer->setInitialValuesForClone(this);
+ return layer;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 53d5b5b..634a800 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -30,29 +30,28 @@
std::shared_ptr<compositionengine::Layer> getCompositionLayer() const override;
- virtual const char* getTypeId() const { return "ColorLayer"; }
+ const char* getType() const override { return "ColorLayer"; }
bool isVisible() const override;
bool setColor(const half3& color) override;
bool setDataspace(ui::Dataspace dataspace) override;
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) override;
+ ui::Dataspace getDataSpace() const override;
- void commitTransaction(const State& stateToCommit) override;
-
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
+ bool isOpaque(const Layer::State& s) const override;
protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
-private:
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
+
+ sp<Layer> createClone() override;
};
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 1c31ab9..1407ef7 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -3,9 +3,10 @@
defaults: ["surfaceflinger_defaults"],
cflags: [
"-DLOG_TAG=\"CompositionEngine\"",
+ "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.composer@2.1",
"android.hardware.graphics.composer@2.2",
@@ -47,7 +48,7 @@
"src/DumpHelpers.cpp",
"src/HwcBufferCache.cpp",
"src/Layer.cpp",
- "src/LayerCompositionState.cpp",
+ "src/LayerFECompositionState.cpp",
"src/Output.cpp",
"src/OutputCompositionState.cpp",
"src/OutputLayer.cpp",
@@ -94,6 +95,7 @@
"tests/LayerTest.cpp",
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
+ "tests/MockPowerAdvisor.cpp",
"tests/OutputTest.cpp",
"tests/OutputLayerTest.cpp",
"tests/RenderSurfaceTest.cpp",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
index 896f8aa..8687d0c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionEngine.h
@@ -18,6 +18,8 @@
#include <memory>
+#include <utils/Timers.h>
+
namespace android {
class HWComposer;
@@ -31,6 +33,7 @@
class Display;
class Layer;
+struct CompositionRefreshArgs;
struct DisplayCreationArgs;
struct LayerCreationArgs;
@@ -43,14 +46,29 @@
virtual ~CompositionEngine();
// Create a composition Display
- virtual std::shared_ptr<Display> createDisplay(DisplayCreationArgs&&) = 0;
- virtual std::shared_ptr<Layer> createLayer(LayerCreationArgs&&) = 0;
+ virtual std::shared_ptr<Display> createDisplay(const DisplayCreationArgs&) = 0;
+ virtual std::shared_ptr<Layer> createLayer(const LayerCreationArgs&) = 0;
virtual HWComposer& getHwComposer() const = 0;
virtual void setHwComposer(std::unique_ptr<HWComposer>) = 0;
virtual renderengine::RenderEngine& getRenderEngine() const = 0;
virtual void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) = 0;
+
+ virtual bool needsAnotherUpdate() const = 0;
+ virtual nsecs_t getLastFrameRefreshTimestamp() const = 0;
+
+ // Presents the indicated outputs
+ virtual void present(CompositionRefreshArgs&) = 0;
+
+ // Updates the cursor position for the indicated outputs.
+ virtual void updateCursorAsync(CompositionRefreshArgs&) = 0;
+
+ // TODO(b/121291683): These will become private/internal
+ virtual void preComposition(CompositionRefreshArgs&) = 0;
+
+ // Debugging
+ virtual void dump(std::string&) const = 0;
};
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
new file mode 100644
index 0000000..90158c7
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <optional>
+#include <vector>
+
+#include <compositionengine/Display.h>
+#include <compositionengine/Layer.h>
+#include <compositionengine/OutputColorSetting.h>
+#include <math/mat4.h>
+
+namespace android::compositionengine {
+
+using Layers = std::vector<std::shared_ptr<compositionengine::Layer>>;
+using Outputs = std::vector<std::shared_ptr<compositionengine::Output>>;
+using RawLayers = std::vector<compositionengine::Layer*>;
+
+/**
+ * A parameter object for refreshing a set of outputs
+ */
+struct CompositionRefreshArgs {
+ // All the outputs being refreshed
+ Outputs outputs;
+
+ // All the layers that are potentially visible in the outputs. The order of
+ // the layers is important, and should be in traversal order from back to
+ // front.
+ Layers layers;
+
+ // All the layers that have queued updates.
+ RawLayers layersWithQueuedFrames;
+
+ // If true, forces the entire display to be considered dirty and repainted
+ bool repaintEverything{false};
+
+ // Controls how the color mode is chosen for an output
+ OutputColorSetting outputColorSetting{OutputColorSetting::kEnhanced};
+
+ // If not Dataspace::UNKNOWN, overrides the dataspace on each output
+ ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN};
+
+ // Forces a color mode on the outputs being refreshed
+ ui::ColorMode forceOutputColorMode{ui::ColorMode::NATIVE};
+
+ // If true, the complete output geometry needs to be recomputed this frame
+ bool updatingOutputGeometryThisFrame{false};
+
+ // If true, there was a geometry update this frame
+ bool updatingGeometryThisFrame{false};
+
+ // The color matrix to use for this
+ // frame. Only set if the color transform is changing this frame.
+ std::optional<mat4> colorTransformMatrix;
+
+ // If true, client composition is always used.
+ bool devOptForceClientComposition{false};
+
+ // If set, causes the dirty regions to flash with the delay
+ std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay;
+};
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
index dbcd3bd..9193dc0 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Display.h
@@ -47,10 +47,10 @@
virtual void disconnect() = 0;
// Creates a render color mode for the display
- virtual void createDisplayColorProfile(DisplayColorProfileCreationArgs&&) = 0;
+ virtual void createDisplayColorProfile(const DisplayColorProfileCreationArgs&) = 0;
// Creates a render surface for the display
- virtual void createRenderSurface(RenderSurfaceCreationArgs&&) = 0;
+ virtual void createRenderSurface(const RenderSurfaceCreationArgs&) = 0;
protected:
~Display() = default;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
index e2a0d42..d93bfa3 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayColorProfile.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <string>
#include <ui/GraphicTypes.h>
@@ -75,6 +76,13 @@
// Gets the supported HDR capabilities for the profile
virtual const HdrCapabilities& getHdrCapabilities() const = 0;
+ // Returns true if HWC for this profile supports the dataspace
+ virtual bool isDataspaceSupported(ui::Dataspace) const = 0;
+
+ // Returns the target dataspace for picked color mode and dataspace
+ virtual ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace,
+ ui::Dataspace colorSpaceAgnosticDataspace) const = 0;
+
// Debugging
virtual void dump(std::string&) const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
index 0b6b4e4..ced4227 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/DisplayCreationArgs.h
@@ -20,6 +20,7 @@
#include <optional>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine {
@@ -29,14 +30,15 @@
* A parameter object for creating Display instances
*/
struct DisplayCreationArgs {
- // True if this display is secure
- bool isSecure = false;
-
// True if this display is a virtual display
bool isVirtual = false;
// Identifies the display to the HWC, if composition is supported by it
std::optional<DisplayId> displayId;
+
+ // Optional pointer to the power advisor interface, if one is needed for
+ // this display.
+ Hwc2::PowerAdvisor* powerAdvisor = nullptr;
};
/**
@@ -49,17 +51,13 @@
*
* Prefer:
*
- * DisplayCreationArgsBuilder().setIsSecure(false).setIsVirtual(false)
+ * DisplayCreationArgsBuilder().setIsVirtual(false)
* .setDisplayId(displayId).build();
*/
class DisplayCreationArgsBuilder {
public:
DisplayCreationArgs build() { return std::move(mArgs); }
- DisplayCreationArgsBuilder& setIsSecure(bool isSecure) {
- mArgs.isSecure = isSecure;
- return *this;
- }
DisplayCreationArgsBuilder& setIsVirtual(bool isVirtual) {
mArgs.isVirtual = isVirtual;
return *this;
@@ -68,6 +66,10 @@
mArgs.displayId = displayId;
return *this;
}
+ DisplayCreationArgsBuilder& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+ mArgs.powerAdvisor = powerAdvisor;
+ return *this;
+ }
private:
DisplayCreationArgs mArgs;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
index 8cb9203..1259c52 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Layer.h
@@ -21,18 +21,12 @@
#include <utils/StrongPointer.h>
-namespace android {
-
-typedef int64_t nsecs_t;
-
-namespace compositionengine {
+namespace android::compositionengine {
class Display;
class LayerFE;
-namespace impl {
-struct LayerCompositionState;
-} // namespace impl
+struct LayerFECompositionState;
/**
* A layer contains the output-independent composition state for a front-end
@@ -46,21 +40,16 @@
// front-end layer no longer exists.
virtual sp<LayerFE> getLayerFE() const = 0;
- using CompositionState = impl::LayerCompositionState;
-
- // Gets the raw composition state data for the layer
+ // Gets the raw front-end composition state data for the layer
// TODO(lpique): Make this protected once it is only internally called.
- virtual const CompositionState& getState() const = 0;
+ virtual const LayerFECompositionState& getFEState() const = 0;
- // Allows mutable access to the raw composition state data for the layer.
- // This is meant to be used by the various functions that are part of the
- // composition process.
+ // Allows mutable access to the raw front-end composition state
// TODO(lpique): Make this protected once it is only internally called.
- virtual CompositionState& editState() = 0;
+ virtual LayerFECompositionState& editFEState() = 0;
// Debugging
virtual void dump(std::string& result) const = 0;
};
-} // namespace compositionengine
-} // namespace android
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 9f635b9..e585769 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,7 +16,12 @@
#pragma once
+#include <optional>
+#include <unordered_set>
+
+#include <renderengine/LayerSettings.h>
#include <utils/RefBase.h>
+#include <utils/Timers.h>
namespace android {
@@ -30,9 +35,63 @@
// of the front-end layer
class LayerFE : public virtual RefBase {
public:
- // Latches the output-independent state. If includeGeometry is false, the
- // geometry state can be skipped.
- virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ // Called before composition starts. Should return true if this layer has
+ // pending updates which would require an extra display refresh cycle to
+ // process.
+ virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
+
+ // Used with latchCompositionState()
+ enum class StateSubset {
+ // Gets the basic geometry (bounds, transparent region, visibility,
+ // transforms, alpha) for the layer, for computing visibility and
+ // coverage.
+ BasicGeometry,
+
+ // Gets the full geometry (crops, buffer transforms, metadata) and
+ // content (buffer or color) state for the layer.
+ GeometryAndContent,
+
+ // Gets the per frame content (buffer or color) state the layer.
+ Content,
+ };
+
+ // Latches the output-independent composition state for the layer. The
+ // StateSubset argument selects what portion of the state is actually needed
+ // by the CompositionEngine code, since computing everything may be
+ // expensive.
+ virtual void latchCompositionState(LayerFECompositionState&, StateSubset) const = 0;
+
+ // Latches the minimal bit of state for the cursor for a fast asynchronous
+ // update.
+ virtual void latchCursorCompositionState(LayerFECompositionState&) const = 0;
+
+ struct ClientCompositionTargetSettings {
+ // The clip region, or visible region that is being rendered to
+ const Region& clip;
+
+ // If true, the layer should use an identity transform for its position
+ // transform. Used only by the captureScreen API call.
+ const bool useIdentityTransform;
+
+ // If set to true, the layer should enable filtering when rendering.
+ const bool needsFiltering;
+
+ // If set to true, the buffer is being sent to a destination that is
+ // expected to treat the buffer contents as secure.
+ const bool isSecure;
+
+ // If set to true, the target buffer has protected content support.
+ const bool supportsProtectedContent;
+
+ // Modified by each call to prepareClientComposition to indicate the
+ // region of the target buffer that should be cleared.
+ Region& clearRegion;
+ };
+
+ // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
+ // nullopt_t if the layer does not render
+ virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+ ClientCompositionTargetSettings&) = 0;
// Called after the layer is displayed to update the presentation fence
virtual void onLayerDisplayed(const sp<Fence>&) = 0;
@@ -41,5 +100,13 @@
virtual const char* getDebugName() const = 0;
};
+// TODO(b/121291683): Specialize std::hash<> for sp<T> so these and others can
+// be removed.
+struct LayerFESpHash {
+ size_t operator()(const sp<LayerFE>& p) const { return std::hash<LayerFE*>()(p.get()); }
+};
+
+using LayerFESet = std::unordered_set<sp<LayerFE>, LayerFESpHash>;
+
} // namespace compositionengine
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
index e6ee078..2ba781d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFECompositionState.h
@@ -36,9 +36,48 @@
* Used by LayerFE::getCompositionState
*/
struct LayerFECompositionState {
- // TODO(lpique): b/121291683 Remove this one we are sure we don't need the
- // value recomputed / set every frame.
- Region geomVisibleRegion;
+ // If set to true, forces client composition on all output layers until
+ // the next geometry change.
+ bool forceClientComposition{false};
+
+ // TODO(b/121291683): Reorganize and rename the contents of this structure
+
+ /*
+ * Visibility state
+ */
+ // the layer stack this layer belongs to
+ std::optional<uint32_t> layerStackId;
+
+ // If true, this layer should be only visible on the internal display
+ bool internalOnly{false};
+
+ // If false, this layer should not be considered visible
+ bool isVisible{true};
+
+ // True if the layer is completely opaque
+ bool isOpaque{true};
+
+ // If true, invalidates the entire visible region
+ bool contentDirty{false};
+
+ // The alpha value for this layer
+ float alpha{1.f};
+
+ // The transform from layer local coordinates to composition coordinates
+ ui::Transform geomLayerTransform;
+
+ // The inverse of the layer transform
+ ui::Transform geomInverseLayerTransform;
+
+ // The hint from the layer producer as to what portion of the layer is
+ // transparent.
+ Region transparentRegionHint;
+
+ // The blend mode for this layer
+ Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID};
+
+ // The bounds of the layer in layer local coordinates
+ FloatRect geomLayerBounds;
/*
* Geometry state
@@ -48,23 +87,9 @@
bool geomUsesSourceCrop{false};
bool geomBufferUsesDisplayInverseTransform{false};
uint32_t geomBufferTransform{0};
- ui::Transform geomLayerTransform;
- ui::Transform geomInverseLayerTransform;
Rect geomBufferSize;
Rect geomContentCrop;
Rect geomCrop;
- Region geomActiveTransparentRegion;
- FloatRect geomLayerBounds;
-
- /*
- * Presentation
- */
-
- // The blend mode for this layer
- Hwc2::IComposerClient::BlendMode blendMode{Hwc2::IComposerClient::BlendMode::INVALID};
-
- // The alpha value for this layer
- float alpha{1.f};
/*
* Extra metadata
@@ -93,12 +118,16 @@
sp<NativeHandle> sidebandStream;
// The color for this layer
- Hwc2::IComposerClient::Color color;
+ half4 color;
/*
* Per-frame presentation state
*/
+ // If true, this layer will use the dataspace chosen for the output and
+ // ignore the dataspace value just below
+ bool isColorspaceAgnostic{false};
+
// The dataspace for this layer
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
@@ -107,6 +136,20 @@
// The color transform
mat4 colorTransform;
+ bool colorTransformIsIdentity{true};
+
+ // True if the layer has protected content
+ bool hasProtectedContent{false};
+
+ /*
+ * Cursor state
+ */
+
+ // The output-independent frame for the cursor
+ Rect cursorFrame;
+
+ // Debugging
+ void dump(std::string& out) const;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 54e6bd6..5f42ea1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -17,10 +17,16 @@
#pragma once
#include <cstdint>
+#include <iterator>
#include <optional>
#include <string>
+#include <type_traits>
+#include <unordered_map>
+#include <utility>
-#include <math/mat4.h>
+#include <compositionengine/LayerFE.h>
+#include <renderengine/LayerSettings.h>
+#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -28,6 +34,10 @@
#include "DisplayHardware/DisplayIdentification.h"
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
namespace android::compositionengine {
class DisplayColorProfile;
@@ -36,6 +46,9 @@
class RenderSurface;
class OutputLayer;
+struct CompositionRefreshArgs;
+struct LayerFECompositionState;
+
namespace impl {
struct OutputCompositionState;
} // namespace impl
@@ -45,7 +58,95 @@
*/
class Output {
public:
- using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
+ using ReleasedLayers = std::vector<wp<LayerFE>>;
+ using UniqueFELayerStateMap = std::unordered_map<LayerFE*, LayerFECompositionState*>;
+
+ // A helper class for enumerating the output layers using a C++11 ranged-based for loop
+ template <typename T>
+ class OutputLayersEnumerator {
+ public:
+ // TODO(lpique): Consider turning this into a C++20 view when possible.
+ template <bool IsConstIter>
+ class IteratorImpl {
+ public:
+ // Required definitions to be considered an iterator
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = decltype(std::declval<T>().getOutputLayerOrderedByZByIndex(0));
+ using difference_type = std::ptrdiff_t;
+ using pointer = std::conditional_t<IsConstIter, const value_type*, value_type*>;
+ using reference = std::conditional_t<IsConstIter, const value_type&, value_type&>;
+
+ IteratorImpl() = default;
+ IteratorImpl(const T* output, size_t index) : mOutput(output), mIndex(index) {}
+
+ value_type operator*() const {
+ return mOutput->getOutputLayerOrderedByZByIndex(mIndex);
+ }
+ value_type operator->() const {
+ return mOutput->getOutputLayerOrderedByZByIndex(mIndex);
+ }
+
+ bool operator==(const IteratorImpl& other) const {
+ return mOutput == other.mOutput && mIndex == other.mIndex;
+ }
+ bool operator!=(const IteratorImpl& other) const { return !operator==(other); }
+
+ IteratorImpl& operator++() {
+ ++mIndex;
+ return *this;
+ }
+ IteratorImpl operator++(int) {
+ auto prev = *this;
+ ++mIndex;
+ return prev;
+ }
+
+ private:
+ const T* mOutput{nullptr};
+ size_t mIndex{0};
+ };
+
+ using iterator = IteratorImpl<false>;
+ using const_iterator = IteratorImpl<true>;
+
+ explicit OutputLayersEnumerator(const T& output) : mOutput(output) {}
+ auto begin() const { return iterator(&mOutput, 0); }
+ auto end() const { return iterator(&mOutput, mOutput.getOutputLayerCount()); }
+ auto cbegin() const { return const_iterator(&mOutput, 0); }
+ auto cend() const { return const_iterator(&mOutput, mOutput.getOutputLayerCount()); }
+
+ private:
+ const T& mOutput;
+ };
+
+ struct FrameFences {
+ sp<Fence> presentFence{Fence::NO_FENCE};
+ sp<Fence> clientTargetAcquireFence{Fence::NO_FENCE};
+ std::unordered_map<HWC2::Layer*, sp<Fence>> layerFences;
+ };
+
+ struct ColorProfile {
+ ui::ColorMode mode{ui::ColorMode::NATIVE};
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
+ ui::Dataspace colorSpaceAgnosticDataspace{ui::Dataspace::UNKNOWN};
+ };
+
+ // Use internally to incrementally compute visibility/coverage
+ struct CoverageState {
+ explicit CoverageState(LayerFESet& latchedLayers) : latchedLayers(latchedLayers) {}
+
+ // The set of layers that had been latched for the coverage calls, to
+ // avoid duplicate requests to obtain the same front-end layer state.
+ LayerFESet& latchedLayers;
+
+ // The region of the output which is covered by layers
+ Region aboveCoveredLayers;
+ // The region of the output which is opaquely covered by layers
+ Region aboveOpaqueLayers;
+ // The region of the output which should be considered dirty
+ Region dirtyRegion;
+ };
virtual ~Output();
@@ -54,6 +155,9 @@
// constructor.
virtual bool isValid() const = 0;
+ // Returns the DisplayId the output represents, if it has one
+ virtual std::optional<DisplayId> getDisplayId() const = 0;
+
// Enables (or disables) composition on this output
virtual void setCompositionEnabled(bool) = 0;
@@ -67,11 +171,8 @@
// belongsInOutput for full details.
virtual void setLayerStackFilter(uint32_t layerStackId, bool isInternal) = 0;
- // Sets the color transform matrix to use
- virtual void setColorTransform(const mat4&) = 0;
-
// Sets the output color mode
- virtual void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) = 0;
+ virtual void setColorProfile(const ColorProfile&) = 0;
// Outputs a string with a state dump
virtual void dump(std::string&) const = 0;
@@ -111,28 +212,71 @@
// A layer belongs to the output if its layerStackId matches. Additionally
// if the layer should only show in the internal (primary) display only and
// this output allows that.
- virtual bool belongsInOutput(uint32_t layerStackId, bool internalOnly) const = 0;
+ virtual bool belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const = 0;
+
+ // Determines if a layer belongs to the output.
+ virtual bool belongsInOutput(const Layer*) const = 0;
// Returns a pointer to the output layer corresponding to the given layer on
// this output, or nullptr if the layer does not have one
virtual OutputLayer* getOutputLayerForLayer(Layer*) const = 0;
- // Gets the OutputLayer corresponding to the input Layer instance from the
- // current ordered set of output layers. If there is no such layer, a new
- // one is created and returned.
- virtual std::unique_ptr<OutputLayer> getOrCreateOutputLayer(std::optional<DisplayId>,
- std::shared_ptr<Layer>,
- sp<LayerFE>) = 0;
+ // Immediately clears all layers from the output.
+ virtual void clearOutputLayers() = 0;
- // Sets the new ordered set of output layers for this output
- virtual void setOutputLayersOrderedByZ(OutputLayers&&) = 0;
+ // For tests use only. Creates and appends an OutputLayer into the output.
+ virtual OutputLayer* injectOutputLayerForTest(const std::shared_ptr<Layer>&,
+ const sp<LayerFE>&) = 0;
- // Gets the ordered set of output layers for this output
- virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
+ // Gets the count of output layers managed by this output
+ virtual size_t getOutputLayerCount() const = 0;
+
+ // Gets an output layer in Z order given its index
+ virtual OutputLayer* getOutputLayerOrderedByZByIndex(size_t) const = 0;
+
+ // A helper function for enumerating all the output layers in Z order using
+ // a C++11 range-based for loop.
+ auto getOutputLayersOrderedByZ() const { return OutputLayersEnumerator(*this); }
+
+ // Sets the new set of layers being released this frame
+ virtual void setReleasedLayers(ReleasedLayers&&) = 0;
+
+ // Prepare the output, updating the OutputLayers used in the output
+ virtual void prepare(const CompositionRefreshArgs&, LayerFESet&) = 0;
+
+ // Presents the output, finalizing all composition details
+ virtual void present(const CompositionRefreshArgs&) = 0;
+
+ // Latches the front-end layer state for each output layer
+ virtual void updateLayerStateFromFE(const CompositionRefreshArgs&) const = 0;
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+
+ virtual void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) = 0;
+ virtual void collectVisibleLayers(const CompositionRefreshArgs&, CoverageState&) = 0;
+ virtual void ensureOutputLayerIfVisible(std::shared_ptr<Layer>, CoverageState&) = 0;
+ virtual void setReleasedLayers(const CompositionRefreshArgs&) = 0;
+
+ virtual void updateAndWriteCompositionState(const CompositionRefreshArgs&) = 0;
+ virtual void setColorTransform(const CompositionRefreshArgs&) = 0;
+ virtual void updateColorProfile(const CompositionRefreshArgs&) = 0;
+ virtual void beginFrame() = 0;
+ virtual void prepareFrame() = 0;
+ virtual void devOptRepaintFlash(const CompositionRefreshArgs&) = 0;
+ virtual void finishFrame(const CompositionRefreshArgs&) = 0;
+ virtual std::optional<base::unique_fd> composeSurfaces(const Region&) = 0;
+ virtual void postFramebuffer() = 0;
+ virtual void chooseCompositionStrategy() = 0;
+ virtual bool getSkipColorTransform() const = 0;
+ virtual FrameFences presentAndGetFrameFences() = 0;
+ virtual std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) = 0;
+ virtual void appendRegionFlashRequests(
+ const Region& flashRegion,
+ std::vector<renderengine::LayerSettings>& clientCompositionLayers) = 0;
+ virtual void setExpensiveRenderingExpected(bool enabled) = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h
new file mode 100644
index 0000000..6e798ce
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputColorSetting.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+namespace android::compositionengine {
+
+enum class OutputColorSetting : int32_t {
+ kManaged = 0,
+ kUnmanaged = 1,
+ kEnhanced = 2,
+};
+
+} // namespace android::compositionengine
\ No newline at end of file
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index cd63b57..389b605 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -21,8 +21,13 @@
#include <utils/StrongPointer.h>
+#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
namespace android {
namespace compositionengine {
@@ -43,6 +48,9 @@
public:
virtual ~OutputLayer();
+ // Sets the HWC2::Layer associated with this layer
+ virtual void setHwcLayer(std::shared_ptr<HWC2::Layer>) = 0;
+
// Gets the output which owns this output layer
virtual const Output& getOutput() const = 0;
@@ -71,7 +79,31 @@
// Writes the geometry state to the HWC, or does nothing if this layer does
// not use the HWC. If includeGeometry is false, the geometry state can be
// skipped.
- virtual void writeStateToHWC(bool includeGeometry) const = 0;
+ virtual void writeStateToHWC(bool includeGeometry) = 0;
+
+ // Updates the cursor position with the HWC
+ virtual void writeCursorPositionToHWC() const = 0;
+
+ // Returns the HWC2::Layer associated with this layer, if it exists
+ virtual HWC2::Layer* getHwcLayer() const = 0;
+
+ // Returns true if the current layer state requires client composition
+ virtual bool requiresClientComposition() const = 0;
+
+ // Returns true if the current layer should be treated as a cursor layer
+ virtual bool isHardwareCursor() const = 0;
+
+ // Applies a HWC device requested composition type change
+ virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0;
+
+ // Prepares to apply any HWC device layer requests
+ virtual void prepareForDeviceLayerRequests() = 0;
+
+ // Applies a HWC device layer request
+ virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
+
+ // Returns true if the composition settings scale pixels
+ virtual bool needsFiltering() const = 0;
// Debugging
virtual void dump(std::string& result) const = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index e21128c..5ce2fdc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,22 +71,18 @@
virtual status_t beginFrame(bool mustRecompose) = 0;
// Prepares the frame for rendering
- virtual status_t prepareFrame() = 0;
+ virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0;
// Allocates a buffer as scratch space for GPU composition
virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 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;
+ virtual void queueBuffer(base::unique_fd readyFence) = 0;
// Called after the HWC calls are made to present the display
virtual void onPresentDisplayCompleted() = 0;
- // Called to set the viewport and projection state for rendering into this
- // surface
- virtual void setViewportAndProjection() = 0;
-
// Called after the surface has been rendering to signal the surface should
// be made ready for displaying
virtual void flip() = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
index b01eb64..f416c9c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/CompositionEngine.h
@@ -26,9 +26,9 @@
~CompositionEngine() override;
std::shared_ptr<compositionengine::Display> createDisplay(
- compositionengine::DisplayCreationArgs&&) override;
+ const compositionengine::DisplayCreationArgs&) override;
std::shared_ptr<compositionengine::Layer> createLayer(
- compositionengine::LayerCreationArgs&&) override;
+ const compositionengine::LayerCreationArgs&) override;
HWComposer& getHwComposer() const override;
void setHwComposer(std::unique_ptr<HWComposer>) override;
@@ -36,9 +36,28 @@
renderengine::RenderEngine& getRenderEngine() const override;
void setRenderEngine(std::unique_ptr<renderengine::RenderEngine>) override;
+ bool needsAnotherUpdate() const override;
+ nsecs_t getLastFrameRefreshTimestamp() const override;
+
+ void present(CompositionRefreshArgs&) override;
+
+ void updateCursorAsync(CompositionRefreshArgs&) override;
+
+ void preComposition(CompositionRefreshArgs&) override;
+
+ // Debugging
+ void dump(std::string&) const override;
+
+ void updateLayerStateFromFE(CompositionRefreshArgs& args);
+
+ // Testing
+ void setNeedsAnotherUpdateForTest(bool);
+
private:
std::unique_ptr<HWComposer> mHwComposer;
std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
+ bool mNeedsAnotherUpdate = false;
+ nsecs_t mRefreshStartTime = 0;
};
std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine();
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 0e20c43..ace876c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -16,45 +16,83 @@
#pragma once
-#include <memory>
-
#include <compositionengine/Display.h>
+#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/impl/Output.h>
+#include <memory>
+
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine {
class CompositionEngine;
-struct DisplayCreationArgs;
-
namespace impl {
-class Display : public compositionengine::impl::Output, public compositionengine::Display {
+// The implementation class contains the common implementation, but does not
+// actually contain the final display state.
+class Display : public compositionengine::impl::Output, public virtual compositionengine::Display {
public:
- Display(const CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+ explicit Display(const compositionengine::DisplayCreationArgs&);
virtual ~Display();
// compositionengine::Output overrides
+ std::optional<DisplayId> getDisplayId() const override;
void dump(std::string&) const override;
- void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ using compositionengine::impl::Output::setReleasedLayers;
+ void setReleasedLayers(const CompositionRefreshArgs&) override;
+ void setColorTransform(const CompositionRefreshArgs&) override;
+ void setColorProfile(const ColorProfile&) override;
+ void chooseCompositionStrategy() override;
+ bool getSkipColorTransform() const override;
+ compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ void setExpensiveRenderingExpected(bool) override;
+ void finishFrame(const CompositionRefreshArgs&) override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
bool isSecure() const override;
bool isVirtual() const override;
void disconnect() override;
- void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
- void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
+ void createDisplayColorProfile(
+ const compositionengine::DisplayColorProfileCreationArgs&) override;
+ void createRenderSurface(const compositionengine::RenderSurfaceCreationArgs&) override;
+
+ // Internal helpers used by chooseCompositionStrategy()
+ using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
+ using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
+ using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
+ virtual bool anyLayersRequireClientComposition() const;
+ virtual bool allLayersRequireClientComposition() const;
+ virtual void applyChangedTypesToLayers(const ChangedTypes&);
+ virtual void applyDisplayRequests(const DisplayRequests&);
+ virtual void applyLayerRequestsToLayers(const LayerRequests&);
+
+ // Internal
+ std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&) const;
private:
const bool mIsVirtual;
std::optional<DisplayId> mId;
+ Hwc2::PowerAdvisor* const mPowerAdvisor{nullptr};
};
-std::shared_ptr<compositionengine::Display> createDisplay(
- const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+// This template factory function standardizes the implementation details of the
+// final class using the types actually required by the implementation. This is
+// not possible to do in the base class as those types may not even be visible
+// to the base code.
+template <typename BaseDisplay, typename CompositionEngine, typename DisplayCreationArgs>
+std::shared_ptr<BaseDisplay> createDisplayTemplated(const CompositionEngine& compositionEngine,
+ const DisplayCreationArgs& args) {
+ return createOutputTemplated<BaseDisplay>(compositionEngine, args);
+}
+
+std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
+ const compositionengine::DisplayCreationArgs&);
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
index 49c2d2c..9bc0e68 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DisplayColorProfile.h
@@ -33,7 +33,7 @@
class DisplayColorProfile : public compositionengine::DisplayColorProfile {
public:
- DisplayColorProfile(DisplayColorProfileCreationArgs&&);
+ DisplayColorProfile(const DisplayColorProfileCreationArgs&);
~DisplayColorProfile() override;
bool isValid() const override;
@@ -54,6 +54,8 @@
bool hasDolbyVisionSupport() const override;
const HdrCapabilities& getHdrCapabilities() const override;
+ bool isDataspaceSupported(ui::Dataspace) const override;
+ ui::Dataspace getTargetDataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace) const override;
void dump(std::string&) const override;
@@ -89,7 +91,7 @@
};
std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
- DisplayColorProfileCreationArgs&&);
+ const DisplayColorProfileCreationArgs&);
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
index 3e56b21..46489fb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Layer.h
@@ -19,42 +19,66 @@
#include <memory>
#include <compositionengine/Layer.h>
-#include <compositionengine/impl/LayerCompositionState.h>
-#include <utils/RefBase.h>
+#include <compositionengine/LayerCreationArgs.h>
#include <utils/StrongPointer.h>
namespace android::compositionengine {
-class CompositionEngine;
-class LayerFE;
-
struct LayerCreationArgs;
namespace impl {
-class Display;
-
-class Layer : public compositionengine::Layer {
+// The implementation class contains the common implementation, but does not
+// actually contain the final layer state.
+class Layer : public virtual compositionengine::Layer {
public:
- Layer(const CompositionEngine&, compositionengine::LayerCreationArgs&&);
~Layer() override;
- sp<LayerFE> getLayerFE() const override;
+ // compositionengine::Layer overrides
+ void dump(std::string&) const override;
- const LayerCompositionState& getState() const override;
- LayerCompositionState& editState() override;
-
- void dump(std::string& result) const override;
-
-private:
- const compositionengine::CompositionEngine& mCompositionEngine;
- const wp<LayerFE> mLayerFE;
-
- LayerCompositionState mState;
+protected:
+ // Implemented by the final implementation for the final state it uses.
+ virtual void dumpFEState(std::string&) const = 0;
};
-std::shared_ptr<compositionengine::Layer> createLayer(const compositionengine::CompositionEngine&,
- compositionengine::LayerCreationArgs&&);
+// This template factory function standardizes the implementation details of the
+// final class using the types actually required by the implementation. This is
+// not possible to do in the base class as those types may not even be visible
+// to the base code.
+template <typename BaseLayer, typename LayerCreationArgs>
+std::shared_ptr<BaseLayer> createLayerTemplated(const LayerCreationArgs& args) {
+ class Layer final : public BaseLayer {
+ public:
+// Clang incorrectly complains that these are unused.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
+ using LayerFE = std::remove_pointer_t<decltype(
+ std::declval<decltype(std::declval<LayerCreationArgs>().layerFE)>().unsafe_get())>;
+ using LayerFECompositionState = std::remove_const_t<
+ std::remove_reference_t<decltype(std::declval<BaseLayer>().getFEState())>>;
+#pragma clang diagnostic pop
+
+ explicit Layer(const LayerCreationArgs& args) : mLayerFE(args.layerFE) {}
+ ~Layer() override = default;
+
+ private:
+ // compositionengine::Layer overrides
+ sp<compositionengine::LayerFE> getLayerFE() const override { return mLayerFE.promote(); }
+ const LayerFECompositionState& getFEState() const override { return mFrontEndState; }
+ LayerFECompositionState& editFEState() override { return mFrontEndState; }
+
+ // compositionengine::impl::Layer overrides
+ void dumpFEState(std::string& out) const override { mFrontEndState.dump(out); }
+
+ const wp<LayerFE> mLayerFE;
+ LayerFECompositionState mFrontEndState;
+ };
+
+ return std::make_shared<Layer>(args);
+}
+
+std::shared_ptr<Layer> createLayer(const LayerCreationArgs&);
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index b1d1f42..a2342ae 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -16,36 +16,33 @@
#pragma once
+#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+
#include <memory>
#include <utility>
#include <vector>
-#include <compositionengine/Output.h>
-#include <compositionengine/impl/OutputCompositionState.h>
+namespace android::compositionengine::impl {
-namespace android::compositionengine {
-
-class CompositionEngine;
-class Layer;
-class OutputLayer;
-
-namespace impl {
-
+// The implementation class contains the common implementation, but does not
+// actually contain the final output state.
class Output : public virtual compositionengine::Output {
public:
- Output(const CompositionEngine&);
~Output() override;
+ // compositionengine::Output overrides
bool isValid() const override;
-
+ std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
void setProjection(const ui::Transform&, int32_t orientation, const Rect& frame,
const Rect& viewport, const Rect& scissor, bool needsFiltering) override;
void setBounds(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
- void setColorTransform(const mat4&) override;
- void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent) override;
+ void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
+ void setColorProfile(const ColorProfile&) override;
void dump(std::string&) const override;
@@ -58,42 +55,176 @@
compositionengine::RenderSurface* getRenderSurface() const override;
void setRenderSurface(std::unique_ptr<compositionengine::RenderSurface>) override;
- const OutputCompositionState& getState() const override;
- OutputCompositionState& editState() override;
-
Region getDirtyRegion(bool repaintEverything) const override;
- bool belongsInOutput(uint32_t, bool) const override;
+ bool belongsInOutput(std::optional<uint32_t>, bool) const override;
+ bool belongsInOutput(const compositionengine::Layer*) const override;
compositionengine::OutputLayer* getOutputLayerForLayer(
compositionengine::Layer*) const override;
- std::unique_ptr<compositionengine::OutputLayer> getOrCreateOutputLayer(
- std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
- sp<LayerFE>) override;
- void setOutputLayersOrderedByZ(OutputLayers&&) override;
- const OutputLayers& getOutputLayersOrderedByZ() const override;
+
+ void setReleasedLayers(ReleasedLayers&&) override;
+
+ void prepare(const CompositionRefreshArgs&, LayerFESet&) override;
+ void present(const CompositionRefreshArgs&) override;
+
+ void rebuildLayerStacks(const CompositionRefreshArgs&, LayerFESet&) override;
+ void collectVisibleLayers(const CompositionRefreshArgs&,
+ compositionengine::Output::CoverageState&) override;
+ void ensureOutputLayerIfVisible(std::shared_ptr<compositionengine::Layer>,
+ compositionengine::Output::CoverageState&) override;
+ void setReleasedLayers(const compositionengine::CompositionRefreshArgs&) override;
+
+ void updateLayerStateFromFE(const CompositionRefreshArgs&) const override;
+ void updateAndWriteCompositionState(const compositionengine::CompositionRefreshArgs&) override;
+ void updateColorProfile(const compositionengine::CompositionRefreshArgs&) override;
+ void beginFrame() override;
+ void prepareFrame() override;
+ void devOptRepaintFlash(const CompositionRefreshArgs&) override;
+ void finishFrame(const CompositionRefreshArgs&) override;
+ std::optional<base::unique_fd> composeSurfaces(const Region&) override;
+ void postFramebuffer() override;
// Testing
+ const ReleasedLayers& getReleasedLayersForTest() const;
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
protected:
- const CompositionEngine& getCompositionEngine() const;
+ std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&) const;
+ std::optional<size_t> findCurrentOutputLayerForLayer(compositionengine::Layer*) const;
+ void chooseCompositionStrategy() override;
+ bool getSkipColorTransform() const override;
+ compositionengine::Output::FrameFences presentAndGetFrameFences() override;
+ std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) override;
+ void appendRegionFlashRequests(const Region&,
+ std::vector<renderengine::LayerSettings>&) override;
+ void setExpensiveRenderingExpected(bool enabled) override;
void dumpBase(std::string&) const;
+ // Implemented by the final implementation for the final state it uses.
+ virtual compositionengine::OutputLayer* ensureOutputLayer(
+ std::optional<size_t>, const std::shared_ptr<compositionengine::Layer>&,
+ const sp<LayerFE>&) = 0;
+ virtual compositionengine::OutputLayer* injectOutputLayerForTest(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&) = 0;
+ virtual void finalizePendingOutputLayers() = 0;
+ virtual const compositionengine::CompositionEngine& getCompositionEngine() const = 0;
+ virtual void dumpState(std::string& out) const = 0;
+
private:
void dirtyEntireOutput();
-
- const CompositionEngine& mCompositionEngine;
+ ui::Dataspace getBestDataspace(ui::Dataspace*, bool*) const;
+ compositionengine::Output::ColorProfile pickColorProfile(
+ const compositionengine::CompositionRefreshArgs&) const;
std::string mName;
- OutputCompositionState mState;
-
std::unique_ptr<compositionengine::DisplayColorProfile> mDisplayColorProfile;
std::unique_ptr<compositionengine::RenderSurface> mRenderSurface;
- OutputLayers mOutputLayersOrderedByZ;
+ ReleasedLayers mReleasedLayers;
};
-} // namespace impl
-} // namespace android::compositionengine
+// This template factory function standardizes the implementation details of the
+// final class using the types actually required by the implementation. This is
+// not possible to do in the base class as those types may not even be visible
+// to the base code.
+template <typename BaseOutput, typename CompositionEngine, typename... Args>
+std::shared_ptr<BaseOutput> createOutputTemplated(const CompositionEngine& compositionEngine,
+ Args... args) {
+ class Output final : public BaseOutput {
+ public:
+// Clang incorrectly complains that these are unused.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
+
+ using OutputCompositionState = std::remove_const_t<
+ std::remove_reference_t<decltype(std::declval<BaseOutput>().getState())>>;
+ using OutputLayer = std::remove_pointer_t<decltype(
+ std::declval<BaseOutput>().getOutputLayerOrderedByZByIndex(0))>;
+
+#pragma clang diagnostic pop
+
+ explicit Output(const CompositionEngine& compositionEngine, Args... args)
+ : BaseOutput(std::forward<Args>(args)...), mCompositionEngine(compositionEngine) {}
+ ~Output() override = default;
+
+ private:
+ // compositionengine::Output overrides
+ const OutputCompositionState& getState() const override { return mState; }
+
+ OutputCompositionState& editState() override { return mState; }
+
+ size_t getOutputLayerCount() const override {
+ return mCurrentOutputLayersOrderedByZ.size();
+ }
+
+ OutputLayer* getOutputLayerOrderedByZByIndex(size_t index) const override {
+ if (index >= mCurrentOutputLayersOrderedByZ.size()) {
+ return nullptr;
+ }
+ return mCurrentOutputLayersOrderedByZ[index].get();
+ }
+
+ // compositionengine::impl::Output overrides
+ const CompositionEngine& getCompositionEngine() const override {
+ return mCompositionEngine;
+ };
+
+ OutputLayer* ensureOutputLayer(std::optional<size_t> prevIndex,
+ const std::shared_ptr<compositionengine::Layer>& layer,
+ const sp<LayerFE>& layerFE) {
+ auto outputLayer = (prevIndex && *prevIndex <= mCurrentOutputLayersOrderedByZ.size())
+ ? std::move(mCurrentOutputLayersOrderedByZ[*prevIndex])
+ : BaseOutput::createOutputLayer(layer, layerFE);
+ auto result = outputLayer.get();
+ mPendingOutputLayersOrderedByZ.emplace_back(std::move(outputLayer));
+ return result;
+ }
+
+ void finalizePendingOutputLayers() override {
+ // The pending layers are added in reverse order. Reverse them to
+ // get the back-to-front ordered list of layers.
+ std::reverse(mPendingOutputLayersOrderedByZ.begin(),
+ mPendingOutputLayersOrderedByZ.end());
+
+ mCurrentOutputLayersOrderedByZ = std::move(mPendingOutputLayersOrderedByZ);
+ }
+
+ void dumpState(std::string& out) const override { mState.dump(out); }
+
+ OutputLayer* injectOutputLayerForTest(
+ const std::shared_ptr<compositionengine::Layer>& layer,
+ const sp<LayerFE>& layerFE) override {
+ auto outputLayer = BaseOutput::createOutputLayer(layer, layerFE);
+ auto result = outputLayer.get();
+ mCurrentOutputLayersOrderedByZ.emplace_back(std::move(outputLayer));
+ return result;
+ }
+
+ // Note: This is declared as a private virtual non-override so it can be
+ // an override implementation in the unit tests, but otherwise is not an
+ // accessible override for the normal implementation.
+ virtual void injectOutputLayerForTest(std::unique_ptr<OutputLayer> outputLayer) {
+ mCurrentOutputLayersOrderedByZ.emplace_back(std::move(outputLayer));
+ }
+
+ void clearOutputLayers() override {
+ mCurrentOutputLayersOrderedByZ.clear();
+ mPendingOutputLayersOrderedByZ.clear();
+ }
+
+ const CompositionEngine& mCompositionEngine;
+ OutputCompositionState mState;
+ std::vector<std::unique_ptr<OutputLayer>> mCurrentOutputLayersOrderedByZ;
+ std::vector<std::unique_ptr<OutputLayer>> mPendingOutputLayersOrderedByZ;
+ };
+
+ return std::make_shared<Output>(compositionEngine, std::forward<Args>(args)...);
+}
+
+std::shared_ptr<Output> createOutput(const compositionengine::CompositionEngine&);
+
+} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 0c47eb5..17d3d3f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -35,6 +35,16 @@
// If false, this output is not considered secure
bool isSecure{false};
+ // If true, the current frame on this output uses client composition
+ bool usesClientComposition{false};
+
+ // If true, the current frame on this output uses device composition
+ bool usesDeviceComposition{false};
+
+ // If true, the client target should be flipped when performing client
+ // composition
+ bool flipClientTarget{false};
+
// If true, this output displays layers that are internal-only
bool layerStackInternal{false};
@@ -76,11 +86,8 @@
// True if the last composition frame had visible layers
bool lastCompositionHadVisibleLayers{false};
- // The color transform to apply
- android_color_transform_t colorTransform{HAL_COLOR_TRANSFORM_IDENTITY};
-
- // The color transform matrix to apply, corresponding with colorTransform.
- mat4 colorTransformMat;
+ // The color transform matrix to apply
+ mat4 colorTransformMatrix;
// Current active color mode
ui::ColorMode colorMode{ui::ColorMode::NATIVE};
@@ -88,9 +95,12 @@
// Current active render intent
ui::RenderIntent renderIntent{ui::RenderIntent::COLORIMETRIC};
- // Current active dstaspace
+ // Current active dataspace
ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+ // Current target dataspace
+ ui::Dataspace targetDataspace{ui::Dataspace::UNKNOWN};
+
// Debugging
void dump(std::string& result) const;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 6a4818f..34dbfb7 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -20,50 +20,113 @@
#include <string>
#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <ui/FloatRect.h>
#include <ui/Rect.h>
#include "DisplayHardware/DisplayIdentification.h"
-namespace android::compositionengine::impl {
+namespace android::compositionengine {
-class OutputLayer : public compositionengine::OutputLayer {
+struct LayerFECompositionState;
+
+namespace impl {
+
+// The implementation class contains the common implementation, but does not
+// actually contain the final layer state.
+class OutputLayer : public virtual compositionengine::OutputLayer {
public:
- OutputLayer(const compositionengine::Output&, std::shared_ptr<compositionengine::Layer>,
- sp<compositionengine::LayerFE>);
~OutputLayer() override;
- void initialize(const CompositionEngine&, std::optional<DisplayId>);
-
- const compositionengine::Output& getOutput() const override;
- compositionengine::Layer& getLayer() const override;
- compositionengine::LayerFE& getLayerFE() const override;
-
- const OutputLayerCompositionState& getState() const override;
- OutputLayerCompositionState& editState() override;
+ void setHwcLayer(std::shared_ptr<HWC2::Layer>) override;
void updateCompositionState(bool) override;
- void writeStateToHWC(bool) const override;
+ void writeStateToHWC(bool) override;
+ void writeCursorPositionToHWC() const override;
- void dump(std::string& result) const override;
+ HWC2::Layer* getHwcLayer() const override;
+ bool requiresClientComposition() const override;
+ bool isHardwareCursor() const override;
+ void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
+ void prepareForDeviceLayerRequests() override;
+ void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+ bool needsFiltering() const override;
+
+ void dump(std::string&) const override;
virtual FloatRect calculateOutputSourceCrop() const;
virtual Rect calculateOutputDisplayFrame() const;
virtual uint32_t calculateOutputRelativeBufferTransform() const;
+protected:
+ // Implemented by the final implementation for the final state it uses.
+ virtual void dumpState(std::string&) const = 0;
+
private:
Rect calculateInitialCrop() const;
-
- const compositionengine::Output& mOutput;
- std::shared_ptr<compositionengine::Layer> mLayer;
- sp<compositionengine::LayerFE> mLayerFE;
-
- OutputLayerCompositionState mState;
+ void writeOutputDependentGeometryStateToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void writeOutputIndependentGeometryStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeOutputDependentPerFrameStateToHWC(HWC2::Layer*);
+ void writeOutputIndependentPerFrameStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSolidColorStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
+ void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
+ Hwc2::IComposerClient::Composition to) const;
};
-std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
- const CompositionEngine&, std::optional<DisplayId>, const compositionengine::Output&,
- std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
+// This template factory function standardizes the implementation details of the
+// final class using the types actually required by the implementation. This is
+// not possible to do in the base class as those types may not even be visible
+// to the base code.
+template <typename BaseOutputLayer>
+std::unique_ptr<BaseOutputLayer> createOutputLayerTemplated(const Output& output,
+ std::shared_ptr<Layer> layer,
+ sp<LayerFE> layerFE) {
+ class OutputLayer final : public BaseOutputLayer {
+ public:
+// Clang incorrectly complains that these are unused.
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-local-typedef"
-} // namespace android::compositionengine::impl
+ using OutputLayerCompositionState = std::remove_const_t<
+ std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getState())>>;
+ using Output = std::remove_const_t<
+ std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getOutput())>>;
+ using Layer = std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getLayer())>;
+ using LayerFE =
+ std::remove_reference_t<decltype(std::declval<BaseOutputLayer>().getLayerFE())>;
+
+#pragma clang diagnostic pop
+
+ OutputLayer(const Output& output, const std::shared_ptr<Layer>& layer,
+ const sp<LayerFE>& layerFE)
+ : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+ ~OutputLayer() override = default;
+
+ private:
+ // compositionengine::OutputLayer overrides
+ const Output& getOutput() const override { return mOutput; }
+ Layer& getLayer() const override { return *mLayer; }
+ LayerFE& getLayerFE() const override { return *mLayerFE; }
+ const OutputLayerCompositionState& getState() const override { return mState; }
+ OutputLayerCompositionState& editState() override { return mState; }
+
+ // compositionengine::impl::OutputLayer overrides
+ void dumpState(std::string& out) const override { mState.dump(out); }
+
+ const Output& mOutput;
+ const std::shared_ptr<Layer> mLayer;
+ const sp<LayerFE> mLayerFE;
+ OutputLayerCompositionState mState;
+ };
+
+ return std::make_unique<OutputLayer>(output, layer, layerFE);
+}
+
+std::unique_ptr<OutputLayer> createOutputLayer(const compositionengine::Output&,
+ const std::shared_ptr<compositionengine::Layer>&,
+ const sp<LayerFE>&);
+
+} // namespace impl
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index b78e9e0..1347449 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -23,6 +23,7 @@
#include <compositionengine/impl/HwcBufferCache.h>
#include <renderengine/Mesh.h>
#include <ui/FloatRect.h>
+#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -39,9 +40,18 @@
namespace compositionengine::impl {
struct OutputLayerCompositionState {
- // The region of this layer which is visible on this output
+ // The portion of the layer that is not obscured by opaque layers on top
Region visibleRegion;
+ // The portion of the layer that is not obscured and is also opaque
+ Region visibleNonTransparentRegion;
+
+ // The portion of the layer that is obscured by opaque layers on top
+ Region coveredRegion;
+
+ // The visibleRegion transformed to output space
+ Region outputSpaceVisibleRegion;
+
// If true, client composition will be used on this output
bool forceClientComposition{false};
@@ -57,8 +67,11 @@
// The buffer transform to use for this layer o on this output.
Hwc2::Transform bufferTransform{static_cast<Hwc2::Transform>(0)};
+ // The dataspace for this layer
+ ui::Dataspace dataspace{ui::Dataspace::UNKNOWN};
+
// The Z order index of this layer on this output
- uint32_t z;
+ uint32_t z{0};
/*
* HWC state
@@ -70,7 +83,7 @@
// The HWC Layer backing this layer
std::shared_ptr<HWC2::Layer> hwcLayer;
- // The HWC composition type for this layer
+ // The most recently set HWC composition type for this layer
Hwc2::IComposerClient::Composition hwcCompositionType{
Hwc2::IComposerClient::Composition::INVALID};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index 0f57315..692d78d 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -39,7 +39,7 @@
class RenderSurface : public compositionengine::RenderSurface {
public:
RenderSurface(const CompositionEngine&, compositionengine::Display&,
- compositionengine::RenderSurfaceCreationArgs&&);
+ const compositionengine::RenderSurfaceCreationArgs&);
~RenderSurface() override;
bool isValid() const override;
@@ -52,11 +52,10 @@
void setDisplaySize(const ui::Size&) override;
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
- status_t prepareFrame() override;
+ void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override;
sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
- void queueBuffer(base::unique_fd&& readyFence) override;
+ void queueBuffer(base::unique_fd readyFence) override;
void onPresentDisplayCompleted() override;
- void setViewportAndProjection() override;
void flip() override;
// Debugging
@@ -85,7 +84,7 @@
std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
const compositionengine::CompositionEngine&, compositionengine::Display&,
- compositionengine::RenderSurfaceCreationArgs&&);
+ const compositionengine::RenderSurfaceCreationArgs&);
} // namespace impl
} // namespace compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
index 0f57685..8e6f2e2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/CompositionEngine.h
@@ -17,6 +17,7 @@
#pragma once
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/LayerCreationArgs.h>
#include <gmock/gmock.h>
@@ -31,14 +32,24 @@
CompositionEngine();
~CompositionEngine() override;
- MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(DisplayCreationArgs&&));
- MOCK_METHOD1(createLayer, std::shared_ptr<Layer>(LayerCreationArgs&&));
+ MOCK_METHOD1(createDisplay, std::shared_ptr<Display>(const DisplayCreationArgs&));
+ MOCK_METHOD1(createLayer, std::shared_ptr<Layer>(const LayerCreationArgs&));
MOCK_CONST_METHOD0(getHwComposer, HWComposer&());
MOCK_METHOD1(setHwComposer, void(std::unique_ptr<HWComposer>));
MOCK_CONST_METHOD0(getRenderEngine, renderengine::RenderEngine&());
MOCK_METHOD1(setRenderEngine, void(std::unique_ptr<renderengine::RenderEngine>));
+
+ MOCK_CONST_METHOD0(needsAnotherUpdate, bool());
+ MOCK_CONST_METHOD0(getLastFrameRefreshTimestamp, nsecs_t());
+
+ MOCK_METHOD1(present, void(CompositionRefreshArgs&));
+ MOCK_METHOD1(updateCursorAsync, void(CompositionRefreshArgs&));
+
+ MOCK_METHOD1(preComposition, void(CompositionRefreshArgs&));
+
+ MOCK_CONST_METHOD1(dump, void(std::string&));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
index d763aa6..57f33ae 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Display.h
@@ -38,8 +38,8 @@
MOCK_METHOD0(disconnect, void());
- MOCK_METHOD1(createDisplayColorProfile, void(DisplayColorProfileCreationArgs&&));
- MOCK_METHOD1(createRenderSurface, void(RenderSurfaceCreationArgs&&));
+ MOCK_METHOD1(createDisplayColorProfile, void(const DisplayColorProfileCreationArgs&));
+ MOCK_METHOD1(createRenderSurface, void(const RenderSurfaceCreationArgs&));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
index 8056c9d..1aaebea 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/DisplayColorProfile.h
@@ -42,6 +42,9 @@
MOCK_CONST_METHOD0(hasDolbyVisionSupport, bool());
MOCK_CONST_METHOD0(getHdrCapabilities, const HdrCapabilities&());
+ MOCK_CONST_METHOD1(isDataspaceSupported, bool(ui::Dataspace));
+ MOCK_CONST_METHOD3(getTargetDataspace,
+ ui::Dataspace(ui::ColorMode, ui::Dataspace, ui::Dataspace));
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
index cce3b97..4f03cb4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Layer.h
@@ -18,7 +18,7 @@
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
-#include <compositionengine/impl/LayerCompositionState.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <gmock/gmock.h>
namespace android::compositionengine::mock {
@@ -30,8 +30,8 @@
MOCK_CONST_METHOD0(getLayerFE, sp<LayerFE>());
- MOCK_CONST_METHOD0(getState, const CompositionState&());
- MOCK_METHOD0(editState, CompositionState&());
+ MOCK_CONST_METHOD0(getFEState, const LayerFECompositionState&());
+ MOCK_METHOD0(editFEState, LayerFECompositionState&());
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index aab18db..3eada3c 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -30,7 +30,14 @@
LayerFE();
virtual ~LayerFE();
- MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_METHOD1(onPreComposition, bool(nsecs_t));
+
+ MOCK_CONST_METHOD2(latchCompositionState,
+ void(LayerFECompositionState&, compositionengine::LayerFE::StateSubset));
+ MOCK_CONST_METHOD1(latchCursorCompositionState, void(LayerFECompositionState&));
+ MOCK_METHOD1(prepareClientComposition,
+ std::optional<renderengine::LayerSettings>(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
MOCK_CONST_METHOD0(getDebugName, const char*());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index d0e7b19..02e68fc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -16,6 +16,7 @@
#pragma once
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
@@ -33,6 +34,7 @@
virtual ~Output();
MOCK_CONST_METHOD0(isValid, bool());
+ MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
MOCK_METHOD1(setCompositionEnabled, void(bool));
MOCK_METHOD6(setProjection,
@@ -40,33 +42,75 @@
MOCK_METHOD1(setBounds, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
- MOCK_METHOD1(setColorTransform, void(const mat4&));
- MOCK_METHOD3(setColorMode, void(ui::ColorMode, ui::Dataspace, ui::RenderIntent));
+ MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
+ MOCK_METHOD1(setColorProfile, void(const ColorProfile&));
MOCK_CONST_METHOD1(dump, void(std::string&));
MOCK_CONST_METHOD0(getName, const std::string&());
MOCK_METHOD1(setName, void(const std::string&));
- MOCK_CONST_METHOD0(getDisplayColorProfile, DisplayColorProfile*());
- MOCK_METHOD1(setDisplayColorProfile, void(std::unique_ptr<DisplayColorProfile>));
+ MOCK_CONST_METHOD0(getDisplayColorProfile, compositionengine::DisplayColorProfile*());
+ MOCK_METHOD1(setDisplayColorProfile,
+ void(std::unique_ptr<compositionengine::DisplayColorProfile>));
- MOCK_CONST_METHOD0(getRenderSurface, RenderSurface*());
- MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<RenderSurface>));
+ MOCK_CONST_METHOD0(getRenderSurface, compositionengine::RenderSurface*());
+ MOCK_METHOD1(setRenderSurface, void(std::unique_ptr<compositionengine::RenderSurface>));
MOCK_CONST_METHOD0(getState, const OutputCompositionState&());
MOCK_METHOD0(editState, OutputCompositionState&());
MOCK_CONST_METHOD1(getDirtyRegion, Region(bool));
- MOCK_CONST_METHOD2(belongsInOutput, bool(uint32_t, bool));
+ MOCK_CONST_METHOD2(belongsInOutput, bool(std::optional<uint32_t>, bool));
+ MOCK_CONST_METHOD1(belongsInOutput, bool(const compositionengine::Layer*));
MOCK_CONST_METHOD1(getOutputLayerForLayer,
compositionengine::OutputLayer*(compositionengine::Layer*));
- MOCK_METHOD3(getOrCreateOutputLayer,
- std::unique_ptr<compositionengine::OutputLayer>(
- std::optional<DisplayId>, std::shared_ptr<compositionengine::Layer>,
- sp<compositionengine::LayerFE>));
- MOCK_METHOD1(setOutputLayersOrderedByZ, void(OutputLayers&&));
- MOCK_CONST_METHOD0(getOutputLayersOrderedByZ, OutputLayers&());
+ MOCK_METHOD0(clearOutputLayers, void());
+ MOCK_METHOD2(injectOutputLayerForTest,
+ compositionengine::OutputLayer*(const std::shared_ptr<compositionengine::Layer>&,
+ const sp<compositionengine::LayerFE>&));
+ MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
+ MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex, OutputLayer*(size_t));
+
+ MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
+
+ MOCK_METHOD2(prepare, void(const compositionengine::CompositionRefreshArgs&, LayerFESet&));
+ MOCK_METHOD1(present, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_METHOD2(rebuildLayerStacks,
+ void(const compositionengine::CompositionRefreshArgs&, LayerFESet&));
+ MOCK_METHOD2(collectVisibleLayers,
+ void(const compositionengine::CompositionRefreshArgs&,
+ compositionengine::Output::CoverageState&));
+ MOCK_METHOD2(ensureOutputLayerIfVisible,
+ void(std::shared_ptr<compositionengine::Layer>,
+ compositionengine::Output::CoverageState&));
+ MOCK_METHOD1(setReleasedLayers, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_CONST_METHOD1(updateLayerStateFromFE, void(const CompositionRefreshArgs&));
+ MOCK_METHOD1(updateAndWriteCompositionState, void(const CompositionRefreshArgs&));
+ MOCK_METHOD1(updateColorProfile, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_METHOD0(beginFrame, void());
+
+ MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD0(chooseCompositionStrategy, void());
+
+ MOCK_METHOD1(devOptRepaintFlash, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_METHOD1(finishFrame, void(const compositionengine::CompositionRefreshArgs&));
+
+ MOCK_METHOD1(composeSurfaces, std::optional<base::unique_fd>(const Region&));
+ MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+
+ MOCK_METHOD0(postFramebuffer, void());
+ MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
+
+ MOCK_METHOD2(generateClientCompositionRequests,
+ std::vector<renderengine::LayerSettings>(bool, Region&));
+ MOCK_METHOD2(appendRegionFlashRequests,
+ void(const Region&, std::vector<renderengine::LayerSettings>&));
+ MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index 29cd08a..4f2afac 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -31,6 +31,8 @@
OutputLayer();
virtual ~OutputLayer();
+ MOCK_METHOD1(setHwcLayer, void(std::shared_ptr<HWC2::Layer>));
+
MOCK_CONST_METHOD0(getOutput, const compositionengine::Output&());
MOCK_CONST_METHOD0(getLayer, compositionengine::Layer&());
MOCK_CONST_METHOD0(getLayerFE, compositionengine::LayerFE&());
@@ -39,7 +41,16 @@
MOCK_METHOD0(editState, impl::OutputLayerCompositionState&());
MOCK_METHOD1(updateCompositionState, void(bool));
- MOCK_CONST_METHOD1(writeStateToHWC, void(bool));
+ MOCK_METHOD1(writeStateToHWC, void(bool));
+ MOCK_CONST_METHOD0(writeCursorPositionToHWC, void());
+
+ MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*());
+ MOCK_CONST_METHOD0(requiresClientComposition, bool());
+ MOCK_CONST_METHOD0(isHardwareCursor, bool());
+ MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
+ MOCK_METHOD0(prepareForDeviceLayerRequests, void());
+ MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+ MOCK_CONST_METHOD0(needsFiltering, bool());
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index ca2299a..ed4d492 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,11 +37,10 @@
MOCK_METHOD1(setProtected, void(bool));
MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
- MOCK_METHOD0(prepareFrame, status_t());
+ MOCK_METHOD2(prepareFrame, void(bool, bool));
MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
- MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
+ MOCK_METHOD1(queueBuffer, void(base::unique_fd));
MOCK_METHOD0(onPresentDisplayCompleted, void());
- MOCK_METHOD0(setViewportAndProjection, void());
MOCK_METHOD0(flip, void());
MOCK_CONST_METHOD1(dump, void(std::string& result));
MOCK_CONST_METHOD0(getPageFlipCount, std::uint32_t());
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index cb08b81..be8646c 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -14,10 +14,14 @@
* limitations under the License.
*/
+#include <compositionengine/CompositionRefreshArgs.h>
+#include <compositionengine/LayerFE.h>
+#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/Layer.h>
#include <renderengine/RenderEngine.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
@@ -35,12 +39,13 @@
CompositionEngine::~CompositionEngine() = default;
std::shared_ptr<compositionengine::Display> CompositionEngine::createDisplay(
- DisplayCreationArgs&& args) {
- return compositionengine::impl::createDisplay(*this, std::move(args));
+ const DisplayCreationArgs& args) {
+ return compositionengine::impl::createDisplay(*this, args);
}
-std::shared_ptr<compositionengine::Layer> CompositionEngine::createLayer(LayerCreationArgs&& args) {
- return compositionengine::impl::createLayer(*this, std::move(args));
+std::shared_ptr<compositionengine::Layer> CompositionEngine::createLayer(
+ const LayerCreationArgs& args) {
+ return compositionengine::impl::createLayer(args);
}
HWComposer& CompositionEngine::getHwComposer() const {
@@ -59,5 +64,86 @@
mRenderEngine = std::move(renderEngine);
}
+bool CompositionEngine::needsAnotherUpdate() const {
+ return mNeedsAnotherUpdate;
+}
+
+nsecs_t CompositionEngine::getLastFrameRefreshTimestamp() const {
+ return mRefreshStartTime;
+}
+
+void CompositionEngine::present(CompositionRefreshArgs& args) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ preComposition(args);
+
+ {
+ // latchedLayers is used to track the set of front-end layer state that
+ // has been latched across all outputs for the prepare step, and is not
+ // needed for anything else.
+ LayerFESet latchedLayers;
+
+ for (const auto& output : args.outputs) {
+ output->prepare(args, latchedLayers);
+ }
+ }
+
+ updateLayerStateFromFE(args);
+
+ for (const auto& output : args.outputs) {
+ output->present(args);
+ }
+}
+
+void CompositionEngine::updateCursorAsync(CompositionRefreshArgs& args) {
+ std::unordered_map<compositionengine::LayerFE*, compositionengine::LayerFECompositionState*>
+ uniqueVisibleLayers;
+
+ for (const auto& output : args.outputs) {
+ for (auto* layer : output->getOutputLayersOrderedByZ()) {
+ if (layer->isHardwareCursor()) {
+ // Latch the cursor composition state from each front-end layer.
+ layer->getLayerFE().latchCursorCompositionState(layer->getLayer().editFEState());
+
+ layer->writeCursorPositionToHWC();
+ }
+ }
+ }
+}
+
+void CompositionEngine::preComposition(CompositionRefreshArgs& args) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ bool needsAnotherUpdate = false;
+
+ mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ for (auto& layer : args.layers) {
+ sp<compositionengine::LayerFE> layerFE = layer->getLayerFE();
+ if (layerFE && layerFE->onPreComposition(mRefreshStartTime)) {
+ needsAnotherUpdate = true;
+ }
+ }
+
+ mNeedsAnotherUpdate = needsAnotherUpdate;
+}
+
+void CompositionEngine::dump(std::string&) const {
+ // The base class has no state to dump, but derived classes might.
+}
+
+void CompositionEngine::setNeedsAnotherUpdateForTest(bool value) {
+ mNeedsAnotherUpdate = value;
+}
+
+void CompositionEngine::updateLayerStateFromFE(CompositionRefreshArgs& args) {
+ // Update the composition state from each front-end layer
+ for (const auto& output : args.outputs) {
+ output->updateLayerStateFromFE(args);
+ }
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index f9d70e3..e885629 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -16,29 +16,30 @@
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayCreationArgs.h>
#include <compositionengine/DisplaySurface.h>
+#include <compositionengine/LayerFE.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/DisplayColorProfile.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/RenderSurface.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/PowerAdvisor.h"
namespace android::compositionengine::impl {
-std::shared_ptr<compositionengine::Display> createDisplay(
+std::shared_ptr<Display> createDisplay(
const compositionengine::CompositionEngine& compositionEngine,
- compositionengine::DisplayCreationArgs&& args) {
- return std::make_shared<Display>(compositionEngine, std::move(args));
+ const compositionengine::DisplayCreationArgs& args) {
+ return createDisplayTemplated<Display>(compositionEngine, args);
}
-Display::Display(const CompositionEngine& compositionEngine, DisplayCreationArgs&& args)
- : compositionengine::impl::Output(compositionEngine),
- mIsVirtual(args.isVirtual),
- mId(args.displayId) {
- editState().isSecure = args.isSecure;
-}
+Display::Display(const DisplayCreationArgs& args)
+ : mIsVirtual(args.isVirtual), mId(args.displayId), mPowerAdvisor(args.powerAdvisor) {}
Display::~Display() = default;
@@ -54,6 +55,10 @@
return mIsVirtual;
}
+std::optional<DisplayId> Display::getDisplayId() const {
+ return mId;
+}
+
void Display::disconnect() {
if (!mId) {
return;
@@ -64,19 +69,28 @@
mId.reset();
}
-void Display::setColorTransform(const mat4& transform) {
- Output::setColorTransform(transform);
+void Display::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
+ Output::setColorTransform(args);
+
+ if (!mId || CC_LIKELY(!args.colorTransformMatrix)) {
+ return;
+ }
auto& hwc = getCompositionEngine().getHwComposer();
- status_t result = hwc.setColorTransform(*mId, transform);
+ status_t result = hwc.setColorTransform(*mId, *args.colorTransformMatrix);
ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display \"%s\": %d",
mId ? to_string(*mId).c_str() : "", result);
}
-void Display::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
- if (mode == getState().colorMode && dataspace == getState().dataspace &&
- renderIntent == getState().renderIntent) {
+void Display::setColorProfile(const ColorProfile& colorProfile) {
+ const ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace,
+ colorProfile.colorSpaceAgnosticDataspace);
+
+ if (colorProfile.mode == getState().colorMode &&
+ colorProfile.dataspace == getState().dataspace &&
+ colorProfile.renderIntent == getState().renderIntent &&
+ targetDataspace == getState().targetDataspace) {
return;
}
@@ -85,10 +99,10 @@
return;
}
- Output::setColorMode(mode, dataspace, renderIntent);
+ Output::setColorProfile(colorProfile);
auto& hwc = getCompositionEngine().getHwComposer();
- hwc.setActiveColorMode(*mId, mode, renderIntent);
+ hwc.setActiveColorMode(*mId, colorProfile.mode, colorProfile.renderIntent);
}
void Display::dump(std::string& out) const {
@@ -110,13 +124,216 @@
Output::dumpBase(out);
}
-void Display::createDisplayColorProfile(DisplayColorProfileCreationArgs&& args) {
- setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(std::move(args)));
+void Display::createDisplayColorProfile(const DisplayColorProfileCreationArgs& args) {
+ setDisplayColorProfile(compositionengine::impl::createDisplayColorProfile(args));
}
-void Display::createRenderSurface(RenderSurfaceCreationArgs&& args) {
- setRenderSurface(compositionengine::impl::createRenderSurface(getCompositionEngine(), *this,
- std::move(args)));
+void Display::createRenderSurface(const RenderSurfaceCreationArgs& args) {
+ setRenderSurface(
+ compositionengine::impl::createRenderSurface(getCompositionEngine(), *this, args));
+}
+
+std::unique_ptr<compositionengine::OutputLayer> Display::createOutputLayer(
+ const std::shared_ptr<compositionengine::Layer>& layer,
+ const sp<compositionengine::LayerFE>& layerFE) const {
+ auto result = impl::createOutputLayer(*this, layer, layerFE);
+
+ if (result && mId) {
+ auto& hwc = getCompositionEngine().getHwComposer();
+ auto displayId = *mId;
+ // Note: For the moment we ensure it is safe to take a reference to the
+ // HWComposer implementation by destroying all the OutputLayers (and
+ // hence the HWC2::Layers they own) before setting a new HWComposer. See
+ // for example SurfaceFlinger::updateVrFlinger().
+ // TODO(b/121291683): Make this safer.
+ auto hwcLayer = std::shared_ptr<HWC2::Layer>(hwc.createLayer(displayId),
+ [&hwc, displayId](HWC2::Layer* layer) {
+ hwc.destroyLayer(displayId, layer);
+ });
+ ALOGE_IF(!hwcLayer, "Failed to create a HWC layer for a HWC supported display %s",
+ getName().c_str());
+ result->setHwcLayer(std::move(hwcLayer));
+ }
+ return result;
+}
+
+void Display::setReleasedLayers(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ Output::setReleasedLayers(refreshArgs);
+
+ if (!mId || refreshArgs.layersWithQueuedFrames.empty()) {
+ return;
+ }
+
+ // For layers that are being removed from a HWC display, and that have
+ // queued frames, add them to a a list of released layers so we can properly
+ // set a fence.
+ compositionengine::Output::ReleasedLayers releasedLayers;
+
+ // Any non-null entries in the current list of layers are layers that are no
+ // longer going to be visible
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ if (!layer) {
+ continue;
+ }
+
+ sp<compositionengine::LayerFE> layerFE(&layer->getLayerFE());
+ const bool hasQueuedFrames =
+ std::find(refreshArgs.layersWithQueuedFrames.cbegin(),
+ refreshArgs.layersWithQueuedFrames.cend(),
+ &layer->getLayer()) != refreshArgs.layersWithQueuedFrames.cend();
+
+ if (hasQueuedFrames) {
+ releasedLayers.emplace_back(layerFE);
+ }
+ }
+
+ setReleasedLayers(std::move(releasedLayers));
+}
+
+void Display::chooseCompositionStrategy() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ // Default to the base settings -- client composition only.
+ Output::chooseCompositionStrategy();
+
+ // If we don't have a HWC display, then we are done
+ if (!mId) {
+ return;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
+ if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(),
+ &changes);
+ result != NO_ERROR) {
+ ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
+ strerror(-result));
+ return;
+ }
+ if (changes) {
+ applyChangedTypesToLayers(changes->changedTypes);
+ applyDisplayRequests(changes->displayRequests);
+ applyLayerRequestsToLayers(changes->layerRequests);
+ }
+
+ // Determine what type of composition we are doing from the final state
+ auto& state = editState();
+ state.usesClientComposition = anyLayersRequireClientComposition();
+ state.usesDeviceComposition = !allLayersRequireClientComposition();
+}
+
+bool Display::getSkipColorTransform() const {
+ if (!mId) {
+ return false;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ return hwc.hasDisplayCapability(*mId, HWC2::DisplayCapability::SkipClientColorTransform);
+}
+
+bool Display::anyLayersRequireClientComposition() const {
+ const auto layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.begin(), layers.end(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+bool Display::allLayersRequireClientComposition() const {
+ const auto layers = getOutputLayersOrderedByZ();
+ return std::all_of(layers.begin(), layers.end(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Display::applyChangedTypesToLayers(const ChangedTypes& changedTypes) {
+ if (changedTypes.empty()) {
+ return;
+ }
+
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ if (auto it = changedTypes.find(hwcLayer); it != changedTypes.end()) {
+ layer->applyDeviceCompositionTypeChange(
+ static_cast<Hwc2::IComposerClient::Composition>(it->second));
+ }
+ }
+}
+
+void Display::applyDisplayRequests(const DisplayRequests& displayRequests) {
+ auto& state = editState();
+ state.flipClientTarget = (static_cast<uint32_t>(displayRequests) &
+ static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0;
+ // Note: HWC2::DisplayRequest::WriteClientTargetToOutput is currently ignored.
+}
+
+void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) {
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ layer->prepareForDeviceLayerRequests();
+
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ if (auto it = layerRequests.find(hwcLayer); it != layerRequests.end()) {
+ layer->applyDeviceLayerRequest(
+ static_cast<Hwc2::IComposerClient::LayerRequest>(it->second));
+ }
+ }
+}
+
+compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
+ auto result = impl::Output::presentAndGetFrameFences();
+
+ if (!mId) {
+ return result;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.presentAndGetReleaseFences(*mId);
+
+ result.presentFence = hwc.getPresentFence(*mId);
+
+ // TODO(b/121291683): Change HWComposer call to return entire map
+ for (const auto* layer : getOutputLayersOrderedByZ()) {
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ result.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*mId, hwcLayer));
+ }
+
+ hwc.clearReleaseFences(*mId);
+
+ return result;
+}
+
+void Display::setExpensiveRenderingExpected(bool enabled) {
+ Output::setExpensiveRenderingExpected(enabled);
+
+ if (mPowerAdvisor && mId) {
+ mPowerAdvisor->setExpensiveRenderingExpected(*mId, enabled);
+ }
+}
+
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ // We only need to actually compose the display if:
+ // 1) It is being handled by hardware composer, which may need this to
+ // keep its virtual display state machine in sync, or
+ // 2) There is work to be done (the dirty region isn't empty)
+ if (!mId) {
+ if (getDirtyRegion(refreshArgs.repaintEverything).isEmpty()) {
+ ALOGV("Skipping display composition");
+ return;
+ }
+ }
+
+ impl::Output::finishFrame(refreshArgs);
}
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
index 130ab1d..a7c4512 100644
--- a/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/DisplayColorProfile.cpp
@@ -64,6 +64,12 @@
RenderIntent::TONE_MAP_COLORIMETRIC,
};
+// Returns true if the given colorMode is considered an HDR color mode
+bool isHdrColorMode(const ColorMode colorMode) {
+ return std::any_of(std::begin(sHdrColorModes), std::end(sHdrColorModes),
+ [colorMode](ColorMode hdrColorMode) { return hdrColorMode == colorMode; });
+}
+
// map known color mode to dataspace
Dataspace colorModeToDataspace(ColorMode mode) {
switch (mode) {
@@ -90,13 +96,7 @@
candidates.push_back(mode);
// check if mode is HDR
- bool isHdr = false;
- for (auto hdrMode : sHdrColorModes) {
- if (hdrMode == mode) {
- isHdr = true;
- break;
- }
- }
+ bool isHdr = isHdrColorMode(mode);
// add other HDR candidates when mode is HDR
if (isHdr) {
@@ -184,11 +184,11 @@
} // anonymous namespace
std::unique_ptr<compositionengine::DisplayColorProfile> createDisplayColorProfile(
- DisplayColorProfileCreationArgs&& args) {
- return std::make_unique<DisplayColorProfile>(std::move(args));
+ const DisplayColorProfileCreationArgs& args) {
+ return std::make_unique<DisplayColorProfile>(args);
}
-DisplayColorProfile::DisplayColorProfile(DisplayColorProfileCreationArgs&& args)
+DisplayColorProfile::DisplayColorProfile(const DisplayColorProfileCreationArgs& args)
: mHasWideColorGamut(args.hasWideColorGamut),
mSupportedPerFrameMetadata(args.supportedPerFrameMetadata) {
populateColorModes(args.hwcColorModes);
@@ -376,6 +376,32 @@
}
}
+bool DisplayColorProfile::isDataspaceSupported(Dataspace dataspace) const {
+ switch (dataspace) {
+ case Dataspace::BT2020_PQ:
+ case Dataspace::BT2020_ITU_PQ:
+ return hasHDR10Support();
+
+ case Dataspace::BT2020_HLG:
+ case Dataspace::BT2020_ITU_HLG:
+ return hasHLGSupport();
+
+ default:
+ return true;
+ }
+}
+
+ui::Dataspace DisplayColorProfile::getTargetDataspace(ColorMode mode, Dataspace dataspace,
+ Dataspace colorSpaceAgnosticDataspace) const {
+ if (isHdrColorMode(mode)) {
+ return Dataspace::UNKNOWN;
+ }
+ if (colorSpaceAgnosticDataspace != ui::Dataspace::UNKNOWN) {
+ return colorSpaceAgnosticDataspace;
+ }
+ return dataspace;
+}
+
void DisplayColorProfile::dump(std::string& out) const {
out.append(" Composition Display Color State:");
diff --git a/services/surfaceflinger/CompositionEngine/src/Layer.cpp b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
index 96e9731..ecacaee 100644
--- a/services/surfaceflinger/CompositionEngine/src/Layer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Layer.cpp
@@ -15,9 +15,8 @@
*/
#include <android-base/stringprintf.h>
-#include <compositionengine/CompositionEngine.h>
-#include <compositionengine/LayerCreationArgs.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/Layer.h>
namespace android::compositionengine {
@@ -26,36 +25,18 @@
namespace impl {
-std::shared_ptr<compositionengine::Layer> createLayer(
- const compositionengine::CompositionEngine& compositionEngine,
- compositionengine::LayerCreationArgs&& args) {
- return std::make_shared<Layer>(compositionEngine, std::move(args));
-}
-
-Layer::Layer(const CompositionEngine& compositionEngine, LayerCreationArgs&& args)
- : mCompositionEngine(compositionEngine), mLayerFE(args.layerFE) {
- static_cast<void>(mCompositionEngine); // Temporary use to prevent an unused warning
+std::shared_ptr<Layer> createLayer(const LayerCreationArgs& args) {
+ return compositionengine::impl::createLayerTemplated<Layer>(args);
}
Layer::~Layer() = default;
-sp<LayerFE> Layer::getLayerFE() const {
- return mLayerFE.promote();
-}
-
-const LayerCompositionState& Layer::getState() const {
- return mState;
-}
-
-LayerCompositionState& Layer::editState() {
- return mState;
-}
-
void Layer::dump(std::string& out) const {
auto layerFE = getLayerFE();
android::base::StringAppendF(&out, "* compositionengine::Layer %p (%s)\n", this,
layerFE ? layerFE->getDebugName() : "<unknown>");
- mState.dump(out);
+ out.append(" frontend:\n");
+ dumpFEState(out);
}
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
deleted file mode 100644
index 40c4da9..0000000
--- a/services/surfaceflinger/CompositionEngine/src/LayerCompositionState.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/stringprintf.h>
-#include <compositionengine/impl/DumpHelpers.h>
-#include <compositionengine/impl/LayerCompositionState.h>
-
-namespace android::compositionengine::impl {
-
-namespace {
-
-using android::compositionengine::impl::dumpVal;
-
-void dumpVal(std::string& out, const char* name, Hwc2::IComposerClient::Color value) {
- using android::base::StringAppendF;
- StringAppendF(&out, "%s=[%d %d %d] ", name, value.r, value.g, value.b);
-}
-
-void dumpFrontEnd(std::string& out, const LayerFECompositionState& state) {
- out.append(" ");
- dumpVal(out, "isSecure", state.isSecure);
- dumpVal(out, "geomUsesSourceCrop", state.geomUsesSourceCrop);
- dumpVal(out, "geomBufferUsesDisplayInverseTransform",
- state.geomBufferUsesDisplayInverseTransform);
- dumpVal(out, "geomLayerTransform", state.geomLayerTransform);
-
- out.append("\n ");
- dumpVal(out, "geomBufferSize", state.geomBufferSize);
- dumpVal(out, "geomContentCrop", state.geomContentCrop);
- dumpVal(out, "geomCrop", state.geomCrop);
- dumpVal(out, "geomBufferTransform", state.geomBufferTransform);
-
- out.append("\n ");
- dumpVal(out, "geomActiveTransparentRegion", state.geomActiveTransparentRegion);
-
- out.append(" ");
- dumpVal(out, "geomLayerBounds", state.geomLayerBounds);
-
- out.append("\n ");
- dumpVal(out, "blend", toString(state.blendMode), state.blendMode);
- dumpVal(out, "alpha", state.alpha);
-
- out.append("\n ");
- dumpVal(out, "type", state.type);
- dumpVal(out, "appId", state.appId);
-
- dumpVal(out, "composition type", toString(state.compositionType), state.compositionType);
-
- out.append("\n buffer: ");
- dumpVal(out, "buffer", state.buffer.get());
- dumpVal(out, "slot", state.bufferSlot);
-
- out.append("\n ");
- dumpVal(out, "sideband stream", state.sidebandStream.get());
-
- out.append("\n ");
- dumpVal(out, "color", state.color);
-
- out.append("\n ");
- dumpVal(out, "dataspace", toString(state.dataspace), state.dataspace);
- dumpVal(out, "hdr metadata types", state.hdrMetadata.validTypes);
- dumpVal(out, "colorTransform", state.colorTransform);
-
- out.append("\n");
-}
-
-} // namespace
-
-void LayerCompositionState::dump(std::string& out) const {
- out.append(" frontend:\n");
- dumpFrontEnd(out, frontEnd);
-}
-
-} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
new file mode 100644
index 0000000..1ca03dc
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/src/LayerFECompositionState.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/stringprintf.h>
+#include <compositionengine/LayerFECompositionState.h>
+#include <compositionengine/impl/DumpHelpers.h>
+
+namespace android::compositionengine {
+
+namespace {
+
+using android::compositionengine::impl::dumpVal;
+
+void dumpVal(std::string& out, const char* name, half4 value) {
+ using android::base::StringAppendF;
+ StringAppendF(&out, "%s=[%f %f %f] ", name, static_cast<float>(value.r),
+ static_cast<float>(value.g), static_cast<float>(value.b));
+}
+
+} // namespace
+
+void LayerFECompositionState::dump(std::string& out) const {
+ out.append(" ");
+ dumpVal(out, "isSecure", isSecure);
+ dumpVal(out, "geomUsesSourceCrop", geomUsesSourceCrop);
+ dumpVal(out, "geomBufferUsesDisplayInverseTransform", geomBufferUsesDisplayInverseTransform);
+ dumpVal(out, "geomLayerTransform", geomLayerTransform);
+
+ out.append("\n ");
+ dumpVal(out, "geomBufferSize", geomBufferSize);
+ dumpVal(out, "geomContentCrop", geomContentCrop);
+ dumpVal(out, "geomCrop", geomCrop);
+ dumpVal(out, "geomBufferTransform", geomBufferTransform);
+
+ out.append("\n ");
+ dumpVal(out, "transparentRegionHint", transparentRegionHint);
+
+ out.append(" ");
+ dumpVal(out, "geomLayerBounds", geomLayerBounds);
+
+ out.append("\n ");
+ dumpVal(out, "blend", toString(blendMode), blendMode);
+ dumpVal(out, "alpha", alpha);
+
+ out.append("\n ");
+ dumpVal(out, "type", type);
+ dumpVal(out, "appId", appId);
+
+ dumpVal(out, "composition type", toString(compositionType), compositionType);
+
+ out.append("\n buffer: ");
+ dumpVal(out, "slot", bufferSlot);
+ dumpVal(out, "buffer", buffer.get());
+
+ out.append("\n ");
+ dumpVal(out, "sideband stream", sidebandStream.get());
+
+ out.append("\n ");
+ dumpVal(out, "color", color);
+
+ out.append("\n ");
+ dumpVal(out, "isOpaque", isOpaque);
+ dumpVal(out, "hasProtectedContent", hasProtectedContent);
+ dumpVal(out, "isColorspaceAgnostic", isColorspaceAgnostic);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
+ dumpVal(out, "hdr metadata types", hdrMetadata.validTypes);
+ dumpVal(out, "colorTransform", colorTransform);
+
+ out.append("\n");
+}
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 01b5781..2007ea3 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -14,14 +14,27 @@
* limitations under the License.
*/
+#include <thread>
+
#include <android-base/stringprintf.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/DisplayColorProfile.h>
+#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/RenderSurface.h>
#include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
+#include <renderengine/DisplaySettings.h>
+#include <renderengine/RenderEngine.h>
#include <ui/DebugUtils.h>
+#include <ui/HdrCapabilities.h>
+#include <utils/Trace.h>
+
+#include "TracedOrdinal.h"
namespace android::compositionengine {
@@ -29,20 +42,43 @@
namespace impl {
-Output::Output(const CompositionEngine& compositionEngine)
- : mCompositionEngine(compositionEngine) {}
+namespace {
+
+template <typename T>
+class Reversed {
+public:
+ explicit Reversed(const T& container) : mContainer(container) {}
+ auto begin() { return mContainer.rbegin(); }
+ auto end() { return mContainer.rend(); }
+
+private:
+ const T& mContainer;
+};
+
+// Helper for enumerating over a container in reverse order
+template <typename T>
+Reversed<T> reversed(const T& c) {
+ return Reversed<T>(c);
+}
+
+} // namespace
+
+std::shared_ptr<Output> createOutput(
+ const compositionengine::CompositionEngine& compositionEngine) {
+ return createOutputTemplated<Output>(compositionEngine);
+}
Output::~Output() = default;
-const CompositionEngine& Output::getCompositionEngine() const {
- return mCompositionEngine;
-}
-
bool Output::isValid() const {
return mDisplayColorProfile && mDisplayColorProfile->isValid() && mRenderSurface &&
mRenderSurface->isValid();
}
+std::optional<DisplayId> Output::getDisplayId() const {
+ return {};
+}
+
const std::string& Output::getName() const {
return mName;
}
@@ -52,73 +88,79 @@
}
void Output::setCompositionEnabled(bool enabled) {
- if (mState.isEnabled == enabled) {
+ auto& outputState = editState();
+ if (outputState.isEnabled == enabled) {
return;
}
- mState.isEnabled = enabled;
+ outputState.isEnabled = enabled;
dirtyEntireOutput();
}
void Output::setProjection(const ui::Transform& transform, int32_t orientation, const Rect& frame,
const Rect& viewport, const Rect& scissor, bool needsFiltering) {
- mState.transform = transform;
- mState.orientation = orientation;
- mState.scissor = scissor;
- mState.frame = frame;
- mState.viewport = viewport;
- mState.needsFiltering = needsFiltering;
+ auto& outputState = editState();
+ outputState.transform = transform;
+ outputState.orientation = orientation;
+ outputState.scissor = scissor;
+ outputState.frame = frame;
+ outputState.viewport = viewport;
+ outputState.needsFiltering = needsFiltering;
dirtyEntireOutput();
}
-// TODO(lpique): Rename setSize() once more is moved.
+// TODO(b/121291683): Rename setSize() once more is moved.
void Output::setBounds(const ui::Size& size) {
mRenderSurface->setDisplaySize(size);
- // TODO(lpique): Rename mState.size once more is moved.
- mState.bounds = Rect(mRenderSurface->getSize());
+ // TODO(b/121291683): Rename outputState.size once more is moved.
+ editState().bounds = Rect(mRenderSurface->getSize());
dirtyEntireOutput();
}
void Output::setLayerStackFilter(uint32_t layerStackId, bool isInternal) {
- mState.layerStackId = layerStackId;
- mState.layerStackInternal = isInternal;
+ auto& outputState = editState();
+ outputState.layerStackId = layerStackId;
+ outputState.layerStackInternal = isInternal;
dirtyEntireOutput();
}
-void Output::setColorTransform(const mat4& transform) {
- if (mState.colorTransformMat == transform) {
+void Output::setColorTransform(const compositionengine::CompositionRefreshArgs& args) {
+ auto& colorTransformMatrix = editState().colorTransformMatrix;
+ if (!args.colorTransformMatrix || colorTransformMatrix == args.colorTransformMatrix) {
return;
}
- const bool isIdentity = (transform == mat4());
- const auto newColorTransform =
- isIdentity ? HAL_COLOR_TRANSFORM_IDENTITY : HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX;
-
- mState.colorTransform = newColorTransform;
- mState.colorTransformMat = transform;
+ colorTransformMatrix = *args.colorTransformMatrix;
dirtyEntireOutput();
}
-void Output::setColorMode(ui::ColorMode mode, ui::Dataspace dataspace,
- ui::RenderIntent renderIntent) {
- if (mState.colorMode == mode && mState.dataspace == dataspace &&
- mState.renderIntent == renderIntent) {
+void Output::setColorProfile(const ColorProfile& colorProfile) {
+ ui::Dataspace targetDataspace =
+ getDisplayColorProfile()->getTargetDataspace(colorProfile.mode, colorProfile.dataspace,
+ colorProfile.colorSpaceAgnosticDataspace);
+
+ auto& outputState = editState();
+ if (outputState.colorMode == colorProfile.mode &&
+ outputState.dataspace == colorProfile.dataspace &&
+ outputState.renderIntent == colorProfile.renderIntent &&
+ outputState.targetDataspace == targetDataspace) {
return;
}
- mState.colorMode = mode;
- mState.dataspace = dataspace;
- mState.renderIntent = renderIntent;
+ outputState.colorMode = colorProfile.mode;
+ outputState.dataspace = colorProfile.dataspace;
+ outputState.renderIntent = colorProfile.renderIntent;
+ outputState.targetDataspace = targetDataspace;
- mRenderSurface->setBufferDataspace(dataspace);
+ mRenderSurface->setBufferDataspace(colorProfile.dataspace);
ALOGV("Set active color mode: %s (%d), active render intent: %s (%d)",
- decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
- renderIntent);
+ decodeColorMode(colorProfile.mode).c_str(), colorProfile.mode,
+ decodeRenderIntent(colorProfile.renderIntent).c_str(), colorProfile.renderIntent);
dirtyEntireOutput();
}
@@ -134,7 +176,7 @@
}
void Output::dumpBase(std::string& out) const {
- mState.dump(out);
+ dumpState(out);
if (mDisplayColorProfile) {
mDisplayColorProfile->dump(out);
@@ -148,8 +190,8 @@
out.append(" No render surface!\n");
}
- android::base::StringAppendF(&out, "\n %zu Layers\b", mOutputLayersOrderedByZ.size());
- for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+ android::base::StringAppendF(&out, "\n %zu Layers\n", getOutputLayerCount());
+ for (const auto* outputLayer : getOutputLayersOrderedByZ()) {
if (!outputLayer) {
continue;
}
@@ -165,6 +207,10 @@
mDisplayColorProfile = std::move(mode);
}
+const Output::ReleasedLayers& Output::getReleasedLayersForTest() const {
+ return mReleasedLayers;
+}
+
void Output::setDisplayColorProfileForTest(
std::unique_ptr<compositionengine::DisplayColorProfile> mode) {
mDisplayColorProfile = std::move(mode);
@@ -176,7 +222,7 @@
void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
mRenderSurface = std::move(surface);
- mState.bounds = Rect(mRenderSurface->getSize());
+ editState().bounds = Rect(mRenderSurface->getSize());
dirtyEntireOutput();
}
@@ -185,59 +231,787 @@
mRenderSurface = std::move(surface);
}
-const OutputCompositionState& Output::getState() const {
- return mState;
-}
-
-OutputCompositionState& Output::editState() {
- return mState;
-}
-
Region Output::getDirtyRegion(bool repaintEverything) const {
- Region dirty(mState.viewport);
+ const auto& outputState = getState();
+ Region dirty(outputState.viewport);
if (!repaintEverything) {
- dirty.andSelf(mState.dirtyRegion);
+ dirty.andSelf(outputState.dirtyRegion);
}
return dirty;
}
-bool Output::belongsInOutput(uint32_t layerStackId, bool internalOnly) const {
+bool Output::belongsInOutput(std::optional<uint32_t> layerStackId, bool internalOnly) const {
// The layerStackId's must match, and also the layer must not be internal
// only when not on an internal output.
- return (layerStackId == mState.layerStackId) && (!internalOnly || mState.layerStackInternal);
+ const auto& outputState = getState();
+ return layerStackId && (*layerStackId == outputState.layerStackId) &&
+ (!internalOnly || outputState.layerStackInternal);
+}
+
+bool Output::belongsInOutput(const compositionengine::Layer* layer) const {
+ if (!layer) {
+ return false;
+ }
+
+ const auto& layerFEState = layer->getFEState();
+ return belongsInOutput(layerFEState.layerStackId, layerFEState.internalOnly);
+}
+
+std::unique_ptr<compositionengine::OutputLayer> Output::createOutputLayer(
+ const std::shared_ptr<compositionengine::Layer>& layer, const sp<LayerFE>& layerFE) const {
+ return impl::createOutputLayer(*this, layer, layerFE);
}
compositionengine::OutputLayer* Output::getOutputLayerForLayer(
compositionengine::Layer* layer) const {
- for (const auto& outputLayer : mOutputLayersOrderedByZ) {
+ auto index = findCurrentOutputLayerForLayer(layer);
+ return index ? getOutputLayerOrderedByZByIndex(*index) : nullptr;
+}
+
+std::optional<size_t> Output::findCurrentOutputLayerForLayer(
+ compositionengine::Layer* layer) const {
+ for (size_t i = 0; i < getOutputLayerCount(); i++) {
+ auto outputLayer = getOutputLayerOrderedByZByIndex(i);
if (outputLayer && &outputLayer->getLayer() == layer) {
- return outputLayer.get();
+ return i;
}
}
- return nullptr;
+ return std::nullopt;
}
-std::unique_ptr<compositionengine::OutputLayer> Output::getOrCreateOutputLayer(
- std::optional<DisplayId> displayId, std::shared_ptr<compositionengine::Layer> layer,
- sp<compositionengine::LayerFE> layerFE) {
- for (auto& outputLayer : mOutputLayersOrderedByZ) {
- if (outputLayer && &outputLayer->getLayer() == layer.get()) {
- return std::move(outputLayer);
+void Output::setReleasedLayers(Output::ReleasedLayers&& layers) {
+ mReleasedLayers = std::move(layers);
+}
+
+void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ LayerFESet& geomSnapshots) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ rebuildLayerStacks(refreshArgs, geomSnapshots);
+}
+
+void Output::present(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ updateColorProfile(refreshArgs);
+ updateAndWriteCompositionState(refreshArgs);
+ setColorTransform(refreshArgs);
+ beginFrame();
+ prepareFrame();
+ devOptRepaintFlash(refreshArgs);
+ finishFrame(refreshArgs);
+ postFramebuffer();
+}
+
+void Output::rebuildLayerStacks(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ LayerFESet& layerFESet) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ auto& outputState = editState();
+
+ // Do nothing if this output is not enabled or there is no need to perform this update
+ if (!outputState.isEnabled || CC_LIKELY(!refreshArgs.updatingOutputGeometryThisFrame)) {
+ return;
+ }
+
+ // Process the layers to determine visibility and coverage
+ compositionengine::Output::CoverageState coverage{layerFESet};
+ collectVisibleLayers(refreshArgs, coverage);
+
+ // Compute the resulting coverage for this output, and store it for later
+ const ui::Transform& tr = outputState.transform;
+ Region undefinedRegion{outputState.bounds};
+ undefinedRegion.subtractSelf(tr.transform(coverage.aboveOpaqueLayers));
+
+ outputState.undefinedRegion = undefinedRegion;
+ outputState.dirtyRegion.orSelf(coverage.dirtyRegion);
+}
+
+void Output::collectVisibleLayers(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ compositionengine::Output::CoverageState& coverage) {
+ // Evaluate the layers from front to back to determine what is visible. This
+ // also incrementally calculates the coverage information for each layer as
+ // well as the entire output.
+ for (auto& layer : reversed(refreshArgs.layers)) {
+ // Incrementally process the coverage for each layer
+ ensureOutputLayerIfVisible(layer, coverage);
+
+ // TODO(b/121291683): Stop early if the output is completely covered and
+ // no more layers could even be visible underneath the ones on top.
+ }
+
+ setReleasedLayers(refreshArgs);
+
+ finalizePendingOutputLayers();
+
+ // Generate a simple Z-order values to each visible output layer
+ uint32_t zOrder = 0;
+ for (auto* outputLayer : getOutputLayersOrderedByZ()) {
+ outputLayer->editState().z = zOrder++;
+ }
+}
+
+void Output::ensureOutputLayerIfVisible(std::shared_ptr<compositionengine::Layer> layer,
+ compositionengine::Output::CoverageState& coverage) {
+ // Note: Converts a wp<LayerFE> to a sp<LayerFE>
+ auto layerFE = layer->getLayerFE();
+ if (layerFE == nullptr) {
+ return;
+ }
+
+ // Ensure we have a snapshot of the basic geometry layer state. Limit the
+ // snapshots to once per frame for each candidate layer, as layers may
+ // appear on multiple outputs.
+ if (!coverage.latchedLayers.count(layerFE)) {
+ coverage.latchedLayers.insert(layerFE);
+ layerFE->latchCompositionState(layer->editFEState(),
+ compositionengine::LayerFE::StateSubset::BasicGeometry);
+ }
+
+ // Obtain a read-only reference to the front-end layer state
+ const auto& layerFEState = layer->getFEState();
+
+ // Only consider the layers on the given layer stack
+ if (!belongsInOutput(layer.get())) {
+ return;
+ }
+
+ /*
+ * opaqueRegion: area of a surface that is fully opaque.
+ */
+ Region opaqueRegion;
+
+ /*
+ * visibleRegion: area of a surface that is visible on screen and not fully
+ * transparent. This is essentially the layer's footprint minus the opaque
+ * regions above it. Areas covered by a translucent surface are considered
+ * visible.
+ */
+ Region visibleRegion;
+
+ /*
+ * coveredRegion: area of a surface that is covered by all visible regions
+ * above it (which includes the translucent areas).
+ */
+ Region coveredRegion;
+
+ /*
+ * transparentRegion: area of a surface that is hinted to be completely
+ * transparent. This is only used to tell when the layer has no visible non-
+ * transparent regions and can be removed from the layer list. It does not
+ * affect the visibleRegion of this layer or any layers beneath it. The hint
+ * may not be correct if apps don't respect the SurfaceView restrictions
+ * (which, sadly, some don't).
+ */
+ Region transparentRegion;
+
+ // handle hidden surfaces by setting the visible region to empty
+ if (CC_UNLIKELY(!layerFEState.isVisible)) {
+ return;
+ }
+
+ const ui::Transform& tr = layerFEState.geomLayerTransform;
+
+ // Get the visible region
+ // TODO(b/121291683): Is it worth creating helper methods on LayerFEState
+ // for computations like this?
+ visibleRegion.set(Rect(tr.transform(layerFEState.geomLayerBounds)));
+
+ if (visibleRegion.isEmpty()) {
+ return;
+ }
+
+ // Remove the transparent area from the visible region
+ if (!layerFEState.isOpaque) {
+ if (tr.preserveRects()) {
+ // transform the transparent region
+ transparentRegion = tr.transform(layerFEState.transparentRegionHint);
+ } else {
+ // transformation too complex, can't do the
+ // transparent region optimization.
+ transparentRegion.clear();
}
}
- return createOutputLayer(mCompositionEngine, displayId, *this, layer, layerFE);
+
+ // compute the opaque region
+ const int32_t layerOrientation = tr.getOrientation();
+ if (layerFEState.isOpaque && ((layerOrientation & ui::Transform::ROT_INVALID) == 0)) {
+ // If we one of the simple category of transforms (0/90/180/270 rotation
+ // + any flip), then the opaque region is the layer's footprint.
+ // Otherwise we don't try and compute the opaque region since there may
+ // be errors at the edges, and we treat the entire layer as
+ // translucent.
+ opaqueRegion = visibleRegion;
+ }
+
+ // Clip the covered region to the visible region
+ coveredRegion = coverage.aboveCoveredLayers.intersect(visibleRegion);
+
+ // Update accumAboveCoveredLayers for next (lower) layer
+ coverage.aboveCoveredLayers.orSelf(visibleRegion);
+
+ // subtract the opaque region covered by the layers above us
+ visibleRegion.subtractSelf(coverage.aboveOpaqueLayers);
+
+ if (visibleRegion.isEmpty()) {
+ return;
+ }
+
+ // Get coverage information for the layer as previously displayed,
+ // also taking over ownership from mOutputLayersorderedByZ.
+ auto prevOutputLayerIndex = findCurrentOutputLayerForLayer(layer.get());
+ auto prevOutputLayer =
+ prevOutputLayerIndex ? getOutputLayerOrderedByZByIndex(*prevOutputLayerIndex) : nullptr;
+
+ // Get coverage information for the layer as previously displayed
+ // TODO(b/121291683): Define kEmptyRegion as a constant in Region.h
+ const Region kEmptyRegion;
+ const Region& oldVisibleRegion =
+ prevOutputLayer ? prevOutputLayer->getState().visibleRegion : kEmptyRegion;
+ const Region& oldCoveredRegion =
+ prevOutputLayer ? prevOutputLayer->getState().coveredRegion : kEmptyRegion;
+
+ // compute this layer's dirty region
+ Region dirty;
+ if (layerFEState.contentDirty) {
+ // we need to invalidate the whole region
+ dirty = visibleRegion;
+ // as well, as the old visible region
+ dirty.orSelf(oldVisibleRegion);
+ } else {
+ /* compute the exposed region:
+ * the exposed region consists of two components:
+ * 1) what's VISIBLE now and was COVERED before
+ * 2) what's EXPOSED now less what was EXPOSED before
+ *
+ * note that (1) is conservative, we start with the whole visible region
+ * but only keep what used to be covered by something -- which mean it
+ * may have been exposed.
+ *
+ * (2) handles areas that were not covered by anything but got exposed
+ * because of a resize.
+ *
+ */
+ const Region newExposed = visibleRegion - coveredRegion;
+ const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
+ dirty = (visibleRegion & oldCoveredRegion) | (newExposed - oldExposed);
+ }
+ dirty.subtractSelf(coverage.aboveOpaqueLayers);
+
+ // accumulate to the screen dirty region
+ coverage.dirtyRegion.orSelf(dirty);
+
+ // Update accumAboveOpaqueLayers for next (lower) layer
+ coverage.aboveOpaqueLayers.orSelf(opaqueRegion);
+
+ // Compute the visible non-transparent region
+ Region visibleNonTransparentRegion = visibleRegion.subtract(transparentRegion);
+
+ // Peform the final check to see if this layer is visible on this output
+ // TODO(b/121291683): Why does this not use visibleRegion? (see outputSpaceVisibleRegion below)
+ const auto& outputState = getState();
+ Region drawRegion(outputState.transform.transform(visibleNonTransparentRegion));
+ drawRegion.andSelf(outputState.bounds);
+ if (drawRegion.isEmpty()) {
+ return;
+ }
+
+ // The layer is visible. Either reuse the existing outputLayer if we have
+ // one, or create a new one if we do not.
+ auto result = ensureOutputLayer(prevOutputLayerIndex, layer, layerFE);
+
+ // Store the layer coverage information into the layer state as some of it
+ // is useful later.
+ auto& outputLayerState = result->editState();
+ outputLayerState.visibleRegion = visibleRegion;
+ outputLayerState.visibleNonTransparentRegion = visibleNonTransparentRegion;
+ outputLayerState.coveredRegion = coveredRegion;
+ outputLayerState.outputSpaceVisibleRegion = outputState.transform.transform(
+ outputLayerState.visibleRegion.intersect(outputState.viewport));
}
-void Output::setOutputLayersOrderedByZ(OutputLayers&& layers) {
- mOutputLayersOrderedByZ = std::move(layers);
+void Output::setReleasedLayers(const compositionengine::CompositionRefreshArgs&) {
+ // The base class does nothing with this call.
}
-const Output::OutputLayers& Output::getOutputLayersOrderedByZ() const {
- return mOutputLayersOrderedByZ;
+void Output::updateLayerStateFromFE(const CompositionRefreshArgs& args) const {
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ layer->getLayerFE().latchCompositionState(layer->getLayer().editFEState(),
+ args.updatingGeometryThisFrame
+ ? LayerFE::StateSubset::GeometryAndContent
+ : LayerFE::StateSubset::Content);
+ }
+}
+
+void Output::updateAndWriteCompositionState(
+ const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ if (refreshArgs.devOptForceClientComposition) {
+ layer->editState().forceClientComposition = true;
+ }
+
+ layer->updateCompositionState(refreshArgs.updatingGeometryThisFrame);
+
+ // Send the updated state to the HWC, if appropriate.
+ layer->writeStateToHWC(refreshArgs.updatingGeometryThisFrame);
+ }
+}
+
+void Output::updateColorProfile(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ setColorProfile(pickColorProfile(refreshArgs));
+}
+
+// Returns a data space that fits all visible layers. The returned data space
+// can only be one of
+// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
+// - Dataspace::DISPLAY_P3
+// - Dataspace::DISPLAY_BT2020
+// The returned HDR data space is one of
+// - Dataspace::UNKNOWN
+// - Dataspace::BT2020_HLG
+// - Dataspace::BT2020_PQ
+ui::Dataspace Output::getBestDataspace(ui::Dataspace* outHdrDataSpace,
+ bool* outIsHdrClientComposition) const {
+ ui::Dataspace bestDataSpace = ui::Dataspace::V0_SRGB;
+ *outHdrDataSpace = ui::Dataspace::UNKNOWN;
+
+ for (const auto* layer : getOutputLayersOrderedByZ()) {
+ switch (layer->getLayer().getFEState().dataspace) {
+ case ui::Dataspace::V0_SCRGB:
+ case ui::Dataspace::V0_SCRGB_LINEAR:
+ case ui::Dataspace::BT2020:
+ case ui::Dataspace::BT2020_ITU:
+ case ui::Dataspace::BT2020_LINEAR:
+ case ui::Dataspace::DISPLAY_BT2020:
+ bestDataSpace = ui::Dataspace::DISPLAY_BT2020;
+ break;
+ case ui::Dataspace::DISPLAY_P3:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ break;
+ case ui::Dataspace::BT2020_PQ:
+ case ui::Dataspace::BT2020_ITU_PQ:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ *outHdrDataSpace = ui::Dataspace::BT2020_PQ;
+ *outIsHdrClientComposition = layer->getLayer().getFEState().forceClientComposition;
+ break;
+ case ui::Dataspace::BT2020_HLG:
+ case ui::Dataspace::BT2020_ITU_HLG:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ // When there's mixed PQ content and HLG content, we set the HDR
+ // data space to be BT2020_PQ and convert HLG to PQ.
+ if (*outHdrDataSpace == ui::Dataspace::UNKNOWN) {
+ *outHdrDataSpace = ui::Dataspace::BT2020_HLG;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return bestDataSpace;
+}
+
+compositionengine::Output::ColorProfile Output::pickColorProfile(
+ const compositionengine::CompositionRefreshArgs& refreshArgs) const {
+ if (refreshArgs.outputColorSetting == OutputColorSetting::kUnmanaged) {
+ return ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC,
+ refreshArgs.colorSpaceAgnosticDataspace};
+ }
+
+ ui::Dataspace hdrDataSpace;
+ bool isHdrClientComposition = false;
+ ui::Dataspace bestDataSpace = getBestDataspace(&hdrDataSpace, &isHdrClientComposition);
+
+ switch (refreshArgs.forceOutputColorMode) {
+ case ui::ColorMode::SRGB:
+ bestDataSpace = ui::Dataspace::V0_SRGB;
+ break;
+ case ui::ColorMode::DISPLAY_P3:
+ bestDataSpace = ui::Dataspace::DISPLAY_P3;
+ break;
+ default:
+ break;
+ }
+
+ // respect hdrDataSpace only when there is no legacy HDR support
+ const bool isHdr = hdrDataSpace != ui::Dataspace::UNKNOWN &&
+ !mDisplayColorProfile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
+ if (isHdr) {
+ bestDataSpace = hdrDataSpace;
+ }
+
+ ui::RenderIntent intent;
+ switch (refreshArgs.outputColorSetting) {
+ case OutputColorSetting::kManaged:
+ case OutputColorSetting::kUnmanaged:
+ intent = isHdr ? ui::RenderIntent::TONE_MAP_COLORIMETRIC
+ : ui::RenderIntent::COLORIMETRIC;
+ break;
+ case OutputColorSetting::kEnhanced:
+ intent = isHdr ? ui::RenderIntent::TONE_MAP_ENHANCE : ui::RenderIntent::ENHANCE;
+ break;
+ default: // vendor display color setting
+ intent = static_cast<ui::RenderIntent>(refreshArgs.outputColorSetting);
+ break;
+ }
+
+ ui::ColorMode outMode;
+ ui::Dataspace outDataSpace;
+ ui::RenderIntent outRenderIntent;
+ mDisplayColorProfile->getBestColorMode(bestDataSpace, intent, &outDataSpace, &outMode,
+ &outRenderIntent);
+
+ return ColorProfile{outMode, outDataSpace, outRenderIntent,
+ refreshArgs.colorSpaceAgnosticDataspace};
+}
+
+void Output::beginFrame() {
+ auto& outputState = editState();
+ const bool dirty = !getDirtyRegion(false).isEmpty();
+ const bool empty = getOutputLayerCount() == 0;
+ const bool wasEmpty = !outputState.lastCompositionHadVisibleLayers;
+
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ const bool mustRecompose = dirty && !(empty && wasEmpty);
+
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
+ mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
+ flagPrefix[empty], flagPrefix[wasEmpty]);
+
+ mRenderSurface->beginFrame(mustRecompose);
+
+ if (mustRecompose) {
+ outputState.lastCompositionHadVisibleLayers = !empty;
+ }
+}
+
+void Output::prepareFrame() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const auto& outputState = getState();
+ if (!outputState.isEnabled) {
+ return;
+ }
+
+ chooseCompositionStrategy();
+
+ mRenderSurface->prepareFrame(outputState.usesClientComposition,
+ outputState.usesDeviceComposition);
+}
+
+void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+ if (CC_LIKELY(!refreshArgs.devOptFlashDirtyRegionsDelay)) {
+ return;
+ }
+
+ if (getState().isEnabled) {
+ // transform the dirty region into this screen's coordinate space
+ const Region dirtyRegion = getDirtyRegion(refreshArgs.repaintEverything);
+ if (!dirtyRegion.isEmpty()) {
+ base::unique_fd readyFence;
+ // redraw the whole screen
+ static_cast<void>(composeSurfaces(dirtyRegion));
+
+ mRenderSurface->queueBuffer(std::move(readyFence));
+ }
+ }
+
+ postFramebuffer();
+
+ std::this_thread::sleep_for(*refreshArgs.devOptFlashDirtyRegionsDelay);
+
+ prepareFrame();
+}
+
+void Output::finishFrame(const compositionengine::CompositionRefreshArgs&) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!getState().isEnabled) {
+ return;
+ }
+
+ // Repaint the framebuffer (if needed), getting the optional fence for when
+ // the composition completes.
+ auto optReadyFence = composeSurfaces(Region::INVALID_REGION);
+ if (!optReadyFence) {
+ return;
+ }
+
+ // swap buffers (presentation)
+ mRenderSurface->queueBuffer(std::move(*optReadyFence));
+}
+
+std::optional<base::unique_fd> Output::composeSurfaces(const Region& debugRegion) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ const auto& outputState = getState();
+ const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
+ outputState.usesClientComposition};
+ base::unique_fd readyFence;
+ if (!hasClientComposition) {
+ return readyFence;
+ }
+
+ ALOGV("hasClientComposition");
+
+ auto& renderEngine = getCompositionEngine().getRenderEngine();
+ const bool supportsProtectedContent = renderEngine.supportsProtectedContent();
+
+ renderengine::DisplaySettings clientCompositionDisplay;
+ clientCompositionDisplay.physicalDisplay = outputState.scissor;
+ clientCompositionDisplay.clip = outputState.scissor;
+ clientCompositionDisplay.globalTransform = outputState.transform.asMatrix4();
+ clientCompositionDisplay.orientation = outputState.orientation;
+ clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
+ ? outputState.dataspace
+ : ui::Dataspace::UNKNOWN;
+ clientCompositionDisplay.maxLuminance =
+ mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
+
+ // Compute the global color transform matrix.
+ if (!outputState.usesDeviceComposition && !getSkipColorTransform()) {
+ clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
+ }
+
+ // Note: Updated by generateClientCompositionRequests
+ clientCompositionDisplay.clearRegion = Region::INVALID_REGION;
+
+ // Generate the client composition requests for the layers on this output.
+ std::vector<renderengine::LayerSettings> clientCompositionLayers =
+ generateClientCompositionRequests(supportsProtectedContent,
+ clientCompositionDisplay.clearRegion);
+ appendRegionFlashRequests(debugRegion, clientCompositionLayers);
+
+ // If we the display is secure, protected content support is enabled, and at
+ // least one layer has protected content, we need to use a secure back
+ // buffer.
+ if (outputState.isSecure && supportsProtectedContent) {
+ auto layers = getOutputLayersOrderedByZ();
+ bool needsProtected = std::any_of(layers.begin(), layers.end(), [](auto* layer) {
+ return layer->getLayer().getFEState().hasProtectedContent;
+ });
+ if (needsProtected != renderEngine.isProtected()) {
+ renderEngine.useProtectedContext(needsProtected);
+ }
+ if (needsProtected != mRenderSurface->isProtected() &&
+ needsProtected == renderEngine.isProtected()) {
+ mRenderSurface->setProtected(needsProtected);
+ }
+ }
+
+ base::unique_fd fd;
+ sp<GraphicBuffer> buf = mRenderSurface->dequeueBuffer(&fd);
+ if (buf == nullptr) {
+ ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
+ "client composition for this frame",
+ mName.c_str());
+ return std::nullopt;
+ }
+
+ // We boost GPU frequency here because there will be color spaces conversion
+ // and it's expensive. We boost the GPU frequency so that GPU composition can
+ // finish in time. We must reset GPU frequency afterwards, because high frequency
+ // consumes extra battery.
+ const bool expensiveRenderingExpected =
+ clientCompositionDisplay.outputDataspace == ui::Dataspace::DISPLAY_P3;
+ if (expensiveRenderingExpected) {
+ setExpensiveRenderingExpected(true);
+ }
+
+ renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+ &readyFence);
+
+ if (expensiveRenderingExpected) {
+ setExpensiveRenderingExpected(false);
+ }
+
+ return readyFence;
+}
+
+std::vector<renderengine::LayerSettings> Output::generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) {
+ std::vector<renderengine::LayerSettings> clientCompositionLayers;
+ ALOGV("Rendering client layers");
+
+ const auto& outputState = getState();
+ const Region viewportRegion(outputState.viewport);
+ const bool useIdentityTransform = false;
+ bool firstLayer = true;
+ // Used when a layer clears part of the buffer.
+ Region dummyRegion;
+
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ const auto& layerState = layer->getState();
+ const auto& layerFEState = layer->getLayer().getFEState();
+ auto& layerFE = layer->getLayerFE();
+
+ const Region clip(viewportRegion.intersect(layerState.visibleRegion));
+ ALOGV("Layer: %s", layerFE.getDebugName());
+ if (clip.isEmpty()) {
+ ALOGV(" Skipping for empty clip");
+ firstLayer = false;
+ continue;
+ }
+
+ bool clientComposition = layer->requiresClientComposition();
+
+ // We clear the client target for non-client composed layers if
+ // requested by the HWC. We skip this if the layer is not an opaque
+ // rectangle, as by definition the layer must blend with whatever is
+ // underneath. We also skip the first layer as the buffer target is
+ // guaranteed to start out cleared.
+ bool clearClientComposition =
+ layerState.clearClientTarget && layerFEState.isOpaque && !firstLayer;
+
+ ALOGV(" Composition type: client %d clear %d", clientComposition, clearClientComposition);
+
+ if (clientComposition || clearClientComposition) {
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering() || outputState.needsFiltering,
+ outputState.isSecure,
+ supportsProtectedContent,
+ clientComposition ? clearRegion : dummyRegion,
+ };
+ if (auto result = layerFE.prepareClientComposition(targetSettings)) {
+ if (!clientComposition) {
+ auto& layerSettings = *result;
+ 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(*result);
+ }
+ }
+
+ firstLayer = false;
+ }
+
+ return clientCompositionLayers;
+}
+
+void Output::appendRegionFlashRequests(
+ const Region& flashRegion,
+ std::vector<renderengine::LayerSettings>& clientCompositionLayers) {
+ if (flashRegion.isEmpty()) {
+ return;
+ }
+
+ renderengine::LayerSettings layerSettings;
+ layerSettings.source.buffer.buffer = nullptr;
+ layerSettings.source.solidColor = half3(1.0, 0.0, 1.0);
+ layerSettings.alpha = half(1.0);
+
+ for (const auto& rect : flashRegion) {
+ layerSettings.geometry.boundaries = rect.toFloatRect();
+ clientCompositionLayers.push_back(layerSettings);
+ }
+}
+
+void Output::setExpensiveRenderingExpected(bool) {
+ // The base class does nothing with this call.
+}
+
+void Output::postFramebuffer() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!getState().isEnabled) {
+ return;
+ }
+
+ auto& outputState = editState();
+ outputState.dirtyRegion.clear();
+ mRenderSurface->flip();
+
+ auto frame = presentAndGetFrameFences();
+
+ mRenderSurface->onPresentDisplayCompleted();
+
+ for (auto* layer : getOutputLayersOrderedByZ()) {
+ // The layer buffer from the previous frame (if any) is released
+ // by HWC only when the release fence from this frame (if any) is
+ // signaled. Always get the release fence from HWC first.
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+
+ if (auto hwcLayer = layer->getHwcLayer()) {
+ if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
+ releaseFence = f->second;
+ }
+ }
+
+ // If the layer was client composited in the previous frame, we
+ // need to merge with the previous client target acquire fence.
+ // Since we do not track that, always merge with the current
+ // client target acquire fence when it is available, even though
+ // this is suboptimal.
+ // TODO(b/121291683): Track previous frame client target acquire fence.
+ if (outputState.usesClientComposition) {
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
+ }
+
+ layer->getLayerFE().onLayerDisplayed(releaseFence);
+ }
+
+ // We've got a list of layers needing fences, that are disjoint with
+ // OutputLayersOrderedByZ. The best we can do is to
+ // supply them with the present fence.
+ for (auto& weakLayer : mReleasedLayers) {
+ if (auto layer = weakLayer.promote(); layer != nullptr) {
+ layer->onLayerDisplayed(frame.presentFence);
+ }
+ }
+
+ // Clear out the released layers now that we're done with them.
+ mReleasedLayers.clear();
}
void Output::dirtyEntireOutput() {
- mState.dirtyRegion.set(mState.bounds);
+ auto& outputState = editState();
+ outputState.dirtyRegion.set(outputState.bounds);
+}
+
+void Output::chooseCompositionStrategy() {
+ // The base output implementation can only do client composition
+ auto& outputState = editState();
+ outputState.usesClientComposition = true;
+ outputState.usesDeviceComposition = false;
+}
+
+bool Output::getSkipColorTransform() const {
+ return true;
+}
+
+compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
+ compositionengine::Output::FrameFences result;
+ if (getState().usesClientComposition) {
+ result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
+ }
+ return result;
}
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 9549054..0fcc308 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -24,6 +24,10 @@
dumpVal(out, "isEnabled", isEnabled);
dumpVal(out, "isSecure", isSecure);
+ dumpVal(out, "usesClientComposition", usesClientComposition);
+ dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+ dumpVal(out, "flipClientTarget", flipClientTarget);
+
dumpVal(out, "layerStack", layerStackId);
dumpVal(out, "layerStackInternal", layerStackInternal);
@@ -43,7 +47,8 @@
dumpVal(out, "colorMode", toString(colorMode), colorMode);
dumpVal(out, "renderIntent", toString(renderIntent), renderIntent);
dumpVal(out, "dataspace", toString(dataspace), dataspace);
- dumpVal(out, "colorTransform", colorTransform);
+ dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
+ dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
out.append("\n");
}
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 5ce72b0..0124e5b 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -15,11 +15,11 @@
*/
#include <android-base/stringprintf.h>
-#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/DisplayColorProfile.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFE.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/Output.h>
-#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -44,56 +44,26 @@
} // namespace
-std::unique_ptr<compositionengine::OutputLayer> createOutputLayer(
- const CompositionEngine& compositionEngine, std::optional<DisplayId> displayId,
- const compositionengine::Output& output, std::shared_ptr<compositionengine::Layer> layer,
- sp<compositionengine::LayerFE> layerFE) {
- auto result = std::make_unique<OutputLayer>(output, layer, layerFE);
- result->initialize(compositionEngine, displayId);
- return result;
+std::unique_ptr<OutputLayer> createOutputLayer(
+ const compositionengine::Output& output,
+ const std::shared_ptr<compositionengine::Layer>& layer,
+ const sp<compositionengine::LayerFE>& layerFE) {
+ return createOutputLayerTemplated<OutputLayer>(output, layer, layerFE);
}
-OutputLayer::OutputLayer(const Output& output, std::shared_ptr<Layer> layer, sp<LayerFE> layerFE)
- : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
-
OutputLayer::~OutputLayer() = default;
-void OutputLayer::initialize(const CompositionEngine& compositionEngine,
- std::optional<DisplayId> displayId) {
- if (!displayId) {
- return;
+void OutputLayer::setHwcLayer(std::shared_ptr<HWC2::Layer> hwcLayer) {
+ auto& state = editState();
+ if (hwcLayer) {
+ state.hwc.emplace(std::move(hwcLayer));
+ } else {
+ state.hwc.reset();
}
-
- auto& hwc = compositionEngine.getHwComposer();
-
- mState.hwc.emplace(std::shared_ptr<HWC2::Layer>(hwc.createLayer(*displayId),
- [&hwc, displayId](HWC2::Layer* layer) {
- hwc.destroyLayer(*displayId, layer);
- }));
-}
-
-const compositionengine::Output& OutputLayer::getOutput() const {
- return mOutput;
-}
-
-compositionengine::Layer& OutputLayer::getLayer() const {
- return *mLayer;
-}
-
-compositionengine::LayerFE& OutputLayer::getLayerFE() const {
- return *mLayerFE;
-}
-
-const OutputLayerCompositionState& OutputLayer::getState() const {
- return mState;
-}
-
-OutputLayerCompositionState& OutputLayer::editState() {
- return mState;
}
Rect OutputLayer::calculateInitialCrop() const {
- const auto& layerState = mLayer->getState().frontEnd;
+ const auto& layerState = getLayer().getFEState();
// apply the projection's clipping to the window crop in
// layerstack space, and convert-back to layer space.
@@ -101,9 +71,9 @@
// pixels in the buffer.
FloatRect activeCropFloat =
- reduce(layerState.geomLayerBounds, layerState.geomActiveTransparentRegion);
+ reduce(layerState.geomLayerBounds, layerState.transparentRegionHint);
- const Rect& viewport = mOutput.getState().viewport;
+ const Rect& viewport = getOutput().getState().viewport;
const ui::Transform& layerTransform = layerState.geomLayerTransform;
const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
// Transform to screen space.
@@ -126,8 +96,8 @@
}
FloatRect OutputLayer::calculateOutputSourceCrop() const {
- const auto& layerState = mLayer->getState().frontEnd;
- const auto& outputState = mOutput.getState();
+ const auto& layerState = getLayer().getFEState();
+ const auto& outputState = getOutput().getState();
if (!layerState.geomUsesSourceCrop) {
return {};
@@ -203,12 +173,12 @@
}
Rect OutputLayer::calculateOutputDisplayFrame() const {
- const auto& layerState = mLayer->getState().frontEnd;
- const auto& outputState = mOutput.getState();
+ const auto& layerState = getLayer().getFEState();
+ const auto& outputState = getOutput().getState();
// apply the layer's transform, followed by the display's global transform
// here we're guaranteed that the layer's transform preserves rects
- Region activeTransparentRegion = layerState.geomActiveTransparentRegion;
+ Region activeTransparentRegion = layerState.transparentRegionHint;
const ui::Transform& layerTransform = layerState.geomLayerTransform;
const ui::Transform& inverseLayerTransform = layerState.geomInverseLayerTransform;
const Rect& bufferSize = layerState.geomBufferSize;
@@ -250,8 +220,8 @@
}
uint32_t OutputLayer::calculateOutputRelativeBufferTransform() const {
- const auto& layerState = mLayer->getState().frontEnd;
- const auto& outputState = mOutput.getState();
+ const auto& layerState = getLayer().getFEState();
+ const auto& outputState = getOutput().getState();
/*
* Transformations are applied in this order:
@@ -290,98 +260,379 @@
} // namespace impl
void OutputLayer::updateCompositionState(bool includeGeometry) {
+ const auto& layerFEState = getLayer().getFEState();
+ const auto& outputState = getOutput().getState();
+ const auto& profile = *getOutput().getDisplayColorProfile();
+ auto& state = editState();
+
if (includeGeometry) {
- mState.displayFrame = calculateOutputDisplayFrame();
- mState.sourceCrop = calculateOutputSourceCrop();
- mState.bufferTransform =
+ // Clear the forceClientComposition flag before it is set for any
+ // reason. Note that since it can be set by some checks below when
+ // updating the geometry state, we only clear it when updating the
+ // geometry since those conditions for forcing client composition won't
+ // go away otherwise.
+ state.forceClientComposition = false;
+
+ state.displayFrame = calculateOutputDisplayFrame();
+ state.sourceCrop = calculateOutputSourceCrop();
+ state.bufferTransform =
static_cast<Hwc2::Transform>(calculateOutputRelativeBufferTransform());
- if ((mLayer->getState().frontEnd.isSecure && !mOutput.getState().isSecure) ||
- (mState.bufferTransform & ui::Transform::ROT_INVALID)) {
- mState.forceClientComposition = true;
+ if ((layerFEState.isSecure && !outputState.isSecure) ||
+ (state.bufferTransform & ui::Transform::ROT_INVALID)) {
+ state.forceClientComposition = true;
+ }
+ }
+
+ // Determine the output dependent dataspace for this layer. If it is
+ // colorspace agnostic, it just uses the dataspace chosen for the output to
+ // avoid the need for color conversion.
+ state.dataspace = layerFEState.isColorspaceAgnostic &&
+ outputState.targetDataspace != ui::Dataspace::UNKNOWN
+ ? outputState.targetDataspace
+ : layerFEState.dataspace;
+
+ // These are evaluated every frame as they can potentially change at any
+ // time.
+ if (layerFEState.forceClientComposition || !profile.isDataspaceSupported(state.dataspace)) {
+ state.forceClientComposition = true;
+ }
+}
+
+void OutputLayer::writeStateToHWC(bool includeGeometry) {
+ const auto& state = getState();
+ // Skip doing this if there is no HWC interface
+ if (!state.hwc) {
+ return;
+ }
+
+ auto& hwcLayer = (*state.hwc).hwcLayer;
+ if (!hwcLayer) {
+ ALOGE("[%s] failed to write composition state to HWC -- no hwcLayer for output %s",
+ getLayerFE().getDebugName(), getOutput().getName().c_str());
+ return;
+ }
+
+ const auto& outputIndependentState = getLayer().getFEState();
+ auto requestedCompositionType = outputIndependentState.compositionType;
+
+ if (includeGeometry) {
+ writeOutputDependentGeometryStateToHWC(hwcLayer.get(), requestedCompositionType);
+ writeOutputIndependentGeometryStateToHWC(hwcLayer.get(), outputIndependentState);
+ }
+
+ writeOutputDependentPerFrameStateToHWC(hwcLayer.get());
+ writeOutputIndependentPerFrameStateToHWC(hwcLayer.get(), outputIndependentState);
+
+ writeCompositionTypeToHWC(hwcLayer.get(), requestedCompositionType);
+}
+
+void OutputLayer::writeOutputDependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ const auto& outputDependentState = getState();
+
+ if (auto error = hwcLayer->setDisplayFrame(outputDependentState.displayFrame);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
+ getLayerFE().getDebugName(), outputDependentState.displayFrame.left,
+ outputDependentState.displayFrame.top, outputDependentState.displayFrame.right,
+ outputDependentState.displayFrame.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setSourceCrop(outputDependentState.sourceCrop);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
+ "%s (%d)",
+ getLayerFE().getDebugName(), outputDependentState.sourceCrop.left,
+ outputDependentState.sourceCrop.top, outputDependentState.sourceCrop.right,
+ outputDependentState.sourceCrop.bottom, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setZOrder(outputDependentState.z); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set Z %u: %s (%d)", getLayerFE().getDebugName(),
+ outputDependentState.z, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ // Solid-color layers should always use an identity transform.
+ const auto bufferTransform =
+ requestedCompositionType != Hwc2::IComposerClient::Composition::SOLID_COLOR
+ ? outputDependentState.bufferTransform
+ : static_cast<Hwc2::Transform>(0);
+ if (auto error = hwcLayer->setTransform(static_cast<HWC2::Transform>(bufferTransform));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set transform %s: %s (%d)", getLayerFE().getDebugName(),
+ toString(outputDependentState.bufferTransform).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentGeometryStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setBlendMode(
+ static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set blend mode %s: %s (%d)", getLayerFE().getDebugName(),
+ toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", getLayerFE().getDebugName(),
+ outputIndependentState.alpha, to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set info %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputDependentPerFrameStateToHWC(HWC2::Layer* hwcLayer) {
+ const auto& outputDependentState = getState();
+
+ // TODO(lpique): b/121291683 outputSpaceVisibleRegion is output-dependent geometry
+ // state and should not change every frame.
+ if (auto error = hwcLayer->setVisibleRegion(outputDependentState.outputSpaceVisibleRegion);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set visible region: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputDependentState.outputSpaceVisibleRegion.dump(LOG_TAG);
+ }
+
+ if (auto error = hwcLayer->setDataspace(outputDependentState.dataspace);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set dataspace %d: %s (%d)", getLayerFE().getDebugName(),
+ outputDependentState.dataspace, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeOutputIndependentPerFrameStateToHWC(
+ HWC2::Layer* hwcLayer, const LayerFECompositionState& outputIndependentState) {
+ switch (auto error = hwcLayer->setColorTransform(outputIndependentState.colorTransform)) {
+ case HWC2::Error::None:
+ break;
+ case HWC2::Error::Unsupported:
+ editState().forceClientComposition = true;
+ break;
+ default:
+ ALOGE("[%s] Failed to set color transform: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ if (auto error = hwcLayer->setSurfaceDamage(outputIndependentState.surfaceDamage);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set surface damage: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ outputIndependentState.surfaceDamage.dump(LOG_TAG);
+ }
+
+ // Content-specific per-frame state
+ switch (outputIndependentState.compositionType) {
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ writeSolidColorStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ writeSidebandStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ writeBufferStateToHWC(hwcLayer, outputIndependentState);
+ break;
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ // Ignored
+ break;
+ }
+}
+
+void OutputLayer::writeSolidColorStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.r)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.g)),
+ static_cast<uint8_t>(std::round(255.0f * outputIndependentState.color.b)),
+ 255};
+
+ if (auto error = hwcLayer->setColor(color); error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set color: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeSidebandStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ if (auto error = hwcLayer->setSidebandStream(outputIndependentState.sidebandStream->handle());
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", getLayerFE().getDebugName(),
+ outputIndependentState.sidebandStream->handle(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeBufferStateToHWC(HWC2::Layer* hwcLayer,
+ const LayerFECompositionState& outputIndependentState) {
+ auto supportedPerFrameMetadata =
+ getOutput().getDisplayColorProfile()->getSupportedPerFrameMetadata();
+ if (auto error = hwcLayer->setPerFrameMetadata(supportedPerFrameMetadata,
+ outputIndependentState.hdrMetadata);
+ error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+ ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", getLayerFE().getDebugName(),
+ to_string(error).c_str(), static_cast<int32_t>(error));
+ }
+
+ uint32_t hwcSlot = 0;
+ sp<GraphicBuffer> hwcBuffer;
+ // We need access to the output-dependent state for the buffer cache there,
+ // though otherwise the buffer is not output-dependent.
+ editState().hwc->hwcBufferCache.getHwcBuffer(outputIndependentState.bufferSlot,
+ outputIndependentState.buffer, &hwcSlot,
+ &hwcBuffer);
+
+ if (auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, outputIndependentState.acquireFence);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set buffer %p: %s (%d)", getLayerFE().getDebugName(),
+ outputIndependentState.buffer->handle, to_string(error).c_str(),
+ static_cast<int32_t>(error));
+ }
+}
+
+void OutputLayer::writeCompositionTypeToHWC(
+ HWC2::Layer* hwcLayer, Hwc2::IComposerClient::Composition requestedCompositionType) {
+ auto& outputDependentState = editState();
+
+ // If we are forcing client composition, we need to tell the HWC
+ if (outputDependentState.forceClientComposition) {
+ requestedCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+ }
+
+ // Set the requested composition type with the HWC whenever it changes
+ if (outputDependentState.hwc->hwcCompositionType != requestedCompositionType) {
+ outputDependentState.hwc->hwcCompositionType = requestedCompositionType;
+
+ if (auto error = hwcLayer->setCompositionType(
+ static_cast<HWC2::Composition>(requestedCompositionType));
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set composition type %s: %s (%d)", getLayerFE().getDebugName(),
+ toString(requestedCompositionType).c_str(), to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
}
}
-void OutputLayer::writeStateToHWC(bool includeGeometry) const {
+void OutputLayer::writeCursorPositionToHWC() const {
// Skip doing this if there is no HWC interface
- if (!mState.hwc) {
- return;
- }
-
- auto& hwcLayer = (*mState.hwc).hwcLayer;
+ auto hwcLayer = getHwcLayer();
if (!hwcLayer) {
- ALOGE("[%s] failed to write composition state to HWC -- no hwcLayer for output %s",
- mLayerFE->getDebugName(), mOutput.getName().c_str());
return;
}
- if (includeGeometry) {
- // Output dependent state
+ const auto& layerFEState = getLayer().getFEState();
+ const auto& outputState = getOutput().getState();
- if (auto error = hwcLayer->setDisplayFrame(mState.displayFrame);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)",
- mLayerFE->getDebugName(), mState.displayFrame.left, mState.displayFrame.top,
- mState.displayFrame.right, mState.displayFrame.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ Rect frame = layerFEState.cursorFrame;
+ frame.intersect(outputState.viewport, &frame);
+ Rect position = outputState.transform.transform(frame);
- if (auto error = hwcLayer->setSourceCrop(mState.sourceCrop); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
- "%s (%d)",
- mLayerFE->getDebugName(), mState.sourceCrop.left, mState.sourceCrop.top,
- mState.sourceCrop.right, mState.sourceCrop.bottom, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error = hwcLayer->setZOrder(mState.z); error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set Z %u: %s (%d)", mLayerFE->getDebugName(), mState.z,
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
-
- if (auto error =
- hwcLayer->setTransform(static_cast<HWC2::Transform>(mState.bufferTransform));
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set transform %s: %s (%d)", mLayerFE->getDebugName(),
- toString(mState.bufferTransform).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- // Output independent state
-
- const auto& outputIndependentState = mLayer->getState().frontEnd;
-
- if (auto error = hwcLayer->setBlendMode(
- static_cast<HWC2::BlendMode>(outputIndependentState.blendMode));
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set blend mode %s: %s (%d)", mLayerFE->getDebugName(),
- toString(outputIndependentState.blendMode).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error = hwcLayer->setPlaneAlpha(outputIndependentState.alpha);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set plane alpha %.3f: %s (%d)", mLayerFE->getDebugName(),
- outputIndependentState.alpha, to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
-
- if (auto error =
- hwcLayer->setInfo(outputIndependentState.type, outputIndependentState.appId);
- error != HWC2::Error::None) {
- ALOGE("[%s] Failed to set info %s (%d)", mLayerFE->getDebugName(),
- to_string(error).c_str(), static_cast<int32_t>(error));
- }
+ if (auto error = hwcLayer->setCursorPosition(position.left, position.top);
+ error != HWC2::Error::None) {
+ ALOGE("[%s] Failed to set cursor position to (%d, %d): %s (%d)",
+ getLayerFE().getDebugName(), position.left, position.top, to_string(error).c_str(),
+ static_cast<int32_t>(error));
}
}
+HWC2::Layer* OutputLayer::getHwcLayer() const {
+ const auto& state = getState();
+ return state.hwc ? state.hwc->hwcLayer.get() : nullptr;
+}
+
+bool OutputLayer::requiresClientComposition() const {
+ const auto& state = getState();
+ return !state.hwc ||
+ state.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
+}
+
+bool OutputLayer::isHardwareCursor() const {
+ const auto& state = getState();
+ return state.hwc && state.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CURSOR;
+}
+
+void OutputLayer::detectDisallowedCompositionTypeChange(
+ Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const {
+ bool result = false;
+ switch (from) {
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ result = false;
+ break;
+
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ result = (to == Hwc2::IComposerClient::Composition::CLIENT);
+ break;
+
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ result = (to == Hwc2::IComposerClient::Composition::CLIENT ||
+ to == Hwc2::IComposerClient::Composition::DEVICE);
+ break;
+ }
+
+ if (!result) {
+ ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)",
+ getLayerFE().getDebugName(), toString(from).c_str(), static_cast<int>(from),
+ toString(to).c_str(), static_cast<int>(to));
+ }
+}
+
+void OutputLayer::applyDeviceCompositionTypeChange(
+ Hwc2::IComposerClient::Composition compositionType) {
+ auto& state = editState();
+ LOG_FATAL_IF(!state.hwc);
+ auto& hwcState = *state.hwc;
+
+ detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+
+ hwcState.hwcCompositionType = compositionType;
+}
+
+void OutputLayer::prepareForDeviceLayerRequests() {
+ auto& state = editState();
+ state.clearClientTarget = false;
+}
+
+void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) {
+ auto& state = editState();
+ switch (request) {
+ case Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET:
+ state.clearClientTarget = true;
+ break;
+
+ default:
+ ALOGE("[%s] Unknown device layer request %s (%d)", getLayerFE().getDebugName(),
+ toString(request).c_str(), static_cast<int>(request));
+ break;
+ }
+}
+
+bool OutputLayer::needsFiltering() const {
+ const auto& state = getState();
+ const auto& displayFrame = state.displayFrame;
+ const auto& sourceCrop = state.sourceCrop;
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
+ sourceCrop.getWidth() != displayFrame.getWidth();
+}
+
void OutputLayer::dump(std::string& out) const {
using android::base::StringAppendF;
- StringAppendF(&out, " - Output Layer %p (Composition layer %p) (%s)\n", this, mLayer.get(),
- mLayerFE->getDebugName());
- mState.dump(out);
+ StringAppendF(&out, " - Output Layer %p (Composition layer %p) (%s)\n", this, &getLayer(),
+ getLayerFE().getDebugName());
+ dumpState(out);
}
} // namespace impl
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index 861ea57..ad668b6 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -42,11 +42,21 @@
dumpVal(out, "visibleRegion", visibleRegion);
out.append(" ");
+ dumpVal(out, "visibleNonTransparentRegion", visibleNonTransparentRegion);
+
+ out.append(" ");
+ dumpVal(out, "coveredRegion", coveredRegion);
+
+ out.append(" ");
+ dumpVal(out, "output visibleRegion", outputSpaceVisibleRegion);
+
+ out.append(" ");
dumpVal(out, "forceClientComposition", forceClientComposition);
dumpVal(out, "clearClientTarget", clearClientTarget);
dumpVal(out, "displayFrame", displayFrame);
dumpVal(out, "sourceCrop", sourceCrop);
dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
+ dumpVal(out, "dataspace", toString(dataspace), dataspace);
dumpVal(out, "z-index", z);
if (hwc) {
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 3fcd9d1..5ed21fc 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -23,6 +23,7 @@
#include <compositionengine/DisplaySurface.h>
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
#include <log/log.h>
#include <renderengine/RenderEngine.h>
@@ -42,12 +43,13 @@
std::unique_ptr<compositionengine::RenderSurface> createRenderSurface(
const compositionengine::CompositionEngine& compositionEngine,
- compositionengine::Display& display, compositionengine::RenderSurfaceCreationArgs&& args) {
- return std::make_unique<RenderSurface>(compositionEngine, display, std::move(args));
+ compositionengine::Display& display,
+ const compositionengine::RenderSurfaceCreationArgs& args) {
+ return std::make_unique<RenderSurface>(compositionEngine, display, args);
}
RenderSurface::RenderSurface(const CompositionEngine& compositionEngine, Display& display,
- RenderSurfaceCreationArgs&& args)
+ const RenderSurfaceCreationArgs& args)
: mCompositionEngine(compositionEngine),
mDisplay(display),
mNativeWindow(args.nativeWindow),
@@ -110,24 +112,13 @@
return mDisplaySurface->beginFrame(mustRecompose);
}
-status_t RenderSurface::prepareFrame() {
- auto& hwc = mCompositionEngine.getHwComposer();
- const auto id = mDisplay.getId();
- if (id) {
- status_t error = hwc.prepare(*id, mDisplay);
- if (error != NO_ERROR) {
- return error;
- }
- }
-
+void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) {
DisplaySurface::CompositionType compositionType;
- const bool hasClient = hwc.hasClientComposition(id);
- const bool hasDevice = hwc.hasDeviceComposition(id);
- if (hasClient && hasDevice) {
+ if (usesClientComposition && usesDeviceComposition) {
compositionType = DisplaySurface::COMPOSITION_MIXED;
- } else if (hasClient) {
+ } else if (usesClientComposition) {
compositionType = DisplaySurface::COMPOSITION_GLES;
- } else if (hasDevice) {
+ } else if (usesDeviceComposition) {
compositionType = DisplaySurface::COMPOSITION_HWC;
} else {
// Nothing to do -- when turning the screen off we get a frame like
@@ -135,7 +126,11 @@
// will do a prepare/set cycle.
compositionType = DisplaySurface::COMPOSITION_HWC;
}
- return mDisplaySurface->prepareFrame(compositionType);
+
+ if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) {
+ ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result,
+ strerror(-result));
+ }
}
sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
@@ -162,11 +157,10 @@
return mGraphicBuffer;
}
-void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
- auto& hwc = mCompositionEngine.getHwComposer();
- const auto id = mDisplay.getId();
+void RenderSurface::queueBuffer(base::unique_fd readyFence) {
+ auto& state = mDisplay.getState();
- if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ if (state.usesClientComposition || state.flipClientTarget) {
// hasFlipClientTargetRequest could return true even if we haven't
// dequeued a buffer before. Try dequeueing one if we don't have a
// buffer ready.
@@ -215,13 +209,6 @@
mDisplaySurface->onFrameCommitted();
}
-void RenderSurface::setViewportAndProjection() {
- auto& renderEngine = mCompositionEngine.getRenderEngine();
- Rect sourceCrop = Rect(mSize);
- renderEngine.setViewportAndProjection(mSize.width, mSize.height, sourceCrop,
- ui::Transform::ROT_0);
-}
-
void RenderSurface::flip() {
mPageFlipCount++;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
index 3766f27..0dbf8f0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/CompositionEngineTest.cpp
@@ -14,7 +14,11 @@
* limitations under the License.
*/
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/impl/CompositionEngine.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
+#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
@@ -23,19 +27,19 @@
namespace android::compositionengine {
namespace {
+using ::testing::_;
+using ::testing::Return;
+using ::testing::SaveArg;
using ::testing::StrictMock;
class CompositionEngineTest : public testing::Test {
public:
- ~CompositionEngineTest() override;
- mock::HWComposer* mHwc = new StrictMock<mock::HWComposer>();
+ android::mock::HWComposer* mHwc = new StrictMock<android::mock::HWComposer>();
renderengine::mock::RenderEngine* mRenderEngine =
new StrictMock<renderengine::mock::RenderEngine>();
impl::CompositionEngine mEngine;
};
-CompositionEngineTest::~CompositionEngineTest() = default;
-
TEST_F(CompositionEngineTest, canInstantiateCompositionEngine) {
auto engine = impl::createCompositionEngine();
EXPECT_TRUE(engine.get() != nullptr);
@@ -53,5 +57,84 @@
EXPECT_EQ(mRenderEngine, &mEngine.getRenderEngine());
}
+/*
+ * CompositionEngine::preComposition
+ */
+
+class PreCompositionTest : public CompositionEngineTest {
+public:
+ PreCompositionTest() {
+ EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(Return(mLayer1FE));
+ EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(Return(mLayer2FE));
+ EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(Return(mLayer3FE));
+ // getLayerFE() can return nullptr. Ensure that this is handled.
+ EXPECT_CALL(*mLayer4, getLayerFE()).WillRepeatedly(Return(nullptr));
+
+ mRefreshArgs.outputs = {mOutput};
+ mRefreshArgs.layers = {mLayer1, mLayer2, mLayer3, mLayer4};
+ }
+
+ std::shared_ptr<mock::Output> mOutput{std::make_shared<StrictMock<mock::Output>>()};
+ std::shared_ptr<mock::Layer> mLayer1{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer2{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer3{std::make_shared<StrictMock<mock::Layer>>()};
+ std::shared_ptr<mock::Layer> mLayer4{std::make_shared<StrictMock<mock::Layer>>()};
+ sp<StrictMock<mock::LayerFE>> mLayer1FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer2FE{new StrictMock<mock::LayerFE>()};
+ sp<StrictMock<mock::LayerFE>> mLayer3FE{new StrictMock<mock::LayerFE>()};
+
+ CompositionRefreshArgs mRefreshArgs;
+};
+
+TEST_F(PreCompositionTest, preCompositionSetsFrameTimestamp) {
+ const nsecs_t before = systemTime(SYSTEM_TIME_MONOTONIC);
+ CompositionRefreshArgs emptyArgs;
+ mEngine.preComposition(emptyArgs);
+ const nsecs_t after = systemTime(SYSTEM_TIME_MONOTONIC);
+
+ // The frame timestamp should be between the before and after timestamps
+ EXPECT_GE(mEngine.getLastFrameRefreshTimestamp(), before);
+ EXPECT_LE(mEngine.getLastFrameRefreshTimestamp(), after);
+}
+
+TEST_F(PreCompositionTest, preCompositionInvokesLayerPreCompositionWithFrameTimestamp) {
+ nsecs_t ts1 = 0;
+ nsecs_t ts2 = 0;
+ nsecs_t ts3 = 0;
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts1), Return(false)));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts2), Return(false)));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(DoAll(SaveArg<0>(&ts3), Return(false)));
+
+ mEngine.preComposition(mRefreshArgs);
+
+ // Each of the onPreComposition calls should used the same refresh timestamp
+ EXPECT_EQ(ts1, mEngine.getLastFrameRefreshTimestamp());
+ EXPECT_EQ(ts2, mEngine.getLastFrameRefreshTimestamp());
+ EXPECT_EQ(ts3, mEngine.getLastFrameRefreshTimestamp());
+}
+
+TEST_F(PreCompositionTest, preCompositionDefaultsToNoUpdateNeeded) {
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+
+ mEngine.setNeedsAnotherUpdateForTest(true);
+
+ mEngine.preComposition(mRefreshArgs);
+
+ // The call should have cleared the needsAnotherUpdate flag
+ EXPECT_FALSE(mEngine.needsAnotherUpdate());
+}
+
+TEST_F(PreCompositionTest, preCompositionSetsNeedsAnotherUpdateIfAtLeastOneLayerRequestsIt) {
+ EXPECT_CALL(*mLayer1FE, onPreComposition(_)).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2FE, onPreComposition(_)).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3FE, onPreComposition(_)).WillOnce(Return(false));
+
+ mEngine.preComposition(mRefreshArgs);
+
+ EXPECT_TRUE(mEngine.needsAnotherUpdate());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
index 9215884..c07dfbb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayColorProfileTest.cpp
@@ -638,5 +638,66 @@
checkGetBestColorMode(profile, expectedResults);
}
+/*
+ * RenderSurface::isDataspaceSupported()
+ */
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithNoHdrSupport) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHdr10Support) {
+ auto profile = ProfileFactory::createProfileWithSRGBColorModeSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+TEST_F(DisplayColorProfileTest, isDataspaceSupportedWorksForProfileWithHlgSupport) {
+ auto profile = ProfileFactory::createProfileWithBT2100PQSupport();
+
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::UNKNOWN));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::V0_SRGB));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_PQ));
+ EXPECT_FALSE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_PQ));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_HLG));
+ EXPECT_TRUE(profile.isDataspaceSupported(Dataspace::BT2020_ITU_HLG));
+}
+
+/*
+ * RenderSurface::getTargetDataspace()
+ */
+
+TEST_F(DisplayColorProfileTest, getTargetDataspaceWorks) {
+ auto profile = ProfileFactory::createProfileWithNoColorModeSupport();
+
+ // For a non-HDR colorspace with no colorSpaceAgnosticDataspace override,
+ // the input dataspace should be returned.
+ EXPECT_EQ(Dataspace::DISPLAY_P3,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::UNKNOWN));
+
+ // If colorSpaceAgnosticDataspace is set, its value should be returned
+ EXPECT_EQ(Dataspace::V0_SRGB,
+ profile.getTargetDataspace(ColorMode::DISPLAY_P3, Dataspace::DISPLAY_P3,
+ Dataspace::V0_SRGB));
+
+ // For an HDR colorspace, Dataspace::UNKNOWN should be returned.
+ EXPECT_EQ(Dataspace::UNKNOWN,
+ profile.getTargetDataspace(ColorMode::BT2100_PQ, Dataspace::BT2020_PQ,
+ Dataspace::UNKNOWN));
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 33444a5..4d71d43 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -22,33 +22,79 @@
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/Display.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
+#include <compositionengine/mock/Layer.h>
+#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/NativeWindow.h>
+#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include "MockHWC2.h"
#include "MockHWComposer.h"
+#include "MockPowerAdvisor.h"
namespace android::compositionengine {
namespace {
+using testing::_;
+using testing::DoAll;
using testing::Return;
using testing::ReturnRef;
+using testing::Sequence;
+using testing::SetArgPointee;
using testing::StrictMock;
constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
-class DisplayTest : public testing::Test {
-public:
- ~DisplayTest() override = default;
+struct DisplayTest : public testing::Test {
+ class Display : public impl::Display {
+ public:
+ explicit Display(const compositionengine::DisplayCreationArgs& args)
+ : impl::Display(args) {}
+
+ using impl::Display::injectOutputLayerForTest;
+ virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0;
+ };
+
+ static std::shared_ptr<Display> createDisplay(
+ const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::DisplayCreationArgs&& args) {
+ return impl::createDisplayTemplated<Display>(compositionEngine, args);
+ }
+
+ DisplayTest() {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(*mLayer1, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer1));
+ EXPECT_CALL(*mLayer2, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer2));
+ EXPECT_CALL(*mLayer3, getHwcLayer()).WillRepeatedly(Return(nullptr));
+
+ mDisplay->injectOutputLayerForTest(
+ std::unique_ptr<compositionengine::OutputLayer>(mLayer1));
+ mDisplay->injectOutputLayerForTest(
+ std::unique_ptr<compositionengine::OutputLayer>(mLayer2));
+ mDisplay->injectOutputLayerForTest(
+ std::unique_ptr<compositionengine::OutputLayer>(mLayer3));
+ }
StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<Hwc2::mock::PowerAdvisor> mPowerAdvisor;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
- impl::Display mDisplay{mCompositionEngine,
- DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+ StrictMock<HWC2::mock::Layer> mHWC2Layer1;
+ StrictMock<HWC2::mock::Layer> mHWC2Layer2;
+ StrictMock<HWC2::mock::Layer> mHWC2LayerUnknown;
+ mock::OutputLayer* mLayer1 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
+ std::shared_ptr<Display> mDisplay = createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder()
+ .setDisplayId(DEFAULT_DISPLAY_ID)
+ .setPowerAdvisor(&mPowerAdvisor)
+ .build());
};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -65,12 +111,10 @@
{
constexpr DisplayId display2 = DisplayId{546u};
- auto display = impl::createDisplay(mCompositionEngine,
- DisplayCreationArgsBuilder()
- .setIsSecure(true)
- .setDisplayId(display2)
- .build());
- EXPECT_TRUE(display->isSecure());
+ auto display =
+ impl::createDisplay(mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(display2).build());
+ EXPECT_FALSE(display->isSecure());
EXPECT_FALSE(display->isVirtual());
EXPECT_EQ(display2, display->getId());
}
@@ -88,73 +132,79 @@
}
}
-/* ------------------------------------------------------------------------
+/*
* Display::disconnect()
*/
TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
// The first call to disconnect will disconnect the display with the HWC and
// set mHwcId to -1.
EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
- mDisplay.disconnect();
- EXPECT_FALSE(mDisplay.getId());
+ mDisplay->disconnect();
+ EXPECT_FALSE(mDisplay->getId());
// Subsequent calls will do nothing,
EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(0);
- mDisplay.disconnect();
- EXPECT_FALSE(mDisplay.getId());
+ mDisplay->disconnect();
+ EXPECT_FALSE(mDisplay->getId());
}
-/* ------------------------------------------------------------------------
+/*
* Display::setColorTransform()
*/
TEST_F(DisplayTest, setColorTransformSetsTransform) {
+ // No change does nothing
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = std::nullopt;
+ mDisplay->setColorTransform(refreshArgs);
+
// Identity matrix sets an identity state value
- const mat4 identity;
+ const mat4 kIdentity;
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kIdentity)).Times(1);
- EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
-
- mDisplay.setColorTransform(identity);
-
- EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mDisplay.getState().colorTransform);
+ refreshArgs.colorTransformMatrix = kIdentity;
+ mDisplay->setColorTransform(refreshArgs);
// Non-identity matrix sets a non-identity state value
- const mat4 nonIdentity = mat4() * 2;
+ const mat4 kNonIdentity = mat4() * 2;
- EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, nonIdentity)).Times(1);
+ EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, kNonIdentity)).Times(1);
- mDisplay.setColorTransform(nonIdentity);
-
- EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
+ refreshArgs.colorTransformMatrix = kNonIdentity;
+ mDisplay->setColorTransform(refreshArgs);
}
-/* ------------------------------------------------------------------------
+/*
* Display::setColorMode()
*/
TEST_F(DisplayTest, setColorModeSetsModeUnlessNoChange) {
- mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
- mDisplay.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ using ColorProfile = Output::ColorProfile;
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mDisplay->setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
+
+ EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
+ .WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
// These values are expected to be the initial state.
- ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
- ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
- ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ ASSERT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace);
+ ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent);
+ ASSERT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace);
// Otherwise if the values are unchanged, nothing happens
- mDisplay.setColorMode(ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
- ui::RenderIntent::COLORIMETRIC);
+ mDisplay->setColorProfile(ColorProfile{ui::ColorMode::NATIVE, ui::Dataspace::UNKNOWN,
+ ui::RenderIntent::COLORIMETRIC, ui::Dataspace::UNKNOWN});
- EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay.getState().colorMode);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().dataspace);
- EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay.getState().renderIntent);
+ EXPECT_EQ(ui::ColorMode::NATIVE, mDisplay->getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, mDisplay->getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace);
// Otherwise if the values are different, updates happen
EXPECT_CALL(*renderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
@@ -163,47 +213,559 @@
ui::RenderIntent::TONE_MAP_COLORIMETRIC))
.Times(1);
- mDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ mDisplay->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::Dataspace::UNKNOWN});
- 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);
+ 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);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay->getState().targetDataspace);
}
TEST_F(DisplayTest, setColorModeDoesNothingForVirtualDisplay) {
- impl::Display virtualDisplay{mCompositionEngine,
- DisplayCreationArgs{false, true, DEFAULT_DISPLAY_ID}};
+ using ColorProfile = Output::ColorProfile;
- virtualDisplay.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ std::shared_ptr<impl::Display> virtualDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgs{true, DEFAULT_DISPLAY_ID})};
- EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay.getState().colorMode);
- EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay.getState().dataspace);
- EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay.getState().renderIntent);
+ mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
+ virtualDisplay->setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(colorProfile));
+
+ EXPECT_CALL(*colorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
+
+ virtualDisplay->setColorProfile(
+ ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC, ui::Dataspace::UNKNOWN});
+
+ EXPECT_EQ(ui::ColorMode::NATIVE, virtualDisplay->getState().colorMode);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().dataspace);
+ EXPECT_EQ(ui::RenderIntent::COLORIMETRIC, virtualDisplay->getState().renderIntent);
+ EXPECT_EQ(ui::Dataspace::UNKNOWN, virtualDisplay->getState().targetDataspace);
}
-/* ------------------------------------------------------------------------
+/*
* Display::createDisplayColorProfile()
*/
TEST_F(DisplayTest, createDisplayColorProfileSetsDisplayColorProfile) {
- EXPECT_TRUE(mDisplay.getDisplayColorProfile() == nullptr);
- mDisplay.createDisplayColorProfile(
+ EXPECT_TRUE(mDisplay->getDisplayColorProfile() == nullptr);
+ mDisplay->createDisplayColorProfile(
DisplayColorProfileCreationArgs{false, HdrCapabilities(), 0,
DisplayColorProfileCreationArgs::HwcColorModes()});
- EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
+ EXPECT_TRUE(mDisplay->getDisplayColorProfile() != nullptr);
}
-/* ------------------------------------------------------------------------
+/*
* Display::createRenderSurface()
*/
TEST_F(DisplayTest, createRenderSurfaceSetsRenderSurface) {
EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL)).WillRepeatedly(Return(NO_ERROR));
- EXPECT_TRUE(mDisplay.getRenderSurface() == nullptr);
- mDisplay.createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr});
- EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
+ EXPECT_TRUE(mDisplay->getRenderSurface() == nullptr);
+ mDisplay->createRenderSurface(RenderSurfaceCreationArgs{640, 480, mNativeWindow, nullptr});
+ EXPECT_TRUE(mDisplay->getRenderSurface() != nullptr);
+}
+
+/*
+ * Display::createOutputLayer()
+ */
+
+TEST_F(DisplayTest, createOutputLayerSetsHwcLayer) {
+ sp<mock::LayerFE> layerFE = new StrictMock<mock::LayerFE>();
+ auto layer = std::make_shared<StrictMock<mock::Layer>>();
+ StrictMock<HWC2::mock::Layer> hwcLayer;
+
+ EXPECT_CALL(mHwComposer, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer));
+
+ auto outputLayer = mDisplay->createOutputLayer(layer, layerFE);
+
+ EXPECT_EQ(&hwcLayer, outputLayer->getHwcLayer());
+
+ EXPECT_CALL(mHwComposer, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer));
+ outputLayer.reset();
+}
+
+/*
+ * Display::setReleasedLayers()
+ */
+
+TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNotHwcDisplay) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+ mock::Layer layerXLayer;
+
+ {
+ Output::ReleasedLayers releasedLayers;
+ releasedLayers.emplace_back(layerXLayerFE);
+ nonHwcDisplay->setReleasedLayers(std::move(releasedLayers));
+ }
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer);
+
+ nonHwcDisplay->setReleasedLayers(refreshArgs);
+
+ const auto& releasedLayers = nonHwcDisplay->getReleasedLayersForTest();
+ ASSERT_EQ(1, releasedLayers.size());
+}
+
+TEST_F(DisplayTest, setReleasedLayersDoesNothingIfNoLayersWithQueuedFrames) {
+ sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+
+ {
+ Output::ReleasedLayers releasedLayers;
+ releasedLayers.emplace_back(layerXLayerFE);
+ mDisplay->setReleasedLayers(std::move(releasedLayers));
+ }
+
+ CompositionRefreshArgs refreshArgs;
+ mDisplay->setReleasedLayers(refreshArgs);
+
+ const auto& releasedLayers = mDisplay->getReleasedLayersForTest();
+ ASSERT_EQ(1, releasedLayers.size());
+}
+
+TEST_F(DisplayTest, setReleasedLayers) {
+ sp<mock::LayerFE> layer1LayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layer2LayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layer3LayerFE = new StrictMock<mock::LayerFE>();
+ sp<mock::LayerFE> layerXLayerFE = new StrictMock<mock::LayerFE>();
+ mock::Layer layer1Layer;
+ mock::Layer layer2Layer;
+ mock::Layer layer3Layer;
+ mock::Layer layerXLayer;
+
+ EXPECT_CALL(*mLayer1, getLayer()).WillRepeatedly(ReturnRef(layer1Layer));
+ EXPECT_CALL(*mLayer1, getLayerFE()).WillRepeatedly(ReturnRef(*layer1LayerFE.get()));
+ EXPECT_CALL(*mLayer2, getLayer()).WillRepeatedly(ReturnRef(layer2Layer));
+ EXPECT_CALL(*mLayer2, getLayerFE()).WillRepeatedly(ReturnRef(*layer2LayerFE.get()));
+ EXPECT_CALL(*mLayer3, getLayer()).WillRepeatedly(ReturnRef(layer3Layer));
+ EXPECT_CALL(*mLayer3, getLayerFE()).WillRepeatedly(ReturnRef(*layer3LayerFE.get()));
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.layersWithQueuedFrames.push_back(&layer1Layer);
+ refreshArgs.layersWithQueuedFrames.push_back(&layer2Layer);
+ refreshArgs.layersWithQueuedFrames.push_back(&layerXLayer);
+ refreshArgs.layersWithQueuedFrames.push_back(nullptr);
+
+ mDisplay->setReleasedLayers(refreshArgs);
+
+ const auto& releasedLayers = mDisplay->getReleasedLayersForTest();
+ ASSERT_EQ(2, releasedLayers.size());
+ ASSERT_EQ(layer1LayerFE.get(), releasedLayers[0].promote().get());
+ ASSERT_EQ(layer2LayerFE.get(), releasedLayers[1].promote().get());
+}
+
+/*
+ * Display::chooseCompositionStrategy()
+ */
+
+struct DisplayChooseCompositionStrategyTest : public testing::Test {
+ struct DisplayPartialMock : public impl::Display {
+ DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine,
+ const compositionengine::DisplayCreationArgs& args)
+ : impl::Display(args), mCompositionEngine(compositionEngine) {}
+
+ // Sets up the helper functions called by chooseCompositionStrategy to
+ // use a mock implementations.
+ MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool());
+ MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool());
+ MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&));
+ MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&));
+ MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&));
+
+ // compositionengine::Output overrides
+ const OutputCompositionState& getState() const override { return mState; }
+ OutputCompositionState& editState() override { return mState; }
+
+ // compositionengine::impl::Output overrides
+ const CompositionEngine& getCompositionEngine() const override {
+ return mCompositionEngine;
+ };
+
+ // These need implementations though are not expected to be called.
+ MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
+ MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
+ compositionengine::OutputLayer*(size_t));
+ MOCK_METHOD3(ensureOutputLayer,
+ compositionengine::OutputLayer*(
+ std::optional<size_t>,
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD0(finalizePendingOutputLayers, void());
+ MOCK_METHOD0(clearOutputLayers, void());
+ MOCK_CONST_METHOD1(dumpState, void(std::string&));
+ MOCK_METHOD2(injectOutputLayerForTest,
+ compositionengine::OutputLayer*(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>));
+
+ const compositionengine::CompositionEngine& mCompositionEngine;
+ impl::OutputCompositionState mState;
+ };
+
+ DisplayChooseCompositionStrategyTest() {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ }
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<DisplayPartialMock>
+ mDisplay{mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+ EXPECT_FALSE(nonHwcDisplay->getId());
+
+ nonHwcDisplay->chooseCompositionStrategy();
+
+ auto& state = nonHwcDisplay->getState();
+ EXPECT_TRUE(state.usesClientComposition);
+ EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) {
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.usesClientComposition);
+ EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
+ // Since two calls are made to anyLayersRequireClientComposition with different return values,
+ // use a Sequence to control the matching so the values are returned in a known order.
+ Sequence s;
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
+ android::HWComposer::DeviceRequestedChanges changes{
+ {{nullptr, HWC2::Composition::Client}},
+ HWC2::DisplayRequest::FlipClientTarget,
+ {{nullptr, HWC2::LayerRequest::ClearClientTarget}},
+ };
+
+ // Since two calls are made to anyLayersRequireClientComposition with different return values,
+ // use a Sequence to control the matching so the values are returned in a known order.
+ Sequence s;
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+ .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR)));
+ EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
+ EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
+ EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+ EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+/*
+ * Display::getSkipColorTransform()
+ */
+
+TEST_F(DisplayTest, getSkipColorTransformDoesNothingIfNonHwcDisplay) {
+ auto nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+ EXPECT_FALSE(nonHwcDisplay->getSkipColorTransform());
+}
+
+TEST_F(DisplayTest, getSkipColorTransformChecksHwcCapability) {
+ EXPECT_CALL(mHwComposer,
+ hasDisplayCapability(std::make_optional(DEFAULT_DISPLAY_ID),
+ HWC2::DisplayCapability::SkipClientColorTransform))
+ .WillOnce(Return(true));
+ EXPECT_TRUE(mDisplay->getSkipColorTransform());
+}
+
+/*
+ * Display::anyLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false));
+
+ EXPECT_FALSE(mDisplay->anyLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mDisplay->anyLayersRequireClientComposition());
+}
+
+/*
+ * Display::allLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mDisplay->allLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+
+ EXPECT_FALSE(mDisplay->allLayersRequireClientComposition());
+}
+
+/*
+ * Display::applyChangedTypesToLayers()
+ */
+
+TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) {
+ mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes());
+}
+
+TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) {
+ EXPECT_CALL(*mLayer1,
+ applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT))
+ .Times(1);
+ EXPECT_CALL(*mLayer2,
+ applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE))
+ .Times(1);
+
+ mDisplay->applyChangedTypesToLayers(impl::Display::ChangedTypes{
+ {&mHWC2Layer1, HWC2::Composition::Client},
+ {&mHWC2Layer2, HWC2::Composition::Device},
+ {&mHWC2LayerUnknown, HWC2::Composition::SolidColor},
+ });
+}
+
+/*
+ * Display::applyDisplayRequests()
+ */
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) {
+ mDisplay->applyDisplayRequests(static_cast<HWC2::DisplayRequest>(0));
+
+ auto& state = mDisplay->getState();
+ EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) {
+ mDisplay->applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget);
+
+ auto& state = mDisplay->getState();
+ EXPECT_TRUE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) {
+ mDisplay->applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput);
+
+ auto& state = mDisplay->getState();
+ EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) {
+ mDisplay->applyDisplayRequests(static_cast<HWC2::DisplayRequest>(~0));
+
+ auto& state = mDisplay->getState();
+ EXPECT_TRUE(state.flipClientTarget);
+}
+
+/*
+ * Display::applyLayerRequestsToLayers()
+ */
+
+TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) {
+ EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+ mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests());
+}
+
+TEST_F(DisplayTest, applyLayerRequestsToLayers2) {
+ EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+ EXPECT_CALL(*mLayer1,
+ applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET))
+ .Times(1);
+
+ mDisplay->applyLayerRequestsToLayers(impl::Display::LayerRequests{
+ {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget},
+ {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
+ });
+}
+
+/*
+ * Display::presentAndGetFrameFences()
+ */
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) {
+ auto nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ auto result = nonHwcDisplay->presentAndGetFrameFences();
+
+ ASSERT_TRUE(result.presentFence.get());
+ EXPECT_FALSE(result.presentFence->isValid());
+ EXPECT_EQ(0u, result.layerFences.size());
+}
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) {
+ sp<Fence> presentFence = new Fence();
+ sp<Fence> layer1Fence = new Fence();
+ sp<Fence> layer2Fence = new Fence();
+
+ EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+ EXPECT_CALL(mHwComposer, getPresentFence(DEFAULT_DISPLAY_ID)).WillOnce(Return(presentFence));
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer1))
+ .WillOnce(Return(layer1Fence));
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer2))
+ .WillOnce(Return(layer2Fence));
+ EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+
+ auto result = mDisplay->presentAndGetFrameFences();
+
+ EXPECT_EQ(presentFence, result.presentFence);
+
+ EXPECT_EQ(2u, result.layerFences.size());
+ ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer1));
+ EXPECT_EQ(layer1Fence, result.layerFences[&mHWC2Layer1]);
+ ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer2));
+ EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
+}
+
+/*
+ * Display::setExpensiveRenderingExpected()
+ */
+
+TEST_F(DisplayTest, setExpensiveRenderingExpectedForwardsToPowerAdvisor) {
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, true)).Times(1);
+ mDisplay->setExpensiveRenderingExpected(true);
+
+ EXPECT_CALL(mPowerAdvisor, setExpensiveRenderingExpected(DEFAULT_DISPLAY_ID, false)).Times(1);
+ mDisplay->setExpensiveRenderingExpected(false);
+}
+
+/*
+ * Display::finishFrame()
+ */
+
+TEST_F(DisplayTest, finishFrameDoesNotSkipCompositionIfNotDirtyOnHwcDisplay) {
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ mDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect no calls to queueBuffer if composition was skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+
+ mDisplay->editState().isEnabled = true;
+ mDisplay->editState().usesClientComposition = false;
+ mDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ mDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = false;
+
+ mDisplay->finishFrame(refreshArgs);
+}
+
+TEST_F(DisplayTest, finishFrameSkipsCompositionIfNotDirty) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect no calls to queueBuffer if composition was skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(0);
+
+ nonHwcDisplay->editState().isEnabled = true;
+ nonHwcDisplay->editState().usesClientComposition = false;
+ nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = false;
+
+ nonHwcDisplay->finishFrame(refreshArgs);
+}
+
+TEST_F(DisplayTest, finishFramePerformsCompositionIfDirty) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect a single call to queueBuffer when composition is not skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+
+ nonHwcDisplay->editState().isEnabled = true;
+ nonHwcDisplay->editState().usesClientComposition = false;
+ nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ nonHwcDisplay->editState().dirtyRegion = Region(Rect(0, 0, 1, 1));
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = false;
+
+ nonHwcDisplay->finishFrame(refreshArgs);
+}
+
+TEST_F(DisplayTest, finishFramePerformsCompositionIfRepaintEverything) {
+ std::shared_ptr<impl::Display> nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
+ nonHwcDisplay->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(renderSurface));
+
+ // We expect a single call to queueBuffer when composition is not skipped.
+ EXPECT_CALL(*renderSurface, queueBuffer(_)).Times(1);
+
+ nonHwcDisplay->editState().isEnabled = true;
+ nonHwcDisplay->editState().usesClientComposition = false;
+ nonHwcDisplay->editState().viewport = Rect(0, 0, 1, 1);
+ nonHwcDisplay->editState().dirtyRegion = Region::INVALID_REGION;
+
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.repaintEverything = true;
+
+ nonHwcDisplay->finishFrame(refreshArgs);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
new file mode 100644
index 0000000..6741cc9
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+#include <android-base/stringprintf.h>
+#include <gmock/gmock.h>
+
+namespace {
+
+using android::base::StringAppendF;
+using FloatRect = android::FloatRect;
+
+void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) {
+ StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom);
+}
+
+// Checks for a region match
+MATCHER_P(FloatRectEq, expected, "") {
+ std::string buf;
+ buf.append("FloatRects are not equal\n");
+ dumpFloatRect(expected, buf, "expected rect");
+ dumpFloatRect(arg, buf, "actual rect");
+ *result_listener << buf;
+
+ const float TOLERANCE = 1e-3f;
+ return (std::fabs(expected.left - arg.left) < TOLERANCE) &&
+ (std::fabs(expected.top - arg.top) < TOLERANCE) &&
+ (std::fabs(expected.right - arg.right) < TOLERANCE) &&
+ (std::fabs(expected.bottom - arg.bottom) < TOLERANCE);
+}
+
+} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
index 26115a3..787f973 100644
--- a/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/LayerTest.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include <compositionengine/LayerCreationArgs.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/Layer.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/LayerFE.h>
@@ -26,13 +27,28 @@
using testing::StrictMock;
-class LayerTest : public testing::Test {
-public:
+struct LayerTest : public testing::Test {
+ struct Layer final : public impl::Layer {
+ explicit Layer(const LayerCreationArgs& args) : mLayerFE(args.layerFE) {}
+ ~Layer() override = default;
+
+ // compositionengine::Layer overrides
+ sp<LayerFE> getLayerFE() const { return mLayerFE.promote(); }
+ const LayerFECompositionState& getFEState() const override { return mFrontEndState; }
+ LayerFECompositionState& editFEState() override { return mFrontEndState; }
+
+ // compositionengine::impl::Layer overrides
+ void dumpFEState(std::string& out) const override { mFrontEndState.dump(out); }
+
+ const wp<LayerFE> mLayerFE;
+ LayerFECompositionState mFrontEndState;
+ };
+
~LayerTest() override = default;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<LayerFE> mLayerFE = new StrictMock<mock::LayerFE>();
- impl::Layer mLayer{mCompositionEngine, LayerCreationArgs{mLayerFE}};
+ Layer mLayer{LayerCreationArgs{mLayerFE}};
};
/* ------------------------------------------------------------------------
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 94349de..5cfec77 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,7 +40,9 @@
std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
- MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
+ MOCK_METHOD3(getDeviceCompositionChanges,
+ status_t(DisplayId, bool,
+ std::optional<android::HWComposer::DeviceRequestedChanges>*));
MOCK_METHOD5(setClientTarget,
status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
ui::Dataspace));
@@ -50,8 +52,6 @@
MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
MOCK_METHOD1(disconnectDisplay, void(DisplayId));
MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional<DisplayId>&));
MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(DisplayId));
MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(DisplayId, HWC2::Layer*));
MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
similarity index 60%
copy from services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
copy to services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
index ab01c20..85b9403 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.cpp
@@ -1,6 +1,6 @@
/*
* Copyright 2019 The Android Open Source Project
- *
+
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -14,28 +14,21 @@
* limitations under the License.
*/
-#pragma once
-
-#include <cstdint>
-#include <string>
-
-#include <compositionengine/LayerFECompositionState.h>
-#include <renderengine/Mesh.h>
+#include "MockPowerAdvisor.h"
namespace android {
+namespace Hwc2 {
-namespace compositionengine::impl {
+// This will go away once PowerAdvisor is moved into the "backend" library
+PowerAdvisor::~PowerAdvisor() = default;
-struct LayerCompositionState {
- /*
- * State intended to be set by LayerFE::getCompositionState
- */
+namespace mock {
- LayerFECompositionState frontEnd;
+// The Google Mock documentation recommends explicit non-header instantiations
+// for better compile time performance.
+PowerAdvisor::PowerAdvisor() = default;
+PowerAdvisor::~PowerAdvisor() = default;
- // Debugging
- void dump(std::string& result) const;
-};
-
-} // namespace compositionengine::impl
+} // namespace mock
+} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
similarity index 61%
rename from services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
rename to services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index ab01c20..c5a73f2 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -1,6 +1,6 @@
/*
* Copyright 2019 The Android Open Source Project
- *
+
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -16,26 +16,22 @@
#pragma once
-#include <cstdint>
-#include <string>
+#include <gmock/gmock.h>
-#include <compositionengine/LayerFECompositionState.h>
-#include <renderengine/Mesh.h>
+#include "DisplayHardware/PowerAdvisor.h"
namespace android {
+namespace Hwc2 {
+namespace mock {
-namespace compositionengine::impl {
+class PowerAdvisor : public android::Hwc2::PowerAdvisor {
+public:
+ PowerAdvisor();
+ ~PowerAdvisor() override;
-struct LayerCompositionState {
- /*
- * State intended to be set by LayerFE::getCompositionState
- */
-
- LayerFECompositionState frontEnd;
-
- // Debugging
- void dump(std::string& result) const;
+ MOCK_METHOD2(setExpensiveRenderingExpected, void(DisplayId displayId, bool expected));
};
-} // namespace compositionengine::impl
+} // namespace mock
+} // namespace Hwc2
} // namespace android
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 2060c5a..0347f75 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -15,15 +15,19 @@
*/
#include <compositionengine/impl/OutputLayer.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
+#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
+#include "FloatRectMatcher.h"
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RectMatcher.h"
+#include "RegionMatcher.h"
namespace android::compositionengine {
namespace {
@@ -33,8 +37,6 @@
using testing::ReturnRef;
using testing::StrictMock;
-constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
-
constexpr auto TR_IDENT = 0u;
constexpr auto TR_FLP_H = HAL_TRANSFORM_FLIP_H;
constexpr auto TR_FLP_V = HAL_TRANSFORM_FLIP_V;
@@ -44,26 +46,55 @@
const std::string kOutputName{"Test Output"};
-class OutputLayerTest : public testing::Test {
-public:
+MATCHER_P(ColorEq, expected, "") {
+ *result_listener << "Colors are not equal\n";
+ *result_listener << "expected " << expected.r << " " << expected.g << " " << expected.b << " "
+ << expected.a << "\n";
+ *result_listener << "actual " << arg.r << " " << arg.g << " " << arg.b << " " << arg.a << "\n";
+
+ return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
+}
+
+struct OutputLayerTest : public testing::Test {
+ struct OutputLayer final : public impl::OutputLayer {
+ OutputLayer(const compositionengine::Output& output,
+ std::shared_ptr<compositionengine::Layer> layer,
+ sp<compositionengine::LayerFE> layerFE)
+ : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+ ~OutputLayer() override = default;
+
+ // compositionengine::OutputLayer overrides
+ const compositionengine::Output& getOutput() const override { return mOutput; }
+ compositionengine::Layer& getLayer() const override { return *mLayer; }
+ compositionengine::LayerFE& getLayerFE() const override { return *mLayerFE; }
+ const impl::OutputLayerCompositionState& getState() const override { return mState; }
+ impl::OutputLayerCompositionState& editState() override { return mState; }
+
+ // compositionengine::impl::OutputLayer overrides
+ void dumpState(std::string& out) const override { mState.dump(out); }
+
+ const compositionengine::Output& mOutput;
+ std::shared_ptr<compositionengine::Layer> mLayer;
+ sp<compositionengine::LayerFE> mLayerFE;
+ impl::OutputLayerCompositionState mState;
+ };
+
OutputLayerTest() {
EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
- EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
+ EXPECT_CALL(*mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
}
- ~OutputLayerTest() override = default;
-
compositionengine::mock::Output mOutput;
std::shared_ptr<compositionengine::mock::Layer> mLayer{
new StrictMock<compositionengine::mock::Layer>()};
sp<compositionengine::mock::LayerFE> mLayerFE{
new StrictMock<compositionengine::mock::LayerFE>()};
- impl::OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE};
+ OutputLayer mOutputLayer{mOutput, mLayer, mLayerFE};
- impl::LayerCompositionState mLayerState;
+ LayerFECompositionState mLayerFEState;
impl::OutputCompositionState mOutputState;
};
@@ -74,35 +105,134 @@
TEST_F(OutputLayerTest, canInstantiateOutputLayer) {}
/*
- * OutputLayer::initialize()
+ * OutputLayer::setHwcLayer()
*/
-TEST_F(OutputLayerTest, initializingOutputLayerWithoutHwcDoesNothingInteresting) {
+TEST_F(OutputLayerTest, settingNullHwcLayerSetsEmptyHwcState) {
StrictMock<compositionengine::mock::CompositionEngine> compositionEngine;
- mOutputLayer.initialize(compositionEngine, std::nullopt);
+ mOutputLayer.setHwcLayer(nullptr);
EXPECT_FALSE(mOutputLayer.getState().hwc);
}
-TEST_F(OutputLayerTest, initializingOutputLayerWithHwcDisplayCreatesHwcLayer) {
- StrictMock<compositionengine::mock::CompositionEngine> compositionEngine;
- StrictMock<android::mock::HWComposer> hwc;
- StrictMock<HWC2::mock::Layer> hwcLayer;
+TEST_F(OutputLayerTest, settingHwcLayerSetsHwcState) {
+ auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
- EXPECT_CALL(compositionEngine, getHwComposer()).WillOnce(ReturnRef(hwc));
- EXPECT_CALL(hwc, createLayer(DEFAULT_DISPLAY_ID)).WillOnce(Return(&hwcLayer));
-
- mOutputLayer.initialize(compositionEngine, DEFAULT_DISPLAY_ID);
+ mOutputLayer.setHwcLayer(hwcLayer);
const auto& outputLayerState = mOutputLayer.getState();
ASSERT_TRUE(outputLayerState.hwc);
const auto& hwcState = *outputLayerState.hwc;
- EXPECT_EQ(&hwcLayer, hwcState.hwcLayer.get());
+ EXPECT_EQ(hwcLayer, hwcState.hwcLayer);
+}
- EXPECT_CALL(hwc, destroyLayer(DEFAULT_DISPLAY_ID, &hwcLayer));
- mOutputLayer.editState().hwc.reset();
+/*
+ * OutputLayer::calculateOutputSourceCrop()
+ */
+
+struct OutputLayerSourceCropTest : public OutputLayerTest {
+ OutputLayerSourceCropTest() {
+ // Set reasonable default values for a simple case. Each test will
+ // set one specific value to something different.
+ mLayerFEState.geomUsesSourceCrop = true;
+ mLayerFEState.geomContentCrop = Rect{0, 0, 1920, 1080};
+ mLayerFEState.transparentRegionHint = Region{};
+ mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
+ mLayerFEState.geomLayerTransform = ui::Transform{TR_IDENT};
+ mLayerFEState.geomBufferSize = Rect{0, 0, 1920, 1080};
+ mLayerFEState.geomBufferTransform = TR_IDENT;
+
+ mOutputState.viewport = Rect{0, 0, 1920, 1080};
+ }
+
+ FloatRect calculateOutputSourceCrop() {
+ mLayerFEState.geomInverseLayerTransform = mLayerFEState.geomLayerTransform.inverse();
+
+ return mOutputLayer.calculateOutputSourceCrop();
+ }
+};
+
+TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) {
+ mLayerFEState.geomUsesSourceCrop = false;
+
+ const FloatRect expected{};
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+}
+
+TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) {
+ const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+}
+
+TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) {
+ mLayerFEState.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
+
+ const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+}
+
+TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) {
+ mLayerFEState.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
+ mLayerFEState.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
+
+ const FloatRect expected{0.f, 0.f, 1080.f, 1080.f};
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+}
+
+TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) {
+ struct Entry {
+ uint32_t bufferInvDisplay;
+ uint32_t buffer;
+ uint32_t display;
+ FloatRect expected;
+ };
+ // Not an exhaustive list of cases, but hopefully enough.
+ const std::array<Entry, 12> testData = {
+ // clang-format off
+ // inv buffer display expected
+ /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+
+ /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+
+ /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+ /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
+
+ // clang-format on
+ };
+
+ for (size_t i = 0; i < testData.size(); i++) {
+ const auto& entry = testData[i];
+
+ mLayerFEState.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay;
+ mLayerFEState.geomBufferTransform = entry.buffer;
+ mOutputState.orientation = entry.display;
+
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i;
+ }
+}
+
+TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) {
+ mLayerFEState.geomContentCrop = Rect{0, 0, 960, 540};
+
+ const FloatRect expected{0.f, 0.f, 960.f, 540.f};
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
+}
+
+TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) {
+ mOutputState.viewport = Rect{0, 0, 960, 540};
+
+ const FloatRect expected{0.f, 0.f, 960.f, 540.f};
+ EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
}
/*
@@ -114,20 +244,19 @@
// Set reasonable default values for a simple case. Each test will
// set one specific value to something different.
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{};
- mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT};
- mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = false;
- mLayerState.frontEnd.geomCrop = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
+ mLayerFEState.transparentRegionHint = Region{};
+ mLayerFEState.geomLayerTransform = ui::Transform{TR_IDENT};
+ mLayerFEState.geomBufferSize = Rect{0, 0, 1920, 1080};
+ mLayerFEState.geomBufferUsesDisplayInverseTransform = false;
+ mLayerFEState.geomCrop = Rect{0, 0, 1920, 1080};
+ mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
mOutputState.viewport = Rect{0, 0, 1920, 1080};
mOutputState.transform = ui::Transform{TR_IDENT};
}
Rect calculateOutputDisplayFrame() {
- mLayerState.frontEnd.geomInverseLayerTransform =
- mLayerState.frontEnd.geomLayerTransform.inverse();
+ mLayerFEState.geomInverseLayerTransform = mLayerFEState.geomLayerTransform.inverse();
return mOutputLayer.calculateOutputDisplayFrame();
}
@@ -139,32 +268,32 @@
}
TEST_F(OutputLayerDisplayFrameTest, fullActiveTransparentRegionReturnsEmptyFrame) {
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{Rect{0, 0, 1920, 1080}};
+ mLayerFEState.transparentRegionHint = Region{Rect{0, 0, 1920, 1080}};
const Rect expected{0, 0, 0, 0};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrame) {
- mLayerState.frontEnd.geomCrop = Rect{100, 200, 300, 500};
+ mLayerFEState.geomCrop = Rect{100, 200, 300, 500};
const Rect expected{100, 200, 300, 500};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
TEST_F(OutputLayerDisplayFrameTest, cropAffectsDisplayFrameRotated) {
- mLayerState.frontEnd.geomCrop = Rect{100, 200, 300, 500};
- mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
+ mLayerFEState.geomCrop = Rect{100, 200, 300, 500};
+ mLayerFEState.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
const Rect expected{1420, 100, 1720, 300};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
TEST_F(OutputLayerDisplayFrameTest, emptyGeomCropIsNotUsedToComputeFrame) {
- mLayerState.frontEnd.geomCrop = Rect{};
+ mLayerFEState.geomCrop = Rect{};
const Rect expected{0, 0, 1920, 1080};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
-TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) {
- mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f};
+TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) {
+ mLayerFEState.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f};
const Rect expected{0, 0, 960, 540};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
@@ -186,7 +315,7 @@
*/
TEST_F(OutputLayerTest, calculateOutputRelativeBufferTransformTestsNeeded) {
- mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = false;
+ mLayerFEState.geomBufferUsesDisplayInverseTransform = false;
struct Entry {
uint32_t layer;
@@ -233,8 +362,8 @@
for (size_t i = 0; i < testData.size(); i++) {
const auto& entry = testData[i];
- mLayerState.frontEnd.geomLayerTransform.set(entry.layer, 1920, 1080);
- mLayerState.frontEnd.geomBufferTransform = entry.buffer;
+ mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
+ mLayerFEState.geomBufferTransform = entry.buffer;
mOutputState.orientation = entry.display;
auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
@@ -242,6 +371,230 @@
}
}
+TEST_F(OutputLayerTest,
+ calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) {
+ mLayerFEState.geomBufferUsesDisplayInverseTransform = true;
+
+ struct Entry {
+ uint32_t layer;
+ uint32_t buffer;
+ uint32_t display;
+ uint32_t expected;
+ };
+ // Not an exhaustive list of cases, but hopefully enough.
+ const std::array<Entry, 24> testData = {
+ // clang-format off
+ // layer buffer display expected
+ /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT},
+ /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT},
+ /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT},
+ /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT},
+
+ /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H},
+ /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H},
+ /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H},
+ /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H},
+
+ /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V},
+ /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90},
+ /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180},
+ /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270},
+
+ /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT},
+ /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H},
+ /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT},
+ /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H},
+
+ /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H},
+ /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT},
+ /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H},
+ /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT},
+
+ /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT},
+ /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H},
+ /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H},
+ /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT},
+ // clang-format on
+ };
+
+ for (size_t i = 0; i < testData.size(); i++) {
+ const auto& entry = testData[i];
+
+ mLayerFEState.geomLayerTransform = ui::Transform{entry.layer};
+ mLayerFEState.geomBufferTransform = entry.buffer;
+ mOutputState.orientation = entry.display;
+
+ auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
+ EXPECT_EQ(entry.expected, actual) << "entry " << i;
+ }
+}
+
+/*
+ * OutputLayer::updateCompositionState()
+ */
+
+struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer {
+ OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output,
+ std::shared_ptr<compositionengine::Layer> layer,
+ sp<compositionengine::LayerFE> layerFE)
+ : mOutput(output), mLayer(layer), mLayerFE(layerFE) {}
+ // Mock everything called by updateCompositionState to simplify testing it.
+ MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
+ MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
+ MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t());
+
+ // compositionengine::OutputLayer overrides
+ const compositionengine::Output& getOutput() const override { return mOutput; }
+ compositionengine::Layer& getLayer() const override { return *mLayer; }
+ compositionengine::LayerFE& getLayerFE() const override { return *mLayerFE; }
+ const impl::OutputLayerCompositionState& getState() const override { return mState; }
+ impl::OutputLayerCompositionState& editState() override { return mState; }
+
+ // These need implementations though are not expected to be called.
+ MOCK_CONST_METHOD1(dumpState, void(std::string&));
+
+ const compositionengine::Output& mOutput;
+ std::shared_ptr<compositionengine::Layer> mLayer;
+ sp<compositionengine::LayerFE> mLayerFE;
+ impl::OutputLayerCompositionState mState;
+};
+
+struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest {
+public:
+ OutputLayerUpdateCompositionStateTest() {
+ EXPECT_CALL(*mLayer, getFEState()).WillRepeatedly(ReturnRef(mLayerFEState));
+ EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(true));
+ }
+
+ ~OutputLayerUpdateCompositionStateTest() = default;
+
+ void setupGeometryChildCallValues() {
+ EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop));
+ EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame));
+ EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform())
+ .WillOnce(Return(mBufferTransform));
+ }
+
+ void validateComputedGeometryState() {
+ const auto& state = mOutputLayer.getState();
+ EXPECT_EQ(kSourceCrop, state.sourceCrop);
+ EXPECT_EQ(kDisplayFrame, state.displayFrame);
+ EXPECT_EQ(static_cast<Hwc2::Transform>(mBufferTransform), state.bufferTransform);
+ }
+
+ const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f};
+ const Rect kDisplayFrame{11, 12, 13, 14};
+ uint32_t mBufferTransform{21};
+
+ using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
+ StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
+};
+
+TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
+ mLayerFEState.isSecure = true;
+ mOutputState.isSecure = true;
+ mOutputLayer.editState().forceClientComposition = true;
+
+ setupGeometryChildCallValues();
+
+ mOutputLayer.updateCompositionState(true);
+
+ validateComputedGeometryState();
+
+ EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) {
+ mLayerFEState.isSecure = true;
+ mOutputState.isSecure = false;
+
+ setupGeometryChildCallValues();
+
+ mOutputLayer.updateCompositionState(true);
+
+ validateComputedGeometryState();
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ alsoSetsForceCompositionIfUnsupportedBufferTransform) {
+ mLayerFEState.isSecure = true;
+ mOutputState.isSecure = true;
+
+ mBufferTransform = ui::Transform::ROT_INVALID;
+
+ setupGeometryChildCallValues();
+
+ mOutputLayer.updateCompositionState(true);
+
+ validateComputedGeometryState();
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest, setsOutputLayerColorspaceCorrectly) {
+ mLayerFEState.dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutputState.targetDataspace = ui::Dataspace::V0_SCRGB;
+
+ // If the layer is not colorspace agnostic, the output layer dataspace
+ // should use the layers requested colorspace.
+ mLayerFEState.isColorspaceAgnostic = false;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::DISPLAY_P3, mOutputLayer.getState().dataspace);
+
+ // If the layer is colorspace agnostic, the output layer dataspace
+ // should use the colorspace chosen for the whole output.
+ mLayerFEState.isColorspaceAgnostic = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(ui::Dataspace::V0_SCRGB, mOutputLayer.getState().dataspace);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
+ mOutputLayer.editState().forceClientComposition = false;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ doesNotClearForceClientCompositionIfNotDoingGeometry) {
+ mOutputLayer.editState().forceClientComposition = true;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest, clientCompositionForcedFromFrontEndFlagAtAnyTime) {
+ mLayerFEState.forceClientComposition = true;
+ mOutputLayer.editState().forceClientComposition = false;
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
+TEST_F(OutputLayerUpdateCompositionStateTest,
+ clientCompositionForcedFromUnsupportedDataspaceAtAnyTime) {
+ mOutputLayer.editState().forceClientComposition = false;
+ EXPECT_CALL(mDisplayColorProfile, isDataspaceSupported(_)).WillRepeatedly(Return(false));
+
+ mOutputLayer.updateCompositionState(false);
+
+ EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
+}
+
/*
* OutputLayer::writeStateToHWC()
*/
@@ -256,8 +609,19 @@
static constexpr float kAlpha = 51.f;
static constexpr uint32_t kType = 61u;
static constexpr uint32_t kAppId = 62u;
+ static constexpr ui::Dataspace kDataspace = static_cast<ui::Dataspace>(71);
+ static constexpr int kSupportedPerFrameMetadata = 101;
+ static constexpr int kExpectedHwcSlot = 0;
+ static const half4 kColor;
static const Rect kDisplayFrame;
+ static const Region kOutputSpaceVisibleRegion;
+ static const mat4 kColorTransform;
+ static const Region kSurfaceDamage;
+ static const HdrMetadata kHdrMetadata;
+ static native_handle_t* kSidebandStreamHandle;
+ static const sp<GraphicBuffer> kBuffer;
+ static const sp<Fence> kFence;
OutputLayerWriteStateToHWCTest() {
auto& outputLayerState = mOutputLayer.editState();
@@ -267,13 +631,31 @@
outputLayerState.sourceCrop = kSourceCrop;
outputLayerState.z = kZOrder;
outputLayerState.bufferTransform = static_cast<Hwc2::Transform>(kBufferTransform);
+ outputLayerState.outputSpaceVisibleRegion = kOutputSpaceVisibleRegion;
+ outputLayerState.dataspace = kDataspace;
- mLayerState.frontEnd.blendMode = kBlendMode;
- mLayerState.frontEnd.alpha = kAlpha;
- mLayerState.frontEnd.type = kType;
- mLayerState.frontEnd.appId = kAppId;
+ mLayerFEState.blendMode = kBlendMode;
+ mLayerFEState.alpha = kAlpha;
+ mLayerFEState.type = kType;
+ mLayerFEState.appId = kAppId;
+ mLayerFEState.colorTransform = kColorTransform;
+ mLayerFEState.color = kColor;
+ mLayerFEState.surfaceDamage = kSurfaceDamage;
+ mLayerFEState.hdrMetadata = kHdrMetadata;
+ mLayerFEState.sidebandStream = NativeHandle::create(kSidebandStreamHandle, false);
+ mLayerFEState.buffer = kBuffer;
+ mLayerFEState.bufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+ mLayerFEState.acquireFence = kFence;
+
+ EXPECT_CALL(mOutput, getDisplayColorProfile())
+ .WillRepeatedly(Return(&mDisplayColorProfile));
+ EXPECT_CALL(mDisplayColorProfile, getSupportedPerFrameMetadata())
+ .WillRepeatedly(Return(kSupportedPerFrameMetadata));
}
+ // Some tests may need to simulate unsupported HWC calls
+ enum class SimulateUnsupported { None, ColorTransform };
+
void expectGeometryCommonCalls() {
EXPECT_CALL(*mHwcLayer, setDisplayFrame(kDisplayFrame)).WillOnce(Return(kError));
EXPECT_CALL(*mHwcLayer, setSourceCrop(kSourceCrop)).WillOnce(Return(kError));
@@ -287,10 +669,63 @@
EXPECT_CALL(*mHwcLayer, setInfo(kType, kAppId)).WillOnce(Return(kError));
}
+ void expectPerFrameCommonCalls(SimulateUnsupported unsupported = SimulateUnsupported::None) {
+ EXPECT_CALL(*mHwcLayer, setVisibleRegion(RegionEq(kOutputSpaceVisibleRegion)))
+ .WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setDataspace(kDataspace)).WillOnce(Return(kError));
+ EXPECT_CALL(*mHwcLayer, setColorTransform(kColorTransform))
+ .WillOnce(Return(unsupported == SimulateUnsupported::ColorTransform
+ ? HWC2::Error::Unsupported
+ : HWC2::Error::None));
+ EXPECT_CALL(*mHwcLayer, setSurfaceDamage(RegionEq(kSurfaceDamage)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition compositionType) {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(static_cast<HWC2::Composition>(compositionType)))
+ .WillOnce(Return(kError));
+ }
+
+ void expectNoSetCompositionTypeCall() {
+ EXPECT_CALL(*mHwcLayer, setCompositionType(_)).Times(0);
+ }
+
+ void expectSetColorCall() {
+ hwc_color_t color = {static_cast<uint8_t>(std::round(kColor.r * 255)),
+ static_cast<uint8_t>(std::round(kColor.g * 255)),
+ static_cast<uint8_t>(std::round(kColor.b * 255)), 255};
+
+ EXPECT_CALL(*mHwcLayer, setColor(ColorEq(color))).WillOnce(Return(kError));
+ }
+
+ void expectSetSidebandHandleCall() {
+ EXPECT_CALL(*mHwcLayer, setSidebandStream(kSidebandStreamHandle));
+ }
+
+ void expectSetHdrMetadataAndBufferCalls() {
+ EXPECT_CALL(*mHwcLayer, setPerFrameMetadata(kSupportedPerFrameMetadata, kHdrMetadata));
+ EXPECT_CALL(*mHwcLayer, setBuffer(kExpectedHwcSlot, kBuffer, kFence));
+ }
+
std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+ StrictMock<mock::DisplayColorProfile> mDisplayColorProfile;
};
+const half4 OutputLayerWriteStateToHWCTest::kColor{81.f / 255.f, 82.f / 255.f, 83.f / 255.f,
+ 84.f / 255.f};
const Rect OutputLayerWriteStateToHWCTest::kDisplayFrame{1001, 1002, 1003, 10044};
+const Region OutputLayerWriteStateToHWCTest::kOutputSpaceVisibleRegion{
+ Rect{1005, 1006, 1007, 1008}};
+const mat4 OutputLayerWriteStateToHWCTest::kColorTransform{
+ 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016,
+ 1017, 1018, 1019, 1020, 1021, 1022, 1023, 1024,
+};
+const Region OutputLayerWriteStateToHWCTest::kSurfaceDamage{Rect{1025, 1026, 1027, 1028}};
+const HdrMetadata OutputLayerWriteStateToHWCTest::kHdrMetadata{{/* LightFlattenable */}, 1029};
+native_handle_t* OutputLayerWriteStateToHWCTest::kSidebandStreamHandle =
+ reinterpret_cast<native_handle_t*>(1031);
+const sp<GraphicBuffer> OutputLayerWriteStateToHWCTest::kBuffer;
+const sp<Fence> OutputLayerWriteStateToHWCTest::kFence;
TEST_F(OutputLayerWriteStateToHWCTest, doesNothingIfNoHWCState) {
mOutputLayer.editState().hwc.reset();
@@ -304,11 +739,280 @@
mOutputLayer.writeStateToHWC(true);
}
-TEST_F(OutputLayerWriteStateToHWCTest, canSetsAllState) {
+TEST_F(OutputLayerWriteStateToHWCTest, canSetAllState) {
expectGeometryCommonCalls();
+ expectPerFrameCommonCalls();
+
+ expectNoSetCompositionTypeCall();
mOutputLayer.writeStateToHWC(true);
}
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSolidColor) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SOLID_COLOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForSideband) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SIDEBAND;
+
+ expectPerFrameCommonCalls();
+ expectSetSidebandHandleCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::SIDEBAND);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForCursor) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CURSOR);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, canSetPerFrameStateForDevice) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ expectPerFrameCommonCalls();
+ expectSetHdrMetadataAndBufferCalls();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::DEVICE);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsNotSetIfUnchanged) {
+ (*mOutputLayer.editState().hwc).hwcCompositionType =
+ Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectNoSetCompositionTypeCall();
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfColorTransformNotSupported) {
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls(SimulateUnsupported::ColorTransform);
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+TEST_F(OutputLayerWriteStateToHWCTest, compositionTypeIsSetToClientIfClientCompositionForced) {
+ mOutputLayer.editState().forceClientComposition = true;
+
+ mLayerFEState.compositionType = Hwc2::IComposerClient::Composition::SOLID_COLOR;
+
+ expectPerFrameCommonCalls();
+ expectSetColorCall();
+ expectSetCompositionTypeCall(Hwc2::IComposerClient::Composition::CLIENT);
+
+ mOutputLayer.writeStateToHWC(false);
+}
+
+/*
+ * OutputLayer::writeCursorPositionToHWC()
+ */
+
+struct OutputLayerWriteCursorPositionToHWCTest : public OutputLayerTest {
+ static constexpr int kDefaultTransform = TR_IDENT;
+ static constexpr HWC2::Error kDefaultError = HWC2::Error::Unsupported;
+
+ static const Rect kDefaultDisplayViewport;
+ static const Rect kDefaultCursorFrame;
+
+ OutputLayerWriteCursorPositionToHWCTest() {
+ auto& outputLayerState = mOutputLayer.editState();
+ outputLayerState.hwc = impl::OutputLayerCompositionState::Hwc(mHwcLayer);
+
+ mLayerFEState.cursorFrame = kDefaultCursorFrame;
+
+ mOutputState.viewport = kDefaultDisplayViewport;
+ mOutputState.transform = ui::Transform{kDefaultTransform};
+ }
+
+ std::shared_ptr<HWC2::mock::Layer> mHwcLayer{std::make_shared<StrictMock<HWC2::mock::Layer>>()};
+};
+
+const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultDisplayViewport{0, 0, 1920, 1080};
+const Rect OutputLayerWriteCursorPositionToHWCTest::kDefaultCursorFrame{1, 2, 3, 4};
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCHandlesNoHwcState) {
+ mOutputLayer.editState().hwc.reset();
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCWritesStateToHWC) {
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(1, 2)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCIntersectedWithViewport) {
+ mLayerFEState.cursorFrame = Rect{3000, 3000, 3016, 3016};
+
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(1920, 1080)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+TEST_F(OutputLayerWriteCursorPositionToHWCTest, writeCursorPositionToHWCRotatedByTransform) {
+ mOutputState.transform = ui::Transform{TR_ROT_90};
+
+ EXPECT_CALL(*mHwcLayer, setCursorPosition(-4, 1)).WillOnce(Return(kDefaultError));
+
+ mOutputLayer.writeCursorPositionToHWC();
+}
+
+/*
+ * OutputLayer::getHwcLayer()
+ */
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcState) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcLayer) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+
+ EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerReturnsHwcLayer) {
+ auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{hwcLayer};
+
+ EXPECT_EQ(hwcLayer.get(), mOutputLayer.getHwcLayer());
+}
+
+/*
+ * OutputLayer::requiresClientComposition()
+ */
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+ EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ EXPECT_FALSE(mOutputLayer.requiresClientComposition());
+}
+
+/*
+ * OutputLayer::isHardwareCursor()
+ */
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfNoHWC2State) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_FALSE(mOutputLayer.isHardwareCursor());
+}
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsTrueIfSetToCursorComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CURSOR;
+
+ EXPECT_TRUE(mOutputLayer.isHardwareCursor());
+}
+
+TEST_F(OutputLayerTest, isHardwareCursorReturnsFalseIfSetToDeviceComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ EXPECT_FALSE(mOutputLayer.isHardwareCursor());
+}
+
+/*
+ * OutputLayer::applyDeviceCompositionTypeChange()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT);
+
+ ASSERT_TRUE(mOutputLayer.getState().hwc);
+ EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT,
+ mOutputLayer.getState().hwc->hwcCompositionType);
+}
+
+/*
+ * OutputLayer::prepareForDeviceLayerRequests()
+ */
+
+TEST_F(OutputLayerTest, prepareForDeviceLayerRequestsResetsRequestState) {
+ mOutputLayer.editState().clearClientTarget = true;
+
+ mOutputLayer.prepareForDeviceLayerRequests();
+
+ EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
+/*
+ * OutputLayer::applyDeviceLayerRequest()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesClearClientTarget) {
+ mOutputLayer.editState().clearClientTarget = false;
+
+ mOutputLayer.applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET);
+
+ EXPECT_TRUE(mOutputLayer.getState().clearClientTarget);
+}
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) {
+ mOutputLayer.editState().clearClientTarget = false;
+
+ mOutputLayer.applyDeviceLayerRequest(static_cast<Hwc2::IComposerClient::LayerRequest>(0));
+
+ EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
+/*
+ * OutputLayer::needsFiltering()
+ */
+
+TEST_F(OutputLayerTest, needsFilteringReturnsFalseIfDisplaySizeSameAsSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.f, 100.f};
+
+ EXPECT_FALSE(mOutputLayer.needsFiltering());
+}
+
+TEST_F(OutputLayerTest, needsFilteringReturnsTrueIfDisplaySizeDifferentFromSourceSize) {
+ mOutputLayer.editState().displayFrame = Rect(100, 100, 200, 200);
+ mOutputLayer.editState().sourceCrop = FloatRect{0.f, 0.f, 100.1f, 100.1f};
+
+ EXPECT_TRUE(mOutputLayer.needsFiltering());
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index fee0c11..95ae888 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -16,7 +16,10 @@
#include <cmath>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
+#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
@@ -24,6 +27,7 @@
#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include <renderengine/mock/RenderEngine.h>
#include <ui/Rect.h>
#include <ui/Region.h>
@@ -33,32 +37,49 @@
namespace android::compositionengine {
namespace {
+using testing::_;
using testing::Return;
using testing::ReturnRef;
using testing::StrictMock;
-class OutputTest : public testing::Test {
-public:
- OutputTest() {
- mOutput.setDisplayColorProfileForTest(
- std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
- mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+constexpr auto TR_IDENT = 0u;
+constexpr auto TR_ROT_90 = HAL_TRANSFORM_ROT_90;
- mOutput.editState().bounds = kDefaultDisplaySize;
+const mat4 kIdentity;
+const mat4 kNonIdentityHalf = mat4() * 0.5;
+const mat4 kNonIdentityQuarter = mat4() * 0.25;
+
+struct OutputTest : public testing::Test {
+ class Output : public impl::Output {
+ public:
+ using impl::Output::injectOutputLayerForTest;
+ virtual void injectOutputLayerForTest(std::unique_ptr<compositionengine::OutputLayer>) = 0;
+ };
+
+ static std::shared_ptr<Output> createOutput(
+ const compositionengine::CompositionEngine& compositionEngine) {
+ return impl::createOutputTemplated<Output>(compositionEngine);
}
- ~OutputTest() override = default;
+
+ OutputTest() {
+ mOutput->setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+
+ mOutput->editState().bounds = kDefaultDisplaySize;
+ }
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};
+ std::shared_ptr<Output> mOutput = createOutput(mCompositionEngine);
};
const Rect OutputTest::kDefaultDisplaySize{100, 200};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -67,48 +88,48 @@
EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
EXPECT_CALL(*mRenderSurface, isValid()).WillOnce(Return(true));
- EXPECT_TRUE(mOutput.isValid());
+ EXPECT_TRUE(mOutput->isValid());
// If we take away the required components, it is no longer valid.
- mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
+ mOutput->setRenderSurfaceForTest(std::unique_ptr<RenderSurface>());
EXPECT_CALL(*mDisplayColorProfile, isValid()).WillOnce(Return(true));
- EXPECT_FALSE(mOutput.isValid());
+ EXPECT_FALSE(mOutput->isValid());
}
-/* ------------------------------------------------------------------------
+/*
* Output::setCompositionEnabled()
*/
TEST_F(OutputTest, setCompositionEnabledDoesNothingIfAlreadyEnabled) {
- mOutput.editState().isEnabled = true;
+ mOutput->editState().isEnabled = true;
- mOutput.setCompositionEnabled(true);
+ mOutput->setCompositionEnabled(true);
- EXPECT_TRUE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+ EXPECT_TRUE(mOutput->getState().isEnabled);
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region()));
}
TEST_F(OutputTest, setCompositionEnabledSetsEnabledAndDirtiesEntireOutput) {
- mOutput.editState().isEnabled = false;
+ mOutput->editState().isEnabled = false;
- mOutput.setCompositionEnabled(true);
+ mOutput->setCompositionEnabled(true);
- EXPECT_TRUE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+ EXPECT_TRUE(mOutput->getState().isEnabled);
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
TEST_F(OutputTest, setCompositionEnabledSetsDisabledAndDirtiesEntireOutput) {
- mOutput.editState().isEnabled = true;
+ mOutput->editState().isEnabled = true;
- mOutput.setCompositionEnabled(false);
+ mOutput->setCompositionEnabled(false);
- EXPECT_FALSE(mOutput.getState().isEnabled);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+ EXPECT_FALSE(mOutput->getState().isEnabled);
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setProjection()
*/
@@ -120,17 +141,17 @@
const Rect scissor{9, 10, 11, 12};
const bool needsFiltering = true;
- mOutput.setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
+ mOutput->setProjection(transform, orientation, frame, viewport, scissor, needsFiltering);
- EXPECT_THAT(mOutput.getState().transform, TransformEq(transform));
- EXPECT_EQ(orientation, mOutput.getState().orientation);
- EXPECT_EQ(frame, mOutput.getState().frame);
- EXPECT_EQ(viewport, mOutput.getState().viewport);
- EXPECT_EQ(scissor, mOutput.getState().scissor);
- EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
+ EXPECT_THAT(mOutput->getState().transform, TransformEq(transform));
+ EXPECT_EQ(orientation, mOutput->getState().orientation);
+ EXPECT_EQ(frame, mOutput->getState().frame);
+ EXPECT_EQ(viewport, mOutput->getState().viewport);
+ EXPECT_EQ(scissor, mOutput->getState().scissor);
+ EXPECT_EQ(needsFiltering, mOutput->getState().needsFiltering);
}
-/* ------------------------------------------------------------------------
+/*
* Output::setBounds()
*/
@@ -140,94 +161,158 @@
EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
- mOutput.setBounds(displaySize);
+ mOutput->setBounds(displaySize);
- EXPECT_EQ(Rect(displaySize), mOutput.getState().bounds);
+ EXPECT_EQ(Rect(displaySize), mOutput->getState().bounds);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setLayerStackFilter()
*/
TEST_F(OutputTest, setLayerStackFilterSetsFilterAndDirtiesEntireOutput) {
const uint32_t layerStack = 123u;
- mOutput.setLayerStackFilter(layerStack, true);
+ mOutput->setLayerStackFilter(layerStack, true);
- EXPECT_TRUE(mOutput.getState().layerStackInternal);
- EXPECT_EQ(layerStack, mOutput.getState().layerStackId);
+ EXPECT_TRUE(mOutput->getState().layerStackInternal);
+ EXPECT_EQ(layerStack, mOutput->getState().layerStackId);
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setColorTransform
*/
-TEST_F(OutputTest, setColorTransformSetsTransform) {
- // Identity matrix sets an identity state value
- const mat4 identity;
+TEST_F(OutputTest, setColorTransformWithNoChangeFlaggedSkipsUpdates) {
+ mOutput->editState().colorTransformMatrix = kIdentity;
- mOutput.setColorTransform(identity);
+ // If no colorTransformMatrix is set the update should be skipped.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = std::nullopt;
- EXPECT_EQ(HAL_COLOR_TRANSFORM_IDENTITY, mOutput.getState().colorTransform);
- EXPECT_EQ(identity, mOutput.getState().colorTransformMat);
+ mOutput->setColorTransform(refreshArgs);
- // Since identity is the default, the dirty region should be unchanged (empty)
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+ // The internal state should be unchanged
+ EXPECT_EQ(kIdentity, mOutput->getState().colorTransformMatrix);
- // Non-identity matrix sets a non-identity state value
- const mat4 nonIdentityHalf = mat4() * 0.5;
-
- mOutput.setColorTransform(nonIdentityHalf);
-
- EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
- EXPECT_EQ(nonIdentityHalf, mOutput.getState().colorTransformMat);
-
- // Since this is a state change, the entire output should now be dirty.
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
-
- // Non-identity matrix sets a non-identity state value
- const mat4 nonIdentityQuarter = mat4() * 0.25;
-
- mOutput.setColorTransform(nonIdentityQuarter);
-
- EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mOutput.getState().colorTransform);
- EXPECT_EQ(nonIdentityQuarter, mOutput.getState().colorTransformMat);
-
- // Since this is a state change, the entire output should now be dirty.
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+ // No dirty region should be set
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region()));
}
-/* ------------------------------------------------------------------------
+TEST_F(OutputTest, setColorTransformWithNoActualChangeSkipsUpdates) {
+ mOutput->editState().colorTransformMatrix = kIdentity;
+
+ // Attempting to set the same colorTransformMatrix that is already set should
+ // also skip the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kIdentity;
+
+ mOutput->setColorTransform(refreshArgs);
+
+ // The internal state should be unchanged
+ EXPECT_EQ(kIdentity, mOutput->getState().colorTransformMatrix);
+
+ // No dirty region should be set
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region()));
+}
+
+TEST_F(OutputTest, setColorTransformPerformsUpdateToIdentity) {
+ mOutput->editState().colorTransformMatrix = kNonIdentityHalf;
+
+ // Setting a different colorTransformMatrix should perform the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kIdentity;
+
+ mOutput->setColorTransform(refreshArgs);
+
+ // The internal state should have been updated
+ EXPECT_EQ(kIdentity, mOutput->getState().colorTransformMatrix);
+
+ // The dirtyRegion should be set to the full display size
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+TEST_F(OutputTest, setColorTransformPerformsUpdateForIdentityToHalf) {
+ mOutput->editState().colorTransformMatrix = kIdentity;
+
+ // Setting a different colorTransformMatrix should perform the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kNonIdentityHalf;
+
+ mOutput->setColorTransform(refreshArgs);
+
+ // The internal state should have been updated
+ EXPECT_EQ(kNonIdentityHalf, mOutput->getState().colorTransformMatrix);
+
+ // The dirtyRegion should be set to the full display size
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+TEST_F(OutputTest, setColorTransformPerformsUpdateForHalfToQuarter) {
+ mOutput->editState().colorTransformMatrix = kNonIdentityHalf;
+
+ // Setting a different colorTransformMatrix should perform the update.
+ CompositionRefreshArgs refreshArgs;
+ refreshArgs.colorTransformMatrix = kNonIdentityQuarter;
+
+ mOutput->setColorTransform(refreshArgs);
+
+ // The internal state should have been updated
+ EXPECT_EQ(kNonIdentityQuarter, mOutput->getState().colorTransformMatrix);
+
+ // The dirtyRegion should be set to the full display size
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
+}
+
+/*
* Output::setColorMode
*/
TEST_F(OutputTest, setColorModeSetsStateAndDirtiesOutputIfChanged) {
+ using ColorProfile = Output::ColorProfile;
+
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
EXPECT_CALL(*mRenderSurface, setBufferDataspace(ui::Dataspace::DISPLAY_P3)).Times(1);
- mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::Dataspace::UNKNOWN});
- 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)));
+ 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_EQ(ui::Dataspace::UNKNOWN, mOutput->getState().targetDataspace);
+
+ 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;
+ using ColorProfile = Output::ColorProfile;
- mOutput.setColorMode(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
- ui::RenderIntent::TONE_MAP_COLORIMETRIC);
+ EXPECT_CALL(*mDisplayColorProfile,
+ getTargetDataspace(ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::Dataspace::UNKNOWN))
+ .WillOnce(Return(ui::Dataspace::UNKNOWN));
- EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
+ mOutput->editState().colorMode = ui::ColorMode::DISPLAY_P3;
+ mOutput->editState().dataspace = ui::Dataspace::DISPLAY_P3;
+ mOutput->editState().renderIntent = ui::RenderIntent::TONE_MAP_COLORIMETRIC;
+ mOutput->editState().targetDataspace = ui::Dataspace::UNKNOWN;
+
+ mOutput->setColorProfile(ColorProfile{ui::ColorMode::DISPLAY_P3, ui::Dataspace::DISPLAY_P3,
+ ui::RenderIntent::TONE_MAP_COLORIMETRIC,
+ ui::Dataspace::UNKNOWN});
+
+ EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region()));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setRenderSurface()
*/
@@ -237,22 +322,22 @@
mock::RenderSurface* renderSurface = new StrictMock<mock::RenderSurface>();
EXPECT_CALL(*renderSurface, getSize()).WillOnce(ReturnRef(newDisplaySize));
- mOutput.setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
+ mOutput->setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
- EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
+ EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().bounds);
}
-/* ------------------------------------------------------------------------
+/*
* Output::getDirtyRegion()
*/
TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingTrue) {
const Rect viewport{100, 200};
- mOutput.editState().viewport = viewport;
- mOutput.editState().dirtyRegion.set(50, 300);
+ mOutput->editState().viewport = viewport;
+ mOutput->editState().dirtyRegion.set(50, 300);
{
- Region result = mOutput.getDirtyRegion(true);
+ Region result = mOutput->getDirtyRegion(true);
EXPECT_THAT(result, RegionEq(Region(viewport)));
}
@@ -260,18 +345,18 @@
TEST_F(OutputTest, getDirtyRegionWithRepaintEverythingFalse) {
const Rect viewport{100, 200};
- mOutput.editState().viewport = viewport;
- mOutput.editState().dirtyRegion.set(50, 300);
+ mOutput->editState().viewport = viewport;
+ mOutput->editState().dirtyRegion.set(50, 300);
{
- Region result = mOutput.getDirtyRegion(false);
+ Region result = mOutput->getDirtyRegion(false);
// The dirtyRegion should be clipped to the display bounds.
EXPECT_THAT(result, RegionEq(Region(Rect(50, 200))));
}
}
-/* ------------------------------------------------------------------------
+/*
* Output::belongsInOutput()
*/
@@ -280,25 +365,94 @@
const uint32_t layerStack2 = 456u;
// If the output accepts layerStack1 and internal-only layers....
- mOutput.setLayerStackFilter(layerStack1, true);
+ mOutput->setLayerStackFilter(layerStack1, true);
+
+ // A layer with no layerStack does not belong to it, internal-only or not.
+ EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, false));
+ EXPECT_FALSE(mOutput->belongsInOutput(std::nullopt, true));
// Any layer with layerStack1 belongs to it, internal-only or not.
- EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
- EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, true));
- EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
- EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
+ EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false));
+ EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, true));
+ EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true));
+ EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
// If the output accepts layerStack21 but not internal-only layers...
- mOutput.setLayerStackFilter(layerStack1, false);
+ mOutput->setLayerStackFilter(layerStack1, false);
// Only non-internal layers with layerStack1 belong to it.
- EXPECT_TRUE(mOutput.belongsInOutput(layerStack1, false));
- EXPECT_FALSE(mOutput.belongsInOutput(layerStack1, true));
- EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, true));
- EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
+ EXPECT_TRUE(mOutput->belongsInOutput(layerStack1, false));
+ EXPECT_FALSE(mOutput->belongsInOutput(layerStack1, true));
+ EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, true));
+ EXPECT_FALSE(mOutput->belongsInOutput(layerStack2, false));
}
-/* ------------------------------------------------------------------------
+TEST_F(OutputTest, belongsInOutputFiltersLayersAsExpected) {
+ StrictMock<mock::Layer> layer;
+ LayerFECompositionState layerFEState;
+
+ EXPECT_CALL(layer, getFEState()).WillRepeatedly(ReturnRef(layerFEState));
+
+ const uint32_t layerStack1 = 123u;
+ const uint32_t layerStack2 = 456u;
+
+ // If the output accepts layerStack1 and internal-only layers....
+ mOutput->setLayerStackFilter(layerStack1, true);
+
+ // A null layer pointer does not belong to the output
+ EXPECT_FALSE(mOutput->belongsInOutput(nullptr));
+
+ // A layer with no layerStack does not belong to it, internal-only or not.
+ layerFEState.layerStackId = std::nullopt;
+ layerFEState.internalOnly = false;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = std::nullopt;
+ layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+
+ // Any layer with layerStack1 belongs to it, internal-only or not.
+ layerFEState.layerStackId = layerStack1;
+ layerFEState.internalOnly = false;
+ EXPECT_TRUE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = layerStack1;
+ layerFEState.internalOnly = true;
+ EXPECT_TRUE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = layerStack2;
+ layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = layerStack2;
+ layerFEState.internalOnly = false;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+
+ // If the output accepts layerStack1 but not internal-only layers...
+ mOutput->setLayerStackFilter(layerStack1, false);
+
+ // A null layer pointer does not belong to the output
+ EXPECT_FALSE(mOutput->belongsInOutput(nullptr));
+
+ // Only non-internal layers with layerStack1 belong to it.
+ layerFEState.layerStackId = layerStack1;
+ layerFEState.internalOnly = false;
+ EXPECT_TRUE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = layerStack1;
+ layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = layerStack2;
+ layerFEState.internalOnly = true;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+
+ layerFEState.layerStackId = layerStack2;
+ layerFEState.internalOnly = false;
+ EXPECT_FALSE(mOutput->belongsInOutput(&layer));
+}
+
+/*
* Output::getOutputLayerForLayer()
*/
@@ -306,75 +460,489 @@
mock::OutputLayer* outputLayer1 = new StrictMock<mock::OutputLayer>();
mock::OutputLayer* outputLayer2 = new StrictMock<mock::OutputLayer>();
- Output::OutputLayers outputLayers;
- outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer1));
- outputLayers.emplace_back(nullptr);
- outputLayers.emplace_back(std::unique_ptr<OutputLayer>(outputLayer2));
- mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+ mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(outputLayer1));
+ mOutput->injectOutputLayerForTest(nullptr);
+ mOutput->injectOutputLayerForTest(std::unique_ptr<OutputLayer>(outputLayer2));
StrictMock<mock::Layer> layer;
StrictMock<mock::Layer> otherLayer;
// If the input layer matches the first OutputLayer, it will be returned.
EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(layer));
- EXPECT_EQ(outputLayer1, mOutput.getOutputLayerForLayer(&layer));
+ EXPECT_EQ(outputLayer1, mOutput->getOutputLayerForLayer(&layer));
// If the input layer matches the second OutputLayer, it will be returned.
EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(layer));
- EXPECT_EQ(outputLayer2, mOutput.getOutputLayerForLayer(&layer));
+ EXPECT_EQ(outputLayer2, mOutput->getOutputLayerForLayer(&layer));
// If the input layer does not match an output layer, null will be returned.
EXPECT_CALL(*outputLayer1, getLayer()).WillOnce(ReturnRef(otherLayer));
EXPECT_CALL(*outputLayer2, getLayer()).WillOnce(ReturnRef(otherLayer));
- EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
+ EXPECT_EQ(nullptr, mOutput->getOutputLayerForLayer(&layer));
}
-/* ------------------------------------------------------------------------
- * Output::getOrCreateOutputLayer()
+/*
+ * Output::prepareFrame()
*/
-TEST_F(OutputTest, getOrCreateOutputLayerWorks) {
- mock::OutputLayer* existingOutputLayer = new StrictMock<mock::OutputLayer>();
+struct OutputPrepareFrameTest : public testing::Test {
+ struct OutputPartialMock : public impl::Output {
+ // Sets up the helper functions called by prepareFrame to use a mock
+ // implementations.
+ MOCK_METHOD0(chooseCompositionStrategy, void());
- Output::OutputLayers outputLayers;
- outputLayers.emplace_back(nullptr);
- outputLayers.emplace_back(std::unique_ptr<OutputLayer>(existingOutputLayer));
- mOutput.setOutputLayersOrderedByZ(std::move(outputLayers));
+ // compositionengine::Output overrides
+ const OutputCompositionState& getState() const override { return mState; }
+ OutputCompositionState& editState() override { return mState; }
- std::shared_ptr<mock::Layer> layer{new StrictMock<mock::Layer>()};
- sp<LayerFE> layerFE{new StrictMock<mock::LayerFE>()};
+ // These need implementations though are not expected to be called.
+ MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
+ MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
+ compositionengine::OutputLayer*(size_t));
+ MOCK_METHOD3(ensureOutputLayer,
+ compositionengine::OutputLayer*(
+ std::optional<size_t>,
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD0(finalizePendingOutputLayers, void());
+ MOCK_METHOD0(clearOutputLayers, void());
+ MOCK_CONST_METHOD1(dumpState, void(std::string&));
+ MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&());
+ MOCK_METHOD2(injectOutputLayerForTest,
+ compositionengine::OutputLayer*(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>));
- StrictMock<mock::Layer> otherLayer;
+ impl::OutputCompositionState mState;
+ };
- {
- // If there is no OutputLayer corresponding to the input layer, a
- // new OutputLayer is constructed and returned.
- EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(otherLayer));
- auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
- EXPECT_NE(existingOutputLayer, result.get());
- EXPECT_TRUE(result.get() != nullptr);
- EXPECT_EQ(layer.get(), &result->getLayer());
- EXPECT_EQ(layerFE.get(), &result->getLayerFE());
-
- // The entries in the ordered array should be unchanged.
- auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
- EXPECT_EQ(nullptr, outputLayers[0].get());
- EXPECT_EQ(existingOutputLayer, outputLayers[1].get());
+ OutputPrepareFrameTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
}
- {
- // If there is an existing OutputLayer for the requested layer, an owned
- // pointer is returned
- EXPECT_CALL(*existingOutputLayer, getLayer()).WillOnce(ReturnRef(*layer));
- auto result = mOutput.getOrCreateOutputLayer(std::nullopt, layer, layerFE);
- EXPECT_EQ(existingOutputLayer, result.get());
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput;
+};
- // The corresponding entry in the ordered array should be cleared.
- auto& outputLayers = mOutput.getOutputLayersOrderedByZ();
- EXPECT_EQ(nullptr, outputLayers[0].get());
- EXPECT_EQ(nullptr, outputLayers[1].get());
+TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) {
+ mOutput.editState().isEnabled = false;
+
+ mOutput.prepareFrame();
+}
+
+TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+
+ EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
+
+ mOutput.prepareFrame();
+}
+
+// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
+// base chooseCompositionStrategy() is invoked.
+TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) {
+ mOutput->editState().isEnabled = true;
+ mOutput->editState().usesClientComposition = false;
+ mOutput->editState().usesDeviceComposition = true;
+
+ EXPECT_CALL(*mRenderSurface, prepareFrame(true, false));
+
+ mOutput->prepareFrame();
+
+ EXPECT_TRUE(mOutput->getState().usesClientComposition);
+ EXPECT_FALSE(mOutput->getState().usesDeviceComposition);
+}
+
+/*
+ * Output::composeSurfaces()
+ */
+
+struct OutputComposeSurfacesTest : public testing::Test {
+ static constexpr uint32_t kDefaultOutputOrientation = TR_IDENT;
+ static constexpr ui::Dataspace kDefaultOutputDataspace = ui::Dataspace::DISPLAY_P3;
+
+ static const Rect kDefaultOutputFrame;
+ static const Rect kDefaultOutputViewport;
+ static const Rect kDefaultOutputScissor;
+ static const mat4 kDefaultColorTransformMat;
+
+ struct OutputPartialMock : public impl::Output {
+ // Sets up the helper functions called by composeSurfaces to use a mock
+ // implementations.
+ MOCK_CONST_METHOD0(getSkipColorTransform, bool());
+ MOCK_METHOD2(generateClientCompositionRequests,
+ std::vector<renderengine::LayerSettings>(bool, Region&));
+ MOCK_METHOD2(appendRegionFlashRequests,
+ void(const Region&, std::vector<renderengine::LayerSettings>&));
+ MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+
+ // compositionengine::Output overrides
+ const OutputCompositionState& getState() const override { return mState; }
+ OutputCompositionState& editState() override { return mState; }
+
+ // These need implementations though are not expected to be called.
+ MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
+ MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
+ compositionengine::OutputLayer*(size_t));
+ MOCK_METHOD3(ensureOutputLayer,
+ compositionengine::OutputLayer*(
+ std::optional<size_t>,
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD0(finalizePendingOutputLayers, void());
+ MOCK_METHOD0(clearOutputLayers, void());
+ MOCK_CONST_METHOD1(dumpState, void(std::string&));
+ MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&());
+ MOCK_METHOD2(injectOutputLayerForTest,
+ compositionengine::OutputLayer*(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>));
+
+ impl::OutputCompositionState mState;
+ };
+
+ OutputComposeSurfacesTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+
+ mOutput.editState().frame = kDefaultOutputFrame;
+ mOutput.editState().viewport = kDefaultOutputViewport;
+ mOutput.editState().scissor = kDefaultOutputScissor;
+ mOutput.editState().transform = ui::Transform{kDefaultOutputOrientation};
+ mOutput.editState().orientation = kDefaultOutputOrientation;
+ mOutput.editState().dataspace = kDefaultOutputDataspace;
+ mOutput.editState().colorTransformMatrix = kDefaultColorTransformMat;
+ mOutput.editState().isSecure = true;
+ mOutput.editState().needsFiltering = false;
+ mOutput.editState().usesClientComposition = true;
+ mOutput.editState().usesDeviceComposition = false;
+
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
+ .WillRepeatedly(Return(&mOutputLayer1));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1u))
+ .WillRepeatedly(Return(&mOutputLayer2));
+ EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
+ EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
}
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<mock::OutputLayer> mOutputLayer1;
+ StrictMock<mock::OutputLayer> mOutputLayer2;
+ StrictMock<OutputPartialMock> mOutput;
+ sp<GraphicBuffer> mOutputBuffer = new GraphicBuffer();
+};
+
+const Rect OutputComposeSurfacesTest::kDefaultOutputFrame{1001, 1002, 1003, 1004};
+const Rect OutputComposeSurfacesTest::kDefaultOutputViewport{1005, 1006, 1007, 1008};
+const Rect OutputComposeSurfacesTest::kDefaultOutputScissor{1009, 1010, 1011, 1012};
+const mat4 OutputComposeSurfacesTest::kDefaultColorTransformMat{mat4() * 0.5};
+
+// TODO(b/121291683): Expand unit test coverage for composeSurfaces beyond these
+// basic tests.
+
+TEST_F(OutputComposeSurfacesTest, doesNothingIfNoClientComposition) {
+ mOutput.editState().usesClientComposition = false;
+
+ Region debugRegion;
+ std::optional<base::unique_fd> readyFence = mOutput.composeSurfaces(debugRegion);
+ EXPECT_TRUE(readyFence);
+}
+
+TEST_F(OutputComposeSurfacesTest, worksIfNoClientLayersQueued) {
+ const Region kDebugRegion{Rect{100, 101, 102, 103}};
+
+ constexpr float kDefaultMaxLuminance = 1.0f;
+ constexpr float kDefaultAvgLuminance = 0.7f;
+ constexpr float kDefaultMinLuminance = 0.1f;
+ HdrCapabilities HdrCapabilities{{},
+ kDefaultMaxLuminance,
+ kDefaultAvgLuminance,
+ kDefaultMinLuminance};
+
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillOnce(Return(false));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, _, _, true, _, _)).Times(1);
+
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillOnce(Return(true));
+ EXPECT_CALL(*mDisplayColorProfile, getHdrCapabilities()).WillOnce(ReturnRef(HdrCapabilities));
+
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_)).WillOnce(Return(mOutputBuffer));
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillOnce(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(false, _)).Times(1);
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _)).Times(1);
+ EXPECT_CALL(mOutput, setExpensiveRenderingExpected(true)).Times(1);
+ EXPECT_CALL(mOutput, setExpensiveRenderingExpected(false)).Times(1);
+
+ std::optional<base::unique_fd> readyFence = mOutput.composeSurfaces(kDebugRegion);
+ EXPECT_TRUE(readyFence);
+}
+
+/*
+ * Output::generateClientCompositionRequests()
+ */
+
+struct GenerateClientCompositionRequestsTest : public testing::Test {
+ struct OutputPartialMock : public impl::Output {
+ // compositionengine::Output overrides
+
+ std::vector<renderengine::LayerSettings> generateClientCompositionRequests(
+ bool supportsProtectedContent, Region& clearRegion) override {
+ return impl::Output::generateClientCompositionRequests(supportsProtectedContent,
+ clearRegion);
+ }
+
+ const OutputCompositionState& getState() const override { return mState; }
+ OutputCompositionState& editState() override { return mState; }
+
+ // These need implementations though are not expected to be called.
+ MOCK_CONST_METHOD0(getOutputLayerCount, size_t());
+ MOCK_CONST_METHOD1(getOutputLayerOrderedByZByIndex,
+ compositionengine::OutputLayer*(size_t));
+ MOCK_METHOD3(ensureOutputLayer,
+ compositionengine::OutputLayer*(
+ std::optional<size_t>,
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD0(finalizePendingOutputLayers, void());
+ MOCK_METHOD0(clearOutputLayers, void());
+ MOCK_CONST_METHOD1(dumpState, void(std::string&));
+ MOCK_CONST_METHOD0(getCompositionEngine, const CompositionEngine&());
+ MOCK_METHOD2(injectOutputLayerForTest,
+ compositionengine::OutputLayer*(
+ const std::shared_ptr<compositionengine::Layer>&, const sp<LayerFE>&));
+ MOCK_METHOD1(injectOutputLayerForTest, void(std::unique_ptr<OutputLayer>));
+
+ impl::OutputCompositionState mState;
+ };
+
+ GenerateClientCompositionRequestsTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput;
+};
+
+// TODO(b/121291683): Add more unit test coverage for generateClientCompositionRequests
+
+TEST_F(GenerateClientCompositionRequestsTest, worksForLandscapeModeSplitScreen) {
+ // In split-screen landscape mode, the screen is rotated 90 degrees, with
+ // one layer on the left covering the left side of the output, and one layer
+ // on the right covering that side of the output.
+
+ StrictMock<mock::OutputLayer> leftOutputLayer;
+ StrictMock<mock::OutputLayer> rightOutputLayer;
+
+ StrictMock<mock::Layer> leftLayer;
+ StrictMock<mock::LayerFE> leftLayerFE;
+ StrictMock<mock::Layer> rightLayer;
+ StrictMock<mock::LayerFE> rightLayerFE;
+
+ impl::OutputLayerCompositionState leftOutputLayerState;
+ leftOutputLayerState.clearClientTarget = false;
+ leftOutputLayerState.visibleRegion = Region{Rect{0, 0, 1000, 1000}};
+
+ LayerFECompositionState leftLayerFEState;
+ leftLayerFEState.isOpaque = true;
+
+ const half3 leftLayerColor{1.f, 0.f, 0.f};
+ renderengine::LayerSettings leftLayerRESettings;
+ leftLayerRESettings.source.solidColor = leftLayerColor;
+
+ impl::OutputLayerCompositionState rightOutputLayerState;
+ rightOutputLayerState.clearClientTarget = false;
+ rightOutputLayerState.visibleRegion = Region{Rect{1000, 0, 2000, 1000}};
+
+ LayerFECompositionState rightLayerFEState;
+ rightLayerFEState.isOpaque = true;
+
+ const half3 rightLayerColor{0.f, 1.f, 0.f};
+ renderengine::LayerSettings rightLayerRESettings;
+ rightLayerRESettings.source.solidColor = rightLayerColor;
+
+ EXPECT_CALL(leftOutputLayer, getState()).WillRepeatedly(ReturnRef(leftOutputLayerState));
+ EXPECT_CALL(leftOutputLayer, getLayer()).WillRepeatedly(ReturnRef(leftLayer));
+ EXPECT_CALL(leftOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(leftLayerFE));
+ EXPECT_CALL(leftOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+ EXPECT_CALL(leftOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
+ EXPECT_CALL(leftLayer, getFEState()).WillRepeatedly(ReturnRef(leftLayerFEState));
+ EXPECT_CALL(leftLayerFE, prepareClientComposition(_)).WillOnce(Return(leftLayerRESettings));
+
+ EXPECT_CALL(rightOutputLayer, getState()).WillRepeatedly(ReturnRef(rightOutputLayerState));
+ EXPECT_CALL(rightOutputLayer, getLayer()).WillRepeatedly(ReturnRef(rightLayer));
+ EXPECT_CALL(rightOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(rightLayerFE));
+ EXPECT_CALL(rightOutputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+ EXPECT_CALL(rightOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
+ EXPECT_CALL(rightLayer, getFEState()).WillRepeatedly(ReturnRef(rightLayerFEState));
+ EXPECT_CALL(rightLayerFE, prepareClientComposition(_)).WillOnce(Return(rightLayerRESettings));
+
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
+ .WillRepeatedly(Return(&leftOutputLayer));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1u))
+ .WillRepeatedly(Return(&rightOutputLayer));
+
+ const Rect kPortraitFrame(0, 0, 1000, 2000);
+ const Rect kPortraitViewport(0, 0, 2000, 1000);
+ const Rect kPortraitScissor(0, 0, 1000, 2000);
+ const uint32_t kPortraitOrientation = TR_ROT_90;
+
+ mOutput.editState().frame = kPortraitFrame;
+ mOutput.editState().viewport = kPortraitViewport;
+ mOutput.editState().scissor = kPortraitScissor;
+ mOutput.editState().transform = ui::Transform{kPortraitOrientation};
+ mOutput.editState().orientation = kPortraitOrientation;
+ mOutput.editState().needsFiltering = true;
+ mOutput.editState().isSecure = false;
+
+ constexpr bool supportsProtectedContent = false;
+ Region clearRegion;
+ auto requests =
+ mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion);
+
+ ASSERT_EQ(2u, requests.size());
+ EXPECT_EQ(leftLayerColor, requests[0].source.solidColor);
+ EXPECT_EQ(rightLayerColor, requests[1].source.solidColor);
+}
+
+TEST_F(GenerateClientCompositionRequestsTest, ignoresLayersThatDoNotIntersectWithViewport) {
+ // Layers whose visible region does not intersect with the viewport will be
+ // skipped when generating client composition request state.
+
+ StrictMock<mock::OutputLayer> outputLayer;
+ StrictMock<mock::Layer> layer;
+ StrictMock<mock::LayerFE> layerFE;
+
+ impl::OutputLayerCompositionState outputLayerState;
+ outputLayerState.clearClientTarget = false;
+ outputLayerState.visibleRegion = Region{Rect{3000, 0, 4000, 1000}};
+
+ LayerFECompositionState layerFEState;
+ layerFEState.isOpaque = true;
+
+ EXPECT_CALL(outputLayer, getState()).WillRepeatedly(ReturnRef(outputLayerState));
+ EXPECT_CALL(outputLayer, getLayer()).WillRepeatedly(ReturnRef(layer));
+ EXPECT_CALL(outputLayer, getLayerFE()).WillRepeatedly(ReturnRef(layerFE));
+ EXPECT_CALL(outputLayer, requiresClientComposition()).WillRepeatedly(Return(true));
+ EXPECT_CALL(outputLayer, needsFiltering()).WillRepeatedly(Return(false));
+ EXPECT_CALL(layer, getFEState()).WillRepeatedly(ReturnRef(layerFEState));
+ EXPECT_CALL(layerFE, prepareClientComposition(_)).Times(0);
+
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(1u));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u)).WillRepeatedly(Return(&outputLayer));
+
+ const Rect kPortraitFrame(0, 0, 1000, 2000);
+ const Rect kPortraitViewport(0, 0, 2000, 1000);
+ const Rect kPortraitScissor(0, 0, 1000, 2000);
+ const uint32_t kPortraitOrientation = TR_ROT_90;
+
+ mOutput.editState().frame = kPortraitFrame;
+ mOutput.editState().viewport = kPortraitViewport;
+ mOutput.editState().scissor = kPortraitScissor;
+ mOutput.editState().transform = ui::Transform{kPortraitOrientation};
+ mOutput.editState().orientation = kPortraitOrientation;
+ mOutput.editState().needsFiltering = true;
+ mOutput.editState().isSecure = false;
+
+ constexpr bool supportsProtectedContent = false;
+ Region clearRegion;
+ auto requests =
+ mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion);
+
+ EXPECT_EQ(0u, requests.size());
+}
+
+TEST_F(GenerateClientCompositionRequestsTest, clearsDeviceLayesAfterFirst) {
+ // If client composition is performed with some layers set to use device
+ // composition, device layers after the first layer (device or client) will
+ // clear the frame buffer if they are opaque and if that layer has a flag
+ // set to do so. The first layer is skipped as the frame buffer is already
+ // expected to be clear.
+
+ StrictMock<mock::OutputLayer> leftOutputLayer;
+ StrictMock<mock::OutputLayer> rightOutputLayer;
+
+ StrictMock<mock::Layer> leftLayer;
+ StrictMock<mock::LayerFE> leftLayerFE;
+ StrictMock<mock::Layer> rightLayer;
+ StrictMock<mock::LayerFE> rightLayerFE;
+
+ impl::OutputLayerCompositionState leftOutputLayerState;
+ leftOutputLayerState.clearClientTarget = true;
+ leftOutputLayerState.visibleRegion = Region{Rect{0, 0, 1000, 1000}};
+
+ LayerFECompositionState leftLayerFEState;
+ leftLayerFEState.isOpaque = true;
+
+ impl::OutputLayerCompositionState rightOutputLayerState;
+ rightOutputLayerState.clearClientTarget = true;
+ rightOutputLayerState.visibleRegion = Region{Rect{1000, 0, 2000, 1000}};
+
+ LayerFECompositionState rightLayerFEState;
+ rightLayerFEState.isOpaque = true;
+
+ const half3 rightLayerColor{0.f, 1.f, 0.f};
+ renderengine::LayerSettings rightLayerRESettings;
+ rightLayerRESettings.geometry.boundaries = FloatRect{456, 0, 0, 0};
+ rightLayerRESettings.source.solidColor = rightLayerColor;
+
+ EXPECT_CALL(leftOutputLayer, getState()).WillRepeatedly(ReturnRef(leftOutputLayerState));
+ EXPECT_CALL(leftOutputLayer, getLayer()).WillRepeatedly(ReturnRef(leftLayer));
+ EXPECT_CALL(leftOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(leftLayerFE));
+ EXPECT_CALL(leftOutputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
+ EXPECT_CALL(leftOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
+ EXPECT_CALL(leftLayer, getFEState()).WillRepeatedly(ReturnRef(leftLayerFEState));
+
+ EXPECT_CALL(rightOutputLayer, getState()).WillRepeatedly(ReturnRef(rightOutputLayerState));
+ EXPECT_CALL(rightOutputLayer, getLayer()).WillRepeatedly(ReturnRef(rightLayer));
+ EXPECT_CALL(rightOutputLayer, getLayerFE()).WillRepeatedly(ReturnRef(rightLayerFE));
+ EXPECT_CALL(rightOutputLayer, requiresClientComposition()).WillRepeatedly(Return(false));
+ EXPECT_CALL(rightOutputLayer, needsFiltering()).WillRepeatedly(Return(false));
+ EXPECT_CALL(rightLayer, getFEState()).WillRepeatedly(ReturnRef(rightLayerFEState));
+ EXPECT_CALL(rightLayerFE, prepareClientComposition(_)).WillOnce(Return(rightLayerRESettings));
+
+ EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(2u));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(0u))
+ .WillRepeatedly(Return(&leftOutputLayer));
+ EXPECT_CALL(mOutput, getOutputLayerOrderedByZByIndex(1u))
+ .WillRepeatedly(Return(&rightOutputLayer));
+
+ const Rect kPortraitFrame(0, 0, 1000, 2000);
+ const Rect kPortraitViewport(0, 0, 2000, 1000);
+ const Rect kPortraitScissor(0, 0, 1000, 2000);
+ const uint32_t kPortraitOrientation = TR_ROT_90;
+
+ mOutput.editState().frame = kPortraitFrame;
+ mOutput.editState().viewport = kPortraitViewport;
+ mOutput.editState().scissor = kPortraitScissor;
+ mOutput.editState().transform = ui::Transform{kPortraitOrientation};
+ mOutput.editState().orientation = kPortraitOrientation;
+ mOutput.editState().needsFiltering = true;
+ mOutput.editState().isSecure = false;
+
+ constexpr bool supportsProtectedContent = false;
+ Region clearRegion;
+ auto requests =
+ mOutput.generateClientCompositionRequests(supportsProtectedContent, clearRegion);
+
+ const half3 clearColor{0.f, 0.f, 0.f};
+
+ ASSERT_EQ(1u, requests.size());
+ EXPECT_EQ(456.f, requests[0].geometry.boundaries.left);
+ EXPECT_EQ(clearColor, requests[0].source.solidColor);
}
} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index f75a4dc..da3f4fb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -18,6 +18,7 @@
#include <cstdint>
#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/Display.h>
@@ -27,15 +28,9 @@
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
-#include "MockHWComposer.h"
-
namespace android::compositionengine {
namespace {
-/* ------------------------------------------------------------------------
- * RenderSurfaceTest
- */
-
constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
@@ -55,14 +50,11 @@
RenderSurfaceTest() {
EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
- EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL))
.WillRepeatedly(Return(NO_ERROR));
}
- ~RenderSurfaceTest() override = default;
- StrictMock<android::mock::HWComposer> mHwComposer;
StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
StrictMock<mock::CompositionEngine> mCompositionEngine;
StrictMock<mock::Display> mDisplay;
@@ -74,7 +66,7 @@
mDisplaySurface}};
};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -82,7 +74,7 @@
EXPECT_TRUE(mSurface.isValid());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::initialize()
*/
@@ -95,7 +87,7 @@
mSurface.initialize();
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::getSize()
*/
@@ -105,7 +97,7 @@
EXPECT_EQ(expected, mSurface.getSize());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::getClientTargetAcquireFence()
*/
@@ -117,7 +109,7 @@
EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setDisplaySize()
*/
@@ -127,7 +119,7 @@
mSurface.setDisplaySize(ui::Size(640, 480));
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setBufferDataspace()
*/
@@ -138,7 +130,7 @@
mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setProtected()
*/
@@ -179,7 +171,7 @@
EXPECT_FALSE(mSurface.isProtected());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::beginFrame()
*/
@@ -189,73 +181,39 @@
EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::prepareFrame()
*/
-TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(INVALID_OPERATION));
-
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(INVALID_OPERATION));
-
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
- .WillOnce(Return(INVALID_OPERATION));
+ .WillOnce(Return(NO_ERROR));
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+ mSurface.prepareFrame(true, true);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(true, false);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(false, true);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(false, false);
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::dequeueBuffer()
*/
@@ -272,7 +230,7 @@
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::queueBuffer()
*/
@@ -280,9 +238,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
- .WillOnce(Return(false));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = false;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
mSurface.queueBuffer(base::unique_fd());
@@ -294,7 +254,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = true;
+ state.flipClientTarget = false;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -308,8 +272,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -322,8 +289,11 @@
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
sp<GraphicBuffer> buffer = new GraphicBuffer();
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
.WillOnce(
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
@@ -340,7 +310,10 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(INVALID_OPERATION));
EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
@@ -353,7 +326,7 @@
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::onPresentDisplayCompleted()
*/
@@ -363,21 +336,7 @@
mSurface.onPresentDisplayCompleted();
}
-/* ------------------------------------------------------------------------
- * RenderSurface::setViewportAndProjection()
- */
-
-TEST_F(RenderSurfaceTest, setViewportAndProjectionAppliesChang) {
- mSurface.setSizeForTest(ui::Size(100, 200));
-
- EXPECT_CALL(mRenderEngine,
- setViewportAndProjection(100, 200, Rect(100, 200), ui::Transform::ROT_0))
- .Times(1);
-
- mSurface.setViewportAndProjection();
-}
-
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::flip()
*/
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..cb50d9f 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,20 +26,15 @@
ContainerLayer::~ContainerLayer() = default;
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
- renderengine::LayerSettings&) {
- return false;
-}
-
bool ContainerLayer::isVisible() const {
return false;
}
-bool ContainerLayer::canReceiveInput() const {
- return !isHiddenByPolicy();
+sp<Layer> ContainerLayer::createClone() {
+ String8 name = mName + " (Mirror)";
+ sp<ContainerLayer> layer = new ContainerLayer(
+ LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, 0, LayerMetadata()));
+ layer->setInitialValuesForClone(this);
+ return layer;
}
-
-void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
- const Rect&, int32_t, const ui::Dataspace) {}
-
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..b48d471 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -28,24 +28,13 @@
explicit ContainerLayer(const LayerCreationArgs&);
~ContainerLayer() override;
- const char* getTypeId() const override { return "ContainerLayer"; }
+ const char* getType() const override { return "ContainerLayer"; }
bool isVisible() const override;
- bool canReceiveInput() const override;
-
- void setPerFrameData(const sp<const DisplayDevice>& display, const ui::Transform& transform,
- const Rect& viewport, int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) 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,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
+ sp<Layer> createClone() override;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 5700d72..89123df 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -59,12 +59,13 @@
mSequenceId(args.sequenceId),
mDisplayInstallOrientation(args.displayInstallOrientation),
mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
- compositionengine::DisplayCreationArgs{args.isSecure, args.isVirtual,
- args.displayId})},
+ compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
+ args.powerAdvisor})},
mIsVirtual(args.isVirtual),
mOrientation(),
mActiveConfig(0),
mIsPrimary(args.isPrimary) {
+ mCompositionDisplay->editState().isSecure = args.isSecure;
mCompositionDisplay->createRenderSurface(
compositionengine::RenderSurfaceCreationArgs{ANativeWindow_getWidth(
args.nativeWindow.get()),
@@ -117,24 +118,6 @@
}
// ----------------------------------------------------------------------------
-
-void DisplayDevice::setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers) {
- mVisibleLayersSortedByZ = layers;
-}
-
-const Vector< sp<Layer> >& DisplayDevice::getVisibleLayersSortedByZ() const {
- return mVisibleLayersSortedByZ;
-}
-
-void DisplayDevice::setLayersNeedingFences(const Vector< sp<Layer> >& layers) {
- mLayersNeedingFences = layers;
-}
-
-const Vector< sp<Layer> >& DisplayDevice::getLayersNeedingFences() const {
- return mLayersNeedingFences;
-}
-
-// ----------------------------------------------------------------------------
void DisplayDevice::setPowerMode(int mode) {
mPowerMode = mode;
getCompositionDisplay()->setCompositionEnabled(mPowerMode != HWC_POWER_MODE_OFF);
@@ -303,7 +286,6 @@
result.append(" ");
StringAppendF(&result, "powerMode=%d, ", mPowerMode);
StringAppendF(&result, "activeConfig=%d, ", mActiveConfig);
- StringAppendF(&result, "numLayers=%zu\n", mVisibleLayersSortedByZ.size());
getCompositionDisplay()->dump(result);
}
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 0067b50..ce4e1e6 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -31,6 +31,7 @@
#include <math/mat4.h>
#include <renderengine/RenderEngine.h>
#include <system/window.h>
+#include <ui/DisplayInfo.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
#include <ui/Region.h>
@@ -40,6 +41,7 @@
#include <utils/Timers.h>
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/PowerAdvisor.h"
#include "RenderArea.h"
namespace android {
@@ -64,10 +66,6 @@
constexpr static float sDefaultMinLumiance = 0.0;
constexpr static float sDefaultMaxLumiance = 500.0;
- enum {
- NO_LAYER_STACK = 0xFFFFFFFF,
- };
-
explicit DisplayDevice(DisplayDeviceCreationArgs&& args);
virtual ~DisplayDevice();
@@ -86,11 +84,6 @@
int getHeight() const;
int getInstallOrientation() const { return mDisplayInstallOrientation; }
- void setVisibleLayersSortedByZ(const Vector< sp<Layer> >& layers);
- const Vector< sp<Layer> >& getVisibleLayersSortedByZ() const;
- void setLayersNeedingFences(const Vector< sp<Layer> >& layers);
- const Vector< sp<Layer> >& getLayersNeedingFences() const;
-
void setLayerStack(uint32_t stack);
void setDisplaySize(const int newWidth, const int newHeight);
void setProjection(int orientation, const Rect& viewport, const Rect& frame);
@@ -180,11 +173,6 @@
* don't need synchronization.
*/
- // list of visible layers on that display
- Vector< sp<Layer> > mVisibleLayersSortedByZ;
- // list of layers needing fences
- Vector< sp<Layer> > mLayersNeedingFences;
-
/*
* Transaction state
*/
@@ -210,7 +198,7 @@
int32_t sequenceId = sNextSequenceId++;
std::optional<DisplayId> displayId;
sp<IGraphicBufferProducer> surface;
- uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
+ uint32_t layerStack = NO_LAYER_STACK;
Rect viewport;
Rect frame;
uint8_t orientation = 0;
@@ -245,6 +233,7 @@
std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hwcColorModes;
int initialPowerMode{HWC_POWER_MODE_NORMAL};
bool isPrimary{false};
+ Hwc2::PowerAdvisor* powerAdvisor{nullptr};
};
class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 7f47a2e..e53d099 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -110,6 +110,7 @@
namespace impl {
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Composer::CommandWriter::CommandWriter(uint32_t initialMaxSize)
: CommandWriterBase(initialMaxSize) {}
@@ -160,6 +161,7 @@
writeSigned(static_cast<int32_t>(metadata.format));
write64(metadata.usage);
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Composer::Composer(const std::string& serviceName)
: mWriter(kWriterInitialSize),
@@ -198,12 +200,14 @@
LOG_ALWAYS_FATAL("failed to create composer client");
}
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer) {
sp<IVrComposerClient> vrClient = IVrComposerClient::castFrom(mClient);
if (vrClient == nullptr) {
LOG_ALWAYS_FATAL("failed to create vr composer client");
}
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
}
Composer::~Composer() = default;
@@ -565,17 +569,20 @@
const std::vector<IComposerClient::Rect>& damage)
{
mWriter.selectDisplay(display);
+
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer && target.get()) {
IVrComposerClient::BufferMetadata metadata = {
- .width = target->getWidth(),
- .height = target->getHeight(),
- .stride = target->getStride(),
- .layerCount = target->getLayerCount(),
- .format = static_cast<types::V1_0::PixelFormat>(target->getPixelFormat()),
- .usage = target->getUsage(),
+ .width = target->getWidth(),
+ .height = target->getHeight(),
+ .stride = target->getStride(),
+ .layerCount = target->getLayerCount(),
+ .format = static_cast<types::V1_2::PixelFormat>(target->getPixelFormat()),
+ .usage = target->getUsage(),
};
mWriter.setClientTargetMetadata(metadata);
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
const native_handle_t* handle = nullptr;
if (target.get()) {
@@ -695,17 +702,20 @@
{
mWriter.selectDisplay(display);
mWriter.selectLayer(layer);
+
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
if (mIsUsingVrComposer && buffer.get()) {
IVrComposerClient::BufferMetadata metadata = {
- .width = buffer->getWidth(),
- .height = buffer->getHeight(),
- .stride = buffer->getStride(),
- .layerCount = buffer->getLayerCount(),
- .format = static_cast<types::V1_0::PixelFormat>(buffer->getPixelFormat()),
- .usage = buffer->getUsage(),
+ .width = buffer->getWidth(),
+ .height = buffer->getHeight(),
+ .stride = buffer->getStride(),
+ .layerCount = buffer->getLayerCount(),
+ .format = static_cast<types::V1_2::PixelFormat>(buffer->getPixelFormat()),
+ .usage = buffer->getUsage(),
};
mWriter.setLayerBufferMetadata(metadata);
}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
const native_handle_t* handle = nullptr;
if (buffer.get()) {
@@ -823,6 +833,7 @@
return Error::NONE;
}
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Error Composer::setLayerInfo(Display display, Layer layer, uint32_t type,
uint32_t appId)
{
@@ -833,6 +844,15 @@
}
return Error::NONE;
}
+#else
+Error Composer::setLayerInfo(Display display, Layer layer, uint32_t, uint32_t) {
+ if (mIsUsingVrComposer) {
+ mWriter.selectDisplay(display);
+ mWriter.selectLayer(layer);
+ }
+ return Error::NONE;
+}
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
Error Composer::execute()
{
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index c4e952b..9f6cac2 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -23,7 +23,9 @@
#include <utility>
#include <vector>
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
#include <android/hardware/graphics/common/1.1/types.h>
#include <android/hardware/graphics/composer/2.3/IComposer.h>
#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
@@ -38,7 +40,9 @@
namespace Hwc2 {
-using frameworks::vr::composer::V1_0::IVrComposerClient;
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
+using frameworks::vr::composer::V2_0::IVrComposerClient;
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
namespace types = hardware::graphics::common;
@@ -418,6 +422,7 @@
Error setDisplayBrightness(Display display, float brightness) override;
private:
+#if defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
class CommandWriter : public CommandWriterBase {
public:
explicit CommandWriter(uint32_t initialMaxSize);
@@ -433,6 +438,13 @@
void writeBufferMetadata(
const IVrComposerClient::BufferMetadata& metadata);
};
+#else
+ class CommandWriter : public CommandWriterBase {
+ public:
+ explicit CommandWriter(uint32_t initialMaxSize) : CommandWriterBase(initialMaxSize) {}
+ ~CommandWriter() override {}
+ };
+#endif // defined(USE_VR_COMPOSER) && USE_VR_COMPOSER
// Many public functions above simply write a command into the command
// queue to batch the calls. validateDisplay and presentDisplay will call
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1099041..d480f7c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,6 +20,8 @@
#define LOG_TAG "HWComposer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "HWComposer.h"
+
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -29,12 +31,10 @@
#include <utils/Errors.h>
#include <utils/Trace.h>
-#include "HWComposer.h"
-#include "HWC2.h"
-#include "ComposerHal.h"
-
-#include "../Layer.h" // needed only for debugging
+#include "../Layer.h" // needed only for debugging
#include "../SurfaceFlinger.h"
+#include "ComposerHal.h"
+#include "HWC2.h"
#define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
@@ -113,31 +113,6 @@
return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
}
-void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
- bool valid = true;
- switch (from) {
- case HWC2::Composition::Client:
- valid = false;
- break;
- case HWC2::Composition::Device:
- case HWC2::Composition::SolidColor:
- valid = (to == HWC2::Composition::Client);
- break;
- case HWC2::Composition::Cursor:
- case HWC2::Composition::Sideband:
- valid = (to == HWC2::Composition::Client ||
- to == HWC2::Composition::Device);
- break;
- default:
- break;
- }
-
- if (!valid) {
- ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(),
- to_string(to).c_str());
- }
-}
-
std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
std::optional<DisplayIdentificationInfo> info;
@@ -399,7 +374,9 @@
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) {
+status_t HWComposer::getDeviceCompositionChanges(
+ DisplayId displayId, bool frameUsesClientComposition,
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -419,12 +396,8 @@
// composition. When there is client composition, since we haven't
// rendered to the client target yet, we should not attempt to skip
// validate.
- //
- // displayData.hasClientComposition hasn't been updated for this frame.
- // The check below is incorrect. We actually rely on HWC here to fall
- // back to validate when there is any client layer.
displayData.validateWasSkipped = false;
- if (!displayData.hasClientComposition) {
+ if (!frameUsesClientComposition) {
sp<Fence> outPresentFence;
uint32_t state = UINT32_MAX;
error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
@@ -449,58 +422,19 @@
RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX);
}
- std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
+ android::HWComposer::DeviceRequestedChanges::ChangedTypes changedTypes;
changedTypes.reserve(numTypes);
error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX);
- displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
- std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
+ auto displayRequests = static_cast<HWC2::DisplayRequest>(0);
+ android::HWComposer::DeviceRequestedChanges::LayerRequests layerRequests;
layerRequests.reserve(numRequests);
- error = hwcDisplay->getRequests(&displayData.displayRequests,
- &layerRequests);
+ error = hwcDisplay->getRequests(&displayRequests, &layerRequests);
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
- displayData.hasClientComposition = false;
- displayData.hasDeviceComposition = false;
- for (auto& outputLayer : output.getOutputLayersOrderedByZ()) {
- auto& state = outputLayer->editState();
- LOG_FATAL_IF(!state.hwc.);
- auto hwcLayer = (*state.hwc).hwcLayer;
-
- if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) {
- auto newCompositionType = it->second;
- validateChange(static_cast<HWC2::Composition>((*state.hwc).hwcCompositionType),
- newCompositionType);
- (*state.hwc).hwcCompositionType =
- static_cast<Hwc2::IComposerClient::Composition>(newCompositionType);
- }
-
- switch ((*state.hwc).hwcCompositionType) {
- case Hwc2::IComposerClient::Composition::CLIENT:
- displayData.hasClientComposition = true;
- break;
- case Hwc2::IComposerClient::Composition::DEVICE:
- case Hwc2::IComposerClient::Composition::SOLID_COLOR:
- case Hwc2::IComposerClient::Composition::CURSOR:
- case Hwc2::IComposerClient::Composition::SIDEBAND:
- displayData.hasDeviceComposition = true;
- break;
- default:
- break;
- }
-
- state.clearClientTarget = false;
- if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) {
- auto request = it->second;
- if (request == HWC2::LayerRequest::ClearClientTarget) {
- state.clearClientTarget = true;
- } else {
- LOG_DISPLAY_ERROR(displayId,
- ("Unknown layer request " + to_string(request)).c_str());
- }
- }
- }
+ outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
+ std::move(layerRequests)});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
@@ -508,40 +442,6 @@
return NO_ERROR;
}
-bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are never composed by
- // the device
- return false;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return mDisplayData.at(*displayId).hasDeviceComposition;
-}
-
-bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are never composed by
- // the device
- return false;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
- static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
-}
-
-bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are always composed by
- // the client
- return true;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, true);
- return mDisplayData.at(*displayId).hasClientComposition;
-}
-
sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
return mDisplayData.at(displayId).lastPresentFence;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index de863b8..e87c5c3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -71,8 +71,26 @@
// Destroy a previously created layer
virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
- // Asks the HAL what it can do
- virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0;
+ struct DeviceRequestedChanges {
+ using ChangedTypes = std::unordered_map<HWC2::Layer*, HWC2::Composition>;
+ using DisplayRequests = HWC2::DisplayRequest;
+ using LayerRequests = std::unordered_map<HWC2::Layer*, HWC2::LayerRequest>;
+
+ ChangedTypes changedTypes;
+ DisplayRequests displayRequests;
+ LayerRequests layerRequests;
+ };
+
+ // Gets any required composition change requests from the HWC device.
+ //
+ // Note that frameUsesClientComposition must be set correctly based on
+ // whether the current frame appears to use client composition. If it is
+ // false some internal optimizations are allowed to present the display
+ // with fewer handshakes, but this does not work if client composition is
+ // expected.
+ virtual status_t getDeviceCompositionChanges(
+ DisplayId, bool frameUsesClientComposition,
+ std::optional<DeviceRequestedChanges>* outChanges) = 0;
virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
@@ -93,15 +111,6 @@
// reset state when an external, non-virtual display is disconnected
virtual void disconnectDisplay(DisplayId displayId) = 0;
- // does this display have layers handled by HWC
- virtual bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const = 0;
-
- // does this display have pending request to flip client target
- virtual bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const = 0;
-
- // does this display have layers handled by GLES
- virtual bool hasClientComposition(const std::optional<DisplayId>& displayId) const = 0;
-
// get the present fence received from the last call to present.
virtual sp<Fence> getPresentFence(DisplayId displayId) const = 0;
@@ -210,8 +219,9 @@
// Destroy a previously created layer
void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
- // Asks the HAL what it can do
- status_t prepare(DisplayId displayId, const compositionengine::Output&) override;
+ status_t getDeviceCompositionChanges(
+ DisplayId, bool frameUsesClientComposition,
+ std::optional<DeviceRequestedChanges>* outChanges) override;
status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
@@ -231,15 +241,6 @@
// reset state when an external, non-virtual display is disconnected
void disconnectDisplay(DisplayId displayId) override;
- // does this display have layers handled by HWC
- bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const override;
-
- // does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const override;
-
- // does this display have layers handled by GLES
- bool hasClientComposition(const std::optional<DisplayId>& displayId) const override;
-
// get the present fence received from the last call to present.
sp<Fence> getPresentFence(DisplayId displayId) const override;
@@ -326,14 +327,10 @@
std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
- static void validateChange(HWC2::Composition from, HWC2::Composition to);
-
struct DisplayData {
bool isVirtual = false;
- bool hasClientComposition = false;
- bool hasDeviceComposition = false;
+
HWC2::Display* hwcDisplay = nullptr;
- HWC2::DisplayRequest displayRequests;
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle = nullptr;
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.cpp b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
new file mode 100644
index 0000000..006dbfe
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "FrameTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "FrameTracer.h"
+
+#include <android-base/stringprintf.h>
+
+#include <algorithm>
+#include <mutex>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::FrameTracer::FrameTracerDataSource);
+
+namespace android {
+
+void FrameTracer::initialize() {
+ std::call_once(mInitializationFlag, [this]() {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kSystemBackend;
+ perfetto::Tracing::Initialize(args);
+ registerDataSource();
+ });
+}
+
+void FrameTracer::registerDataSource() {
+ perfetto::DataSourceDescriptor dsd;
+ dsd.set_name(kFrameTracerDataSource);
+ FrameTracerDataSource::Register(dsd);
+}
+
+void FrameTracer::traceNewLayer(int32_t layerID, const std::string& layerName) {
+ FrameTracerDataSource::Trace([this, layerID, &layerName](FrameTracerDataSource::TraceContext) {
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ mTraceTracker[layerID].layerName = layerName;
+ }
+ });
+}
+
+void FrameTracer::traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, timestamp, type,
+ duration](FrameTracerDataSource::TraceContext ctx) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ // Complete current trace.
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+ });
+}
+
+void FrameTracer::traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence,
+ FrameEvent::BufferEventType type, nsecs_t startTime) {
+ FrameTracerDataSource::Trace([this, layerID, bufferID, frameNumber, &fence, type,
+ startTime](FrameTracerDataSource::TraceContext ctx) {
+ const nsecs_t signalTime = fence->getSignalTime();
+ if (signalTime != Fence::SIGNAL_TIME_INVALID) {
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ if (mTraceTracker.find(layerID) == mTraceTracker.end()) {
+ return;
+ }
+
+ // Handle any pending fences for this buffer.
+ tracePendingFencesLocked(ctx, layerID, bufferID);
+
+ if (signalTime != Fence::SIGNAL_TIME_PENDING) {
+ traceSpanLocked(ctx, layerID, bufferID, frameNumber, type, startTime, signalTime);
+ } else {
+ mTraceTracker[layerID].pendingFences[bufferID].push_back(
+ {.frameNumber = frameNumber,
+ .type = type,
+ .fence = fence,
+ .startTime = startTime});
+ }
+ }
+ });
+}
+
+void FrameTracer::tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx,
+ int32_t layerID, uint64_t bufferID) {
+ if (mTraceTracker[layerID].pendingFences.count(bufferID)) {
+ auto& pendingFences = mTraceTracker[layerID].pendingFences[bufferID];
+ for (size_t i = 0; i < pendingFences.size(); ++i) {
+ auto& pendingFence = pendingFences[i];
+
+ nsecs_t signalTime = Fence::SIGNAL_TIME_INVALID;
+ if (pendingFence.fence && pendingFence.fence->isValid()) {
+ signalTime = pendingFence.fence->getSignalTime();
+ if (signalTime == Fence::SIGNAL_TIME_PENDING) {
+ continue;
+ }
+ }
+
+ if (signalTime != Fence::SIGNAL_TIME_INVALID &&
+ systemTime() - signalTime < kFenceSignallingDeadline) {
+ traceSpanLocked(ctx, layerID, bufferID, pendingFence.frameNumber, pendingFence.type,
+ pendingFence.startTime, signalTime);
+ }
+
+ pendingFences.erase(pendingFences.begin() + i);
+ --i;
+ }
+ }
+}
+
+void FrameTracer::traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration) {
+ auto packet = ctx.NewTracePacket();
+ packet->set_timestamp(timestamp);
+ auto* event = packet->set_graphics_frame_event()->set_buffer_event();
+ event->set_buffer_id(static_cast<uint32_t>(bufferID));
+ event->set_frame_number(frameNumber);
+ event->set_type(type);
+
+ if (mTraceTracker.find(layerID) != mTraceTracker.end() &&
+ !mTraceTracker[layerID].layerName.empty()) {
+ const std::string& layerName = mTraceTracker[layerID].layerName;
+ event->set_layer_name(layerName.c_str(), layerName.size());
+ }
+
+ if (duration > 0) {
+ event->set_duration_ns(duration);
+ }
+}
+
+void FrameTracer::traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber,
+ FrameEvent::BufferEventType type, nsecs_t startTime,
+ nsecs_t endTime) {
+ nsecs_t timestamp = endTime;
+ nsecs_t duration = 0;
+ if (startTime > 0 && startTime < endTime) {
+ timestamp = startTime;
+ duration = endTime - startTime;
+ }
+ traceLocked(ctx, layerID, bufferID, frameNumber, timestamp, type, duration);
+}
+
+void FrameTracer::onDestroy(int32_t layerID) {
+ std::lock_guard<std::mutex> traceLock(mTraceMutex);
+ mTraceTracker.erase(layerID);
+}
+
+std::string FrameTracer::miniDump() {
+ std::string result = "FrameTracer miniDump:\n";
+ std::lock_guard<std::mutex> lock(mTraceMutex);
+ android::base::StringAppendF(&result, "Number of layers currently being traced is %zu\n",
+ mTraceTracker.size());
+ return result;
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/FrameTracer/FrameTracer.h b/services/surfaceflinger/FrameTracer/FrameTracer.h
new file mode 100644
index 0000000..d4dfab9
--- /dev/null
+++ b/services/surfaceflinger/FrameTracer/FrameTracer.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <perfetto/trace/android/graphics_frame_event.pbzero.h>
+#include <perfetto/tracing.h>
+#include <ui/FenceTime.h>
+
+#include <mutex>
+#include <unordered_map>
+
+namespace android {
+
+class FrameTracer {
+public:
+ class FrameTracerDataSource : public perfetto::DataSource<FrameTracerDataSource> {
+ virtual void OnSetup(const SetupArgs&) override{};
+ virtual void OnStart(const StartArgs&) override{};
+ virtual void OnStop(const StopArgs&) override{};
+ };
+
+ using FrameEvent = perfetto::protos::pbzero::GraphicsFrameEvent;
+
+ ~FrameTracer() = default;
+
+ // Sets up the perfetto tracing backend and data source.
+ void initialize();
+ // Registers the data source with the perfetto backend. Called as part of initialize()
+ // and should not be called manually outside of tests. Public to allow for substituting a
+ // perfetto::kInProcessBackend in tests.
+ void registerDataSource();
+ // Starts tracking a new layer for tracing. Needs to be called once before traceTimestamp() or
+ // traceFence() for each layer.
+ void traceNewLayer(int32_t layerID, const std::string& layerName);
+ // Creates a trace point at the timestamp provided.
+ void traceTimestamp(int32_t layerID, uint64_t bufferID, uint64_t frameNumber, nsecs_t timestamp,
+ FrameEvent::BufferEventType type, nsecs_t duration = 0);
+ // Creates a trace point after the provided fence has been signalled. If a startTime is provided
+ // the trace will have be timestamped from startTime until fence signalling time. If no
+ // startTime is provided, a durationless trace point will be created timestamped at fence
+ // signalling time. If the fence hasn't signalled yet, the trace point will be created the next
+ // time after signalling a trace call for this buffer occurs.
+ void traceFence(int32_t layerID, uint64_t bufferID, uint64_t frameNumber,
+ const std::shared_ptr<FenceTime>& fence, FrameEvent::BufferEventType type,
+ nsecs_t startTime = 0);
+
+ // Takes care of cleanup when a layer is destroyed.
+ void onDestroy(int32_t layerID);
+
+ std::string miniDump();
+
+ static constexpr char kFrameTracerDataSource[] = "android.surfaceflinger.frame";
+
+ // The maximum amount of time a fence has to signal before it is discarded.
+ // Used to avoid fences from previous traces generating new trace points in later ones.
+ // Public for testing.
+ static constexpr nsecs_t kFenceSignallingDeadline = 60'000'000'000; // 60 seconds
+
+private:
+ struct PendingFence {
+ uint64_t frameNumber;
+ FrameEvent::BufferEventType type;
+ std::shared_ptr<FenceTime> fence;
+ nsecs_t startTime;
+ };
+
+ struct TraceRecord {
+ std::string layerName;
+ using BufferID = uint64_t;
+ std::unordered_map<BufferID, std::vector<PendingFence>> pendingFences;
+ };
+
+ // Checks if any pending fences for a layer and buffer have signalled and, if they have, creates
+ // trace points for them.
+ void tracePendingFencesLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID);
+ // Creates a trace point by translating a start time and an end time to a timestamp and
+ // duration. If startTime is later than end time it sets end time as the timestamp and the
+ // duration to 0. Used by traceFence().
+ void traceSpanLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID,
+ uint64_t bufferID, uint64_t frameNumber, FrameEvent::BufferEventType type,
+ nsecs_t startTime, nsecs_t endTime);
+ void traceLocked(FrameTracerDataSource::TraceContext& ctx, int32_t layerID, uint64_t bufferID,
+ uint64_t frameNumber, nsecs_t timestamp, FrameEvent::BufferEventType type,
+ nsecs_t duration = 0);
+
+ std::mutex mTraceMutex;
+ std::unordered_map<int32_t, TraceRecord> mTraceTracker;
+ std::once_flag mInitializationFlag;
+};
+
+} // namespace android
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 9f0b5d9..6a45625 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -22,11 +22,11 @@
#include "Layer.h"
#include <android-base/stringprintf.h>
+#include <binder/IPCThreadState.h>
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
-#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <cutils/compiler.h>
#include <cutils/native_handle.h>
@@ -57,6 +57,7 @@
#include "Colorizer.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWComposer.h"
+#include "FrameTracer/FrameTracer.h"
#include "LayerProtoHelper.h"
#include "LayerRejecter.h"
#include "MonitoredProducer.h"
@@ -76,7 +77,6 @@
mName(args.name),
mClientRef(args.client),
mWindowType(args.metadata.getInt32(METADATA_WINDOW_TYPE, 0)) {
- mCurrentCrop.makeInvalid();
uint32_t layerFlags = 0;
if (args.flags & ISurfaceComposerClient::eHidden) layerFlags |= layer_state_t::eLayerHidden;
@@ -105,7 +105,7 @@
mCurrentState.acquireFence = new Fence(-1);
mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
mCurrentState.hdrMetadata.validTypes = 0;
- mCurrentState.surfaceDamageRegion.clear();
+ mCurrentState.surfaceDamageRegion = Region::INVALID_REGION;
mCurrentState.cornerRadius = 0.0f;
mCurrentState.api = -1;
mCurrentState.hasColorTransform = false;
@@ -121,7 +121,8 @@
mFrameTracker.setDisplayRefreshPeriod(compositorTiming.interval);
mSchedulerLayerHandle = mFlinger->mScheduler->registerLayer(mName.c_str(), mWindowType);
-
+ mCallingPid = args.callingPid;
+ mCallingUid = args.callingUid;
mFlinger->onLayerCreated();
}
@@ -135,6 +136,21 @@
mFlinger->onLayerDestroyed(this);
}
+LayerCreationArgs::LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client,
+ const String8& name, uint32_t w, uint32_t h, uint32_t flags,
+ LayerMetadata metadata)
+ : flinger(flinger),
+ client(client),
+ name(name),
+ w(w),
+ h(h),
+ flags(flags),
+ metadata(std::move(metadata)) {
+ IPCThreadState* ipc = IPCThreadState::self();
+ callingPid = ipc->getCallingPid();
+ callingUid = ipc->getCallingUid();
+}
+
// ---------------------------------------------------------------------------
// callbacks
// ---------------------------------------------------------------------------
@@ -241,37 +257,6 @@
// h/w composer set-up
// ---------------------------------------------------------------------------
-bool Layer::hasHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().hwc && (*outputLayer->getState().hwc).hwcLayer != nullptr;
-}
-
-HWC2::Layer* Layer::getHwcLayer(const sp<const DisplayDevice>& displayDevice) {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (!outputLayer || !outputLayer->getState().hwc) {
- return nullptr;
- }
- return (*outputLayer->getState().hwc).hwcLayer.get();
-}
-
-Rect Layer::getContentCrop() const {
- // this is the crop rectangle that applies to the buffer
- // itself (as opposed to the window)
- Rect crop;
- if (!mCurrentCrop.isEmpty()) {
- // if the buffer crop is defined, we use that
- crop = mCurrentCrop;
- } else if (mActiveBuffer != nullptr) {
- // otherwise we use the whole buffer
- crop = mActiveBuffer->getBounds();
- } else {
- // if we don't have a buffer yet, we use an empty/invalid crop
- crop.makeInvalid();
- }
- return crop;
-}
-
static Rect reduce(const Rect& win, const Region& exclude) {
if (CC_LIKELY(exclude.isEmpty())) {
return win;
@@ -316,7 +301,7 @@
// If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
// it isFixedSize) then there may be additional scaling not accounted
// for in the layer transform.
- if (!isFixedSize() || !mActiveBuffer) {
+ if (!isFixedSize() || getBuffer() == nullptr) {
return {};
}
@@ -328,10 +313,10 @@
return {};
}
- int bufferWidth = mActiveBuffer->getWidth();
- int bufferHeight = mActiveBuffer->getHeight();
+ int bufferWidth = getBuffer()->getWidth();
+ int bufferHeight = getBuffer()->getHeight();
- if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ if (getBufferTransform() & NATIVE_WINDOW_TRANSFORM_ROT_90) {
std::swap(bufferWidth, bufferHeight);
}
@@ -346,7 +331,7 @@
ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const {
// We need to mirror this scaling to child surfaces or we will break the contract where WM can
// treat child surfaces as pixels in the parent surface.
- if (!isFixedSize() || !mActiveBuffer) {
+ if (!isFixedSize() || getBuffer() == nullptr) {
return mEffectiveTransform;
}
return mEffectiveTransform * bufferScaleTransform;
@@ -355,7 +340,7 @@
FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const {
// We need the pre scaled layer bounds when computing child bounds to make sure the child is
// cropped to its parent layer after any buffer transform scaling is applied.
- if (!isFixedSize() || !mActiveBuffer) {
+ if (!isFixedSize() || getBuffer() == nullptr) {
return mBounds;
}
return bufferScaleTransform.inverse().transform(mBounds);
@@ -413,14 +398,43 @@
win.bottom -= roundedCornersCrop.top;
}
+void Layer::latchBasicGeometry(compositionengine::LayerFECompositionState& compositionState) const {
+ const auto& drawingState{getDrawingState()};
+ const uint32_t layerStack = getLayerStack();
+ const auto alpha = static_cast<float>(getAlpha());
+ const bool opaque = isOpaque(drawingState);
+ const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+
+ auto blendMode = Hwc2::IComposerClient::BlendMode::NONE;
+ if (!opaque || alpha != 1.0f) {
+ blendMode = mPremultipliedAlpha ? Hwc2::IComposerClient::BlendMode::PREMULTIPLIED
+ : Hwc2::IComposerClient::BlendMode::COVERAGE;
+ }
+
+ // TODO(b/121291683): Instead of filling in a passed-in compositionState
+ // structure, switch to Layer owning the structure and have
+ // CompositionEngine be able to get a reference to it.
+
+ compositionState.layerStackId =
+ (layerStack != ~0u) ? std::make_optional(layerStack) : std::nullopt;
+ compositionState.internalOnly = getPrimaryDisplayOnly();
+ compositionState.isVisible = isVisible();
+ compositionState.isOpaque = opaque && !usesRoundedCorners && alpha == 1.f;
+
+ compositionState.contentDirty = contentDirty;
+ contentDirty = false;
+
+ compositionState.geomLayerBounds = mBounds;
+ compositionState.geomLayerTransform = getTransform();
+ compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse();
+ compositionState.transparentRegionHint = getActiveTransparentRegion(drawingState);
+
+ compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
+ compositionState.alpha = alpha;
+}
+
void Layer::latchGeometry(compositionengine::LayerFECompositionState& compositionState) const {
const auto& drawingState{getDrawingState()};
- auto alpha = static_cast<float>(getAlpha());
- auto blendMode = HWC2::BlendMode::None;
- if (!isOpaque(drawingState) || alpha != 1.0f) {
- blendMode =
- mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
- }
int type = drawingState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
int appId = drawingState.metadata.getInt32(METADATA_OWNER_UID, 0);
@@ -429,34 +443,82 @@
auto& parentState = parent->getDrawingState();
const int parentType = parentState.metadata.getInt32(METADATA_WINDOW_TYPE, 0);
const int parentAppId = parentState.metadata.getInt32(METADATA_OWNER_UID, 0);
- if (parentType >= 0 || parentAppId >= 0) {
+ if (parentType > 0 && parentAppId > 0) {
type = parentType;
appId = parentAppId;
}
}
- compositionState.geomLayerTransform = getTransform();
- compositionState.geomInverseLayerTransform = compositionState.geomLayerTransform.inverse();
compositionState.geomBufferSize = getBufferSize(drawingState);
- compositionState.geomContentCrop = getContentCrop();
+ compositionState.geomContentCrop = getBufferCrop();
compositionState.geomCrop = getCrop(drawingState);
- compositionState.geomBufferTransform = mCurrentTransform;
+ compositionState.geomBufferTransform = getBufferTransform();
compositionState.geomBufferUsesDisplayInverseTransform = getTransformToDisplayInverse();
- compositionState.geomActiveTransparentRegion = getActiveTransparentRegion(drawingState);
- compositionState.geomLayerBounds = mBounds;
compositionState.geomUsesSourceCrop = usesSourceCrop();
compositionState.isSecure = isSecure();
- compositionState.blendMode = static_cast<Hwc2::IComposerClient::BlendMode>(blendMode);
- compositionState.alpha = alpha;
compositionState.type = type;
compositionState.appId = appId;
}
+void Layer::latchPerFrameState(compositionengine::LayerFECompositionState& compositionState) const {
+ const auto& drawingState{getDrawingState()};
+ compositionState.forceClientComposition = false;
+
+ compositionState.isColorspaceAgnostic = isColorSpaceAgnostic();
+ compositionState.dataspace = getDataSpace();
+ compositionState.colorTransform = getColorTransform();
+ compositionState.colorTransformIsIdentity = !hasColorTransform();
+ compositionState.surfaceDamage = surfaceDamageRegion;
+ compositionState.hasProtectedContent = isProtected();
+
+ const bool usesRoundedCorners = getRoundedCornerState().radius != 0.f;
+ compositionState.isOpaque =
+ isOpaque(drawingState) && !usesRoundedCorners && getAlpha() == 1.0_hf;
+
+ // Force client composition for special cases known only to the front-end.
+ if (isHdrY410() || usesRoundedCorners) {
+ compositionState.forceClientComposition = true;
+ }
+}
+
+void Layer::latchCursorCompositionState(
+ compositionengine::LayerFECompositionState& compositionState) const {
+ // This gives us only the "orientation" component of the transform
+ const State& drawingState{getDrawingState()};
+
+ // Apply the layer's transform, followed by the display's global transform
+ // Here we're guaranteed that the layer's transform preserves rects
+ Rect win = getCroppedBufferSize(drawingState);
+ // Subtract the transparent region and snap to the bounds
+ Rect bounds = reduce(win, getActiveTransparentRegion(drawingState));
+ Rect frame(getTransform().transform(bounds));
+
+ compositionState.cursorFrame = frame;
+}
+
+bool Layer::onPreComposition(nsecs_t) {
+ return false;
+}
+
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
- bool includeGeometry) const {
- if (includeGeometry) {
- latchGeometry(compositionState);
+ compositionengine::LayerFE::StateSubset subset) const {
+ using StateSubset = compositionengine::LayerFE::StateSubset;
+
+ switch (subset) {
+ case StateSubset::BasicGeometry:
+ latchBasicGeometry(compositionState);
+ break;
+
+ case StateSubset::GeometryAndContent:
+ latchBasicGeometry(compositionState);
+ latchGeometry(compositionState);
+ latchPerFrameState(compositionState);
+ break;
+
+ case StateSubset::Content:
+ latchPerFrameState(compositionState);
+ break;
}
}
@@ -464,125 +526,37 @@
return mName.string();
}
-void Layer::forceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- outputLayer->editState().forceClientComposition = true;
-}
-
-bool Layer::getForceClientComposition(const sp<DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- return outputLayer->getState().forceClientComposition;
-}
-
-void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
-
- if (!outputLayer->getState().hwc ||
- (*outputLayer->getState().hwc).hwcCompositionType !=
- Hwc2::IComposerClient::Composition::CURSOR) {
- return;
- }
-
- // This gives us only the "orientation" component of the transform
- const State& s(getDrawingState());
-
- // Apply the layer's transform, followed by the display's global transform
- // Here we're guaranteed that the layer's transform preserves rects
- Rect win = getCroppedBufferSize(s);
- // Subtract the transparent region and snap to the bounds
- Rect bounds = reduce(win, getActiveTransparentRegion(s));
- Rect frame(getTransform().transform(bounds));
- frame.intersect(display->getViewport(), &frame);
- auto& displayTransform = display->getTransform();
- auto position = displayTransform.transform(frame);
-
- auto error =
- (*outputLayer->getState().hwc).hwcLayer->setCursorPosition(position.left, position.top);
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set cursor position "
- "to (%d, %d): %s (%d)",
- mName.string(), position.left, position.top, to_string(error).c_str(),
- static_cast<int32_t>(error));
-}
-
// ---------------------------------------------------------------------------
// drawing...
// ---------------------------------------------------------------------------
-bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
-}
+std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ if (!getCompositionLayer()) {
+ return {};
+ }
-bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
- clearRegion, supportProtectedContent, layer);
-}
-
-bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
- bool useIdentityTransform, Region& /*clearRegion*/,
- const bool /*supportProtectedContent*/,
- renderengine::LayerSettings& layer) {
FloatRect bounds = getBounds();
half alpha = getAlpha();
- layer.geometry.boundaries = bounds;
- if (useIdentityTransform) {
- layer.geometry.positionTransform = mat4();
+ renderengine::LayerSettings layerSettings;
+ layerSettings.geometry.boundaries = bounds;
+ if (targetSettings.useIdentityTransform) {
+ layerSettings.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;
+ layerSettings.geometry.positionTransform = getTransform().asMatrix4();
}
if (hasColorTransform()) {
- layer.colorTransform = getColorTransform();
+ layerSettings.colorTransform = getColorTransform();
}
const auto roundedCornerState = getRoundedCornerState();
- layer.geometry.roundedCornersRadius = roundedCornerState.radius;
- layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+ layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
+ layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
- layer.alpha = alpha;
- layer.sourceDataspace = mCurrentDataSpace;
- return true;
-}
-
-void Layer::setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type) {
- const auto outputLayer = findOutputLayerForDisplay(display);
- LOG_FATAL_IF(!outputLayer);
- LOG_FATAL_IF(!outputLayer->getState().hwc);
- auto& compositionState = outputLayer->editState();
-
- ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", ((*compositionState.hwc).hwcLayer)->getId(),
- toString(type).c_str(), 1);
- if ((*compositionState.hwc).hwcCompositionType != type) {
- ALOGV(" actually setting");
- (*compositionState.hwc).hwcCompositionType = type;
-
- auto error = (*compositionState.hwc)
- .hwcLayer->setCompositionType(static_cast<HWC2::Composition>(type));
- ALOGE_IF(error != HWC2::Error::None,
- "[%s] Failed to set "
- "composition type %s: %s (%d)",
- mName.string(), toString(type).c_str(), to_string(error).c_str(),
- static_cast<int32_t>(error));
- }
+ layerSettings.alpha = alpha;
+ layerSettings.sourceDataspace = getDataSpace();
+ return layerSettings;
}
Hwc2::IComposerClient::Composition Layer::getCompositionType(
@@ -618,58 +592,11 @@
// local state
// ----------------------------------------------------------------------------
-void Layer::computeGeometry(const RenderArea& renderArea,
- renderengine::Mesh& mesh,
- bool useIdentityTransform) const {
- const ui::Transform renderAreaTransform(renderArea.getTransform());
- FloatRect win = getBounds();
-
- vec2 lt = vec2(win.left, win.top);
- vec2 lb = vec2(win.left, win.bottom);
- vec2 rb = vec2(win.right, win.bottom);
- vec2 rt = vec2(win.right, win.top);
-
- ui::Transform layerTransform = getTransform();
- if (!useIdentityTransform) {
- lt = layerTransform.transform(lt);
- lb = layerTransform.transform(lb);
- rb = layerTransform.transform(rb);
- rt = layerTransform.transform(rt);
- }
-
- renderengine::Mesh::VertexArray<vec2> position(mesh.getPositionArray<vec2>());
- position[0] = renderAreaTransform.transform(lt);
- position[1] = renderAreaTransform.transform(lb);
- position[2] = renderAreaTransform.transform(rb);
- position[3] = renderAreaTransform.transform(rt);
-}
-
bool Layer::isSecure() const {
const State& s(mDrawingState);
return (s.flags & layer_state_t::eLayerSecure);
}
-void Layer::setVisibleRegion(const Region& visibleRegion) {
- // always called from main thread
- this->visibleRegion = visibleRegion;
-}
-
-void Layer::setCoveredRegion(const Region& coveredRegion) {
- // always called from main thread
- this->coveredRegion = coveredRegion;
-}
-
-void Layer::setVisibleNonTransparentRegion(const Region& setVisibleNonTransparentRegion) {
- // always called from main thread
- this->visibleNonTransparentRegion = setVisibleNonTransparentRegion;
-}
-
-void Layer::clearVisibilityRegions() {
- visibleRegion.clear();
- visibleNonTransparentRegion.clear();
- coveredRegion.clear();
-}
-
// ----------------------------------------------------------------------------
// transaction
// ----------------------------------------------------------------------------
@@ -790,7 +717,7 @@
" requested={ wh={%4u,%4u} }}\n"
" drawing={ active ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
" requested={ wh={%4u,%4u} }}\n",
- this, getName().string(), mCurrentTransform, getEffectiveScalingMode(),
+ this, getName().string(), getBufferTransform(), getEffectiveScalingMode(),
stateToCommit->active_legacy.w, stateToCommit->active_legacy.h,
stateToCommit->crop_legacy.left, stateToCommit->crop_legacy.top,
stateToCommit->crop_legacy.right, stateToCommit->crop_legacy.bottom,
@@ -822,7 +749,7 @@
const bool resizePending =
((stateToCommit->requested_legacy.w != stateToCommit->active_legacy.w) ||
(stateToCommit->requested_legacy.h != stateToCommit->active_legacy.h)) &&
- (mActiveBuffer != nullptr);
+ (getBuffer() != nullptr);
if (!isFixedSize()) {
if (resizePending && mSidebandStream == nullptr) {
flags |= eDontUpdateGeometryState;
@@ -835,11 +762,6 @@
if (!(flags & eDontUpdateGeometryState)) {
State& editCurrentState(getCurrentState());
- // If mFreezeGeometryUpdates is true we are in the setGeometryAppliesWithResize
- // mode, which causes attributes which normally latch regardless of scaling mode,
- // to be delayed. We copy the requested state to the active state making sure
- // to respect these rules (again see Layer.h for a detailed discussion).
- //
// There is an awkward asymmetry in the handling of the crop states in the position
// states, as can be seen below. Largely this arises from position and transform
// being stored in the same data structure while having different latching rules.
@@ -847,16 +769,8 @@
//
// Careful that "stateToCommit" and editCurrentState may not begin as equivalent due to
// applyPendingStates in the presence of deferred transactions.
- if (mFreezeGeometryUpdates) {
- float tx = stateToCommit->active_legacy.transform.tx();
- float ty = stateToCommit->active_legacy.transform.ty();
- stateToCommit->active_legacy = stateToCommit->requested_legacy;
- stateToCommit->active_legacy.transform.set(tx, ty);
- editCurrentState.active_legacy = stateToCommit->active_legacy;
- } else {
- editCurrentState.active_legacy = editCurrentState.requested_legacy;
- stateToCommit->active_legacy = stateToCommit->requested_legacy;
- }
+ editCurrentState.active_legacy = editCurrentState.requested_legacy;
+ stateToCommit->active_legacy = stateToCommit->requested_legacy;
}
return flags;
@@ -866,6 +780,15 @@
ATRACE_CALL();
if (mLayerDetached) {
+ // Ensure BLAST buffer callbacks are processed.
+ // detachChildren and mLayerDetached were implemented to avoid geometry updates
+ // to layers in the cases of animation. For BufferQueue layers buffers are still
+ // consumed as normal. This is useful as otherwise the client could get hung
+ // inevitably waiting on a buffer to return. We recreate this semantic for BufferQueue
+ // even though it is a little consistent. detachChildren is shortly slated for removal
+ // by the hierarchy mirroring work so we don't need to worry about it too much.
+ mDrawingState.callbackHandles = mCurrentState.callbackHandles;
+ mCurrentState.callbackHandles = {};
return flags;
}
@@ -923,7 +846,7 @@
return mTransactionFlags.fetch_or(flags);
}
-bool Layer::setPosition(float x, float y, bool immediate) {
+bool Layer::setPosition(float x, float y) {
if (mCurrentState.requested_legacy.transform.tx() == x &&
mCurrentState.requested_legacy.transform.ty() == y)
return false;
@@ -933,14 +856,11 @@
// we want to apply the position portion of the transform matrix immediately,
// but still delay scaling when resizing a SCALING_MODE_FREEZE layer.
mCurrentState.requested_legacy.transform.set(x, y);
- if (immediate && !mFreezeGeometryUpdates) {
- // Here we directly update the active state
- // unlike other setters, because we store it within
- // the transform, but use different latching rules.
- // b/38182305
- mCurrentState.active_legacy.transform.set(x, y);
- }
- mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
+ // Here we directly update the active state
+ // unlike other setters, because we store it within
+ // the transform, but use different latching rules.
+ // b/38182305
+ mCurrentState.active_legacy.transform.set(x, y);
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -988,6 +908,7 @@
}
setZOrderRelativeOf(nullptr);
}
+ mCurrentState.isRelativeOf = false;
setTransactionFlags(eTransactionNeeded);
return true;
}
@@ -1031,6 +952,7 @@
mCurrentState.sequence++;
mCurrentState.modified = true;
mCurrentState.z = relativeZ;
+ mCurrentState.isRelativeOf = true;
auto oldZOrderRelativeOf = mCurrentState.zOrderRelativeOf.promote();
if (oldZOrderRelativeOf != nullptr) {
@@ -1078,7 +1000,7 @@
// create background color layer if one does not yet exist
uint32_t flags = ISurfaceComposerClient::eFXSurfaceColor;
const String8& name = mName + "BackgroundColorLayer";
- mCurrentState.bgColorLayer = new ColorLayer(
+ mCurrentState.bgColorLayer = mFlinger->getFactory().createColorLayer(
LayerCreationArgs(mFlinger.get(), nullptr, name, 0, 0, flags, LayerMetadata()));
// add to child list
@@ -1146,14 +1068,11 @@
return true;
}
-bool Layer::setCrop_legacy(const Rect& crop, bool immediate) {
+bool Layer::setCrop_legacy(const Rect& crop) {
if (mCurrentState.requestedCrop_legacy == crop) return false;
mCurrentState.sequence++;
mCurrentState.requestedCrop_legacy = crop;
- if (immediate && !mFreezeGeometryUpdates) {
- mCurrentState.crop_legacy = crop;
- }
- mFreezeGeometryUpdates = mFreezeGeometryUpdates || !immediate;
+ mCurrentState.crop_legacy = crop;
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
@@ -1282,9 +1201,10 @@
info.mName = getName();
sp<Layer> parent = getParent();
info.mParentName = (parent == nullptr ? std::string("none") : parent->getName().string());
- info.mType = std::string(getTypeId());
+ info.mType = getType();
info.mTransparentRegion = ds.activeTransparentRegion_legacy;
- info.mVisibleRegion = visibleRegion;
+
+ info.mVisibleRegion = debugGetVisibleRegionOnDefaultDisplay();
info.mSurfaceDamageRegion = surfaceDamageRegion;
info.mLayerStack = getLayerStack();
info.mX = ds.active_legacy.transform.tx();
@@ -1296,13 +1216,13 @@
info.mColor = ds.color;
info.mFlags = ds.flags;
info.mPixelFormat = getPixelFormat();
- info.mDataSpace = static_cast<android_dataspace>(mCurrentDataSpace);
+ info.mDataSpace = static_cast<android_dataspace>(getDataSpace());
info.mMatrix[0][0] = ds.active_legacy.transform[0][0];
info.mMatrix[0][1] = ds.active_legacy.transform[0][1];
info.mMatrix[1][0] = ds.active_legacy.transform[1][0];
info.mMatrix[1][1] = ds.active_legacy.transform[1][1];
{
- sp<const GraphicBuffer> buffer = mActiveBuffer;
+ sp<const GraphicBuffer> buffer = getBuffer();
if (buffer != 0) {
info.mActiveBufferWidth = buffer->getWidth();
info.mActiveBufferHeight = buffer->getHeight();
@@ -1399,16 +1319,23 @@
}
void Layer::dumpFrameEvents(std::string& result) {
- StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().string(), getTypeId(), this);
+ StringAppendF(&result, "- Layer %s (%s, %p)\n", getName().string(), getType(), this);
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.checkFencesForCompletion();
mFrameEventHistory.dump(result);
}
+void Layer::dumpCallingUidPid(std::string& result) const {
+ StringAppendF(&result, "Layer %s (%s) pid:%d uid:%d\n", getName().string(), getType(),
+ mCallingPid, mCallingUid);
+}
+
void Layer::onDisconnect() {
Mutex::Autolock lock(mFrameEventHistoryMutex);
mFrameEventHistory.onDisconnect();
- mFlinger->mTimeStats->onDestroy(getSequence());
+ const int32_t layerID = getSequence();
+ mFlinger->mTimeStats->onDestroy(layerID);
+ mFlinger->mFrameTracer->onDestroy(layerID);
}
void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
@@ -1608,8 +1535,9 @@
bool Layer::isLegacyDataSpace() const {
// return true when no higher bits are set
- return !(mCurrentDataSpace & (ui::Dataspace::STANDARD_MASK |
- ui::Dataspace::TRANSFER_MASK | ui::Dataspace::RANGE_MASK));
+ return !(getDataSpace() &
+ (ui::Dataspace::STANDARD_MASK | ui::Dataspace::TRANSFER_MASK |
+ ui::Dataspace::RANGE_MASK));
}
void Layer::setParent(const sp<Layer>& layer) {
@@ -1623,7 +1551,7 @@
bool Layer::usingRelativeZ(LayerVector::StateSet stateSet) const {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const State& state = useDrawing ? mDrawingState : mCurrentState;
- return state.zOrderRelativeOf != nullptr;
+ return state.isRelativeOf;
}
__attribute__((no_sanitize("unsigned-integer-overflow"))) LayerVector Layer::makeTraversalList(
@@ -1648,8 +1576,7 @@
}
for (const sp<Layer>& child : children) {
- const State& childState = useDrawing ? child->mDrawingState : child->mCurrentState;
- if (childState.zOrderRelativeOf != nullptr) {
+ if (child->usingRelativeZ(stateSet)) {
continue;
}
traverse.add(child);
@@ -1887,17 +1814,16 @@
}
}
- auto buffer = mActiveBuffer;
+ auto buffer = getBuffer();
if (buffer != nullptr) {
LayerProtoHelper::writeToProto(buffer,
[&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+ LayerProtoHelper::writeToProto(ui::Transform(getBufferTransform()),
layerInfo->mutable_buffer_transform());
}
layerInfo->set_invalidate(contentDirty);
layerInfo->set_is_protected(isProtected());
- layerInfo->set_dataspace(
- dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+ layerInfo->set_dataspace(dataspaceDetails(static_cast<android_dataspace>(getDataSpace())));
layerInfo->set_queued_frames(getQueuedFrameCount());
layerInfo->set_refresh_pending(isBufferLatched());
layerInfo->set_curr_frame(mCurrentFrameNumber);
@@ -1908,7 +1834,7 @@
LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
[&]() { return layerInfo->mutable_position(); });
LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
- LayerProtoHelper::writeToProto(visibleRegion,
+ LayerProtoHelper::writeToProto(debugGetVisibleRegionOnDefaultDisplay(),
[&]() { return layerInfo->mutable_visible_region(); });
LayerProtoHelper::writeToProto(surfaceDamageRegion,
[&]() { return layerInfo->mutable_damage_region(); });
@@ -1933,7 +1859,7 @@
if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
layerInfo->set_id(sequence);
layerInfo->set_name(getName().c_str());
- layerInfo->set_type(String8(getTypeId()));
+ layerInfo->set_type(getType());
for (const auto& child : children) {
layerInfo->add_children(child->sequence);
@@ -2003,46 +1929,10 @@
}
}
-void Layer::writeToProtoCompositionState(LayerProto* layerInfo,
- const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags) const {
- auto outputLayer = findOutputLayerForDisplay(displayDevice);
- if (!outputLayer) {
- return;
- }
-
- writeToProtoDrawingState(layerInfo, traceFlags);
- writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
-
- const auto& compositionState = outputLayer->getState();
-
- const Rect& frame = compositionState.displayFrame;
- LayerProtoHelper::writeToProto(frame, [&]() { return layerInfo->mutable_hwc_frame(); });
-
- const FloatRect& crop = compositionState.sourceCrop;
- LayerProtoHelper::writeToProto(crop, [&]() { return layerInfo->mutable_hwc_crop(); });
-
- const int32_t transform =
- getCompositionLayer() ? static_cast<int32_t>(compositionState.bufferTransform) : 0;
- layerInfo->set_hwc_transform(transform);
-
- const int32_t compositionType =
- static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
- : Hwc2::IComposerClient::Composition::CLIENT);
- layerInfo->set_hwc_composition_type(compositionType);
-}
-
bool Layer::isRemovedFromCurrentState() const {
return mRemovedFromCurrentState;
}
-// Debug helper for b/137560795
-#define INT32_MIGHT_OVERFLOW(n) (((n) >= INT32_MAX / 2) || ((n) <= INT32_MIN / 2))
-
-#define RECT_BOUNDS_INVALID(rect) \
- (INT32_MIGHT_OVERFLOW((rect).left) || INT32_MIGHT_OVERFLOW((rect).right) || \
- INT32_MIGHT_OVERFLOW((rect).bottom) || INT32_MIGHT_OVERFLOW((rect).top))
-
InputWindowInfo Layer::fillInputInfo() {
InputWindowInfo info = mDrawingState.inputInfo;
@@ -2053,14 +1943,14 @@
ui::Transform t = getTransform();
const float xScale = t.sx();
const float yScale = t.sy();
- float xSurfaceInset = info.surfaceInset;
- float ySurfaceInset = info.surfaceInset;
+ int32_t xSurfaceInset = info.surfaceInset;
+ int32_t ySurfaceInset = info.surfaceInset;
if (xScale != 1.0f || yScale != 1.0f) {
- info.windowXScale *= 1.0f / xScale;
- info.windowYScale *= 1.0f / yScale;
+ info.windowXScale *= (xScale != 0.0f) ? 1.0f / xScale : 0.0f;
+ info.windowYScale *= (yScale != 0.0f) ? 1.0f / yScale : 0.0f;
info.touchableRegion.scaleSelf(xScale, yScale);
- xSurfaceInset *= xScale;
- ySurfaceInset *= yScale;
+ xSurfaceInset = std::round(xSurfaceInset * xScale);
+ ySurfaceInset = std::round(ySurfaceInset * yScale);
}
// Transform layer size to screen space and inset it by surface insets.
@@ -2073,25 +1963,10 @@
}
layerBounds = t.transform(layerBounds);
- // debug check for b/137560795
- {
- if (RECT_BOUNDS_INVALID(layerBounds)) {
- ALOGE("layer %s bounds are invalid (%" PRIi32 ", %" PRIi32 ", %" PRIi32 ", %" PRIi32
- ")",
- mName.c_str(), layerBounds.left, layerBounds.top, layerBounds.right,
- layerBounds.bottom);
- std::string out;
- getTransform().dump(out, "Transform");
- ALOGE("%s", out.c_str());
- layerBounds.left = layerBounds.top = layerBounds.right = layerBounds.bottom = 0;
- }
+ // clamp inset to layer bounds
+ xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
+ ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
- if (INT32_MIGHT_OVERFLOW(xSurfaceInset) || INT32_MIGHT_OVERFLOW(ySurfaceInset)) {
- ALOGE("layer %s surface inset are invalid (%" PRIi32 ", %" PRIi32 ")", mName.c_str(),
- int32_t(xSurfaceInset), int32_t(ySurfaceInset));
- xSurfaceInset = ySurfaceInset = 0;
- }
- }
layerBounds.inset(xSurfaceInset, ySurfaceInset, xSurfaceInset, ySurfaceInset);
// Input coordinate should match the layer bounds.
@@ -2128,7 +2003,7 @@
}
bool Layer::canReceiveInput() const {
- return isVisible();
+ return !isHiddenByPolicy();
}
compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
@@ -2136,6 +2011,141 @@
return display->getCompositionDisplay()->getOutputLayerForLayer(getCompositionLayer().get());
}
+Region Layer::debugGetVisibleRegionOnDefaultDisplay() const {
+ sp<DisplayDevice> displayDevice = mFlinger->getDefaultDisplayDeviceLocked();
+ if (displayDevice == nullptr) {
+ return {};
+ }
+
+ auto outputLayer = findOutputLayerForDisplay(displayDevice);
+ if (outputLayer == nullptr) {
+ return {};
+ }
+
+ return outputLayer->getState().visibleRegion;
+}
+
+void Layer::setInitialValuesForClone(const sp<Layer>& clonedFrom) {
+ // copy drawing state from cloned layer
+ mDrawingState = clonedFrom->mDrawingState;
+ mClonedFrom = clonedFrom;
+
+ // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+ // InputWindows per client token yet.
+ mDrawingState.inputInfo.token = nullptr;
+}
+
+void Layer::updateMirrorInfo() {
+ if (mClonedChild == nullptr || !mClonedChild->isClonedFromAlive()) {
+ // If mClonedChild is null, there is nothing to mirror. If isClonedFromAlive returns false,
+ // it means that there is a clone, but the layer it was cloned from has been destroyed. In
+ // that case, we want to delete the reference to the clone since we want it to get
+ // destroyed. The root, this layer, will still be around since the client can continue
+ // to hold a reference, but no cloned layers will be displayed.
+ mClonedChild = nullptr;
+ return;
+ }
+
+ std::map<sp<Layer>, sp<Layer>> clonedLayersMap;
+ // If the real layer exists and is in current state, add the clone as a child of the root.
+ // There's no need to remove from drawingState when the layer is offscreen since currentState is
+ // copied to drawingState for the root layer. So the clonedChild is always removed from
+ // drawingState and then needs to be added back each traversal.
+ if (!mClonedChild->getClonedFrom()->isRemovedFromCurrentState()) {
+ addChildToDrawing(mClonedChild);
+ }
+
+ mClonedChild->updateClonedDrawingState(clonedLayersMap);
+ mClonedChild->updateClonedChildren(this, clonedLayersMap);
+ mClonedChild->updateClonedRelatives(clonedLayersMap);
+}
+
+void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+ // If the layer the clone was cloned from is alive, copy the content of the drawingState
+ // to the clone. If the real layer is no longer alive, continue traversing the children
+ // since we may be able to pull out other children that are still alive.
+ if (isClonedFromAlive()) {
+ sp<Layer> clonedFrom = getClonedFrom();
+ mDrawingState = clonedFrom->mDrawingState;
+ // TODO: (b/140756730) Ignore input for now since InputDispatcher doesn't support multiple
+ // InputWindows per client token yet.
+ mDrawingState.inputInfo.token = nullptr;
+ clonedLayersMap.emplace(clonedFrom, this);
+ }
+
+ // The clone layer may have children in drawingState since they may have been created and
+ // added from a previous request to updateMirorInfo. This is to ensure we don't recreate clones
+ // that already exist, since we can just re-use them.
+ // The drawingChildren will not get overwritten by the currentChildren since the clones are
+ // not updated in the regular traversal. They are skipped since the root will lose the
+ // reference to them when it copies its currentChildren to drawing.
+ for (sp<Layer>& child : mDrawingChildren) {
+ child->updateClonedDrawingState(clonedLayersMap);
+ }
+}
+
+void Layer::updateClonedChildren(const sp<Layer>& mirrorRoot,
+ std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
+ mDrawingChildren.clear();
+
+ if (!isClonedFromAlive()) {
+ return;
+ }
+
+ sp<Layer> clonedFrom = getClonedFrom();
+ for (sp<Layer>& child : clonedFrom->mDrawingChildren) {
+ if (child == mirrorRoot) {
+ // This is to avoid cyclical mirroring.
+ continue;
+ }
+ sp<Layer> clonedChild = clonedLayersMap[child];
+ if (clonedChild == nullptr) {
+ clonedChild = child->createClone();
+ clonedLayersMap[child] = clonedChild;
+ }
+ addChildToDrawing(clonedChild);
+ clonedChild->updateClonedChildren(mirrorRoot, clonedLayersMap);
+ }
+}
+
+void Layer::updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap) {
+ mDrawingState.zOrderRelativeOf = nullptr;
+ mDrawingState.zOrderRelatives.clear();
+
+ if (!isClonedFromAlive()) {
+ return;
+ }
+
+ sp<Layer> clonedFrom = getClonedFrom();
+ for (wp<Layer>& relativeWeak : clonedFrom->mDrawingState.zOrderRelatives) {
+ sp<Layer> relative = relativeWeak.promote();
+ auto clonedRelative = clonedLayersMap[relative];
+ if (clonedRelative != nullptr) {
+ mDrawingState.zOrderRelatives.add(clonedRelative);
+ }
+ }
+
+ // Check if the relativeLayer for the real layer is part of the cloned hierarchy.
+ // It's possible that the layer it's relative to is outside the requested cloned hierarchy.
+ // In that case, we treat the layer as if the relativeOf has been removed. This way, it will
+ // still traverse the children, but the layer with the missing relativeOf will not be shown
+ // on screen.
+ sp<Layer> relativeOf = clonedFrom->mDrawingState.zOrderRelativeOf.promote();
+ sp<Layer> clonedRelativeOf = clonedLayersMap[relativeOf];
+ if (clonedRelativeOf != nullptr) {
+ mDrawingState.zOrderRelativeOf = clonedRelativeOf;
+ }
+
+ for (sp<Layer>& child : mDrawingChildren) {
+ child->updateClonedRelatives(clonedLayersMap);
+ }
+}
+
+void Layer::addChildToDrawing(const sp<Layer>& layer) {
+ mDrawingChildren.add(layer);
+ layer->mDrawingParent = this;
+}
+
// ---------------------------------------------------------------------------
}; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3b4d873..3023cf5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -80,9 +80,7 @@
struct LayerCreationArgs {
LayerCreationArgs(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
- uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata)
- : flinger(flinger), client(client), name(name), w(w), h(h), flags(flags),
- metadata(std::move(metadata)) {}
+ uint32_t w, uint32_t h, uint32_t flags, LayerMetadata metadata);
SurfaceFlinger* flinger;
const sp<Client>& client;
@@ -91,17 +89,17 @@
uint32_t h;
uint32_t flags;
LayerMetadata metadata;
+ pid_t callingPid;
+ uid_t callingUid;
+ sp<const DisplayDevice> displayDevice;
+ uint32_t textureName;
};
-class Layer : public virtual compositionengine::LayerFE {
+class Layer : public compositionengine::LayerFE {
static std::atomic<int32_t> sSequence;
public:
mutable bool contentDirty{false};
- // regions below are in window-manager space
- Region visibleRegion;
- Region coveredRegion;
- Region visibleNonTransparentRegion;
Region surfaceDamageRegion;
// Layer serial number. This gives layers an explicit ordering, so we
@@ -174,6 +172,7 @@
// If non-null, a Surface this Surface's Z-order is interpreted relative to.
wp<Layer> zOrderRelativeOf;
+ bool isRelativeOf{false};
// A list of surfaces whose Z-order is interpreted relative to ours.
SortedVector<wp<Layer>> zOrderRelatives;
@@ -217,6 +216,7 @@
// recent callback handle.
std::deque<sp<CallbackHandle>> callbackHandles;
bool colorSpaceAgnostic;
+ nsecs_t desiredPresentTime = -1;
};
explicit Layer(const LayerCreationArgs& args);
@@ -267,9 +267,9 @@
// setPosition operates in parent buffer space (pre parent-transform) or display
// space for top-level layers.
- virtual bool setPosition(float x, float y, bool immediate);
+ virtual bool setPosition(float x, float y);
// Buffer space
- virtual bool setCrop_legacy(const Rect& crop, bool immediate);
+ virtual bool setCrop_legacy(const Rect& crop);
// TODO(b/38182121): Could we eliminate the various latching modes by
// using the layer hierarchy?
@@ -329,7 +329,7 @@
virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
virtual bool setColorSpaceAgnostic(const bool agnostic);
- ui::Dataspace getDataSpace() const { return mCurrentDataSpace; }
+ virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
// Before color management is introduced, contents on Android have to be
// desaturated in order to match what they appears like visually.
@@ -357,8 +357,6 @@
return getLayerStack() == layerStack && (!mPrimaryDisplayOnly || isPrimaryDisplay);
}
- void computeGeometry(const RenderArea& renderArea, renderengine::Mesh& mesh,
- bool useIdentityTransform) const;
FloatRect getBounds(const Region& activeTransparentRegion) const;
FloatRect getBounds() const;
@@ -377,9 +375,19 @@
int32_t getSequence() const { return sequence; }
+ // For tracing.
+ // TODO: Replace with raw buffer id from buffer metadata when that becomes available.
+ // GraphicBuffer::getId() does not provide a reliable global identifier. Since the traces
+ // creates its tracks by buffer id and has no way of associating a buffer back to the process
+ // that created it, the current implementation is only sufficient for cases where a buffer is
+ // only used within a single layer.
+ uint64_t getCurrentBufferId() const { return getBuffer() ? getBuffer()->getId() : 0; }
+
// -----------------------------------------------------------------------
// Virtuals
- virtual const char* getTypeId() const = 0;
+
+ // Provide unique string for each class type in the Layer hierarchy
+ virtual const char* getType() const = 0;
/*
* isOpaque - true if this surface is opaque
@@ -442,11 +450,6 @@
// thread.
void writeToProtoDrawingState(LayerProto* layerInfo,
uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
- // Write states that are modified by the main thread. This includes drawing
- // state as well as buffer data and composition data for layers on the specified
- // display. This should be called in the main or tracing thread.
- void writeToProtoCompositionState(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
// Write drawing or current state. If writing current state, the caller should hold the
// external mStateLock. If writing drawing state, this function should be called on the
// main or tracing thread.
@@ -463,56 +466,63 @@
return s.activeTransparentRegion_legacy;
}
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
+ virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
+
+ // This layer is not a clone, but it's the parent to the cloned hierarchy. The
+ // variable mClonedChild represents the top layer that will be cloned so this
+ // layer will be the parent of mClonedChild.
+ // The layers in the cloned hierarchy will match the lifetime of the real layers. That is
+ // if the real layer is destroyed, then the clone layer will also be destroyed.
+ sp<Layer> mClonedChild;
+
+ virtual sp<Layer> createClone() = 0;
+ void updateMirrorInfo();
+ virtual void updateCloneBufferInfo(){};
protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
+ sp<Layer> getClonedFrom() { return mClonedFrom != nullptr ? mClonedFrom.promote() : nullptr; }
+ bool isClone() { return mClonedFrom != nullptr; }
+ bool isClonedFromAlive() { return getClonedFrom() != nullptr; }
+
+ virtual void setInitialValuesForClone(const sp<Layer>& clonedFrom);
+
+ void updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+ void updateClonedChildren(const sp<Layer>& mirrorRoot,
+ std::map<sp<Layer>, sp<Layer>>& clonedLayersMap);
+ void updateClonedRelatives(std::map<sp<Layer>, sp<Layer>> clonedLayersMap);
+ void addChildToDrawing(const sp<Layer>& layer);
public:
/*
* compositionengine::LayerFE overrides
*/
+ bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
- bool includeGeometry) const override;
+ compositionengine::LayerFE::StateSubset subset) const override;
+ void latchCursorCompositionState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
protected:
+ void latchBasicGeometry(compositionengine::LayerFECompositionState& outState) const;
void latchGeometry(compositionengine::LayerFECompositionState& outState) const;
+ virtual void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const;
public:
virtual void setDefaultBufferSize(uint32_t /*w*/, uint32_t /*h*/) {}
virtual bool isHdrY410() const { return false; }
- void forceClientComposition(const sp<DisplayDevice>& display);
- bool getForceClientComposition(const sp<DisplayDevice>& display);
- virtual void setPerFrameData(const sp<const DisplayDevice>& display,
- const ui::Transform& transform, const Rect& viewport,
- int32_t supportedPerFrameMetadata,
- const ui::Dataspace targetDataspace) = 0;
-
- // callIntoHwc exists so we can update our local state and call
- // acceptDisplayChanges without unnecessarily updating the device's state
- void setCompositionType(const sp<const DisplayDevice>& display,
- Hwc2::IComposerClient::Composition type);
Hwc2::IComposerClient::Composition getCompositionType(
const sp<const DisplayDevice>& display) const;
bool getClearClientTarget(const sp<const DisplayDevice>& display) const;
- void updateCursorPosition(const sp<const DisplayDevice>& display);
virtual bool shouldPresentNow(nsecs_t /*expectedPresentTime*/) const { return false; }
virtual void setTransformHint(uint32_t /*orientation*/) const { }
/*
- * called before composition.
- * returns true if the layer has pending updates.
- */
- virtual bool onPreComposition(nsecs_t refreshStartTime) = 0;
-
- /*
* called after composition.
* returns true if the layer latched a new buffer this frame.
*/
@@ -527,58 +537,26 @@
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
/*
- * prepareClientLayer - populates a renderengine::LayerSettings to passed to
- * RenderEngine::drawLayers. Returns true if the layer can be used, and
- * false otherwise.
- */
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
- const bool supportProtectedContent, renderengine::LayerSettings& layer);
- bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
-
- /*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
uint32_t doTransaction(uint32_t transactionFlags);
/*
- * setVisibleRegion - called to set the new visible region. This gives
- * a chance to update the new visible region or record the fact it changed.
- */
- void setVisibleRegion(const Region& visibleRegion);
-
- /*
- * setCoveredRegion - called when the covered region changes. The covered
- * region corresponds to any area of the surface that is covered
- * (transparently or not) by another surface.
- */
- void setCoveredRegion(const Region& coveredRegion);
-
- /*
- * setVisibleNonTransparentRegion - called when the visible and
- * non-transparent region changes.
- */
- void setVisibleNonTransparentRegion(const Region& visibleNonTransparentRegion);
-
- /*
- * Clear the visible, covered, and non-transparent regions.
- */
- void clearVisibilityRegions();
-
- /*
* latchBuffer - called each time the screen is redrawn and returns whether
* the visible regions need to be recomputed (this is a fairly heavy
* 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 bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/) {
- return {};
+ virtual bool latchBuffer(bool& /*recomputeVisibleRegions*/, nsecs_t /*latchTime*/,
+ nsecs_t /*expectedPresentTime*/) {
+ return false;
}
virtual bool isBufferLatched() const { return false; }
+ virtual void latchAndReleaseBuffer() {}
+
/*
* Remove relative z for the layer if its relative parent is not part of the
* provided layer tree.
@@ -609,7 +587,14 @@
* returns the rectangle that crops the content of the layer and scales it
* to the layer's size.
*/
- Rect getContentCrop() const;
+ virtual Rect getBufferCrop() const { return Rect(); }
+
+ /*
+ * Returns the transform applied to the buffer.
+ */
+ virtual uint32_t getBufferTransform() const { return 0; }
+
+ virtual sp<GraphicBuffer> getBuffer() const { return nullptr; }
/*
* Returns if a frame is ready
@@ -619,10 +604,6 @@
virtual int32_t getQueuedFrameCount() const { return 0; }
// -----------------------------------------------------------------------
-
- bool hasHwcLayer(const sp<const DisplayDevice>& displayDevice);
- HWC2::Layer* getHwcLayer(const sp<const DisplayDevice>& displayDevice);
-
inline const State& getDrawingState() const { return mDrawingState; }
inline const State& getCurrentState() const { return mCurrentState; }
inline State& getCurrentState() { return mCurrentState; }
@@ -634,6 +615,7 @@
void miniDump(std::string& result, const sp<DisplayDevice>& display) const;
void dumpFrameStats(std::string& result) const;
void dumpFrameEvents(std::string& result);
+ void dumpCallingUidPid(std::string& result) const;
void clearFrameStats();
void logFrameStats();
void getFrameStats(FrameStats* outStats) const;
@@ -710,6 +692,8 @@
compositionengine::OutputLayer* findOutputLayerForDisplay(
const sp<const DisplayDevice>& display) const;
+ Region debugGetVisibleRegionOnDefaultDisplay() const;
+
protected:
// constant
sp<SurfaceFlinger> mFlinger;
@@ -821,7 +805,7 @@
// this to be called once.
sp<IBinder> getHandle();
const String8& getName() const;
- virtual void notifyAvailableFrames() {}
+ virtual void notifyAvailableFrames(nsecs_t /*expectedPresentTime*/) {}
virtual PixelFormat getPixelFormat() const { return PIXEL_FORMAT_NONE; }
bool getPremultipledAlpha() const;
@@ -864,20 +848,13 @@
// main thread
sp<NativeHandle> mSidebandStream;
- // 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};
// We encode unset as -1.
int32_t mOverrideScalingMode{-1};
std::atomic<uint64_t> mCurrentFrameNumber{0};
- bool mFrameLatencyNeeded{false};
// Whether filtering is needed b/c of the drawingstate
bool mNeedsFiltering{false};
@@ -894,8 +871,6 @@
// This layer can be a cursor on some displays.
bool mPotentialCursor{false};
- bool mFreezeGeometryUpdates{false};
-
// Child list about to be committed/used for editing.
LayerVector mCurrentChildren{LayerVector::StateSet::Current};
// Child list used for rendering.
@@ -958,6 +933,17 @@
bool mGetHandleCalled = false;
void removeRemoteSyncPoints();
+
+ // Tracks the process and user id of the caller when creating this layer
+ // to help debugging.
+ pid_t mCallingPid;
+ uid_t mCallingUid;
+
+ // The current layer is a clone of mClonedFrom. This means that this layer will update it's
+ // properties based on mClonedFrom. When mClonedFrom latches a new buffer for BufferLayers,
+ // this layer will update it's buffer. When mClonedFrom updates it's drawing state, children,
+ // and relatives, this layer will update as well.
+ wp<Layer> mClonedFrom;
};
} // namespace android
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 72abea8..8a22183 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -23,22 +23,16 @@
namespace android {
-LayerRejecter::LayerRejecter(Layer::State& front,
- Layer::State& current,
- bool& recomputeVisibleRegions,
- bool stickySet,
- const char* name,
- int32_t overrideScalingMode,
- bool transformToDisplayInverse,
- bool& freezePositionUpdates)
- : mFront(front),
- mCurrent(current),
- mRecomputeVisibleRegions(recomputeVisibleRegions),
- mStickyTransformSet(stickySet),
- mName(name),
- mOverrideScalingMode(overrideScalingMode),
- mTransformToDisplayInverse(transformToDisplayInverse),
- mFreezeGeometryUpdates(freezePositionUpdates) {}
+LayerRejecter::LayerRejecter(Layer::State& front, Layer::State& current,
+ bool& recomputeVisibleRegions, bool stickySet, const char* name,
+ int32_t overrideScalingMode, bool transformToDisplayInverse)
+ : mFront(front),
+ mCurrent(current),
+ mRecomputeVisibleRegions(recomputeVisibleRegions),
+ mStickyTransformSet(stickySet),
+ mName(name),
+ mOverrideScalingMode(overrideScalingMode),
+ mTransformToDisplayInverse(transformToDisplayInverse) {}
bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
if (buf == nullptr) {
@@ -83,8 +77,6 @@
// recompute visible region
mRecomputeVisibleRegions = true;
- mFreezeGeometryUpdates = false;
-
if (mFront.crop_legacy != mFront.requestedCrop_legacy) {
mFront.crop_legacy = mFront.requestedCrop_legacy;
mCurrent.crop_legacy = mFront.requestedCrop_legacy;
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 63d51de..1bd0c26 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -23,14 +23,9 @@
namespace android {
class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
public:
- LayerRejecter(Layer::State &front,
- Layer::State ¤t,
- bool &recomputeVisibleRegions,
- bool stickySet,
- const char *name,
- int32_t overrideScalingMode,
- bool transformToDisplayInverse,
- bool &freezePositionUpdates);
+ LayerRejecter(Layer::State &front, Layer::State ¤t, bool &recomputeVisibleRegions,
+ bool stickySet, const char *name, int32_t overrideScalingMode,
+ bool transformToDisplayInverse);
virtual bool reject(const sp<GraphicBuffer> &buf, const BufferItem &item);
@@ -42,7 +37,6 @@
const char *mName;
int32_t mOverrideScalingMode;
bool mTransformToDisplayInverse;
- bool &mFreezeGeometryUpdates;
};
} // namespace android
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
deleted file mode 100644
index a2d1feb..0000000
--- a/services/surfaceflinger/LayerStats.cpp
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#undef LOG_TAG
-#define LOG_TAG "LayerStats"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-
-#include "LayerStats.h"
-#include "DisplayHardware/HWComposer.h"
-#include "ui/DebugUtils.h"
-
-#include <android-base/stringprintf.h>
-#include <log/log.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-using base::StringAppendF;
-using base::StringPrintf;
-
-void LayerStats::enable() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- if (mEnabled) return;
- mLayerShapeStatsMap.clear();
- mEnabled = true;
- ALOGD("Logging enabled");
-}
-
-void LayerStats::disable() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- if (!mEnabled) return;
- mEnabled = false;
- ALOGD("Logging disabled");
-}
-
-void LayerStats::clear() {
- ATRACE_CALL();
- std::lock_guard<std::mutex> lock(mMutex);
- mLayerShapeStatsMap.clear();
- ALOGD("Cleared current layer stats");
-}
-
-bool LayerStats::isEnabled() {
- return mEnabled;
-}
-
-void LayerStats::traverseLayerTreeStatsLocked(
- const std::vector<LayerProtoParser::Layer*>& layerTree,
- const LayerProtoParser::LayerGlobal& layerGlobal,
- std::vector<std::string>* const outLayerShapeVec) {
- for (const auto& layer : layerTree) {
- if (!layer) continue;
- traverseLayerTreeStatsLocked(layer->children, layerGlobal, outLayerShapeVec);
- std::string key = "";
- StringAppendF(&key, ",%s", layer->type.c_str());
- StringAppendF(&key, ",%s", layerCompositionType(layer->hwcCompositionType));
- StringAppendF(&key, ",%d", layer->isProtected);
- StringAppendF(&key, ",%s", layerTransform(layer->hwcTransform));
- StringAppendF(&key, ",%s", layerPixelFormat(layer->activeBuffer.format).c_str());
- StringAppendF(&key, ",%s", layer->dataspace.c_str());
- StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.left, layerGlobal.resolution[0], true));
- StringAppendF(&key, ",%s",
- destinationLocation(layer->hwcFrame.top, layerGlobal.resolution[1], false));
- StringAppendF(&key, ",%s",
- destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
- layerGlobal.resolution[0], true));
- StringAppendF(&key, ",%s",
- destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
- layerGlobal.resolution[1], false));
- StringAppendF(&key, ",%s", scaleRatioWH(layer).c_str());
- StringAppendF(&key, ",%s", alpha(static_cast<float>(layer->color.a)));
-
- outLayerShapeVec->push_back(key);
- ALOGV("%s", key.c_str());
- }
-}
-
-void LayerStats::logLayerStats(const LayersProto& layersProto) {
- ATRACE_CALL();
- ALOGV("Logging");
- auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
- auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- std::vector<std::string> layerShapeVec;
-
- std::lock_guard<std::mutex> lock(mMutex);
- traverseLayerTreeStatsLocked(layerTree.topLevelLayers, layerGlobal, &layerShapeVec);
-
- std::string layerShapeKey =
- StringPrintf("%d,%s,%s,%s", static_cast<int32_t>(layerShapeVec.size()),
- layerGlobal.colorMode.c_str(), layerGlobal.colorTransform.c_str(),
- layerTransform(layerGlobal.globalTransform));
- ALOGV("%s", layerShapeKey.c_str());
-
- std::sort(layerShapeVec.begin(), layerShapeVec.end(), std::greater<std::string>());
- for (auto const& s : layerShapeVec) {
- layerShapeKey += s;
- }
-
- mLayerShapeStatsMap[layerShapeKey]++;
-}
-
-void LayerStats::dump(std::string& result) {
- ATRACE_CALL();
- ALOGD("Dumping");
- std::lock_guard<std::mutex> lock(mMutex);
- result.append("Frequency,LayerCount,ColorMode,ColorTransform,Orientation\n");
- result.append("LayerType,CompositionType,IsProtected,Transform,PixelFormat,Dataspace,");
- result.append("DstX,DstY,DstWidth,DstHeight,WScale,HScale,Alpha\n");
- for (auto& u : mLayerShapeStatsMap) {
- StringAppendF(&result, "%u,%s\n", u.second, u.first.c_str());
- }
-}
-
-const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
- static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
- int32_t ratio = location * 8 / range;
- if (ratio < 0) return "N/A";
- if (isHorizontal) {
- // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
- if (ratio > 6) return "3/4";
- // use index 0, 2, 4, 6
- return locationArray[ratio & ~1];
- }
- if (ratio > 7) return "7/8";
- return locationArray[ratio];
-}
-
-const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
- static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
- int32_t ratio = size * 8 / range;
- if (ratio < 0) return "N/A";
- if (isWidth) {
- // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
- if (ratio > 6) return "1";
- // use index 1, 3, 5, 7
- return sizeArray[ratio | 1];
- }
- if (ratio > 7) return "1";
- return sizeArray[ratio];
-}
-
-const char* LayerStats::layerTransform(int32_t transform) {
- return getTransformName(static_cast<hwc_transform_t>(transform));
-}
-
-const char* LayerStats::layerCompositionType(int32_t compositionType) {
- return getCompositionName(static_cast<hwc2_composition_t>(compositionType));
-}
-
-std::string LayerStats::layerPixelFormat(int32_t pixelFormat) {
- return decodePixelFormat(pixelFormat);
-}
-
-std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
- if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
- std::string ret = "";
- if (isRotated(layer->hwcTransform)) {
- ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
- static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
- ret += ",";
- ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
- static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
- } else {
- ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
- static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
- ret += ",";
- ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
- static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
- }
- return ret;
-}
-
-const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
- // Make scale buckets from <1/64 to >= 16, to avoid floating point
- // calculation, x64 on destinationScale first
- int32_t scale = destinationScale * 64 / sourceScale;
- if (!scale) return "<1/64";
- if (scale < 2) return "1/64";
- if (scale < 4) return "1/32";
- if (scale < 8) return "1/16";
- if (scale < 16) return "1/8";
- if (scale < 32) return "1/4";
- if (scale < 64) return "1/2";
- if (scale < 128) return "1";
- if (scale < 256) return "2";
- if (scale < 512) return "4";
- if (scale < 1024) return "8";
- return ">=16";
-}
-
-const char* LayerStats::alpha(float a) {
- if (a == 1.0f) return "1.0";
- if (a > 0.9f) return "0.99";
- if (a > 0.8f) return "0.9";
- if (a > 0.7f) return "0.8";
- if (a > 0.6f) return "0.7";
- if (a > 0.5f) return "0.6";
- if (a > 0.4f) return "0.5";
- if (a > 0.3f) return "0.4";
- if (a > 0.2f) return "0.3";
- if (a > 0.1f) return "0.2";
- if (a > 0.0f) return "0.1";
- return "0.0";
-}
-
-bool LayerStats::isRotated(int32_t transform) {
- return transform & HWC_TRANSFORM_ROT_90;
-}
-
-bool LayerStats::isVFlipped(int32_t transform) {
- return transform & HWC_TRANSFORM_FLIP_V;
-}
-
-bool LayerStats::isHFlipped(int32_t transform) {
- return transform & HWC_TRANSFORM_FLIP_H;
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
deleted file mode 100644
index 62b2688..0000000
--- a/services/surfaceflinger/LayerStats.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <layerproto/LayerProtoHeader.h>
-#include <layerproto/LayerProtoParser.h>
-#include <mutex>
-#include <unordered_map>
-
-using namespace android::surfaceflinger;
-
-namespace android {
-
-class LayerStats {
-public:
- void enable();
- void disable();
- void clear();
- bool isEnabled();
- void logLayerStats(const LayersProto& layersProto);
- void dump(std::string& result);
-
-private:
- // Traverse layer tree to get all visible layers' stats
- void traverseLayerTreeStatsLocked(
- const std::vector<LayerProtoParser::Layer*>& layerTree,
- const LayerProtoParser::LayerGlobal& layerGlobal,
- std::vector<std::string>* const outLayerShapeVec);
- // Convert layer's top-left position into 8x8 percentage of the display
- static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
- // Convert layer's size into 8x8 percentage of the display
- static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
- // Return the name of the transform
- static const char* layerTransform(int32_t transform);
- // Return the name of the composition type
- static const char* layerCompositionType(int32_t compositionType);
- // Return the name of the pixel format
- static std::string layerPixelFormat(int32_t pixelFormat);
- // Calculate scale ratios of layer's width/height with rotation information
- static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
- // Calculate scale ratio from source to destination and convert to string
- static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
- // Bucket the alpha into designed buckets
- static const char* alpha(float a);
- // Return whether the original buffer is rotated in final composition
- static bool isRotated(int32_t transform);
- // Return whether the original buffer is V-flipped in final composition
- static bool isVFlipped(int32_t transform);
- // Return whether the original buffer is H-flipped in final composition
- static bool isHFlipped(int32_t transform);
-
- bool mEnabled = false;
- // Protect mLayersStatsMap
- std::mutex mMutex;
- // Hashmap for tracking the frame(layer shape) stats
- // KEY is a concatenation of all layers' properties within a frame
- // VALUE is the number of times this particular set has been scanned out
- std::unordered_map<std::string, uint32_t> mLayerShapeStatsMap;
-};
-
-} // namespace android
diff --git a/services/surfaceflinger/LayerVector.cpp b/services/surfaceflinger/LayerVector.cpp
index 8494524..8271fd9 100644
--- a/services/surfaceflinger/LayerVector.cpp
+++ b/services/surfaceflinger/LayerVector.cpp
@@ -64,7 +64,7 @@
const auto& layer = (*this)[i];
auto& state = (stateSet == StateSet::Current) ? layer->getCurrentState()
: layer->getDrawingState();
- if (state.zOrderRelativeOf != nullptr) {
+ if (state.isRelativeOf) {
continue;
}
layer->traverseInZOrder(stateSet, visitor);
@@ -76,7 +76,7 @@
const auto& layer = (*this)[i];
auto& state = (stateSet == StateSet::Current) ? layer->getCurrentState()
: layer->getDrawingState();
- if (state.zOrderRelativeOf != nullptr) {
+ if (state.isRelativeOf) {
continue;
}
layer->traverseInReverseZOrder(stateSet, visitor);
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index c60421b..7a959f7 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -154,6 +154,10 @@
return mProducer->getConsumerUsage(outUsage);
}
+status_t MonitoredProducer::setAutoPrerotation(bool autoPrerotation) {
+ return mProducer->setAutoPrerotation(autoPrerotation);
+}
+
IBinder* MonitoredProducer::onAsBinder() {
return this;
}
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index d346f82..788919b 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -70,6 +70,7 @@
virtual void getFrameTimestamps(FrameEventHistoryDelta *outDelta) override;
virtual status_t getUniqueId(uint64_t* outId) const override;
virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+ virtual status_t setAutoPrerotation(bool autoPrerotation) override;
// The Layer which created this producer, and on which queued Buffer's will be displayed.
sp<Layer> getLayer() const;
diff --git a/services/surfaceflinger/RefreshRateOverlay.cpp b/services/surfaceflinger/RefreshRateOverlay.cpp
index 5b4bec9..976fedb 100644
--- a/services/surfaceflinger/RefreshRateOverlay.cpp
+++ b/services/surfaceflinger/RefreshRateOverlay.cpp
@@ -39,7 +39,7 @@
Mutex::Autolock _l(mFlinger.mStateLock);
mLayer = mClient->getLayerUser(mIBinder);
- mLayer->setCrop_legacy(Rect(50, 70, 200, 100), true);
+ mLayer->setCrop_legacy(Rect(50, 70, 200, 100));
// setting Layer's Z requires resorting layersSortedByZ
ssize_t idx = mFlinger.mCurrentState.layersSortedByZ.indexOf(mLayer);
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 07fdead..1c1367c 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -21,15 +21,18 @@
#include "RegionSamplingThread.h"
-#include <cutils/properties.h>
-#include <gui/IRegionSamplingListener.h>
-#include <utils/Trace.h>
-#include <string>
-
#include <compositionengine/Display.h>
#include <compositionengine/impl/OutputCompositionState.h>
+#include <cutils/properties.h>
+#include <gui/IRegionSamplingListener.h>
+#include <ui/DisplayStatInfo.h>
+#include <utils/Trace.h>
+
+#include <string>
+
#include "DisplayDevice.h"
#include "Layer.h"
+#include "Scheduler/DispSync.h"
#include "SurfaceFlinger.h"
namespace android {
@@ -105,9 +108,8 @@
if (mVsyncListening) return;
mPhaseIntervalSetting = Phase::ZERO;
- mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
- sync.addEventListener("SamplingThreadDispSyncListener", 0, this, mLastCallbackTime);
- });
+ mScheduler.getPrimaryDispSync().addEventListener("SamplingThreadDispSyncListener", 0, this,
+ mLastCallbackTime);
mVsyncListening = true;
}
@@ -120,9 +122,7 @@
void stopVsyncListenerLocked() /*REQUIRES(mMutex)*/ {
if (!mVsyncListening) return;
- mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
- sync.removeEventListener(this, &mLastCallbackTime);
- });
+ mScheduler.getPrimaryDispSync().removeEventListener(this, &mLastCallbackTime);
mVsyncListening = false;
}
@@ -132,16 +132,13 @@
if (mPhaseIntervalSetting == Phase::ZERO) {
ATRACE_INT(lumaSamplingStepTag, static_cast<int>(samplingStep::waitForSamplePhase));
mPhaseIntervalSetting = Phase::SAMPLING;
- mScheduler.withPrimaryDispSync([this](android::DispSync& sync) {
- sync.changePhaseOffset(this, mTargetSamplingOffset.count());
- });
+ mScheduler.getPrimaryDispSync().changePhaseOffset(this, mTargetSamplingOffset.count());
return;
}
if (mPhaseIntervalSetting == Phase::SAMPLING) {
mPhaseIntervalSetting = Phase::ZERO;
- mScheduler.withPrimaryDispSync(
- [this](android::DispSync& sync) { sync.changePhaseOffset(this, 0); });
+ mScheduler.getPrimaryDispSync().changePhaseOffset(this, 0);
stopVsyncListenerLocked();
lock.unlock();
mRegionSamplingThread.notifySamplingOffset();
diff --git a/services/surfaceflinger/RegionSamplingThread.h b/services/surfaceflinger/RegionSamplingThread.h
index 96ffe20..99c07c2 100644
--- a/services/surfaceflinger/RegionSamplingThread.h
+++ b/services/surfaceflinger/RegionSamplingThread.h
@@ -27,7 +27,7 @@
#include <ui/GraphicBuffer.h>
#include <ui/Rect.h>
#include <utils/StrongPointer.h>
-#include "Scheduler/IdleTimer.h"
+#include "Scheduler/OneShotTimer.h"
namespace android {
@@ -107,7 +107,7 @@
SurfaceFlinger& mFlinger;
Scheduler& mScheduler;
const TimingTunables mTunables;
- scheduler::IdleTimer mIdleTimer;
+ scheduler::OneShotTimer mIdleTimer;
std::unique_ptr<SamplingOffsetCallback> const mPhaseCallback;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 0c94052..4bdfad9 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -64,7 +64,7 @@
DispSyncThread(const char* name, bool showTraceDetailedInfo)
: mName(name),
mStop(false),
- mModelLocked(false),
+ mModelLocked("DispSync:ModelLocked", false),
mPeriod(0),
mPhase(0),
mReferenceTime(0),
@@ -121,13 +121,11 @@
void lockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = true;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
void unlockModel() {
Mutex::Autolock lock(mMutex);
mModelLocked = false;
- ATRACE_INT("DispSync:ModelLocked", mModelLocked);
}
virtual bool threadLoop() {
@@ -431,7 +429,7 @@
const char* const mName;
bool mStop;
- bool mModelLocked;
+ TracedOrdinal<bool> mModelLocked;
nsecs_t mPeriod;
nsecs_t mPhase;
@@ -454,33 +452,24 @@
class ZeroPhaseTracer : public DispSync::Callback {
public:
- ZeroPhaseTracer() : mParity(false) {}
+ ZeroPhaseTracer() : mParity("ZERO_PHASE_VSYNC", false) {}
virtual void onDispSyncEvent(nsecs_t /*when*/) {
mParity = !mParity;
- ATRACE_INT("ZERO_PHASE_VSYNC", mParity ? 1 : 0);
}
private:
- bool mParity;
+ TracedOrdinal<bool> mParity;
};
-DispSync::DispSync(const char* name) : mName(name), mRefreshSkipCount(0) {
+DispSync::DispSync(const char* name, bool hasSyncFramework)
+ : mName(name), mIgnorePresentFences(!hasSyncFramework) {
// This flag offers the ability to turn on systrace logging from the shell.
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.dispsync_trace_detailed_info", value, "0");
mTraceDetailedInfo = atoi(value);
+
mThread = new DispSyncThread(name, mTraceDetailedInfo);
-}
-
-DispSync::~DispSync() {
- mThread->stop();
- mThread->requestExitAndWait();
-}
-
-void DispSync::init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset) {
- mIgnorePresentFences = !hasSyncFramework;
- mPresentTimeOffset = dispSyncPresentTimeOffset;
mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
// set DispSync to SCHED_FIFO to minimize jitter
@@ -498,6 +487,11 @@
}
}
+DispSync::~DispSync() {
+ mThread->stop();
+ mThread->requestExitAndWait();
+}
+
void DispSync::reset() {
Mutex::Autolock lock(mMutex);
resetLocked();
@@ -623,13 +617,6 @@
return mThread->addEventListener(name, phase, callback, lastCallbackTime);
}
-void DispSync::setRefreshSkipCount(int count) {
- Mutex::Autolock lock(mMutex);
- ALOGD("setRefreshSkipCount(%d)", count);
- mRefreshSkipCount = count;
- updateModelLocked();
-}
-
status_t DispSync::removeEventListener(Callback* callback, nsecs_t* outLastCallbackTime) {
Mutex::Autolock lock(mMutex);
return mThread->removeEventListener(callback, outLastCallbackTime);
@@ -712,9 +699,6 @@
ALOGV("[%s] Adjusting mPhase -> %" PRId64, mName, ns2us(mPhase));
}
- // Artificially inflate the period if requested.
- mPeriod += mPeriod * mRefreshSkipCount;
-
mThread->updateModel(mPeriod, mPhase, mReferenceTime);
mModelUpdated = true;
}
@@ -725,10 +709,6 @@
return;
}
- // Need to compare present fences against the un-adjusted refresh period,
- // since they might arrive between two events.
- nsecs_t period = mPeriod / (1 + mRefreshSkipCount);
-
int numErrSamples = 0;
nsecs_t sqErrSum = 0;
@@ -747,9 +727,9 @@
continue;
}
- nsecs_t sampleErr = (sample - mPhase) % period;
- if (sampleErr > period / 2) {
- sampleErr -= period;
+ nsecs_t sampleErr = (sample - mPhase) % mPeriod;
+ if (sampleErr > mPeriod / 2) {
+ sampleErr -= mPeriod;
}
sqErrSum += sampleErr * sampleErr;
numErrSamples++;
@@ -804,8 +784,7 @@
void DispSync::dump(std::string& result) const {
Mutex::Autolock lock(mMutex);
StringAppendF(&result, "present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
- StringAppendF(&result, "mPeriod: %" PRId64 " ns (%.3f fps; skipCount=%d)\n", mPeriod,
- 1000000000.0 / mPeriod, mRefreshSkipCount);
+ StringAppendF(&result, "mPeriod: %" PRId64 " ns (%.3f fps)\n", mPeriod, 1000000000.0 / mPeriod);
StringAppendF(&result, "mPhase: %" PRId64 " ns\n", mPhase);
StringAppendF(&result, "mError: %" PRId64 " ns (sqrt=%.1f)\n", mError, sqrt(mError));
StringAppendF(&result, "mNumResyncSamplesSincePresent: %d (limit %d)\n",
diff --git a/services/surfaceflinger/Scheduler/DispSync.h b/services/surfaceflinger/Scheduler/DispSync.h
index 3e33c7e..c6aadbb 100644
--- a/services/surfaceflinger/Scheduler/DispSync.h
+++ b/services/surfaceflinger/Scheduler/DispSync.h
@@ -53,7 +53,6 @@
virtual void endResync() = 0;
virtual void setPeriod(nsecs_t period) = 0;
virtual nsecs_t getPeriod() = 0;
- virtual void setRefreshSkipCount(int count) = 0;
virtual status_t addEventListener(const char* name, nsecs_t phase, Callback* callback,
nsecs_t lastCallbackTime) = 0;
virtual status_t removeEventListener(Callback* callback, nsecs_t* outLastCallback) = 0;
@@ -88,11 +87,10 @@
// needed.
class DispSync : public android::DispSync {
public:
- explicit DispSync(const char* name);
+ // hasSyncFramework specifies whether the platform supports present fences.
+ DispSync(const char* name, bool hasSyncFramework);
~DispSync() override;
- void init(bool hasSyncFramework, int64_t dispSyncPresentTimeOffset);
-
// reset clears the resync samples and error value.
void reset() override;
@@ -138,12 +136,6 @@
// The getPeriod method returns the current vsync period.
nsecs_t getPeriod() override;
- // setRefreshSkipCount specifies an additional number of refresh
- // cycles to skip. For example, on a 60Hz display, a skip count of 1
- // will result in events happening at 30Hz. Default is zero. The idea
- // is to sacrifice smoothness for battery life.
- void setRefreshSkipCount(int count) override;
-
// addEventListener registers a callback to be called repeatedly at the
// given phase offset from the hardware vsync events. The callback is
// called from a separate thread and it should return reasonably quickly
@@ -252,18 +244,12 @@
std::shared_ptr<FenceTime> mPresentFences[NUM_PRESENT_SAMPLES]{FenceTime::NO_FENCE};
size_t mPresentSampleOffset;
- int mRefreshSkipCount;
-
// mThread is the thread from which all the callbacks are called.
sp<DispSyncThread> mThread;
// mMutex is used to protect access to all member variables.
mutable Mutex mMutex;
- // This is the offset from the present fence timestamps to the corresponding
- // vsync event.
- int64_t mPresentTimeOffset;
-
// Ignore present (retire) fences if the device doesn't have support for the
// sync framework
bool mIgnorePresentFences;
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 5faf46e..571c9ca 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -31,19 +31,16 @@
nsecs_t offsetThresholdForNextVsync, bool traceVsync,
const char* name)
: mName(name),
+ mValue(base::StringPrintf("VSYNC-%s", name), 0),
mTraceVsync(traceVsync),
mVsyncOnLabel(base::StringPrintf("VsyncOn-%s", name)),
- mVsyncEventLabel(base::StringPrintf("VSYNC-%s", name)),
- mVsyncOffsetLabel(base::StringPrintf("VsyncOffset-%s", name)),
- mVsyncNegativeOffsetLabel(base::StringPrintf("VsyncNegativeOffset-%s", name)),
mDispSync(dispSync),
- mPhaseOffset(phaseOffset),
+ mPhaseOffset(base::StringPrintf("VsyncOffset-%s", name), phaseOffset),
mOffsetThresholdForNextVsync(offsetThresholdForNextVsync) {}
void DispSyncSource::setVSyncEnabled(bool enable) {
std::lock_guard lock(mVsyncMutex);
if (enable) {
- tracePhaseOffset();
status_t err = mDispSync->addEventListener(mName, mPhaseOffset,
static_cast<DispSync::Callback*>(this),
mLastCallbackTime);
@@ -83,7 +80,6 @@
}
mPhaseOffset = phaseOffset;
- tracePhaseOffset();
// If we're not enabled, we don't need to mess with the listeners
if (!mEnabled) {
@@ -106,7 +102,6 @@
if (mTraceVsync) {
mValue = (mValue + 1) % 2;
- ATRACE_INT(mVsyncEventLabel.c_str(), mValue);
}
if (callback != nullptr) {
@@ -114,14 +109,4 @@
}
}
-void DispSyncSource::tracePhaseOffset() {
- if (mPhaseOffset > 0) {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), mPhaseOffset);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), 0);
- } else {
- ATRACE_INT(mVsyncOffsetLabel.c_str(), 0);
- ATRACE_INT(mVsyncNegativeOffsetLabel.c_str(), -mPhaseOffset);
- }
-}
-
} // namespace android
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.h b/services/surfaceflinger/Scheduler/DispSyncSource.h
index 50560a5..536464e 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.h
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.h
@@ -20,6 +20,7 @@
#include "DispSync.h"
#include "EventThread.h"
+#include "TracedOrdinal.h"
namespace android {
@@ -31,6 +32,7 @@
~DispSyncSource() override = default;
// The following methods are implementation of VSyncSource.
+ const char* getName() const override { return mName; }
void setVSyncEnabled(bool enable) override;
void setCallback(VSyncSource::Callback* callback) override;
void setPhaseOffset(nsecs_t phaseOffset) override;
@@ -39,16 +41,11 @@
// The following method is the implementation of the DispSync::Callback.
virtual void onDispSyncEvent(nsecs_t when);
- void tracePhaseOffset() REQUIRES(mVsyncMutex);
-
const char* const mName;
- int mValue = 0;
+ TracedOrdinal<int> mValue;
const bool mTraceVsync;
const std::string mVsyncOnLabel;
- const std::string mVsyncEventLabel;
- const std::string mVsyncOffsetLabel;
- const std::string mVsyncNegativeOffsetLabel;
nsecs_t mLastCallbackTime GUARDED_BY(mVsyncMutex) = 0;
DispSync* mDispSync;
@@ -57,7 +54,7 @@
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
std::mutex mVsyncMutex;
- nsecs_t mPhaseOffset GUARDED_BY(mVsyncMutex);
+ TracedOrdinal<nsecs_t> mPhaseOffset GUARDED_BY(mVsyncMutex);
const nsecs_t mOffsetThresholdForNextVsync;
bool mEnabled GUARDED_BY(mVsyncMutex) = false;
};
diff --git a/services/surfaceflinger/Scheduler/EventControlThread.cpp b/services/surfaceflinger/Scheduler/EventControlThread.cpp
index fb6cff5..85a7f82 100644
--- a/services/surfaceflinger/Scheduler/EventControlThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventControlThread.cpp
@@ -31,7 +31,7 @@
namespace impl {
EventControlThread::EventControlThread(EventControlThread::SetVSyncEnabledFunction function)
- : mSetVSyncEnabled(function) {
+ : mSetVSyncEnabled(std::move(function)) {
pthread_setname_np(mThread.native_handle(), "EventControlThread");
pid_t tid = pthread_gettid_np(mThread.native_handle());
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 9d1f777..8d9adc8 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -154,23 +154,11 @@
namespace impl {
-EventThread::EventThread(std::unique_ptr<VSyncSource> src,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
- : EventThread(nullptr, std::move(src), std::move(interceptVSyncsCallback), threadName) {}
-
-EventThread::EventThread(VSyncSource* src, InterceptVSyncsCallback interceptVSyncsCallback,
- const char* threadName)
- : EventThread(src, nullptr, std::move(interceptVSyncsCallback), threadName) {}
-
-EventThread::EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName)
- : mVSyncSource(src),
- mVSyncSourceUnique(std::move(uniqueSrc)),
+EventThread::EventThread(std::unique_ptr<VSyncSource> vsyncSource,
+ InterceptVSyncsCallback interceptVSyncsCallback)
+ : mVSyncSource(std::move(vsyncSource)),
mInterceptVSyncsCallback(std::move(interceptVSyncsCallback)),
- mThreadName(threadName) {
- if (src == nullptr) {
- mVSyncSource = mVSyncSourceUnique.get();
- }
+ mThreadName(mVSyncSource->getName()) {
mVSyncSource->setCallback(this);
mThread = std::thread([this]() NO_THREAD_SAFETY_ANALYSIS {
@@ -178,7 +166,7 @@
threadMain(lock);
});
- pthread_setname_np(mThread.native_handle(), threadName);
+ pthread_setname_np(mThread.native_handle(), mThreadName);
pid_t tid = pthread_gettid_np(mThread.native_handle());
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index dd23b88..a029586 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -62,6 +62,8 @@
};
virtual ~VSyncSource() {}
+
+ virtual const char* getName() const = 0;
virtual void setVSyncEnabled(bool enable) = 0;
virtual void setCallback(Callback* callback) = 0;
virtual void setPhaseOffset(nsecs_t phaseOffset) = 0;
@@ -126,9 +128,7 @@
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
- // TODO(b/128863962): Once the Scheduler is complete this constructor will become obsolete.
- EventThread(VSyncSource*, InterceptVSyncsCallback, const char* threadName);
- EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
+ EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback);
~EventThread();
sp<EventThreadConnection> createEventConnection(
@@ -157,10 +157,6 @@
using DisplayEventConsumers = std::vector<sp<EventThreadConnection>>;
- // TODO(b/128863962): Once the Scheduler is complete this constructor will become obsolete.
- EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
- InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
-
void threadMain(std::unique_lock<std::mutex>& lock) REQUIRES(mMutex);
bool shouldConsumeEvent(const DisplayEventReceiver::Event& event,
@@ -174,9 +170,7 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
- // TODO(b/128863962): Once the Scheduler is complete this pointer will become obsolete.
- VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
- std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
+ const std::unique_ptr<VSyncSource> mVSyncSource GUARDED_BY(mMutex);
const InterceptVSyncsCallback mInterceptVSyncsCallback;
const char* const mThreadName;
diff --git a/services/surfaceflinger/Scheduler/InjectVSyncSource.h b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
index 90609af..6c502e6 100644
--- a/services/surfaceflinger/Scheduler/InjectVSyncSource.h
+++ b/services/surfaceflinger/Scheduler/InjectVSyncSource.h
@@ -42,6 +42,7 @@
}
}
+ const char* getName() const override { return "inject"; }
void setVSyncEnabled(bool) override {}
void setPhaseOffset(nsecs_t) override {}
void pauseVsyncCallback(bool) {}
@@ -51,4 +52,4 @@
VSyncSource::Callback* mCallback GUARDED_BY(mCallbackMutex) = nullptr;
};
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.cpp b/services/surfaceflinger/Scheduler/MessageQueue.cpp
index fcb307f..5318b00 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.cpp
+++ b/services/surfaceflinger/Scheduler/MessageQueue.cpp
@@ -85,24 +85,6 @@
mHandler = new Handler(*this);
}
-void MessageQueue::setEventThread(android::EventThread* eventThread,
- ResyncCallback resyncCallback) {
- if (mEventThread == eventThread) {
- return;
- }
-
- if (mEventTube.getFd() >= 0) {
- mLooper->removeFd(mEventTube.getFd());
- }
-
- mEventThread = eventThread;
- mEvents = eventThread->createEventConnection(std::move(resyncCallback),
- ISurfaceComposer::eConfigChangedSuppress);
- mEvents->stealReceiveChannel(&mEventTube);
- mLooper->addFd(mEventTube.getFd(), 0, Looper::EVENT_INPUT, MessageQueue::cb_eventReceiver,
- this);
-}
-
void MessageQueue::setEventConnection(const sp<EventThreadConnection>& connection) {
if (mEventTube.getFd() >= 0) {
mLooper->removeFd(mEventTube.getFd());
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 0b2206d..fcfc4aa 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -85,8 +85,6 @@
virtual ~MessageQueue();
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
- // TODO(b/128863962): Remove this function once everything is migrated to Scheduler.
- virtual void setEventThread(EventThread* events, ResyncCallback resyncCallback) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
virtual status_t postMessage(const sp<MessageBase>& message, nsecs_t reltime = 0) = 0;
@@ -115,7 +113,6 @@
sp<SurfaceFlinger> mFlinger;
sp<Looper> mLooper;
- android::EventThread* mEventThread;
sp<EventThreadConnection> mEvents;
gui::BitTube mEventTube;
sp<Handler> mHandler;
@@ -126,7 +123,6 @@
public:
~MessageQueue() override = default;
void init(const sp<SurfaceFlinger>& flinger) override;
- void setEventThread(android::EventThread* events, ResyncCallback resyncCallback) override;
void setEventConnection(const sp<EventThreadConnection>& connection) override;
void waitMessage() override;
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.cpp b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
similarity index 88%
rename from services/surfaceflinger/Scheduler/IdleTimer.cpp
rename to services/surfaceflinger/Scheduler/OneShotTimer.cpp
index 37fdfc7..4870a3b 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.cpp
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "IdleTimer.h"
+#include "OneShotTimer.h"
#include <chrono>
#include <thread>
@@ -22,23 +22,23 @@
namespace android {
namespace scheduler {
-IdleTimer::IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback)
+OneShotTimer::OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+ const TimeoutCallback& timeoutCallback)
: mInterval(interval), mResetCallback(resetCallback), mTimeoutCallback(timeoutCallback) {}
-IdleTimer::~IdleTimer() {
+OneShotTimer::~OneShotTimer() {
stop();
}
-void IdleTimer::start() {
+void OneShotTimer::start() {
{
std::lock_guard<std::mutex> lock(mMutex);
mState = TimerState::RESET;
}
- mThread = std::thread(&IdleTimer::loop, this);
+ mThread = std::thread(&OneShotTimer::loop, this);
}
-void IdleTimer::stop() {
+void OneShotTimer::stop() {
{
std::lock_guard<std::mutex> lock(mMutex);
mState = TimerState::STOPPED;
@@ -49,7 +49,7 @@
}
}
-void IdleTimer::loop() {
+void OneShotTimer::loop() {
while (true) {
bool triggerReset = false;
bool triggerTimeout = false;
@@ -100,7 +100,7 @@
}
} // namespace scheduler
-void IdleTimer::reset() {
+void OneShotTimer::reset() {
{
std::lock_guard<std::mutex> lock(mMutex);
mState = TimerState::RESET;
diff --git a/services/surfaceflinger/Scheduler/IdleTimer.h b/services/surfaceflinger/Scheduler/OneShotTimer.h
similarity index 91%
rename from services/surfaceflinger/Scheduler/IdleTimer.h
rename to services/surfaceflinger/Scheduler/OneShotTimer.h
index 2646688..921631e 100644
--- a/services/surfaceflinger/Scheduler/IdleTimer.h
+++ b/services/surfaceflinger/Scheduler/OneShotTimer.h
@@ -29,15 +29,17 @@
* Class that sets off a timer for a given interval, and fires a callback when the
* interval expires.
*/
-class IdleTimer {
+class OneShotTimer {
public:
using Interval = std::chrono::milliseconds;
using ResetCallback = std::function<void()>;
using TimeoutCallback = std::function<void()>;
- IdleTimer(const Interval& interval, const ResetCallback& resetCallback,
- const TimeoutCallback& timeoutCallback);
- ~IdleTimer();
+ OneShotTimer(const Interval& interval, const ResetCallback& resetCallback,
+ const TimeoutCallback& timeoutCallback);
+ ~OneShotTimer();
+
+ const Interval& interval() const { return mInterval; }
// Initializes and turns on the idle timer.
void start();
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
index 8a2604f..6be88f8 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.cpp
@@ -18,115 +18,102 @@
#include <cutils/properties.h>
+#include <optional>
+
#include "SurfaceFlingerProperties.h"
-namespace android {
-using namespace android::sysprop;
+namespace {
-namespace scheduler {
+std::optional<nsecs_t> getProperty(const char* name) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get(name, value, "-1");
+ if (const int i = atoi(value); i != -1) return i;
+ return std::nullopt;
+}
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+} // namespace
+
+namespace android::scheduler {
+
PhaseOffsets::~PhaseOffsets() = default;
namespace impl {
+
PhaseOffsets::PhaseOffsets() {
- int64_t vsyncPhaseOffsetNs = vsync_event_phase_offset_ns(1000000);
-
- int64_t sfVsyncPhaseOffsetNs = vsync_sf_event_phase_offset_ns(1000000);
-
- char value[PROPERTY_VALUE_MAX];
- property_get("debug.sf.early_phase_offset_ns", value, "-1");
- const int earlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
- const int earlyGlSfOffsetNs = atoi(value);
-
- property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
- const int earlyAppOffsetNs = atoi(value);
-
- property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
- const int earlyGlAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_phase_offset_ns", value, "-1");
- const int highFpsEarlySfOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_gl_phase_offset_ns", value, "-1");
- const int highFpsEarlyGlSfOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_app_phase_offset_ns", value, "-1");
- const int highFpsEarlyAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_early_gl_app_phase_offset_ns", value, "-1");
- const int highFpsEarlyGlAppOffsetNs = atoi(value);
-
- // TODO(b/122905996): Define these in device.mk.
- property_get("debug.sf.high_fps_late_app_phase_offset_ns", value, "2000000");
- const int highFpsLateAppOffsetNs = atoi(value);
-
- property_get("debug.sf.high_fps_late_sf_phase_offset_ns", value, "1000000");
- const int highFpsLateSfOffsetNs = atoi(value);
-
// Below defines the threshold when an offset is considered to be negative, i.e. targeting
// for the N+2 vsync instead of N+1. This means that:
// For offset < threshold, SF wake up (vsync_duration - offset) before HW vsync.
// For offset >= threshold, SF wake up (2 * vsync_duration - offset) before HW vsync.
- property_get("debug.sf.phase_offset_threshold_for_next_vsync_ns", value, "-1");
- const int phaseOffsetThresholdForNextVsyncNs = atoi(value);
+ const nsecs_t thresholdForNextVsync =
+ getProperty("debug.sf.phase_offset_threshold_for_next_vsync_ns")
+ .value_or(std::numeric_limits<nsecs_t>::max());
- Offsets defaultOffsets;
- Offsets highFpsOffsets;
- defaultOffsets.early = {RefreshRateType::DEFAULT,
- earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
- defaultOffsets.earlyGl = {RefreshRateType::DEFAULT,
- earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
- earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
- defaultOffsets.late = {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs};
+ const Offsets defaultOffsets = getDefaultOffsets(thresholdForNextVsync);
+ const Offsets highFpsOffsets = getHighFpsOffsets(thresholdForNextVsync);
- highFpsOffsets.early = {RefreshRateType::PERFORMANCE,
- highFpsEarlySfOffsetNs != -1 ? highFpsEarlySfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyAppOffsetNs != -1 ? highFpsEarlyAppOffsetNs
- : highFpsLateAppOffsetNs};
- highFpsOffsets.earlyGl = {RefreshRateType::PERFORMANCE,
- highFpsEarlyGlSfOffsetNs != -1 ? highFpsEarlyGlSfOffsetNs
- : highFpsLateSfOffsetNs,
- highFpsEarlyGlAppOffsetNs != -1 ? highFpsEarlyGlAppOffsetNs
- : highFpsLateAppOffsetNs};
- highFpsOffsets.late = {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs,
- highFpsLateAppOffsetNs};
-
- mOffsets.insert({RefreshRateType::POWER_SAVING, defaultOffsets});
mOffsets.insert({RefreshRateType::DEFAULT, defaultOffsets});
mOffsets.insert({RefreshRateType::PERFORMANCE, highFpsOffsets});
-
- mOffsetThresholdForNextVsync = phaseOffsetThresholdForNextVsyncNs != -1
- ? phaseOffsetThresholdForNextVsyncNs
- : std::numeric_limits<nsecs_t>::max();
}
PhaseOffsets::Offsets PhaseOffsets::getOffsetsForRefreshRate(
- android::scheduler::RefreshRateConfigs::RefreshRateType refreshRateType) const {
+ RefreshRateType refreshRateType) const {
return mOffsets.at(refreshRateType);
}
void PhaseOffsets::dump(std::string& result) const {
- const auto [early, earlyGl, late] = getCurrentOffsets();
- base::StringAppendF(&result,
- " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
- " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
- "GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n",
- late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf);
+ const auto [early, earlyGl, late, threshold] = getCurrentOffsets();
+ using base::StringAppendF;
+ StringAppendF(&result,
+ " app phase: %9" PRId64 " ns\t SF phase: %9" PRId64 " ns\n"
+ " early app phase: %9" PRId64 " ns\t early SF phase: %9" PRId64 " ns\n"
+ " GL early app phase: %9" PRId64 " ns\tGL early SF phase: %9" PRId64 " ns\n"
+ "next VSYNC threshold: %9" PRId64 " ns\n",
+ late.app, late.sf, early.app, early.sf, earlyGl.app, earlyGl.sf, threshold);
}
-nsecs_t PhaseOffsets::getCurrentAppOffset() {
- return getCurrentOffsets().late.app;
+PhaseOffsets::Offsets PhaseOffsets::getDefaultOffsets(nsecs_t thresholdForNextVsync) {
+ const int64_t vsyncPhaseOffsetNs = sysprop::vsync_event_phase_offset_ns(1000000);
+ const int64_t sfVsyncPhaseOffsetNs = sysprop::vsync_sf_event_phase_offset_ns(1000000);
+
+ const auto earlySfOffsetNs = getProperty("debug.sf.early_phase_offset_ns");
+ const auto earlyGlSfOffsetNs = getProperty("debug.sf.early_gl_phase_offset_ns");
+ const auto earlyAppOffsetNs = getProperty("debug.sf.early_app_phase_offset_ns");
+ const auto earlyGlAppOffsetNs = getProperty("debug.sf.early_gl_app_phase_offset_ns");
+
+ return {{RefreshRateType::DEFAULT, earlySfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
+ earlyAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+
+ {RefreshRateType::DEFAULT, earlyGlSfOffsetNs.value_or(sfVsyncPhaseOffsetNs),
+ earlyGlAppOffsetNs.value_or(vsyncPhaseOffsetNs)},
+
+ {RefreshRateType::DEFAULT, sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs},
+
+ thresholdForNextVsync};
}
-nsecs_t PhaseOffsets::getCurrentSfOffset() {
- return getCurrentOffsets().late.sf;
+PhaseOffsets::Offsets PhaseOffsets::getHighFpsOffsets(nsecs_t thresholdForNextVsync) {
+ // TODO(b/122905996): Define these in device.mk.
+ const int highFpsLateAppOffsetNs =
+ getProperty("debug.sf.high_fps_late_app_phase_offset_ns").value_or(2000000);
+ const int highFpsLateSfOffsetNs =
+ getProperty("debug.sf.high_fps_late_sf_phase_offset_ns").value_or(1000000);
+
+ const auto highFpsEarlySfOffsetNs = getProperty("debug.sf.high_fps_early_phase_offset_ns");
+ const auto highFpsEarlyGlSfOffsetNs = getProperty("debug.sf.high_fps_early_gl_phase_offset_ns");
+ const auto highFpsEarlyAppOffsetNs = getProperty("debug.sf.high_fps_early_app_phase_offset_ns");
+ const auto highFpsEarlyGlAppOffsetNs =
+ getProperty("debug.sf.high_fps_early_gl_app_phase_offset_ns");
+
+ return {{RefreshRateType::PERFORMANCE, highFpsEarlySfOffsetNs.value_or(highFpsLateSfOffsetNs),
+ highFpsEarlyAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+
+ {RefreshRateType::PERFORMANCE, highFpsEarlyGlSfOffsetNs.value_or(highFpsLateSfOffsetNs),
+ highFpsEarlyGlAppOffsetNs.value_or(highFpsLateAppOffsetNs)},
+
+ {RefreshRateType::PERFORMANCE, highFpsLateSfOffsetNs, highFpsLateAppOffsetNs},
+
+ thresholdForNextVsync};
}
} // namespace impl
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/PhaseOffsets.h b/services/surfaceflinger/Scheduler/PhaseOffsets.h
index 2b5c2f1..2c52432 100644
--- a/services/surfaceflinger/Scheduler/PhaseOffsets.h
+++ b/services/surfaceflinger/Scheduler/PhaseOffsets.h
@@ -16,14 +16,12 @@
#pragma once
-#include <cinttypes>
#include <unordered_map>
#include "RefreshRateConfigs.h"
#include "VSyncModulator.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
/*
* This class encapsulates offsets for different refresh rates. Depending
@@ -33,35 +31,33 @@
*/
class PhaseOffsets {
public:
- struct Offsets {
- VSyncModulator::Offsets early;
- VSyncModulator::Offsets earlyGl;
- VSyncModulator::Offsets late;
- };
+ using Offsets = VSyncModulator::OffsetsConfig;
+ using RefreshRateType = RefreshRateConfigs::RefreshRateType;
virtual ~PhaseOffsets();
- virtual nsecs_t getCurrentAppOffset() = 0;
- virtual nsecs_t getCurrentSfOffset() = 0;
- virtual Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType refreshRateType) const = 0;
+ nsecs_t getCurrentAppOffset() const { return getCurrentOffsets().late.app; }
+ nsecs_t getCurrentSfOffset() const { return getCurrentOffsets().late.sf; }
+ nsecs_t getOffsetThresholdForNextVsync() const {
+ return getCurrentOffsets().thresholdForNextVsync;
+ }
+
virtual Offsets getCurrentOffsets() const = 0;
- virtual void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) = 0;
- virtual nsecs_t getOffsetThresholdForNextVsync() const = 0;
+ virtual Offsets getOffsetsForRefreshRate(RefreshRateType) const = 0;
+
+ virtual void setRefreshRateType(RefreshRateType) = 0;
+
virtual void dump(std::string& result) const = 0;
};
namespace impl {
+
class PhaseOffsets : public scheduler::PhaseOffsets {
public:
PhaseOffsets();
- nsecs_t getCurrentAppOffset() override;
- nsecs_t getCurrentSfOffset() override;
-
// Returns early, early GL, and late offsets for Apps and SF for a given refresh rate.
- Offsets getOffsetsForRefreshRate(
- RefreshRateConfigs::RefreshRateType refreshRateType) const override;
+ Offsets getOffsetsForRefreshRate(RefreshRateType) const override;
// Returns early, early GL, and late offsets for Apps and SF.
Offsets getCurrentOffsets() const override {
@@ -70,23 +66,21 @@
// This function should be called when the device is switching between different
// refresh rates, to properly update the offsets.
- void setRefreshRateType(RefreshRateConfigs::RefreshRateType refreshRateType) override {
+ void setRefreshRateType(RefreshRateType refreshRateType) override {
mRefreshRateType = refreshRateType;
}
- nsecs_t getOffsetThresholdForNextVsync() const override { return mOffsetThresholdForNextVsync; }
-
// Returns current offsets in human friendly format.
void dump(std::string& result) const override;
private:
- std::atomic<RefreshRateConfigs::RefreshRateType> mRefreshRateType =
- RefreshRateConfigs::RefreshRateType::DEFAULT;
+ static Offsets getDefaultOffsets(nsecs_t thresholdForNextVsync);
+ static Offsets getHighFpsOffsets(nsecs_t thresholdForNextVsync);
- std::unordered_map<RefreshRateConfigs::RefreshRateType, Offsets> mOffsets;
- nsecs_t mOffsetThresholdForNextVsync;
+ std::atomic<RefreshRateType> mRefreshRateType = RefreshRateType::DEFAULT;
+
+ std::unordered_map<RefreshRateType, Offsets> mOffsets;
};
-} // namespace impl
-} // namespace scheduler
-} // namespace android
+} // namespace impl
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index d730058..2fd100f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -16,16 +16,23 @@
#pragma once
+#include <android-base/stringprintf.h>
+
#include <algorithm>
#include <numeric>
-
-#include "android-base/stringprintf.h"
+#include <type_traits>
#include "DisplayHardware/HWComposer.h"
#include "Scheduler/SchedulerUtils.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
+
+enum class RefreshRateConfigEvent : unsigned { None = 0b0, Changed = 0b1 };
+
+inline RefreshRateConfigEvent operator|(RefreshRateConfigEvent lhs, RefreshRateConfigEvent rhs) {
+ using T = std::underlying_type_t<RefreshRateConfigEvent>;
+ return static_cast<RefreshRateConfigEvent>(static_cast<T>(lhs) | static_cast<T>(rhs));
+}
/**
* This class is used to encapsulate configuration for refresh rates. It holds information
@@ -34,10 +41,9 @@
*/
class RefreshRateConfigs {
public:
- // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
- // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
+ // Enum to indicate which vsync rate to run at. Default is the old 60Hz, and performance
// is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
- enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
+ enum class RefreshRateType { DEFAULT, PERFORMANCE };
struct RefreshRate {
// This config ID corresponds to the position of the config in the vector that is stored
@@ -47,26 +53,57 @@
std::string name;
// Refresh rate in frames per second, rounded to the nearest integer.
uint32_t fps = 0;
- // config Id (returned from HWC2::Display::Config::getId())
- hwc2_config_t id;
+ // Vsync period in nanoseconds.
+ nsecs_t vsyncPeriod;
+ // Hwc config Id (returned from HWC2::Display::Config::getId())
+ hwc2_config_t hwcId;
};
+ // Returns true if this device is doing refresh rate switching. This won't change at runtime.
+ bool refreshRateSwitchingSupported() const { return mRefreshRateSwitchingSupported; }
+
+ // Returns the refresh rate map. This map won't be modified at runtime, so it's safe to access
+ // from multiple threads. This can only be called if refreshRateSwitching() returns true.
// TODO(b/122916473): Get this information from configs prepared by vendors, instead of
// baking them in.
- const std::map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() const {
- return mRefreshRates;
- }
- std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) const {
- const auto& refreshRate = mRefreshRates.find(type);
- if (refreshRate != mRefreshRates.end()) {
- return refreshRate->second;
- }
- return nullptr;
+ const std::map<RefreshRateType, RefreshRate>& getRefreshRateMap() const {
+ LOG_ALWAYS_FATAL_IF(!mRefreshRateSwitchingSupported);
+ return mRefreshRateMap;
}
- RefreshRateType getRefreshRateType(hwc2_config_t id) const {
- for (const auto& [type, refreshRate] : mRefreshRates) {
- if (refreshRate->id == id) {
+ const RefreshRate& getRefreshRateFromType(RefreshRateType type) const {
+ if (!mRefreshRateSwitchingSupported) {
+ return getCurrentRefreshRate().second;
+ } else {
+ auto refreshRate = mRefreshRateMap.find(type);
+ LOG_ALWAYS_FATAL_IF(refreshRate == mRefreshRateMap.end());
+ return refreshRate->second;
+ }
+ }
+
+ std::pair<RefreshRateType, const RefreshRate&> getCurrentRefreshRate() const {
+ int currentConfig = mCurrentConfig;
+ if (mRefreshRateSwitchingSupported) {
+ for (const auto& [type, refresh] : mRefreshRateMap) {
+ if (refresh.configId == currentConfig) {
+ return {type, refresh};
+ }
+ }
+ LOG_ALWAYS_FATAL();
+ }
+ return {RefreshRateType::DEFAULT, mRefreshRates[currentConfig]};
+ }
+
+ const RefreshRate& getRefreshRateFromConfigId(int configId) const {
+ LOG_ALWAYS_FATAL_IF(configId >= mRefreshRates.size());
+ return mRefreshRates[configId];
+ }
+
+ RefreshRateType getRefreshRateTypeFromHwcConfigId(hwc2_config_t hwcId) const {
+ if (!mRefreshRateSwitchingSupported) return RefreshRateType::DEFAULT;
+
+ for (const auto& [type, refreshRate] : mRefreshRateMap) {
+ if (refreshRate.hwcId == hwcId) {
return type;
}
}
@@ -74,65 +111,102 @@
return RefreshRateType::DEFAULT;
}
- void populate(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
- mRefreshRates.clear();
+ void setCurrentConfig(int config) {
+ LOG_ALWAYS_FATAL_IF(config >= mRefreshRates.size());
+ mCurrentConfig = config;
+ }
- // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
- mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
- std::make_shared<RefreshRate>(
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0,
- HWC2_SCREEN_OFF_CONFIG_ID}));
+ struct InputConfig {
+ hwc2_config_t hwcId = 0;
+ nsecs_t vsyncPeriod = 0;
+ };
- if (configs.size() < 1) {
- ALOGE("Device does not have valid configs. Config size is 0.");
- return;
+ RefreshRateConfigs(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ int currentConfig) {
+ init(refreshRateSwitching, configs, currentConfig);
+ }
+
+ RefreshRateConfigs(bool refreshRateSwitching,
+ const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs,
+ int currentConfig) {
+ std::vector<InputConfig> inputConfigs;
+ for (const auto& config : configs) {
+ inputConfigs.push_back({config->getId(), config->getVsyncPeriod()});
}
-
- // Create a map between config index and vsync period. This is all the info we need
- // from the configs.
- std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
- for (int i = 0; i < configs.size(); ++i) {
- configIdToVsyncPeriod.emplace_back(i, configs.at(i)->getVsyncPeriod());
- }
-
- std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(),
- [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
- return a.second > b.second;
- });
-
- // When the configs are ordered by the resync rate. We assume that the first one is DEFAULT.
- nsecs_t vsyncPeriod = configIdToVsyncPeriod[0].second;
- if (vsyncPeriod != 0) {
- const float fps = 1e9 / vsyncPeriod;
- const int configId = configIdToVsyncPeriod[0].first;
- mRefreshRates.emplace(RefreshRateType::DEFAULT,
- std::make_shared<RefreshRate>(
- RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps),
- configs.at(configId)->getId()}));
- }
-
- if (configs.size() < 2) {
- return;
- }
-
- // When the configs are ordered by the resync rate. We assume that the second one is
- // PERFORMANCE, eg. the higher rate.
- vsyncPeriod = configIdToVsyncPeriod[1].second;
- if (vsyncPeriod != 0) {
- const float fps = 1e9 / vsyncPeriod;
- const int configId = configIdToVsyncPeriod[1].first;
- mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
- std::make_shared<RefreshRate>(
- RefreshRate{configId, base::StringPrintf("%2.ffps", fps),
- static_cast<uint32_t>(fps),
- configs.at(configId)->getId()}));
- }
+ init(refreshRateSwitching, inputConfigs, currentConfig);
}
private:
- std::map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
+ void init(bool refreshRateSwitching, const std::vector<InputConfig>& configs,
+ int currentConfig) {
+ mRefreshRateSwitchingSupported = refreshRateSwitching;
+ LOG_ALWAYS_FATAL_IF(configs.empty());
+ LOG_ALWAYS_FATAL_IF(currentConfig >= configs.size());
+ mCurrentConfig = currentConfig;
+
+ auto buildRefreshRate = [&](int configId) -> RefreshRate {
+ const nsecs_t vsyncPeriod = configs[configId].vsyncPeriod;
+ const float fps = 1e9 / vsyncPeriod;
+ return {configId, base::StringPrintf("%2.ffps", fps), static_cast<uint32_t>(fps),
+ vsyncPeriod, configs[configId].hwcId};
+ };
+
+ for (int i = 0; i < configs.size(); ++i) {
+ mRefreshRates.push_back(buildRefreshRate(i));
+ }
+
+ if (!mRefreshRateSwitchingSupported) return;
+
+ auto findDefaultAndPerfConfigs = [&]() -> std::optional<std::pair<int, int>> {
+ if (configs.size() < 2) {
+ return {};
+ }
+
+ std::vector<const RefreshRate*> sortedRefreshRates;
+ for (const auto& refreshRate : mRefreshRates) {
+ sortedRefreshRates.push_back(&refreshRate);
+ }
+ std::sort(sortedRefreshRates.begin(), sortedRefreshRates.end(),
+ [](const RefreshRate* refreshRate1, const RefreshRate* refreshRate2) {
+ return refreshRate1->vsyncPeriod > refreshRate2->vsyncPeriod;
+ });
+
+ // When the configs are ordered by the resync rate, we assume that
+ // the first one is DEFAULT and the second one is PERFORMANCE,
+ // i.e. the higher rate.
+ if (sortedRefreshRates[0]->vsyncPeriod == 0 ||
+ sortedRefreshRates[1]->vsyncPeriod == 0) {
+ return {};
+ }
+
+ return std::pair<int, int>(sortedRefreshRates[0]->configId,
+ sortedRefreshRates[1]->configId);
+ };
+
+ auto defaultAndPerfConfigs = findDefaultAndPerfConfigs();
+ if (!defaultAndPerfConfigs) {
+ mRefreshRateSwitchingSupported = false;
+ return;
+ }
+
+ mRefreshRateMap[RefreshRateType::DEFAULT] = mRefreshRates[defaultAndPerfConfigs->first];
+ mRefreshRateMap[RefreshRateType::PERFORMANCE] =
+ mRefreshRates[defaultAndPerfConfigs->second];
+ }
+
+ // Whether this device is doing refresh rate switching or not. This must not change after this
+ // object is initialized.
+ bool mRefreshRateSwitchingSupported;
+ // The list of refresh rates, indexed by display config ID. This must not change after this
+ // object is initialized.
+ std::vector<RefreshRate> mRefreshRates;
+ // The mapping of refresh rate type to RefreshRate. This must not change after this object is
+ // initialized.
+ std::map<RefreshRateType, RefreshRate> mRefreshRateMap;
+ // The ID of the current config. This will change at runtime. This is set by SurfaceFlinger on
+ // the main thread, and read by the Scheduler (and other objects) on other threads, so it's
+ // atomic.
+ std::atomic<int> mCurrentConfig;
};
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index 7e7c630..8afc93e 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -41,21 +41,18 @@
static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
public:
- RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats)
- : mRefreshRateConfigs(refreshRateConfigs), mTimeStats(timeStats) {}
+ RefreshRateStats(const RefreshRateConfigs& refreshRateConfigs, TimeStats& timeStats,
+ int currentConfigMode, int currentPowerMode)
+ : mRefreshRateConfigs(refreshRateConfigs),
+ mTimeStats(timeStats),
+ mCurrentConfigMode(currentConfigMode),
+ mCurrentPowerMode(currentPowerMode) {}
- // Sets power mode. We only collect the information when the power mode is not
- // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
- // on config mode.
+ // Sets power mode.
void setPowerMode(int mode) {
if (mCurrentPowerMode == mode) {
return;
}
- // If power mode is normal, the time is going to be recorded under config modes.
- if (mode == HWC_POWER_MODE_NORMAL) {
- mCurrentPowerMode = mode;
- return;
- }
flushTime();
mCurrentPowerMode = mode;
}
@@ -79,57 +76,50 @@
flushTime();
std::unordered_map<std::string, int64_t> totalTime;
- for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
- int64_t totalTimeForConfig = 0;
- if (!config) {
- continue;
- }
- if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
- totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
- }
- totalTime[config->name] = totalTimeForConfig;
+ // Multiple configs may map to the same name, e.g. "60fps". Add the
+ // times for such configs together.
+ for (const auto& [config, time] : mConfigModesTotalTime) {
+ totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] = 0;
}
+ for (const auto& [config, time] : mConfigModesTotalTime) {
+ totalTime[mRefreshRateConfigs.getRefreshRateFromConfigId(config).name] += time;
+ }
+ totalTime["ScreenOff"] = mScreenOffTime;
return totalTime;
}
// Traverses through the map of config modes and returns how long they've been running in easy
// to read format.
- std::string doDump() const {
- std::ostringstream stream;
- stream << "+ Refresh rate: running time in seconds\n";
+ void dump(std::string& result) const {
+ std::ostringstream stream("+ Refresh rate: running time in seconds\n");
+
for (const auto& [name, time] : const_cast<RefreshRateStats*>(this)->getTotalTimes()) {
stream << name << ": " << getDateFormatFromMs(time) << '\n';
}
- return stream.str();
+ result.append(stream.str());
}
private:
- void flushTime() {
- // Normal power mode is counted under different config modes.
- if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
- flushTimeForMode(mCurrentConfigMode);
- } else {
- flushTimeForMode(SCREEN_OFF_CONFIG_ID);
- }
- }
-
// Calculates the time that passed in ms between the last time we recorded time and the time
// this method was called.
- void flushTimeForMode(int mode) {
+ void flushTime() {
nsecs_t currentTime = systemTime();
nsecs_t timeElapsed = currentTime - mPreviousRecordedTime;
int64_t timeElapsedMs = ns2ms(timeElapsed);
mPreviousRecordedTime = currentTime;
- mConfigModesTotalTime[mode] += timeElapsedMs;
- for (const auto& [type, config] : mRefreshRateConfigs.getRefreshRates()) {
- if (!config) {
- continue;
+ uint32_t fps = 0;
+ if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
+ // Normal power mode is counted under different config modes.
+ if (mConfigModesTotalTime.find(mCurrentConfigMode) == mConfigModesTotalTime.end()) {
+ mConfigModesTotalTime[mCurrentConfigMode] = 0;
}
- if (config->configId == mode) {
- mTimeStats.recordRefreshRate(config->fps, timeElapsed);
- }
+ mConfigModesTotalTime[mCurrentConfigMode] += timeElapsedMs;
+ fps = mRefreshRateConfigs.getRefreshRateFromConfigId(mCurrentConfigMode).fps;
+ } else {
+ mScreenOffTime += timeElapsedMs;
}
+ mTimeStats.recordRefreshRate(fps, timeElapsed);
}
// Formats the time in milliseconds into easy to read format.
@@ -149,10 +139,11 @@
// Aggregate refresh rate statistics for telemetry.
TimeStats& mTimeStats;
- int64_t mCurrentConfigMode = SCREEN_OFF_CONFIG_ID;
- int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
+ int mCurrentConfigMode;
+ int32_t mCurrentPowerMode;
- std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
+ std::unordered_map<int /* config */, int64_t /* duration in ms */> mConfigModesTotalTime;
+ int64_t mScreenOffTime = 0;
nsecs_t mPreviousRecordedTime = systemTime();
};
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 8da5612..d60e101 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#undef LOG_TAG
+#define LOG_TAG "Scheduler"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
#include "Scheduler.h"
@@ -21,6 +23,7 @@
#include <algorithm>
#include <cinttypes>
#include <cstdint>
+#include <functional>
#include <memory>
#include <numeric>
@@ -38,185 +41,156 @@
#include "DispSyncSource.h"
#include "EventControlThread.h"
#include "EventThread.h"
-#include "IdleTimer.h"
#include "InjectVSyncSource.h"
-#include "LayerInfo.h"
+#include "OneShotTimer.h"
#include "SchedulerUtils.h"
#include "SurfaceFlingerProperties.h"
+#define RETURN_IF_INVALID_HANDLE(handle, ...) \
+ do { \
+ if (mConnections.count(handle) == 0) { \
+ ALOGE("Invalid connection handle %" PRIuPTR, handle.id); \
+ return __VA_ARGS__; \
+ } \
+ } while (false)
+
namespace android {
-using namespace android::hardware::configstore;
-using namespace android::hardware::configstore::V1_0;
-using namespace android::sysprop;
-
-#define RETURN_VALUE_IF_INVALID(value) \
- if (handle == nullptr || mConnections.count(handle->id) == 0) return value
-#define RETURN_IF_INVALID() \
- if (handle == nullptr || mConnections.count(handle->id) == 0) return
-
-std::atomic<int64_t> Scheduler::sNextId = 0;
-
Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
const scheduler::RefreshRateConfigs& refreshRateConfig)
- : mHasSyncFramework(running_without_sync_framework(true)),
- mDispSyncPresentTimeOffset(present_time_offset_from_vsync_ns(0)),
- mPrimaryHWVsyncEnabled(false),
- mHWVsyncAvailable(false),
+ : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync",
+ sysprop::running_without_sync_framework(true))),
+ mEventControlThread(new impl::EventControlThread(std::move(function))),
+ mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
mRefreshRateConfigs(refreshRateConfig) {
- // Note: We create a local temporary with the real DispSync implementation
- // type temporarily so we can initialize it with the configured values,
- // before storing it for more generic use using the interface type.
- auto primaryDispSync = std::make_unique<impl::DispSync>("SchedulerDispSync");
- primaryDispSync->init(mHasSyncFramework, mDispSyncPresentTimeOffset);
- mPrimaryDispSync = std::move(primaryDispSync);
- mEventControlThread = std::make_unique<impl::EventControlThread>(function);
-
- mSetIdleTimerMs = set_idle_timer_ms(0);
- mSupportKernelTimer = support_kernel_idle_timer(false);
-
- mSetTouchTimerMs = set_touch_timer_ms(0);
- mSetDisplayPowerTimerMs = set_display_power_timer_ms(0);
+ using namespace sysprop;
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.set_idle_timer_ms", value, "0");
- int int_value = atoi(value);
- if (int_value) {
- mSetIdleTimerMs = atoi(value);
- }
+ const int setIdleTimerMs = atoi(value);
- if (mSetIdleTimerMs > 0) {
- if (mSupportKernelTimer) {
- mIdleTimer =
- std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
- mSetIdleTimerMs),
- [this] { resetKernelTimerCallback(); },
- [this] {
- expiredKernelTimerCallback();
- });
- } else {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
- mSetIdleTimerMs),
- [this] { resetTimerCallback(); },
- [this] { expiredTimerCallback(); });
- }
+ if (const auto millis = setIdleTimerMs ? setIdleTimerMs : set_idle_timer_ms(0); millis > 0) {
+ const auto callback = mSupportKernelTimer ? &Scheduler::kernelIdleTimerCallback
+ : &Scheduler::idleTimerCallback;
+
+ mIdleTimer.emplace(
+ std::chrono::milliseconds(millis),
+ [this, callback] { std::invoke(callback, this, TimerState::Reset); },
+ [this, callback] { std::invoke(callback, this, TimerState::Expired); });
mIdleTimer->start();
}
- if (mSetTouchTimerMs > 0) {
+ if (const int64_t millis = set_touch_timer_ms(0); millis > 0) {
// Touch events are coming to SF every 100ms, so the timer needs to be higher than that
- mTouchTimer =
- std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(mSetTouchTimerMs),
- [this] { resetTouchTimerCallback(); },
- [this] { expiredTouchTimerCallback(); });
+ mTouchTimer.emplace(
+ std::chrono::milliseconds(millis),
+ [this] { touchTimerCallback(TimerState::Reset); },
+ [this] { touchTimerCallback(TimerState::Expired); });
mTouchTimer->start();
}
- if (mSetDisplayPowerTimerMs > 0) {
- mDisplayPowerTimer =
- std::make_unique<scheduler::IdleTimer>(std::chrono::milliseconds(
- mSetDisplayPowerTimerMs),
- [this] { resetDisplayPowerTimerCallback(); },
- [this] {
- expiredDisplayPowerTimerCallback();
- });
+ if (const int64_t millis = set_display_power_timer_ms(0); millis > 0) {
+ mDisplayPowerTimer.emplace(
+ std::chrono::milliseconds(millis),
+ [this] { displayPowerTimerCallback(TimerState::Reset); },
+ [this] { displayPowerTimerCallback(TimerState::Expired); });
mDisplayPowerTimer->start();
}
}
+Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ const scheduler::RefreshRateConfigs& configs)
+ : mPrimaryDispSync(std::move(primaryDispSync)),
+ mEventControlThread(std::move(eventControlThread)),
+ mSupportKernelTimer(false),
+ mRefreshRateConfigs(configs) {}
+
Scheduler::~Scheduler() {
- // Ensure the IdleTimer thread is joined before we start destroying state.
+ // Ensure the OneShotTimer threads are joined before we start destroying state.
mDisplayPowerTimer.reset();
mTouchTimer.reset();
mIdleTimer.reset();
}
-sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
- const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
- ResyncCallback resyncCallback,
- impl::EventThread::InterceptVSyncsCallback interceptCallback) {
- const int64_t id = sNextId++;
- ALOGV("Creating a connection handle with ID: %" PRId64 "\n", id);
-
- std::unique_ptr<EventThread> eventThread =
- makeEventThread(connectionName, mPrimaryDispSync.get(), phaseOffsetNs,
- offsetThresholdForNextVsync, std::move(interceptCallback));
-
- auto eventThreadConnection =
- createConnectionInternal(eventThread.get(), std::move(resyncCallback),
- ISurfaceComposer::eConfigChangedSuppress);
- mConnections.emplace(id,
- std::make_unique<Connection>(new ConnectionHandle(id),
- eventThreadConnection,
- std::move(eventThread)));
- return mConnections[id]->handle;
+DispSync& Scheduler::getPrimaryDispSync() {
+ return *mPrimaryDispSync;
}
-std::unique_ptr<EventThread> Scheduler::makeEventThread(
- const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
- nsecs_t offsetThresholdForNextVsync,
+std::unique_ptr<VSyncSource> Scheduler::makePrimaryDispSyncSource(
+ const char* name, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync) {
+ return std::make_unique<DispSyncSource>(mPrimaryDispSync.get(), phaseOffsetNs,
+ offsetThresholdForNextVsync, true /* traceVsync */,
+ name);
+}
+
+Scheduler::ConnectionHandle Scheduler::createConnection(
+ const char* connectionName, nsecs_t phaseOffsetNs, nsecs_t offsetThresholdForNextVsync,
impl::EventThread::InterceptVSyncsCallback interceptCallback) {
- std::unique_ptr<VSyncSource> eventThreadSource =
- std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, offsetThresholdForNextVsync,
- true, connectionName);
- return std::make_unique<impl::EventThread>(std::move(eventThreadSource),
- std::move(interceptCallback), connectionName);
+ auto vsyncSource =
+ makePrimaryDispSyncSource(connectionName, phaseOffsetNs, offsetThresholdForNextVsync);
+ auto eventThread = std::make_unique<impl::EventThread>(std::move(vsyncSource),
+ std::move(interceptCallback));
+ return createConnection(std::move(eventThread));
+}
+
+Scheduler::ConnectionHandle Scheduler::createConnection(std::unique_ptr<EventThread> eventThread) {
+ const ConnectionHandle handle = ConnectionHandle{mNextConnectionHandleId++};
+ ALOGV("Creating a connection handle with ID %" PRIuPTR, handle.id);
+
+ auto connection =
+ createConnectionInternal(eventThread.get(), ISurfaceComposer::eConfigChangedSuppress);
+
+ mConnections.emplace(handle, Connection{connection, std::move(eventThread)});
+ return handle;
}
sp<EventThreadConnection> Scheduler::createConnectionInternal(
- EventThread* eventThread, ResyncCallback&& resyncCallback,
- ISurfaceComposer::ConfigChanged configChanged) {
- return eventThread->createEventConnection(std::move(resyncCallback), configChanged);
+ EventThread* eventThread, ISurfaceComposer::ConfigChanged configChanged) {
+ return eventThread->createEventConnection([&] { resync(); }, configChanged);
}
sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
- const sp<Scheduler::ConnectionHandle>& handle, ResyncCallback resyncCallback,
- ISurfaceComposer::ConfigChanged configChanged) {
- RETURN_VALUE_IF_INVALID(nullptr);
- return createConnectionInternal(mConnections[handle->id]->thread.get(),
- std::move(resyncCallback), configChanged);
+ ConnectionHandle handle, ISurfaceComposer::ConfigChanged configChanged) {
+ RETURN_IF_INVALID_HANDLE(handle, nullptr);
+ return createConnectionInternal(mConnections[handle].thread.get(), configChanged);
}
-EventThread* Scheduler::getEventThread(const sp<Scheduler::ConnectionHandle>& handle) {
- RETURN_VALUE_IF_INVALID(nullptr);
- return mConnections[handle->id]->thread.get();
+sp<EventThreadConnection> Scheduler::getEventConnection(ConnectionHandle handle) {
+ RETURN_IF_INVALID_HANDLE(handle, nullptr);
+ return mConnections[handle].connection;
}
-sp<EventThreadConnection> Scheduler::getEventConnection(const sp<ConnectionHandle>& handle) {
- RETURN_VALUE_IF_INVALID(nullptr);
- return mConnections[handle->id]->eventConnection;
+void Scheduler::onHotplugReceived(ConnectionHandle handle, PhysicalDisplayId displayId,
+ bool connected) {
+ RETURN_IF_INVALID_HANDLE(handle);
+ mConnections[handle].thread->onHotplugReceived(displayId, connected);
}
-void Scheduler::hotplugReceived(const sp<Scheduler::ConnectionHandle>& handle,
- PhysicalDisplayId displayId, bool connected) {
- RETURN_IF_INVALID();
- mConnections[handle->id]->thread->onHotplugReceived(displayId, connected);
+void Scheduler::onScreenAcquired(ConnectionHandle handle) {
+ RETURN_IF_INVALID_HANDLE(handle);
+ mConnections[handle].thread->onScreenAcquired();
}
-void Scheduler::onScreenAcquired(const sp<Scheduler::ConnectionHandle>& handle) {
- RETURN_IF_INVALID();
- mConnections[handle->id]->thread->onScreenAcquired();
+void Scheduler::onScreenReleased(ConnectionHandle handle) {
+ RETURN_IF_INVALID_HANDLE(handle);
+ mConnections[handle].thread->onScreenReleased();
}
-void Scheduler::onScreenReleased(const sp<Scheduler::ConnectionHandle>& handle) {
- RETURN_IF_INVALID();
- mConnections[handle->id]->thread->onScreenReleased();
-}
-
-void Scheduler::onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
+void Scheduler::onConfigChanged(ConnectionHandle handle, PhysicalDisplayId displayId,
int32_t configId) {
- RETURN_IF_INVALID();
- mConnections[handle->id]->thread->onConfigChanged(displayId, configId);
+ RETURN_IF_INVALID_HANDLE(handle);
+ mConnections[handle].thread->onConfigChanged(displayId, configId);
}
-void Scheduler::dump(const sp<Scheduler::ConnectionHandle>& handle, std::string& result) const {
- RETURN_IF_INVALID();
- mConnections.at(handle->id)->thread->dump(result);
+void Scheduler::dump(ConnectionHandle handle, std::string& result) const {
+ RETURN_IF_INVALID_HANDLE(handle);
+ mConnections.at(handle).thread->dump(result);
}
-void Scheduler::setPhaseOffset(const sp<Scheduler::ConnectionHandle>& handle, nsecs_t phaseOffset) {
- RETURN_IF_INVALID();
- mConnections[handle->id]->thread->setPhaseOffset(phaseOffset);
+void Scheduler::setPhaseOffset(ConnectionHandle handle, nsecs_t phaseOffset) {
+ RETURN_IF_INVALID_HANDLE(handle);
+ mConnections[handle].thread->setPhaseOffset(phaseOffset);
}
void Scheduler::getDisplayStatInfo(DisplayStatInfo* stats) {
@@ -224,6 +198,37 @@
stats->vsyncPeriod = mPrimaryDispSync->getPeriod();
}
+Scheduler::ConnectionHandle Scheduler::enableVSyncInjection(bool enable) {
+ if (mInjectVSyncs == enable) {
+ return {};
+ }
+
+ ALOGV("%s VSYNC injection", enable ? "Enabling" : "Disabling");
+
+ if (!mInjectorConnectionHandle) {
+ auto vsyncSource = std::make_unique<InjectVSyncSource>();
+ mVSyncInjector = vsyncSource.get();
+
+ auto eventThread =
+ std::make_unique<impl::EventThread>(std::move(vsyncSource),
+ impl::EventThread::InterceptVSyncsCallback());
+
+ mInjectorConnectionHandle = createConnection(std::move(eventThread));
+ }
+
+ mInjectVSyncs = enable;
+ return mInjectorConnectionHandle;
+}
+
+bool Scheduler::injectVSync(nsecs_t when) {
+ if (!mInjectVSyncs || !mVSyncInjector) {
+ return false;
+ }
+
+ mVSyncInjector->onInjectSyncEvent(when);
+ return true;
+}
+
void Scheduler::enableHardwareVsync() {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
@@ -264,31 +269,19 @@
setVsyncPeriod(period);
}
-ResyncCallback Scheduler::makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod) {
- std::weak_ptr<VsyncState> ptr = mPrimaryVsyncState;
- return [ptr, getVsyncPeriod = std::move(getVsyncPeriod)]() {
- if (const auto vsync = ptr.lock()) {
- vsync->resync(getVsyncPeriod);
- }
- };
-}
-
-void Scheduler::VsyncState::resync(const GetVsyncPeriod& getVsyncPeriod) {
+void Scheduler::resync() {
static constexpr nsecs_t kIgnoreDelay = ms2ns(750);
const nsecs_t now = systemTime();
- const nsecs_t last = lastResyncTime.exchange(now);
+ const nsecs_t last = mLastResyncTime.exchange(now);
if (now - last > kIgnoreDelay) {
- scheduler.resyncToHardwareVsync(false, getVsyncPeriod());
+ resyncToHardwareVsync(false,
+ mRefreshRateConfigs.getCurrentRefreshRate().second.vsyncPeriod);
}
}
-void Scheduler::setRefreshSkipCount(int count) {
- mPrimaryDispSync->setRefreshSkipCount(count);
-}
-
-void Scheduler::setVsyncPeriod(const nsecs_t period) {
+void Scheduler::setVsyncPeriod(nsecs_t period) {
std::lock_guard<std::mutex> lock(mHWVsyncLock);
mPrimaryDispSync->setPeriod(period);
@@ -299,7 +292,7 @@
}
}
-void Scheduler::addResyncSample(const nsecs_t timestamp, bool* periodFlushed) {
+void Scheduler::addResyncSample(nsecs_t timestamp, bool* periodFlushed) {
bool needsHwVsync = false;
*periodFlushed = false;
{ // Scope for the lock
@@ -332,21 +325,21 @@
return mPrimaryDispSync->expectedPresentTime();
}
-void Scheduler::dumpPrimaryDispSync(std::string& result) const {
- mPrimaryDispSync->dump(result);
-}
-
std::unique_ptr<scheduler::LayerHistory::LayerHandle> Scheduler::registerLayer(
std::string const& name, int windowType) {
- RefreshRateType refreshRateType = (windowType == InputWindowInfo::TYPE_WALLPAPER)
- ? RefreshRateType::DEFAULT
- : RefreshRateType::PERFORMANCE;
-
- const auto refreshRate = mRefreshRateConfigs.getRefreshRate(refreshRateType);
- const uint32_t performanceFps = (refreshRate) ? refreshRate->fps : 0;
-
- const auto defaultRefreshRate = mRefreshRateConfigs.getRefreshRate(RefreshRateType::DEFAULT);
- const uint32_t defaultFps = (defaultRefreshRate) ? defaultRefreshRate->fps : 0;
+ uint32_t defaultFps, performanceFps;
+ if (mRefreshRateConfigs.refreshRateSwitchingSupported()) {
+ defaultFps = mRefreshRateConfigs.getRefreshRateFromType(RefreshRateType::DEFAULT).fps;
+ performanceFps =
+ mRefreshRateConfigs
+ .getRefreshRateFromType((windowType == InputWindowInfo::TYPE_WALLPAPER)
+ ? RefreshRateType::DEFAULT
+ : RefreshRateType::PERFORMANCE)
+ .fps;
+ } else {
+ defaultFps = mRefreshRateConfigs.getCurrentRefreshRate().second.fps;
+ performanceFps = defaultFps;
+ }
return mLayerHistory.createLayer(name, defaultFps, performanceFps);
}
@@ -361,61 +354,35 @@
mLayerHistory.setVisibility(layerHandle, visible);
}
-void Scheduler::withPrimaryDispSync(std::function<void(DispSync&)> const& fn) {
- fn(*mPrimaryDispSync);
-}
-
void Scheduler::updateFpsBasedOnContent() {
auto [refreshRate, isHDR] = mLayerHistory.getDesiredRefreshRateAndHDR();
const uint32_t refreshRateRound = std::round(refreshRate);
RefreshRateType newRefreshRateType;
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- if (mContentRefreshRate == refreshRateRound && mIsHDRContent == isHDR) {
+ if (mFeatures.contentRefreshRate == refreshRateRound && mFeatures.isHDRContent == isHDR) {
return;
}
- mContentRefreshRate = refreshRateRound;
- ATRACE_INT("ContentFPS", mContentRefreshRate);
+ mFeatures.contentRefreshRate = refreshRateRound;
+ ATRACE_INT("ContentFPS", refreshRateRound);
- mIsHDRContent = isHDR;
- ATRACE_INT("ContentHDR", mIsHDRContent);
+ mFeatures.isHDRContent = isHDR;
+ ATRACE_INT("ContentHDR", isHDR);
- mCurrentContentFeatureState = refreshRateRound > 0
- ? ContentFeatureState::CONTENT_DETECTION_ON
- : ContentFeatureState::CONTENT_DETECTION_OFF;
+ mFeatures.contentDetection =
+ refreshRateRound > 0 ? ContentDetectionState::On : ContentDetectionState::Off;
newRefreshRateType = calculateRefreshRateType();
- if (mRefreshRateType == newRefreshRateType) {
+ if (mFeatures.refreshRateType == newRefreshRateType) {
return;
}
- mRefreshRateType = newRefreshRateType;
+ mFeatures.refreshRateType = newRefreshRateType;
}
changeRefreshRate(newRefreshRateType, ConfigEvent::Changed);
}
-void Scheduler::setChangeRefreshRateCallback(
- const ChangeRefreshRateCallback&& changeRefreshRateCallback) {
+void Scheduler::setChangeRefreshRateCallback(ChangeRefreshRateCallback&& callback) {
std::lock_guard<std::mutex> lock(mCallbackLock);
- mChangeRefreshRateCallback = changeRefreshRateCallback;
-}
-
-void Scheduler::setGetCurrentRefreshRateTypeCallback(
- const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateTypeCallback) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mGetCurrentRefreshRateTypeCallback = getCurrentRefreshRateTypeCallback;
-}
-
-void Scheduler::setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod) {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- mGetVsyncPeriod = getVsyncPeriod;
-}
-
-void Scheduler::updateFrameSkipping(const int64_t skipCount) {
- ATRACE_INT("FrameSkipCount", skipCount);
- if (mSkipCount != skipCount) {
- // Only update DispSync if it hasn't been updated yet.
- mPrimaryDispSync->setRefreshSkipCount(skipCount);
- mSkipCount = skipCount;
- }
+ mChangeRefreshRateCallback = std::move(callback);
}
void Scheduler::resetIdleTimer() {
@@ -429,8 +396,8 @@
mTouchTimer->reset();
}
- if (mSupportKernelTimer) {
- resetIdleTimer();
+ if (mSupportKernelTimer && mIdleTimer) {
+ mIdleTimer->reset();
}
// Touch event will boost the refresh rate to performance.
@@ -441,7 +408,7 @@
void Scheduler::setDisplayPowerState(bool normal) {
{
std::lock_guard<std::mutex> lock(mFeatureStateLock);
- mIsDisplayPowerStateNormal = normal;
+ mFeatures.isDisplayPowerStateNormal = normal;
}
if (mDisplayPowerTimer) {
@@ -453,67 +420,50 @@
mLayerHistory.clearHistory();
}
-void Scheduler::resetTimerCallback() {
- handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::RESET, false);
- ATRACE_INT("ExpiredIdleTimer", 0);
-}
+void Scheduler::kernelIdleTimerCallback(TimerState state) {
+ ATRACE_INT("ExpiredKernelIdleTimer", static_cast<int>(state));
-void Scheduler::resetKernelTimerCallback() {
- ATRACE_INT("ExpiredKernelIdleTimer", 0);
- std::lock_guard<std::mutex> lock(mCallbackLock);
- if (mGetVsyncPeriod && mGetCurrentRefreshRateTypeCallback) {
+ const auto refreshRate = mRefreshRateConfigs.getCurrentRefreshRate();
+ if (state == TimerState::Reset && refreshRate.first == RefreshRateType::PERFORMANCE) {
// If we're not in performance mode then the kernel timer shouldn't do
// anything, as the refresh rate during DPU power collapse will be the
// same.
- if (mGetCurrentRefreshRateTypeCallback() == Scheduler::RefreshRateType::PERFORMANCE) {
- resyncToHardwareVsync(true, mGetVsyncPeriod());
- }
+ resyncToHardwareVsync(true /* makeAvailable */, refreshRate.second.vsyncPeriod);
+ } else if (state == TimerState::Expired && refreshRate.first != RefreshRateType::PERFORMANCE) {
+ // Disable HW VSYNC if the timer expired, as we don't need it enabled if
+ // we're not pushing frames, and if we're in PERFORMANCE mode then we'll
+ // need to update the DispSync model anyway.
+ disableHardwareVsync(false /* makeUnavailable */);
}
}
-void Scheduler::expiredTimerCallback() {
- handleTimerStateChanged(&mCurrentIdleTimerState, IdleTimerState::EXPIRED, false);
- ATRACE_INT("ExpiredIdleTimer", 1);
+void Scheduler::idleTimerCallback(TimerState state) {
+ handleTimerStateChanged(&mFeatures.idleTimer, state, false /* eventOnContentDetection */);
+ ATRACE_INT("ExpiredIdleTimer", static_cast<int>(state));
}
-void Scheduler::resetTouchTimerCallback() {
- handleTimerStateChanged(&mCurrentTouchState, TouchState::ACTIVE, true);
- ATRACE_INT("TouchState", 1);
+void Scheduler::touchTimerCallback(TimerState state) {
+ const TouchState touch = state == TimerState::Reset ? TouchState::Active : TouchState::Inactive;
+ handleTimerStateChanged(&mFeatures.touch, touch, true /* eventOnContentDetection */);
+ ATRACE_INT("TouchState", static_cast<int>(touch));
}
-void Scheduler::expiredTouchTimerCallback() {
- handleTimerStateChanged(&mCurrentTouchState, TouchState::INACTIVE, true);
- ATRACE_INT("TouchState", 0);
+void Scheduler::displayPowerTimerCallback(TimerState state) {
+ handleTimerStateChanged(&mFeatures.displayPowerTimer, state,
+ true /* eventOnContentDetection */);
+ ATRACE_INT("ExpiredDisplayPowerTimer", static_cast<int>(state));
}
-void Scheduler::resetDisplayPowerTimerCallback() {
- handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::RESET, true);
- ATRACE_INT("ExpiredDisplayPowerTimer", 0);
-}
-
-void Scheduler::expiredDisplayPowerTimerCallback() {
- handleTimerStateChanged(&mDisplayPowerTimerState, DisplayPowerTimerState::EXPIRED, true);
- ATRACE_INT("ExpiredDisplayPowerTimer", 1);
-}
-
-void Scheduler::expiredKernelTimerCallback() {
- std::lock_guard<std::mutex> lock(mCallbackLock);
- ATRACE_INT("ExpiredKernelIdleTimer", 1);
- if (mGetCurrentRefreshRateTypeCallback) {
- if (mGetCurrentRefreshRateTypeCallback() != Scheduler::RefreshRateType::PERFORMANCE) {
- // Disable HW Vsync if the timer expired, as we don't need it
- // enabled if we're not pushing frames, and if we're in PERFORMANCE
- // mode then we'll need to re-update the DispSync model anyways.
- disableHardwareVsync(false);
- }
- }
-}
-
-std::string Scheduler::doDump() {
+void Scheduler::dump(std::string& result) const {
std::ostringstream stream;
- stream << "+ Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
- stream << "+ Touch timer interval: " << mSetTouchTimerMs << " ms" << std::endl;
- return stream.str();
+ if (mIdleTimer) {
+ stream << "+ Idle timer interval: " << mIdleTimer->interval().count() << " ms\n";
+ }
+ if (mTouchTimer) {
+ stream << "+ Touch timer interval: " << mTouchTimer->interval().count() << " ms\n";
+ }
+
+ result.append(stream.str());
}
template <class T>
@@ -527,12 +477,11 @@
}
*currentState = newState;
newRefreshRateType = calculateRefreshRateType();
- if (mRefreshRateType == newRefreshRateType) {
+ if (mFeatures.refreshRateType == newRefreshRateType) {
return;
}
- mRefreshRateType = newRefreshRateType;
- if (eventOnContentDetection &&
- mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_ON) {
+ mFeatures.refreshRateType = newRefreshRateType;
+ if (eventOnContentDetection && mFeatures.contentDetection == ContentDetectionState::On) {
event = ConfigEvent::Changed;
}
}
@@ -540,43 +489,44 @@
}
Scheduler::RefreshRateType Scheduler::calculateRefreshRateType() {
+ if (!mRefreshRateConfigs.refreshRateSwitchingSupported()) {
+ return RefreshRateType::DEFAULT;
+ }
+
// HDR content is not supported on PERFORMANCE mode
- if (mForceHDRContentToDefaultRefreshRate && mIsHDRContent) {
+ if (mForceHDRContentToDefaultRefreshRate && mFeatures.isHDRContent) {
return RefreshRateType::DEFAULT;
}
// If Display Power is not in normal operation we want to be in performance mode.
// When coming back to normal mode, a grace period is given with DisplayPowerTimer
- if (!mIsDisplayPowerStateNormal || mDisplayPowerTimerState == DisplayPowerTimerState::RESET) {
+ if (!mFeatures.isDisplayPowerStateNormal || mFeatures.displayPowerTimer == TimerState::Reset) {
return RefreshRateType::PERFORMANCE;
}
// As long as touch is active we want to be in performance mode
- if (mCurrentTouchState == TouchState::ACTIVE) {
+ if (mFeatures.touch == TouchState::Active) {
return RefreshRateType::PERFORMANCE;
}
// If timer has expired as it means there is no new content on the screen
- if (mCurrentIdleTimerState == IdleTimerState::EXPIRED) {
+ if (mFeatures.idleTimer == TimerState::Expired) {
return RefreshRateType::DEFAULT;
}
// If content detection is off we choose performance as we don't know the content fps
- if (mCurrentContentFeatureState == ContentFeatureState::CONTENT_DETECTION_OFF) {
+ if (mFeatures.contentDetection == ContentDetectionState::Off) {
return RefreshRateType::PERFORMANCE;
}
// Content detection is on, find the appropriate refresh rate with minimal error
- auto begin = mRefreshRateConfigs.getRefreshRates().cbegin();
-
- // Skip POWER_SAVING config as it is not a real config
- if (begin->first == RefreshRateType::POWER_SAVING) {
- ++begin;
- }
- auto iter = min_element(begin, mRefreshRateConfigs.getRefreshRates().cend(),
- [rate = mContentRefreshRate](const auto& l, const auto& r) -> bool {
- return std::abs(l.second->fps - static_cast<float>(rate)) <
- std::abs(r.second->fps - static_cast<float>(rate));
+ // TODO(b/139751853): Scan allowed refresh rates only (SurfaceFlinger::mAllowedDisplayConfigs)
+ const float rate = static_cast<float>(mFeatures.contentRefreshRate);
+ auto iter = min_element(mRefreshRateConfigs.getRefreshRateMap().cbegin(),
+ mRefreshRateConfigs.getRefreshRateMap().cend(),
+ [rate](const auto& lhs, const auto& rhs) -> bool {
+ return std::abs(lhs.second.fps - rate) <
+ std::abs(rhs.second.fps - rate);
});
RefreshRateType currRefreshRateType = iter->first;
@@ -584,11 +534,10 @@
// 90Hz config. However we should still prefer a lower refresh rate if the content doesn't
// align well with both
constexpr float MARGIN = 0.05f;
- float ratio = mRefreshRateConfigs.getRefreshRate(currRefreshRateType)->fps /
- float(mContentRefreshRate);
+ float ratio = mRefreshRateConfigs.getRefreshRateFromType(currRefreshRateType).fps / rate;
if (std::abs(std::round(ratio) - ratio) > MARGIN) {
- while (iter != mRefreshRateConfigs.getRefreshRates().cend()) {
- ratio = iter->second->fps / float(mContentRefreshRate);
+ while (iter != mRefreshRateConfigs.getRefreshRateMap().cend()) {
+ ratio = iter->second.fps / rate;
if (std::abs(std::round(ratio) - ratio) <= MARGIN) {
currRefreshRateType = iter->first;
@@ -601,6 +550,11 @@
return currRefreshRateType;
}
+Scheduler::RefreshRateType Scheduler::getPreferredRefreshRateType() {
+ std::lock_guard<std::mutex> lock(mFeatureStateLock);
+ return mFeatures.refreshRateType;
+}
+
void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
std::lock_guard<std::mutex> lock(mCallbackLock);
if (mChangeRefreshRateCallback) {
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 5d8bb4c..a5971fe 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -16,140 +16,88 @@
#pragma once
-#include <cstdint>
+#include <atomic>
#include <functional>
#include <memory>
+#include <mutex>
+#include <optional>
+#include <unordered_map>
-#include <ui/DisplayStatInfo.h>
#include <ui/GraphicTypes.h>
-#include "DispSync.h"
#include "EventControlThread.h"
#include "EventThread.h"
-#include "IdleTimer.h"
-#include "InjectVSyncSource.h"
#include "LayerHistory.h"
+#include "OneShotTimer.h"
#include "RefreshRateConfigs.h"
#include "SchedulerUtils.h"
namespace android {
-class EventControlThread;
+class DispSync;
+class FenceTime;
+class InjectVSyncSource;
+struct DisplayStateInfo;
class Scheduler {
public:
- // Enum to keep track of whether we trigger event to notify choreographer of config changes.
- enum class ConfigEvent { None, Changed };
-
- // logical or operator with the semantics of at least one of the events is Changed
- friend ConfigEvent operator|(const ConfigEvent& first, const ConfigEvent& second) {
- if (first == ConfigEvent::Changed) return ConfigEvent::Changed;
- if (second == ConfigEvent::Changed) return ConfigEvent::Changed;
- return ConfigEvent::None;
- }
-
using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
- using GetCurrentRefreshRateTypeCallback = std::function<RefreshRateType()>;
- using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
- using GetVsyncPeriod = std::function<nsecs_t()>;
+ using ConfigEvent = scheduler::RefreshRateConfigEvent;
- // Enum to indicate whether to start the transaction early, or at vsync time.
+ using ChangeRefreshRateCallback = std::function<void(RefreshRateType, ConfigEvent)>;
+
+ // Indicates whether to start the transaction early, or at vsync time.
enum class TransactionStart { EARLY, NORMAL };
- /* The scheduler handle is a BBinder object passed to the client from which we can extract
- * an ID for subsequent operations.
- */
- class ConnectionHandle : public BBinder {
- public:
- ConnectionHandle(int64_t id) : id(id) {}
-
- ~ConnectionHandle() = default;
-
- const int64_t id;
- };
-
- class Connection {
- public:
- Connection(sp<ConnectionHandle> handle, sp<EventThreadConnection> eventConnection,
- std::unique_ptr<EventThread> eventThread)
- : handle(handle), eventConnection(eventConnection), thread(std::move(eventThread)) {}
-
- ~Connection() = default;
-
- sp<ConnectionHandle> handle;
- sp<EventThreadConnection> eventConnection;
- const std::unique_ptr<EventThread> thread;
- };
-
- // Stores per-display state about VSYNC.
- struct VsyncState {
- explicit VsyncState(Scheduler& scheduler) : scheduler(scheduler) {}
-
- void resync(const GetVsyncPeriod&);
-
- Scheduler& scheduler;
- std::atomic<nsecs_t> lastResyncTime = 0;
- };
-
- explicit Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
- const scheduler::RefreshRateConfigs& refreshRateConfig);
+ Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
+ const scheduler::RefreshRateConfigs&);
virtual ~Scheduler();
- /** Creates an EventThread connection. */
- sp<ConnectionHandle> createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
- nsecs_t offsetThresholdForNextVsync, ResyncCallback,
- impl::EventThread::InterceptVSyncsCallback);
+ DispSync& getPrimaryDispSync();
- sp<IDisplayEventConnection> createDisplayEventConnection(
- const sp<ConnectionHandle>& handle, ResyncCallback,
- ISurfaceComposer::ConfigChanged configChanged);
+ using ConnectionHandle = scheduler::ConnectionHandle;
+ ConnectionHandle createConnection(const char* connectionName, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync,
+ impl::EventThread::InterceptVSyncsCallback);
- // Getter methods.
- EventThread* getEventThread(const sp<ConnectionHandle>& handle);
+ sp<IDisplayEventConnection> createDisplayEventConnection(ConnectionHandle,
+ ISurfaceComposer::ConfigChanged);
- // Provides access to the DispSync object for the primary display.
- void withPrimaryDispSync(std::function<void(DispSync&)> const& fn);
+ sp<EventThreadConnection> getEventConnection(ConnectionHandle);
- sp<EventThreadConnection> getEventConnection(const sp<ConnectionHandle>& handle);
+ void onHotplugReceived(ConnectionHandle, PhysicalDisplayId, bool connected);
+ void onConfigChanged(ConnectionHandle, PhysicalDisplayId, int32_t configId);
- // Should be called when receiving a hotplug event.
- void hotplugReceived(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
- bool connected);
+ void onScreenAcquired(ConnectionHandle);
+ void onScreenReleased(ConnectionHandle);
- // Should be called after the screen is turned on.
- void onScreenAcquired(const sp<ConnectionHandle>& handle);
-
- // Should be called before the screen is turned off.
- void onScreenReleased(const sp<ConnectionHandle>& handle);
-
- // Should be called when display config changed
- void onConfigChanged(const sp<ConnectionHandle>& handle, PhysicalDisplayId displayId,
- int32_t configId);
-
- // Should be called when dumpsys command is received.
- void dump(const sp<ConnectionHandle>& handle, std::string& result) const;
-
- // Offers ability to modify phase offset in the event thread.
- void setPhaseOffset(const sp<ConnectionHandle>& handle, nsecs_t phaseOffset);
+ // Modifies phase offset in the event thread.
+ void setPhaseOffset(ConnectionHandle, nsecs_t phaseOffset);
void getDisplayStatInfo(DisplayStatInfo* stats);
+ // Returns injector handle if injection has toggled, or an invalid handle otherwise.
+ ConnectionHandle enableVSyncInjection(bool enable);
+
+ // Returns false if injection is disabled.
+ bool injectVSync(nsecs_t when);
+
void enableHardwareVsync();
void disableHardwareVsync(bool makeUnavailable);
+
// Resyncs the scheduler to hardware vsync.
// If makeAvailable is true, then hardware vsync will be turned on.
// Otherwise, if hardware vsync is not already enabled then this method will
// no-op.
// The period is the vsync period from the current display configuration.
void resyncToHardwareVsync(bool makeAvailable, nsecs_t period);
- // Creates a callback for resyncing.
- ResyncCallback makeResyncCallback(GetVsyncPeriod&& getVsyncPeriod);
- void setRefreshSkipCount(int count);
+ void resync();
+
// Passes a vsync sample to DispSync. periodFlushed will be true if
// DispSync detected that the vsync period changed, and false otherwise.
- void addResyncSample(const nsecs_t timestamp, bool* periodFlushed);
- void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
+ void addResyncSample(nsecs_t timestamp, bool* periodFlushed);
+ void addPresentFence(const std::shared_ptr<FenceTime>&);
void setIgnorePresentFences(bool ignore);
nsecs_t getDispSyncExpectedPresentTime();
// Registers the layer in the scheduler, and returns the handle for future references.
@@ -165,155 +113,115 @@
const std::unique_ptr<scheduler::LayerHistory::LayerHandle>& layerHandle, bool visible);
// Updates FPS based on the most content presented.
void updateFpsBasedOnContent();
- // Callback that gets invoked when Scheduler wants to change the refresh rate.
- void setChangeRefreshRateCallback(const ChangeRefreshRateCallback&& changeRefreshRateCallback);
- void setGetCurrentRefreshRateTypeCallback(
- const GetCurrentRefreshRateTypeCallback&& getCurrentRefreshRateType);
- void setGetVsyncPeriodCallback(const GetVsyncPeriod&& getVsyncPeriod);
- // Returns whether idle timer is enabled or not
- bool isIdleTimerEnabled() { return mSetIdleTimerMs > 0; }
+ // Called by Scheduler to change refresh rate.
+ void setChangeRefreshRateCallback(ChangeRefreshRateCallback&&);
- // Function that resets the idle timer.
+ bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
void resetIdleTimer();
// Function that resets the touch timer.
void notifyTouchEvent();
- // Function that sets whether display power mode is normal or not.
void setDisplayPowerState(bool normal);
- // Returns relevant information about Scheduler for dumpsys purposes.
- std::string doDump();
+ void dump(std::string&) const;
+ void dump(ConnectionHandle, std::string&) const;
- // calls DispSync::dump() on primary disp sync
- void dumpPrimaryDispSync(std::string& result) const;
-
-protected:
- virtual std::unique_ptr<EventThread> makeEventThread(
- const char* connectionName, DispSync* dispSync, nsecs_t phaseOffsetNs,
- nsecs_t offsetThresholdForNextVsync,
- impl::EventThread::InterceptVSyncsCallback interceptCallback);
+ // Get the appropriate refresh type for current conditions.
+ RefreshRateType getPreferredRefreshRateType();
private:
friend class TestableScheduler;
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
- enum class ContentFeatureState { CONTENT_DETECTION_ON, CONTENT_DETECTION_OFF };
- enum class IdleTimerState { EXPIRED, RESET };
- enum class TouchState { INACTIVE, ACTIVE };
- enum class DisplayPowerTimerState { EXPIRED, RESET };
+ enum class ContentDetectionState { Off, On };
+ enum class TimerState { Reset, Expired };
+ enum class TouchState { Inactive, Active };
- // Creates a connection on the given EventThread and forwards the given callbacks.
- sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&,
+ // Used by tests to inject mocks.
+ Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
+ const scheduler::RefreshRateConfigs&);
+
+ std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs,
+ nsecs_t offsetThresholdForNextVsync);
+
+ // Create a connection on the given EventThread.
+ ConnectionHandle createConnection(std::unique_ptr<EventThread>);
+ sp<EventThreadConnection> createConnectionInternal(EventThread*,
ISurfaceComposer::ConfigChanged);
- nsecs_t calculateAverage() const;
- void updateFrameSkipping(const int64_t skipCount);
+ // Update feature state machine to given state when corresponding timer resets or expires.
+ void kernelIdleTimerCallback(TimerState);
+ void idleTimerCallback(TimerState);
+ void touchTimerCallback(TimerState);
+ void displayPowerTimerCallback(TimerState);
- // Function that is called when the timer resets.
- void resetTimerCallback();
- // Function that is called when the timer expires.
- void expiredTimerCallback();
- // Function that is called when the timer resets when paired with a display
- // driver timeout in the kernel. This enables hardware vsync when we move
- // out from idle.
- void resetKernelTimerCallback();
- // Function that is called when the timer expires when paired with a display
- // driver timeout in the kernel. This disables hardware vsync when we move
- // into idle.
- void expiredKernelTimerCallback();
- // Function that is called when the touch timer resets.
- void resetTouchTimerCallback();
- // Function that is called when the touch timer expires.
- void expiredTouchTimerCallback();
- // Function that is called when the display power timer resets.
- void resetDisplayPowerTimerCallback();
- // Function that is called when the display power timer expires.
- void expiredDisplayPowerTimerCallback();
- // Sets vsync period.
- void setVsyncPeriod(const nsecs_t period);
// handles various timer features to change the refresh rate.
template <class T>
void handleTimerStateChanged(T* currentState, T newState, bool eventOnContentDetection);
- // Calculate the new refresh rate type
+
+ void setVsyncPeriod(nsecs_t period);
+
RefreshRateType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
- // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
- void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);
+ // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters.
+ void changeRefreshRate(RefreshRateType, ConfigEvent);
- // Helper function to calculate error frames
- float getErrorFrames(float contentFps, float configFps);
+ // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
+ struct Connection {
+ sp<EventThreadConnection> connection;
+ std::unique_ptr<EventThread> thread;
+ };
- // If fences from sync Framework are supported.
- const bool mHasSyncFramework;
+ ConnectionHandle::Id mNextConnectionHandleId = 0;
+ std::unordered_map<ConnectionHandle, Connection> mConnections;
- // The offset in nanoseconds to use, when DispSync timestamps present fence
- // signaling time.
- nsecs_t mDispSyncPresentTimeOffset;
-
- // Each connection has it's own ID. This variable keeps track of the count.
- static std::atomic<int64_t> sNextId;
-
- // Connections are stored in a map <connection ID, connection> for easy retrieval.
- std::unordered_map<int64_t, std::unique_ptr<Connection>> mConnections;
+ bool mInjectVSyncs = false;
+ InjectVSyncSource* mVSyncInjector = nullptr;
+ ConnectionHandle mInjectorConnectionHandle;
std::mutex mHWVsyncLock;
- bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock);
- bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock);
- const std::shared_ptr<VsyncState> mPrimaryVsyncState{std::make_shared<VsyncState>(*this)};
+ bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
+ bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;
+
+ std::atomic<nsecs_t> mLastResyncTime = 0;
std::unique_ptr<DispSync> mPrimaryDispSync;
std::unique_ptr<EventControlThread> mEventControlThread;
- // TODO(b/113612090): The following set of variables needs to be revised. For now, this is
- // a proof of concept. We turn on frame skipping if the difference between the timestamps
- // is between 32 and 34ms. We expect this currently for 30fps videos, so we render them at 30Hz.
- nsecs_t mPreviousFrameTimestamp = 0;
- // Keeping track of whether we are skipping the refresh count. If we want to
- // simulate 30Hz rendering, we skip every other frame, and this variable is set
- // to 1.
- int64_t mSkipCount = 0;
- std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
- size_t mCounter = 0;
-
// Historical information about individual layers. Used for predicting the refresh rate.
scheduler::LayerHistory mLayerHistory;
- // Timer that records time between requests for next vsync. If the time is higher than a given
- // interval, a callback is fired. Set this variable to >0 to use this feature.
- int64_t mSetIdleTimerMs = 0;
- std::unique_ptr<scheduler::IdleTimer> mIdleTimer;
- // Enables whether to use idle timer callbacks that support the kernel
- // timer.
- bool mSupportKernelTimer;
+ // Whether to use idle timer callbacks that support the kernel timer.
+ const bool mSupportKernelTimer;
+ // Timer that records time between requests for next vsync.
+ std::optional<scheduler::OneShotTimer> mIdleTimer;
// Timer used to monitor touch events.
- int64_t mSetTouchTimerMs = 0;
- std::unique_ptr<scheduler::IdleTimer> mTouchTimer;
-
+ std::optional<scheduler::OneShotTimer> mTouchTimer;
// Timer used to monitor display power mode.
- int64_t mSetDisplayPowerTimerMs = 0;
- std::unique_ptr<scheduler::IdleTimer> mDisplayPowerTimer;
+ std::optional<scheduler::OneShotTimer> mDisplayPowerTimer;
std::mutex mCallbackLock;
- GetCurrentRefreshRateTypeCallback mGetCurrentRefreshRateTypeCallback GUARDED_BY(mCallbackLock);
ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);
- GetVsyncPeriod mGetVsyncPeriod GUARDED_BY(mCallbackLock);
// In order to make sure that the features don't override themselves, we need a state machine
// to keep track which feature requested the config change.
std::mutex mFeatureStateLock;
- ContentFeatureState mCurrentContentFeatureState GUARDED_BY(mFeatureStateLock) =
- ContentFeatureState::CONTENT_DETECTION_OFF;
- IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
- TouchState mCurrentTouchState GUARDED_BY(mFeatureStateLock) = TouchState::INACTIVE;
- DisplayPowerTimerState mDisplayPowerTimerState GUARDED_BY(mFeatureStateLock) =
- DisplayPowerTimerState::EXPIRED;
- uint32_t mContentRefreshRate GUARDED_BY(mFeatureStateLock);
- RefreshRateType mRefreshRateType GUARDED_BY(mFeatureStateLock);
- bool mIsHDRContent GUARDED_BY(mFeatureStateLock) = false;
- bool mIsDisplayPowerStateNormal GUARDED_BY(mFeatureStateLock) = true;
+
+ struct {
+ ContentDetectionState contentDetection = ContentDetectionState::Off;
+ TimerState idleTimer = TimerState::Reset;
+ TouchState touch = TouchState::Inactive;
+ TimerState displayPowerTimer = TimerState::Expired;
+
+ RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
+ uint32_t contentRefreshRate = 0;
+
+ bool isHDRContent = false;
+ bool isDisplayPowerStateNormal = true;
+ } mFeatures GUARDED_BY(mFeatureStateLock);
const scheduler::RefreshRateConfigs& mRefreshRateConfigs;
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index ac10f83..3b7567c 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -22,20 +22,24 @@
#include <unordered_map>
#include <vector>
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
+
+// Opaque handle to scheduler connection.
+struct ConnectionHandle {
+ using Id = std::uintptr_t;
+ static constexpr Id INVALID_ID = static_cast<Id>(-1);
+
+ Id id = INVALID_ID;
+
+ explicit operator bool() const { return id != INVALID_ID; }
+};
+
+inline bool operator==(ConnectionHandle lhs, ConnectionHandle rhs) {
+ return lhs.id == rhs.id;
+}
+
using namespace std::chrono_literals;
-// This number is used to set the size of the arrays in scheduler that hold information
-// about layers.
-static constexpr size_t ARRAY_SIZE = 30;
-
-// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently
-// the config is not visible to SF, and is completely maintained by HWC. However, we would
-// still like to keep track of time when the device is in this config.
-static constexpr int SCREEN_OFF_CONFIG_ID = -1;
-static constexpr uint32_t HWC2_SCREEN_OFF_CONFIG_ID = 0xffffffff;
-
// This number is used when we try to determine how long do we keep layer information around
// before we remove it. It is also used to determine how long the layer stays relevant.
// This time period captures infrequent updates when playing YouTube video with static image,
@@ -82,5 +86,15 @@
return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first);
}
-} // namespace scheduler
-} // namespace android
\ No newline at end of file
+} // namespace android::scheduler
+
+namespace std {
+
+template <>
+struct hash<android::scheduler::ConnectionHandle> {
+ size_t operator()(android::scheduler::ConnectionHandle handle) const {
+ return hash<android::scheduler::ConnectionHandle::Id>()(handle.id);
+ }
+};
+
+} // namespace std
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.cpp b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
index 7a3bf8e..27fd76c 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.cpp
@@ -24,25 +24,24 @@
#include <cinttypes>
#include <mutex>
-namespace android {
+namespace android::scheduler {
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-VSyncModulator::VSyncModulator() {
+VSyncModulator::VSyncModulator(Scheduler& scheduler,
+ Scheduler::ConnectionHandle appConnectionHandle,
+ Scheduler::ConnectionHandle sfConnectionHandle,
+ const OffsetsConfig& config)
+ : mScheduler(scheduler),
+ mAppConnectionHandle(appConnectionHandle),
+ mSfConnectionHandle(sfConnectionHandle),
+ mOffsetsConfig(config) {
char value[PROPERTY_VALUE_MAX];
property_get("debug.sf.vsync_trace_detailed_info", value, "0");
mTraceDetailedInfo = atoi(value);
- // Populate the offset map with some default offsets.
- const Offsets defaultOffsets = {RefreshRateType::DEFAULT, 0, 0};
- setPhaseOffsets(defaultOffsets, defaultOffsets, defaultOffsets, 0);
}
-void VSyncModulator::setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
- nsecs_t thresholdForNextVsync) {
+void VSyncModulator::setPhaseOffsets(const OffsetsConfig& config) {
std::lock_guard<std::mutex> lock(mMutex);
- mOffsetMap.insert_or_assign(OffsetType::Early, early);
- mOffsetMap.insert_or_assign(OffsetType::EarlyGl, earlyGl);
- mOffsetMap.insert_or_assign(OffsetType::Late, late);
- mThresholdForNextVsync = thresholdForNextVsync;
+ mOffsetsConfig = config;
updateOffsetsLocked();
}
@@ -100,25 +99,21 @@
}
}
-VSyncModulator::Offsets VSyncModulator::getOffsets() {
+VSyncModulator::Offsets VSyncModulator::getOffsets() const {
std::lock_guard<std::mutex> lock(mMutex);
return mOffsets;
}
-VSyncModulator::Offsets VSyncModulator::getNextOffsets() {
- return mOffsetMap.at(getNextOffsetType());
-}
-
-VSyncModulator::OffsetType VSyncModulator::getNextOffsetType() {
+const VSyncModulator::Offsets& VSyncModulator::getNextOffsets() const {
// Early offsets are used if we're in the middle of a refresh rate
// change, or if we recently begin a transaction.
if (mTransactionStart == Scheduler::TransactionStart::EARLY || mRemainingEarlyFrameCount > 0 ||
mRefreshRateChangePending) {
- return OffsetType::Early;
+ return mOffsetsConfig.early;
} else if (mRemainingRenderEngineUsageCount > 0) {
- return OffsetType::EarlyGl;
+ return mOffsetsConfig.earlyGl;
} else {
- return OffsetType::Late;
+ return mOffsetsConfig.late;
}
}
@@ -128,37 +123,29 @@
}
void VSyncModulator::updateOffsetsLocked() {
- const Offsets desired = getNextOffsets();
+ const Offsets& offsets = getNextOffsets();
- if (mSfConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mSfConnectionHandle, desired.sf);
- }
+ mScheduler.setPhaseOffset(mSfConnectionHandle, offsets.sf);
+ mScheduler.setPhaseOffset(mAppConnectionHandle, offsets.app);
- if (mAppConnectionHandle != nullptr) {
- mScheduler->setPhaseOffset(mAppConnectionHandle, desired.app);
- }
+ mOffsets = offsets;
- flushOffsets();
-}
-
-void VSyncModulator::flushOffsets() {
- OffsetType type = getNextOffsetType();
- mOffsets = mOffsetMap.at(type);
if (!mTraceDetailedInfo) {
return;
}
- ATRACE_INT("Vsync-EarlyOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Early);
- ATRACE_INT("Vsync-EarlyGLOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::EarlyGl);
- ATRACE_INT("Vsync-LateOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::DEFAULT && type == OffsetType::Late);
- ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Early);
- ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::EarlyGl);
- ATRACE_INT("Vsync-HighFpsLateOffsetsOn",
- mOffsets.fpsMode == RefreshRateType::PERFORMANCE && type == OffsetType::Late);
+
+ const bool isDefault = mOffsets.fpsMode == RefreshRateType::DEFAULT;
+ const bool isPerformance = mOffsets.fpsMode == RefreshRateType::PERFORMANCE;
+ const bool isEarly = &offsets == &mOffsetsConfig.early;
+ const bool isEarlyGl = &offsets == &mOffsetsConfig.earlyGl;
+ const bool isLate = &offsets == &mOffsetsConfig.late;
+
+ ATRACE_INT("Vsync-EarlyOffsetsOn", isDefault && isEarly);
+ ATRACE_INT("Vsync-EarlyGLOffsetsOn", isDefault && isEarlyGl);
+ ATRACE_INT("Vsync-LateOffsetsOn", isDefault && isLate);
+ ATRACE_INT("Vsync-HighFpsEarlyOffsetsOn", isPerformance && isEarly);
+ ATRACE_INT("Vsync-HighFpsEarlyGLOffsetsOn", isPerformance && isEarlyGl);
+ ATRACE_INT("Vsync-HighFpsLateOffsetsOn", isPerformance && isLate);
}
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncModulator.h b/services/surfaceflinger/Scheduler/VSyncModulator.h
index ddbd221..727cef2 100644
--- a/services/surfaceflinger/Scheduler/VSyncModulator.h
+++ b/services/surfaceflinger/Scheduler/VSyncModulator.h
@@ -16,12 +16,11 @@
#pragma once
-#include <cinttypes>
#include <mutex>
#include "Scheduler.h"
-namespace android {
+namespace android::scheduler {
/*
* Modulates the vsync-offsets depending on current SurfaceFlinger state.
@@ -31,51 +30,36 @@
// Number of frames we'll keep the early phase offsets once they are activated for a
// transaction. This acts as a low-pass filter in case the client isn't quick enough in
// sending new transactions.
- const int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
+ static constexpr int MIN_EARLY_FRAME_COUNT_TRANSACTION = 2;
// Number of frames we'll keep the early gl phase offsets once they are activated.
// This acts as a low-pass filter to avoid scenarios where we rapidly
// switch in and out of gl composition.
- const int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+ static constexpr int MIN_EARLY_GL_FRAME_COUNT_TRANSACTION = 2;
+
+ using RefreshRateType = RefreshRateConfigs::RefreshRateType;
public:
- VSyncModulator();
-
// Wrapper for a collection of surfaceflinger/app offsets for a particular
- // configuration .
+ // configuration.
struct Offsets {
- scheduler::RefreshRateConfigs::RefreshRateType fpsMode;
+ RefreshRateType fpsMode;
nsecs_t sf;
nsecs_t app;
};
- enum class OffsetType {
- Early,
- EarlyGl,
- Late,
+ struct OffsetsConfig {
+ Offsets early; // For transactions with the eEarlyWakeup flag.
+ Offsets earlyGl; // As above but while compositing with GL.
+ Offsets late; // Default.
+
+ nsecs_t thresholdForNextVsync;
};
- // Sets the phase offsets
- //
- // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
- // as early. May be the same as late, in which case we don't shift offsets.
- // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
- // and the transaction was marked as early, we'll use sfEarly.
- // sfLate: The regular SF vsync phase offset.
- // appEarly: Like sfEarly, but for the app-vsync
- // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
- // appLate: The regular app vsync phase offset.
- void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late,
- nsecs_t thresholdForNextVsync) EXCLUDES(mMutex);
+ VSyncModulator(Scheduler&, ConnectionHandle appConnectionHandle,
+ ConnectionHandle sfConnectionHandle, const OffsetsConfig&);
- // Sets the scheduler and vsync connection handlers.
- void setSchedulerAndHandles(Scheduler* scheduler,
- Scheduler::ConnectionHandle* appConnectionHandle,
- Scheduler::ConnectionHandle* sfConnectionHandle) {
- mScheduler = scheduler;
- mAppConnectionHandle = appConnectionHandle;
- mSfConnectionHandle = sfConnectionHandle;
- }
+ void setPhaseOffsets(const OffsetsConfig&) EXCLUDES(mMutex);
// Signals that a transaction has started, and changes offsets accordingly.
void setTransactionStart(Scheduler::TransactionStart transactionStart);
@@ -98,28 +82,23 @@
void onRefreshed(bool usedRenderEngine);
// Returns the offsets that we are currently using
- Offsets getOffsets() EXCLUDES(mMutex);
+ Offsets getOffsets() const EXCLUDES(mMutex);
private:
// Returns the next offsets that we should be using
- Offsets getNextOffsets() REQUIRES(mMutex);
- // Returns the next offset type that we should use.
- OffsetType getNextOffsetType();
+ const Offsets& getNextOffsets() const REQUIRES(mMutex);
// Updates offsets and persists them into the scheduler framework.
void updateOffsets() EXCLUDES(mMutex);
void updateOffsetsLocked() REQUIRES(mMutex);
- // Updates the internal offsets and offset type.
- void flushOffsets() REQUIRES(mMutex);
+
+ Scheduler& mScheduler;
+ const ConnectionHandle mAppConnectionHandle;
+ const ConnectionHandle mSfConnectionHandle;
mutable std::mutex mMutex;
- std::unordered_map<OffsetType, Offsets> mOffsetMap GUARDED_BY(mMutex);
- nsecs_t mThresholdForNextVsync;
+ OffsetsConfig mOffsetsConfig GUARDED_BY(mMutex);
- Scheduler* mScheduler = nullptr;
- Scheduler::ConnectionHandle* mAppConnectionHandle = nullptr;
- Scheduler::ConnectionHandle* mSfConnectionHandle = nullptr;
-
- Offsets mOffsets GUARDED_BY(mMutex) = {Scheduler::RefreshRateType::DEFAULT, 0, 0};
+ Offsets mOffsets GUARDED_BY(mMutex){mOffsetsConfig.late};
std::atomic<Scheduler::TransactionStart> mTransactionStart =
Scheduler::TransactionStart::NORMAL;
@@ -130,4 +109,4 @@
bool mTraceDetailedInfo = false;
};
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 200da2e..b9e95a6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -38,14 +38,12 @@
#include <binder/PermissionCache.h>
#include <compositionengine/CompositionEngine.h>
+#include <compositionengine/CompositionRefreshArgs.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
-#include <compositionengine/Layer.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/RenderSurface.h>
-#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputCompositionState.h>
-#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <dvr/vr_flinger.h>
#include <gui/BufferQueue.h>
#include <gui/DebugEGLImageTracker.h>
@@ -97,12 +95,12 @@
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h"
+#include "FrameTracer/FrameTracer.h"
#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
-#include "Scheduler/InjectVSyncSource.h"
#include "Scheduler/MessageQueue.h"
#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/Scheduler.h"
@@ -110,6 +108,7 @@
#include <cutils/compiler.h>
+#include "android-base/parseint.h"
#include "android-base/stringprintf.h"
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
@@ -162,28 +161,6 @@
return false;
}
-bool isHdrColorMode(const ColorMode colorMode) {
- switch (colorMode) {
- case ColorMode::BT2100_PQ:
- case ColorMode::BT2100_HLG:
- return true;
- case ColorMode::DISPLAY_P3:
- case ColorMode::ADOBE_RGB:
- case ColorMode::DCI_P3:
- case ColorMode::BT2020:
- case ColorMode::DISPLAY_BT2020:
- case ColorMode::NATIVE:
- case ColorMode::STANDARD_BT601_625:
- case ColorMode::STANDARD_BT601_625_UNADJUSTED:
- case ColorMode::STANDARD_BT601_525:
- case ColorMode::STANDARD_BT601_525_UNADJUSTED:
- case ColorMode::STANDARD_BT709:
- case ColorMode::SRGB:
- return false;
- }
- return false;
-}
-
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
@@ -260,11 +237,11 @@
std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
switch(displayColorSetting) {
- case DisplayColorSetting::MANAGED:
+ case DisplayColorSetting::kManaged:
return std::string("Managed");
- case DisplayColorSetting::UNMANAGED:
+ case DisplayColorSetting::kUnmanaged:
return std::string("Unmanaged");
- case DisplayColorSetting::ENHANCED:
+ case DisplayColorSetting::kEnhanced:
return std::string("Enhanced");
default:
return std::string("Unknown ") +
@@ -276,11 +253,12 @@
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
- mPhaseOffsets(mFactory.createPhaseOffsets()),
mInterceptor(mFactory.createSurfaceInterceptor(this)),
- mTimeStats(mFactory.createTimeStats()),
+ mTimeStats(std::make_shared<impl::TimeStats>()),
+ mFrameTracer(std::make_unique<FrameTracer>()),
mEventQueue(mFactory.createMessageQueue()),
- mCompositionEngine(mFactory.createCompositionEngine()) {}
+ mCompositionEngine(mFactory.createCompositionEngine()),
+ mPhaseOffsets(mFactory.createPhaseOffsets()) {}
SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
@@ -386,10 +364,6 @@
property_get("debug.sf.luma_sampling", value, "1");
mLumaSampling = atoi(value);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
-
// We should be reading 'persist.sys.sf.color_saturation' here
// but since /data may be encrypted, we need to wait until after vold
// comes online to attempt to read the property. The property is
@@ -538,6 +512,8 @@
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
+ mFrameTracer->initialize();
+
// wait patiently for the window manager death
const String16 name("window");
mWindowManager = defaultServiceManager()->getService(name);
@@ -569,14 +545,16 @@
readPersistentProperties();
mBootStage = BootStage::FINISHED;
- // set the refresh rate according to the policy
- const auto& performanceRefreshRate =
- mRefreshRateConfigs.getRefreshRate(RefreshRateType::PERFORMANCE);
+ if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ // set the refresh rate according to the policy
+ const auto& performanceRefreshRate =
+ mRefreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE);
- if (performanceRefreshRate && isDisplayConfigAllowed(performanceRefreshRate->configId)) {
- setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
- } else {
- setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
+ if (isDisplayConfigAllowed(performanceRefreshRate.configId)) {
+ setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
+ } else {
+ setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
+ }
}
}));
}
@@ -615,36 +593,9 @@
void SurfaceFlinger::init() {
ALOGI( "SurfaceFlinger's main thread ready to run. "
"Initializing graphics H/W...");
-
- ALOGI("Phase offset NS: %" PRId64 "", mPhaseOffsets->getCurrentAppOffset());
+ ALOGI("Phase offset: %" PRId64 " ns", mPhaseOffsets->getCurrentAppOffset());
Mutex::Autolock _l(mStateLock);
- // start the EventThread
- mScheduler =
- getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
- mRefreshRateConfigs);
- auto resyncCallback =
- mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
-
- mAppConnectionHandle =
- mScheduler->createConnection("app", mVsyncModulator.getOffsets().app,
- mPhaseOffsets->getOffsetThresholdForNextVsync(),
- resyncCallback,
- impl::EventThread::InterceptVSyncsCallback());
- mSfConnectionHandle =
- mScheduler->createConnection("sf", mVsyncModulator.getOffsets().sf,
- mPhaseOffsets->getOffsetThresholdForNextVsync(),
- resyncCallback, [this](nsecs_t timestamp) {
- mInterceptor->saveVSyncEvent(timestamp);
- });
-
- mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
- mVsyncModulator.setSchedulerAndHandles(mScheduler.get(), mAppConnectionHandle.get(),
- mSfConnectionHandle.get());
-
- mRegionSamplingThread =
- new RegionSamplingThread(*this, *mScheduler,
- RegionSamplingThread::EnvironmentTimingTunables());
// Get a RenderEngine for the given display / config (can't fail)
int32_t renderEngineFeature = 0;
@@ -703,7 +654,11 @@
// set initial conditions (e.g. unblank default device)
initializeDisplays();
- getRenderEngine().primeCache();
+ char primeShaderCache[PROPERTY_VALUE_MAX];
+ property_get("service.sf.prime_shader_cache", primeShaderCache, "1");
+ if (atoi(primeShaderCache)) {
+ getRenderEngine().primeCache();
+ }
// Inform native graphics APIs whether the present timestamp is supported:
@@ -715,37 +670,6 @@
ALOGE("Run StartPropertySetThread failed!");
}
- mScheduler->setChangeRefreshRateCallback(
- [this](RefreshRateType type, Scheduler::ConfigEvent event) {
- Mutex::Autolock lock(mStateLock);
- setRefreshRateTo(type, event);
- });
- mScheduler->setGetCurrentRefreshRateTypeCallback([this] {
- Mutex::Autolock lock(mStateLock);
- const auto display = getDefaultDisplayDeviceLocked();
- if (!display) {
- // If we don't have a default display the fallback to the default
- // refresh rate type
- return RefreshRateType::DEFAULT;
- }
-
- const int configId = display->getActiveConfig();
- for (const auto& [type, refresh] : mRefreshRateConfigs.getRefreshRates()) {
- if (refresh && refresh->configId == configId) {
- return type;
- }
- }
- // This should never happen, but just gracefully fallback to default.
- return RefreshRateType::DEFAULT;
- });
- mScheduler->setGetVsyncPeriodCallback([this] {
- Mutex::Autolock lock(mStateLock);
- return getVsyncPeriod();
- });
-
- mRefreshRateConfigs.populate(getHwComposer().getConfigs(*display->getId()));
- mRefreshRateStats.setConfigMode(getHwComposer().getActiveConfigIndex(*display->getId()));
-
ALOGV("Done initializing");
}
@@ -889,17 +813,22 @@
info.viewportW = uint32_t(viewport.getWidth());
info.viewportH = uint32_t(viewport.getHeight());
}
+ info.layerStack = display->getLayerStack();
} else {
// TODO: where should this value come from?
static const int TV_DENSITY = 213;
info.density = TV_DENSITY / 160.0f;
info.orientation = 0;
+
+ const auto display = getDisplayDeviceLocked(displayToken);
+ info.layerStack = display->getLayerStack();
}
info.xdpi = xdpi;
info.ydpi = ydpi;
info.fps = 1e9 / hwConfig->getVsyncPeriod();
- const auto refreshRateType = mRefreshRateConfigs.getRefreshRateType(hwConfig->getId());
+ const auto refreshRateType =
+ mRefreshRateConfigs->getRefreshRateTypeFromHwcConfigId(hwConfig->getId());
const auto offset = mPhaseOffsets->getOffsetsForRefreshRate(refreshRateType);
info.appVsyncOffset = offset.late.app;
@@ -947,7 +876,16 @@
return BAD_VALUE;
}
- return display->getActiveConfig();
+ if (display->isPrimary()) {
+ std::lock_guard<std::mutex> lock(mActiveConfigLock);
+ if (mDesiredActiveConfigChanged) {
+ return mDesiredActiveConfig.configId;
+ } else {
+ return display->getActiveConfig();
+ }
+ } else {
+ return display->getActiveConfig();
+ }
}
void SurfaceFlinger::setDesiredActiveConfig(const ActiveConfigInfo& info) {
@@ -969,14 +907,11 @@
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
// As we called to set period, we will call to onRefreshRateChangeCompleted once
// DispSync model is locked.
- mVsyncModulator.onRefreshRateChangeInitiated();
+ mVSyncModulator->onRefreshRateChangeInitiated();
mPhaseOffsets->setRefreshRateType(info.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
}
mDesiredActiveConfigChanged = true;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
if (mRefreshRateOverlay) {
mRefreshRateOverlay->changeRefreshRate(mDesiredActiveConfig.type);
@@ -1001,14 +936,13 @@
}
std::lock_guard<std::mutex> lock(mActiveConfigLock);
- mRefreshRateStats.setConfigMode(mUpcomingActiveConfig.configId);
+ mRefreshRateConfigs->setCurrentConfig(mUpcomingActiveConfig.configId);
+ mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
display->setActiveConfig(mUpcomingActiveConfig.configId);
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
ATRACE_INT("ActiveConfigMode", mUpcomingActiveConfig.configId);
if (mUpcomingActiveConfig.event != Scheduler::ConfigEvent::None) {
@@ -1021,13 +955,10 @@
std::lock_guard<std::mutex> lock(mActiveConfigLock);
mDesiredActiveConfig.event = Scheduler::ConfigEvent::None;
mDesiredActiveConfigChanged = false;
- ATRACE_INT("DesiredActiveConfigChanged", mDesiredActiveConfigChanged);
mScheduler->resyncToHardwareVsync(true, getVsyncPeriod());
mPhaseOffsets->setRefreshRateType(mUpcomingActiveConfig.type);
- const auto [early, gl, late] = mPhaseOffsets->getCurrentOffsets();
- mVsyncModulator.setPhaseOffsets(early, gl, late,
- mPhaseOffsets->getOffsetThresholdForNextVsync());
+ mVSyncModulator->setPhaseOffsets(mPhaseOffsets->getCurrentOffsets());
}
bool SurfaceFlinger::performSetActiveConfig() {
@@ -1159,8 +1090,10 @@
ALOGW("Attempt to set active color mode %s (%d) for virtual display",
decodeColorMode(mode).c_str(), mode);
} else {
- display->getCompositionDisplay()->setColorMode(mode, Dataspace::UNKNOWN,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorProfile(
+ compositionengine::Output::ColorProfile{mode, Dataspace::UNKNOWN,
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN});
}
}));
@@ -1274,51 +1207,20 @@
status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
postMessageSync(new LambdaMessage([&] {
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
- if (mInjectVSyncs == enable) {
- return;
+ if (const auto handle = mScheduler->enableVSyncInjection(enable)) {
+ mEventQueue->setEventConnection(
+ mScheduler->getEventConnection(enable ? handle : mSfConnectionHandle));
}
-
- auto resyncCallback =
- mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
-
- // TODO(b/128863962): Part of the Injector should be refactored, so that it
- // can be passed to Scheduler.
- if (enable) {
- ALOGV("VSync Injections enabled");
- if (mVSyncInjector.get() == nullptr) {
- mVSyncInjector = std::make_unique<InjectVSyncSource>();
- mInjectorEventThread = std::make_unique<
- impl::EventThread>(mVSyncInjector.get(),
- impl::EventThread::InterceptVSyncsCallback(),
- "injEventThread");
- }
- mEventQueue->setEventThread(mInjectorEventThread.get(), std::move(resyncCallback));
- } else {
- ALOGV("VSync Injections disabled");
- mEventQueue->setEventThread(mScheduler->getEventThread(mSfConnectionHandle),
- std::move(resyncCallback));
- }
-
- mInjectVSyncs = enable;
}));
return NO_ERROR;
}
status_t SurfaceFlinger::injectVSync(nsecs_t when) {
- Mutex::Autolock _l(mStateLock);
-
- if (!mInjectVSyncs) {
- ALOGE("VSync Injections not enabled");
- return BAD_VALUE;
- }
- if (mInjectVSyncs && mInjectorEventThread.get() != nullptr) {
- ALOGV("Injecting VSync inside SurfaceFlinger");
- mVSyncInjector->onInjectSyncEvent(when);
- }
- return NO_ERROR;
+ Mutex::Autolock lock(mStateLock);
+ return mScheduler->injectVSync(when) ? NO_ERROR : BAD_VALUE;
}
status_t SurfaceFlinger::getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const
@@ -1409,16 +1311,10 @@
sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection(
ISurfaceComposer::VsyncSource vsyncSource, ISurfaceComposer::ConfigChanged configChanged) {
- auto resyncCallback = mScheduler->makeResyncCallback([this] {
- Mutex::Autolock lock(mStateLock);
- return getVsyncPeriod();
- });
-
const auto& handle =
vsyncSource == eVsyncSourceSurfaceFlinger ? mSfConnectionHandle : mAppConnectionHandle;
- return mScheduler->createDisplayEventConnection(handle, std::move(resyncCallback),
- configChanged);
+ return mScheduler->createDisplayEventConnection(handle, configChanged);
}
// ----------------------------------------------------------------------------
@@ -1494,7 +1390,7 @@
bool periodFlushed = false;
mScheduler->addResyncSample(timestamp, &periodFlushed);
if (periodFlushed) {
- mVsyncModulator.onRefreshRateChangeCompleted();
+ mVSyncModulator->onRefreshRateChangeCompleted();
}
}
@@ -1503,7 +1399,7 @@
*compositorTiming = getBE().mCompositorTiming;
}
-bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) {
+bool SurfaceFlinger::isDisplayConfigAllowed(int32_t configId) const {
return mAllowedDisplayConfigs.empty() || mAllowedDisplayConfigs.count(configId);
}
@@ -1515,13 +1411,8 @@
ATRACE_CALL();
// Don't do any updating if the current fps is the same as the new one.
- const auto& refreshRateConfig = mRefreshRateConfigs.getRefreshRate(refreshRate);
- if (!refreshRateConfig) {
- ALOGV("Skipping refresh rate change request for unsupported rate.");
- return;
- }
-
- const int desiredConfigId = refreshRateConfig->configId;
+ const auto& refreshRateConfig = mRefreshRateConfigs->getRefreshRateFromType(refreshRate);
+ const int desiredConfigId = refreshRateConfig.configId;
if (!isDisplayConfigAllowed(desiredConfigId)) {
ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
@@ -1627,8 +1518,7 @@
// any HWC layers are destroyed through that interface before it becomes
// invalid.
for (const auto& [token, displayDevice] : mDisplays) {
- displayDevice->getCompositionDisplay()->setOutputLayersOrderedByZ(
- compositionengine::Output::OutputLayers());
+ displayDevice->getCompositionDisplay()->clearOutputLayers();
}
// This DisplayDevice will no longer be relevant once resetDisplayState() is
@@ -1687,7 +1577,7 @@
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
const sp<Fence>& fence =
- mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
+ mVSyncModulator->getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
? mPreviousPresentFences[0]
: mPreviousPresentFences[1];
@@ -1702,15 +1592,15 @@
return (fence->getStatus() == Fence::Status::Unsignaled);
}
-void SurfaceFlinger::populateExpectedPresentTime() NO_THREAD_SAFETY_ANALYSIS {
+void SurfaceFlinger::populateExpectedPresentTime() {
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
const nsecs_t presentTime = mScheduler->getDispSyncExpectedPresentTime();
// Inflate the expected present time if we're targetting the next vsync.
- mExpectedPresentTime =
- mVsyncModulator.getOffsets().sf < mPhaseOffsets->getOffsetThresholdForNextVsync()
- ? presentTime
- : presentTime + stats.vsyncPeriod;
+ mExpectedPresentTime.store(mVSyncModulator->getOffsets().sf <
+ mPhaseOffsets->getOffsetThresholdForNextVsync()
+ ? presentTime
+ : presentTime + stats.vsyncPeriod);
}
void SurfaceFlinger::onMessageReceived(int32_t what) NO_THREAD_SAFETY_ANALYSIS {
@@ -1730,12 +1620,14 @@
(mPropagateBackpressureClientComposition || !mHadClientComposition))
? 1
: 0;
- bool frameMissed = previousFrameMissed(graceTimeForPresentFenceMs);
- bool hwcFrameMissed = mHadDeviceComposition && frameMissed;
- bool gpuFrameMissed = mHadClientComposition && frameMissed;
- ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
- ATRACE_INT("HwcFrameMissed", static_cast<int>(hwcFrameMissed));
- ATRACE_INT("GpuFrameMissed", static_cast<int>(gpuFrameMissed));
+ const TracedOrdinal<bool> frameMissed = {"FrameMissed",
+ previousFrameMissed(
+ graceTimeForPresentFenceMs)};
+ const TracedOrdinal<bool> hwcFrameMissed = {"HwcFrameMissed",
+ mHadDeviceComposition && frameMissed};
+ const TracedOrdinal<bool> gpuFrameMissed = {"GpuFrameMissed",
+ mHadClientComposition && frameMissed};
+
if (frameMissed) {
mFrameMissedCount++;
mTimeStats->incrementMissedFrames();
@@ -1821,34 +1713,62 @@
mRefreshPending = false;
- const bool repaintEverything = mRepaintEverything.exchange(false);
- preComposition();
- rebuildLayerStacks();
- calculateWorkingSet();
- for (const auto& [token, display] : mDisplays) {
- beginFrame(display);
- prepareFrame(display);
- doDebugFlashRegions(display, repaintEverything);
- doComposition(display, repaintEverything);
+ compositionengine::CompositionRefreshArgs refreshArgs;
+ refreshArgs.outputs.reserve(mDisplays.size());
+ for (const auto& [_, display] : mDisplays) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
+ }
+ mDrawingState.traverseInZOrder([&refreshArgs](Layer* layer) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer) refreshArgs.layers.push_back(compositionLayer);
+ });
+ refreshArgs.layersWithQueuedFrames.reserve(mLayersWithQueuedFrames.size());
+ for (sp<Layer> layer : mLayersWithQueuedFrames) {
+ auto compositionLayer = layer->getCompositionLayer();
+ if (compositionLayer) refreshArgs.layersWithQueuedFrames.push_back(compositionLayer.get());
}
- logLayerStats();
+ refreshArgs.repaintEverything = mRepaintEverything.exchange(false);
+ refreshArgs.outputColorSetting = useColorManagement
+ ? mDisplayColorSetting
+ : compositionengine::OutputColorSetting::kUnmanaged;
+ refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
+ refreshArgs.forceOutputColorMode = mForceColorMode;
+
+ refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
+ refreshArgs.updatingGeometryThisFrame = mGeometryInvalid || mVisibleRegionsDirty;
+
+ if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
+ refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
+ mDrawingState.colorMatrixChanged = false;
+ }
+
+ refreshArgs.devOptForceClientComposition = mDebugDisableHWC || mDebugRegion;
+
+ if (mDebugRegion != 0) {
+ refreshArgs.devOptFlashDirtyRegionsDelay =
+ std::chrono::milliseconds(mDebugRegion > 1 ? mDebugRegion : 0);
+ }
+
+ mGeometryInvalid = false;
+
+ mCompositionEngine->present(refreshArgs);
postFrame();
postComposition();
- mHadClientComposition = false;
- mHadDeviceComposition = false;
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- mHadClientComposition =
- mHadClientComposition || getHwComposer().hasClientComposition(displayId);
- mHadDeviceComposition =
- mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
- }
+ mHadClientComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().usesClientComposition;
+ });
+ mHadDeviceComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
+ });
- mVsyncModulator.onRefreshed(mHadClientComposition);
+ mVSyncModulator->onRefreshed(mHadClientComposition);
mLayersWithQueuedFrames.clear();
if (mVisibleRegionsDirty) {
@@ -1857,6 +1777,10 @@
mTracing.notify("visibleRegionsDirty");
}
}
+
+ if (mCompositionEngine->needsAnotherUpdate()) {
+ signalLayerUpdate();
+ }
}
@@ -1877,174 +1801,6 @@
return refreshNeeded;
}
-void SurfaceFlinger::calculateWorkingSet() {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- // build the h/w work list
- if (CC_UNLIKELY(mGeometryInvalid)) {
- mGeometryInvalid = false;
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
-
- uint32_t zOrder = 0;
-
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- auto& compositionState = layer->editState();
- compositionState.forceClientComposition = false;
- if (!compositionState.hwc || mDebugDisableHWC || mDebugRegion) {
- compositionState.forceClientComposition = true;
- }
-
- // The output Z order is set here based on a simple counter.
- compositionState.z = zOrder++;
-
- // Update the display independent composition state. This goes
- // to the general composition layer state structure.
- // TODO: Do this once per compositionengine::CompositionLayer.
- layer->getLayerFE().latchCompositionState(layer->getLayer().editState().frontEnd,
- true);
-
- // Recalculate the geometry state of the output layer.
- layer->updateCompositionState(true);
-
- // Write the updated geometry state to the HWC
- layer->writeStateToHWC(true);
- }
- }
- }
-
- // Set the per-frame data
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- if (!displayId) {
- continue;
- }
- auto* profile = display->getDisplayColorProfile();
-
- if (mDrawingState.colorMatrixChanged) {
- display->setColorTransform(mDrawingState.colorMatrix);
- }
- Dataspace targetDataspace = Dataspace::UNKNOWN;
- if (useColorManagement) {
- ColorMode colorMode;
- RenderIntent renderIntent;
- pickColorMode(displayDevice, &colorMode, &targetDataspace, &renderIntent);
- display->setColorMode(colorMode, targetDataspace, renderIntent);
-
- if (isHdrColorMode(colorMode)) {
- targetDataspace = Dataspace::UNKNOWN;
- } else if (mColorSpaceAgnosticDataspace != Dataspace::UNKNOWN) {
- targetDataspace = mColorSpaceAgnosticDataspace;
- }
- }
-
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- if (layer->isHdrY410()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
- !profile->hasHDR10Support()) {
- layer->forceClientComposition(displayDevice);
- } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
- layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
- !profile->hasHLGSupport()) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getRoundedCornerState().radius > 0.0f) {
- layer->forceClientComposition(displayDevice);
- }
-
- if (layer->getForceClientComposition(displayDevice)) {
- ALOGV("[%s] Requesting Client composition", layer->getName().string());
- layer->setCompositionType(displayDevice,
- Hwc2::IComposerClient::Composition::CLIENT);
- continue;
- }
-
- const auto& displayState = display->getState();
- layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
- }
- }
-
- mDrawingState.colorMatrixChanged = false;
-
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- auto& layerState = layer->getCompositionLayer()->editState().frontEnd;
- layerState.compositionType = static_cast<Hwc2::IComposerClient::Composition>(
- layer->getCompositionType(displayDevice));
- }
- }
-}
-
-void SurfaceFlinger::doDebugFlashRegions(const sp<DisplayDevice>& displayDevice,
- bool repaintEverything) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- // is debugging enabled
- if (CC_LIKELY(!mDebugRegion))
- return;
-
- if (displayState.isEnabled) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
- if (!dirtyRegion.isEmpty()) {
- base::unique_fd readyFence;
- // redraw the whole screen
- doComposeSurfaces(displayDevice, dirtyRegion, &readyFence);
-
- display->getRenderSurface()->queueBuffer(std::move(readyFence));
- }
- }
-
- postFramebuffer(displayDevice);
-
- if (mDebugRegion > 1) {
- usleep(mDebugRegion * 1000);
- }
-
- prepareFrame(displayDevice);
-}
-
-void SurfaceFlinger::logLayerStats() {
- ATRACE_CALL();
- if (CC_UNLIKELY(mLayerStats.isEnabled())) {
- for (const auto& [token, display] : mDisplays) {
- if (display->isPrimary()) {
- mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(display));
- return;
- }
- }
-
- ALOGE("logLayerStats: no primary display");
- }
-}
-
-void SurfaceFlinger::preComposition()
-{
- ATRACE_CALL();
- ALOGV("preComposition");
-
- mRefreshStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
-
- bool needExtraInvalidate = false;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (layer->onPreComposition(mRefreshStartTime)) {
- needExtraInvalidate = true;
- }
- });
-
- if (needExtraInvalidate) {
- signalLayerUpdate();
- }
-}
-
void SurfaceFlinger::updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime) {
// Update queue of past composite+present times and determine the
@@ -2117,7 +1873,7 @@
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
+ if (displayDevice && displayDevice->getCompositionDisplay()->getState().usesClientComposition) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
->getRenderSurface()
@@ -2138,10 +1894,11 @@
DisplayStatInfo stats;
mScheduler->getDisplayStatInfo(&stats);
- // We use the mRefreshStartTime which might be sampled a little later than
- // when we started doing work for this frame, but that should be okay
- // since updateCompositorTiming has snapping logic.
- updateCompositorTiming(stats, mRefreshStartTime, presentFenceTime);
+ // We use the CompositionEngine::getLastFrameRefreshTimestamp() which might
+ // be sampled a little later than when we started doing work for this frame,
+ // but that should be okay since updateCompositorTiming has snapping logic.
+ updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
+ presentFenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -2230,14 +1987,7 @@
}
mTransactionCompletedThread.addPresentFence(mPreviousPresentFences[0]);
-
- // Lock the mStateLock in case SurfaceFlinger is in the middle of applying a transaction.
- // If we do not lock here, a callback could be sent without all of its SurfaceControls and
- // metrics.
- {
- Mutex::Autolock _l(mStateLock);
- mTransactionCompletedThread.sendCallbacks();
- }
+ mTransactionCompletedThread.sendCallbacks();
if (mLumaSampling && mRegionSamplingThread) {
mRegionSamplingThread->notifyNewContent();
@@ -2265,258 +2015,6 @@
}
}
-void SurfaceFlinger::rebuildLayerStacks() {
- ATRACE_CALL();
- ALOGV("rebuildLayerStacks");
-
- // rebuild the visible layer list per screen
- if (CC_UNLIKELY(mVisibleRegionsDirty)) {
- ATRACE_NAME("rebuildLayerStacks VR Dirty");
- invalidateHwcGeometry();
-
- for (const auto& pair : mDisplays) {
- const auto& displayDevice = pair.second;
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- Region opaqueRegion;
- Region dirtyRegion;
- compositionengine::Output::OutputLayers layersSortedByZ;
- Vector<sp<Layer>> deprecated_layersSortedByZ;
- Vector<sp<Layer>> layersNeedingFences;
- const ui::Transform& tr = displayState.transform;
- const Rect bounds = displayState.bounds;
- if (displayState.isEnabled) {
- computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
-
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- auto compositionLayer = layer->getCompositionLayer();
- if (compositionLayer == nullptr) {
- return;
- }
-
- const auto displayId = displayDevice->getId();
- sp<compositionengine::LayerFE> layerFE = compositionLayer->getLayerFE();
- LOG_ALWAYS_FATAL_IF(layerFE.get() == nullptr);
-
- bool needsOutputLayer = false;
-
- if (display->belongsInOutput(layer->getLayerStack(),
- layer->getPrimaryDisplayOnly())) {
- Region drawRegion(tr.transform(
- layer->visibleNonTransparentRegion));
- drawRegion.andSelf(bounds);
- if (!drawRegion.isEmpty()) {
- needsOutputLayer = true;
- }
- }
-
- if (needsOutputLayer) {
- layersSortedByZ.emplace_back(
- display->getOrCreateOutputLayer(displayId, compositionLayer,
- layerFE));
- deprecated_layersSortedByZ.add(layer);
-
- auto& outputLayerState = layersSortedByZ.back()->editState();
- outputLayerState.visibleRegion =
- tr.transform(layer->visibleRegion.intersect(displayState.viewport));
- } else if (displayId) {
- // For layers that are being removed from a HWC display,
- // and that have queued frames, add them to a a list of
- // released layers so we can properly set a fence.
- bool hasExistingOutputLayer =
- display->getOutputLayerForLayer(compositionLayer.get()) != nullptr;
- bool hasQueuedFrames = std::find(mLayersWithQueuedFrames.cbegin(),
- mLayersWithQueuedFrames.cend(),
- layer) != mLayersWithQueuedFrames.cend();
-
- if (hasExistingOutputLayer && hasQueuedFrames) {
- layersNeedingFences.add(layer);
- }
- }
- });
- }
-
- display->setOutputLayersOrderedByZ(std::move(layersSortedByZ));
-
- displayDevice->setVisibleLayersSortedByZ(deprecated_layersSortedByZ);
- displayDevice->setLayersNeedingFences(layersNeedingFences);
-
- Region undefinedRegion{bounds};
- undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
-
- display->editState().undefinedRegion = undefinedRegion;
- display->editState().dirtyRegion.orSelf(dirtyRegion);
- }
- }
-}
-
-// Returns a data space that fits all visible layers. The returned data space
-// can only be one of
-// - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
-// - Dataspace::DISPLAY_P3
-// - Dataspace::DISPLAY_BT2020
-// The returned HDR data space is one of
-// - Dataspace::UNKNOWN
-// - Dataspace::BT2020_HLG
-// - Dataspace::BT2020_PQ
-Dataspace SurfaceFlinger::getBestDataspace(const sp<DisplayDevice>& display,
- Dataspace* outHdrDataSpace,
- bool* outIsHdrClientComposition) const {
- Dataspace bestDataSpace = Dataspace::V0_SRGB;
- *outHdrDataSpace = Dataspace::UNKNOWN;
-
- for (const auto& layer : display->getVisibleLayersSortedByZ()) {
- switch (layer->getDataSpace()) {
- case Dataspace::V0_SCRGB:
- case Dataspace::V0_SCRGB_LINEAR:
- case Dataspace::BT2020:
- case Dataspace::BT2020_ITU:
- case Dataspace::BT2020_LINEAR:
- case Dataspace::DISPLAY_BT2020:
- bestDataSpace = Dataspace::DISPLAY_BT2020;
- break;
- case Dataspace::DISPLAY_P3:
- bestDataSpace = Dataspace::DISPLAY_P3;
- break;
- case Dataspace::BT2020_PQ:
- case Dataspace::BT2020_ITU_PQ:
- bestDataSpace = Dataspace::DISPLAY_P3;
- *outHdrDataSpace = Dataspace::BT2020_PQ;
- *outIsHdrClientComposition = layer->getForceClientComposition(display);
- break;
- case Dataspace::BT2020_HLG:
- case Dataspace::BT2020_ITU_HLG:
- bestDataSpace = Dataspace::DISPLAY_P3;
- // When there's mixed PQ content and HLG content, we set the HDR
- // data space to be BT2020_PQ and convert HLG to PQ.
- if (*outHdrDataSpace == Dataspace::UNKNOWN) {
- *outHdrDataSpace = Dataspace::BT2020_HLG;
- }
- break;
- default:
- break;
- }
- }
-
- return bestDataSpace;
-}
-
-// Pick the ColorMode / Dataspace for the display device.
-void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* outMode,
- Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {
- if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
- *outMode = ColorMode::NATIVE;
- *outDataSpace = Dataspace::UNKNOWN;
- *outRenderIntent = RenderIntent::COLORIMETRIC;
- return;
- }
-
- Dataspace hdrDataSpace;
- bool isHdrClientComposition = false;
- Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace, &isHdrClientComposition);
-
- auto* profile = display->getCompositionDisplay()->getDisplayColorProfile();
-
- switch (mForceColorMode) {
- case ColorMode::SRGB:
- bestDataSpace = Dataspace::V0_SRGB;
- break;
- case ColorMode::DISPLAY_P3:
- bestDataSpace = Dataspace::DISPLAY_P3;
- break;
- default:
- break;
- }
-
- // respect hdrDataSpace only when there is no legacy HDR support
- const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
- !profile->hasLegacyHdrSupport(hdrDataSpace) && !isHdrClientComposition;
- if (isHdr) {
- bestDataSpace = hdrDataSpace;
- }
-
- RenderIntent intent;
- switch (mDisplayColorSetting) {
- case DisplayColorSetting::MANAGED:
- case DisplayColorSetting::UNMANAGED:
- intent = isHdr ? RenderIntent::TONE_MAP_COLORIMETRIC : RenderIntent::COLORIMETRIC;
- break;
- case DisplayColorSetting::ENHANCED:
- intent = isHdr ? RenderIntent::TONE_MAP_ENHANCE : RenderIntent::ENHANCE;
- break;
- default: // vendor display color setting
- intent = static_cast<RenderIntent>(mDisplayColorSetting);
- break;
- }
-
- profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
-}
-
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
-
- // If nothing has changed (!dirty), don't recompose.
- // If something changed, but we don't currently have any visible layers,
- // and didn't when we last did a composition, then skip it this time.
- // The second rule does two things:
- // - When all layers are removed from a display, we'll emit one black
- // frame, then nothing more until we get new layers.
- // - When a display is created with a private layer stack, we won't
- // emit any black frames until a layer is added to the layer stack.
- bool mustRecompose = dirty && !(empty && wasEmpty);
-
- const char flagPrefix[] = {'-', '+'};
- static_cast<void>(flagPrefix);
- ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
- __FUNCTION__, mustRecompose ? "doing" : "skipping",
- displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
- flagPrefix[wasEmpty]);
-
- display->getRenderSurface()->beginFrame(mustRecompose);
-
- if (mustRecompose) {
- display->editState().lastCompositionHadVisibleLayers = !empty;
- }
-}
-
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- if (!displayState.isEnabled) {
- return;
- }
-
- status_t result = display->getRenderSurface()->prepareFrame();
- ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
- displayDevice->getDebugName().c_str(), result, strerror(-result));
-}
-
-void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
- ATRACE_CALL();
- ALOGV("doComposition");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- if (displayState.isEnabled) {
- // transform the dirty region into this screen's coordinate space
- const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
-
- // repaint the framebuffer (if needed)
- doDisplayComposition(displayDevice, dirtyRegion);
-
- display->editState().dirtyRegion.clear();
- display->getRenderSurface()->flip();
- }
- postFramebuffer(displayDevice);
-}
-
void SurfaceFlinger::postFrame()
{
// |mStateLock| not needed as we are on the main thread
@@ -2529,65 +2027,6 @@
}
}
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
- ATRACE_CALL();
- ALOGV("postFramebuffer");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- const auto displayId = display->getId();
-
- if (displayState.isEnabled) {
- if (displayId) {
- getHwComposer().presentAndGetReleaseFences(*displayId);
- }
- display->getRenderSurface()->onPresentDisplayCompleted();
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- sp<Fence> releaseFence = Fence::NO_FENCE;
- bool usedClientComposition = true;
-
- // The layer buffer from the previous frame (if any) is released
- // by HWC only when the release fence from this frame (if any) is
- // signaled. Always get the release fence from HWC first.
- if (layer->getState().hwc) {
- const auto& hwcState = *layer->getState().hwc;
- releaseFence =
- getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
- usedClientComposition =
- hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
- }
-
- // If the layer was client composited in the previous frame, we
- // need to merge with the previous client target acquire fence.
- // Since we do not track that, always merge with the current
- // client target acquire fence when it is available, even though
- // this is suboptimal.
- if (usedClientComposition) {
- releaseFence =
- Fence::merge("LayerRelease", releaseFence,
- display->getRenderSurface()->getClientTargetAcquireFence());
- }
-
- layer->getLayerFE().onLayerDisplayed(releaseFence);
- }
-
- // We've got a list of layers needing fences, that are disjoint with
- // display->getVisibleLayersSortedByZ. The best we can do is to
- // supply them with the present fence.
- if (!displayDevice->getLayersNeedingFences().isEmpty()) {
- sp<Fence> presentFence =
- displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& layer : displayDevice->getLayersNeedingFences()) {
- layer->getCompositionLayer()->getLayerFE()->onLayerDisplayed(presentFence);
- }
- }
-
- if (displayId) {
- getHwComposer().clearReleaseFences(*displayId);
- }
- }
-}
-
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
@@ -2607,7 +2046,7 @@
// with mStateLock held to guarantee that mCurrentState won't change
// until the transaction is committed.
- mVsyncModulator.onTransactionHandled();
+ mVSyncModulator->onTransactionHandled();
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
@@ -2628,6 +2067,9 @@
if (event.connection == HWC2::Connection::Connected) {
if (!mPhysicalDisplayTokens.count(info->id)) {
ALOGV("Creating display %s", to_string(info->id).c_str());
+ if (event.hwcDisplayId == getHwComposer().getInternalHwcDisplayId()) {
+ initScheduler(info->id);
+ }
mPhysicalDisplayTokens[info->id] = new BBinder();
DisplayDeviceState state;
state.displayId = info->id;
@@ -2655,8 +2097,8 @@
}
void SurfaceFlinger::dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected) {
- mScheduler->hotplugReceived(mAppConnectionHandle, displayId, connected);
- mScheduler->hotplugReceived(mSfConnectionHandle, displayId, connected);
+ mScheduler->onHotplugReceived(mAppConnectionHandle, displayId, connected);
+ mScheduler->onHotplugReceived(mSfConnectionHandle, displayId, connected);
}
sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
@@ -2670,6 +2112,7 @@
creationArgs.displaySurface = dispSurface;
creationArgs.hasWideColorGamut = false;
creationArgs.supportedPerFrameMetadata = 0;
+ creationArgs.powerAdvisor = displayId ? &mPowerAdvisor : nullptr;
const bool isInternalDisplay = displayId && displayId == getInternalDisplayIdLocked();
creationArgs.isPrimary = isInternalDisplay;
@@ -2722,8 +2165,10 @@
defaultColorMode = ColorMode::SRGB;
defaultDataSpace = Dataspace::V0_SRGB;
}
- display->getCompositionDisplay()->setColorMode(defaultColorMode, defaultDataSpace,
- RenderIntent::COLORIMETRIC);
+ display->getCompositionDisplay()->setColorProfile(
+ compositionengine::Output::ColorProfile{defaultColorMode, defaultDataSpace,
+ RenderIntent::COLORIMETRIC,
+ Dataspace::UNKNOWN});
if (!state.isVirtual()) {
LOG_ALWAYS_FATAL_IF(!displayId);
display->setActiveConfig(getHwComposer().getActiveConfigIndex(*displayId));
@@ -2880,9 +2325,11 @@
void SurfaceFlinger::handleTransactionLocked(uint32_t transactionFlags)
{
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+
// Notify all layers of available frames
- mCurrentState.traverseInZOrder([](Layer* layer) {
- layer->notifyAvailableFrames();
+ mCurrentState.traverseInZOrder([expectedPresentTime](Layer* layer) {
+ layer->notifyAvailableFrames(expectedPresentTime);
});
/*
@@ -2927,7 +2374,7 @@
// display is used to calculate the hint, otherwise we use the
// default display.
//
- // NOTE: we do this here, rather than in rebuildLayerStacks() so that
+ // NOTE: we do this here, rather than when presenting the display so that
// the hint is set before we acquire a buffer from the surface texture.
//
// NOTE: layer transactions have taken place already, so we use their
@@ -3028,7 +2475,7 @@
setInputWindowsFinished();
}
- executeInputWindowCommands();
+ mInputWindowCommands.clear();
}
void SurfaceFlinger::updateInputWindowInfo() {
@@ -3052,51 +2499,85 @@
mPendingInputWindowCommands.clear();
}
-void SurfaceFlinger::executeInputWindowCommands() {
- for (const auto& transferTouchFocusCommand : mInputWindowCommands.transferTouchFocusCommands) {
- if (transferTouchFocusCommand.fromToken != nullptr &&
- transferTouchFocusCommand.toToken != nullptr &&
- transferTouchFocusCommand.fromToken != transferTouchFocusCommand.toToken) {
- mInputFlinger->transferTouchFocus(transferTouchFocusCommand.fromToken,
- transferTouchFocusCommand.toToken);
- }
- }
-
- mInputWindowCommands.clear();
-}
-
void SurfaceFlinger::updateCursorAsync()
{
- for (const auto& [token, display] : mDisplays) {
- if (!display->getId()) {
- continue;
- }
-
- for (auto& layer : display->getVisibleLayersSortedByZ()) {
- layer->updateCursorPosition(display);
+ compositionengine::CompositionRefreshArgs refreshArgs;
+ for (const auto& [_, display] : mDisplays) {
+ if (display->getId()) {
+ refreshArgs.outputs.push_back(display->getCompositionDisplay());
}
}
+
+ mCompositionEngine->updateCursorAsync(refreshArgs);
}
-void SurfaceFlinger::latchAndReleaseBuffer(const sp<Layer>& layer) {
- if (layer->hasReadyFrame()) {
- bool ignored = false;
- layer->latchBuffer(ignored, systemTime());
+void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
+ if (mScheduler) {
+ // In practice it's not allowed to hotplug in/out the primary display once it's been
+ // connected during startup, but some tests do it, so just warn and return.
+ ALOGW("Can't re-init scheduler");
+ return;
}
- layer->releasePendingBuffer(systemTime());
+
+ int currentConfig = getHwComposer().getActiveConfigIndex(primaryDisplayId);
+ mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(refresh_rate_switching(false),
+ getHwComposer().getConfigs(
+ primaryDisplayId),
+ currentConfig);
+ mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(*mRefreshRateConfigs, *mTimeStats,
+ currentConfig, HWC_POWER_MODE_OFF);
+ mRefreshRateStats->setConfigMode(currentConfig);
+
+ // start the EventThread
+ mScheduler =
+ getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
+ *mRefreshRateConfigs);
+ mAppConnectionHandle =
+ mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ impl::EventThread::InterceptVSyncsCallback());
+ mSfConnectionHandle =
+ mScheduler->createConnection("sf", mPhaseOffsets->getCurrentSfOffset(),
+ mPhaseOffsets->getOffsetThresholdForNextVsync(),
+ [this](nsecs_t timestamp) {
+ mInterceptor->saveVSyncEvent(timestamp);
+ });
+
+ mEventQueue->setEventConnection(mScheduler->getEventConnection(mSfConnectionHandle));
+ mVSyncModulator.emplace(*mScheduler, mAppConnectionHandle, mSfConnectionHandle,
+ mPhaseOffsets->getCurrentOffsets());
+
+ mRegionSamplingThread =
+ new RegionSamplingThread(*this, *mScheduler,
+ RegionSamplingThread::EnvironmentTimingTunables());
+
+ mScheduler->setChangeRefreshRateCallback(
+ [this](RefreshRateType type, Scheduler::ConfigEvent event) {
+ Mutex::Autolock lock(mStateLock);
+ setRefreshRateTo(type, event);
+ });
}
void SurfaceFlinger::commitTransaction()
{
+ withTracingLock([this]() { commitTransactionLocked(); });
+
+ mTransactionPending = false;
+ mAnimTransactionPending = false;
+ mTransactionCV.broadcast();
+}
+
+void SurfaceFlinger::commitTransactionLocked() {
if (!mLayersPendingRemoval.isEmpty()) {
// Notify removed layers now that they can't be drawn from
for (const auto& l : mLayersPendingRemoval) {
- recordBufferingStats(l->getName().string(),
- l->getOccupancyHistory(true));
+ recordBufferingStats(l->getName().string(), l->getOccupancyHistory(true));
// Ensure any buffers set to display on any children are released.
if (l->isRemovedFromCurrentState()) {
- latchAndReleaseBuffer(l);
+ l->latchAndReleaseBuffer();
}
// If the layer has been removed and has no parent, then it will not be reachable
@@ -3113,27 +2594,22 @@
// we composite should be considered an animation as well.
mAnimCompositionPending = mAnimTransactionPending;
- withTracingLock([&]() {
- mDrawingState = mCurrentState;
- // clear the "changed" flags in current state
- mCurrentState.colorMatrixChanged = false;
+ mDrawingState = mCurrentState;
+ // clear the "changed" flags in current state
+ mCurrentState.colorMatrixChanged = false;
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- layer->commitChildList();
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
+ layer->commitChildList();
- // If the layer can be reached when traversing mDrawingState, then the layer is no
- // longer offscreen. Remove the layer from the offscreenLayer set.
- if (mOffscreenLayers.count(layer)) {
- mOffscreenLayers.erase(layer);
- }
- });
-
- commitOffscreenLayers();
+ // If the layer can be reached when traversing mDrawingState, then the layer is no
+ // longer offscreen. Remove the layer from the offscreenLayer set.
+ if (mOffscreenLayers.count(layer)) {
+ mOffscreenLayers.erase(layer);
+ }
});
- mTransactionPending = false;
- mAnimTransactionPending = false;
- mTransactionCV.broadcast();
+ commitOffscreenLayers();
+ mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateMirrorInfo(); });
}
void SurfaceFlinger::withTracingLock(std::function<void()> lockedOperation) {
@@ -3168,147 +2644,6 @@
}
}
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
- Region& outDirtyRegion, Region& outOpaqueRegion) {
- ATRACE_CALL();
- ALOGV("computeVisibleRegions");
-
- auto display = displayDevice->getCompositionDisplay();
-
- Region aboveOpaqueLayers;
- Region aboveCoveredLayers;
- Region dirty;
-
- outDirtyRegion.clear();
-
- mDrawingState.traverseInReverseZOrder([&](Layer* layer) {
- // start with the whole surface at its current location
- const Layer::State& s(layer->getDrawingState());
-
- // only consider the layers on the given layer stack
- if (!display->belongsInOutput(layer->getLayerStack(), layer->getPrimaryDisplayOnly())) {
- return;
- }
-
- /*
- * opaqueRegion: area of a surface that is fully opaque.
- */
- Region opaqueRegion;
-
- /*
- * visibleRegion: area of a surface that is visible on screen
- * and not fully transparent. This is essentially the layer's
- * footprint minus the opaque regions above it.
- * Areas covered by a translucent surface are considered visible.
- */
- Region visibleRegion;
-
- /*
- * coveredRegion: area of a surface that is covered by all
- * visible regions above it (which includes the translucent areas).
- */
- Region coveredRegion;
-
- /*
- * transparentRegion: area of a surface that is hinted to be completely
- * transparent. This is only used to tell when the layer has no visible
- * non-transparent regions and can be removed from the layer list. It
- * does not affect the visibleRegion of this layer or any layers
- * beneath it. The hint may not be correct if apps don't respect the
- * SurfaceView restrictions (which, sadly, some don't).
- */
- Region transparentRegion;
-
-
- // handle hidden surfaces by setting the visible region to empty
- if (CC_LIKELY(layer->isVisible())) {
- const bool translucent = !layer->isOpaque(s);
- Rect bounds(layer->getScreenBounds());
-
- visibleRegion.set(bounds);
- ui::Transform tr = layer->getTransform();
- if (!visibleRegion.isEmpty()) {
- // Remove the transparent area from the visible region
- if (translucent) {
- if (tr.preserveRects()) {
- // transform the transparent region
- transparentRegion = tr.transform(layer->getActiveTransparentRegion(s));
- } else {
- // transformation too complex, can't do the
- // transparent region optimization.
- transparentRegion.clear();
- }
- }
-
- // compute the opaque region
- const int32_t layerOrientation = tr.getOrientation();
- if (layer->getAlpha() == 1.0f && !translucent &&
- layer->getRoundedCornerState().radius == 0.0f &&
- ((layerOrientation & ui::Transform::ROT_INVALID) == false)) {
- // the opaque region is the layer's footprint
- opaqueRegion = visibleRegion;
- }
- }
- }
-
- if (visibleRegion.isEmpty()) {
- layer->clearVisibilityRegions();
- return;
- }
-
- // Clip the covered region to the visible region
- coveredRegion = aboveCoveredLayers.intersect(visibleRegion);
-
- // Update aboveCoveredLayers for next (lower) layer
- aboveCoveredLayers.orSelf(visibleRegion);
-
- // subtract the opaque region covered by the layers above us
- visibleRegion.subtractSelf(aboveOpaqueLayers);
-
- // compute this layer's dirty region
- if (layer->contentDirty) {
- // we need to invalidate the whole region
- dirty = visibleRegion;
- // as well, as the old visible region
- dirty.orSelf(layer->visibleRegion);
- layer->contentDirty = false;
- } else {
- /* compute the exposed region:
- * the exposed region consists of two components:
- * 1) what's VISIBLE now and was COVERED before
- * 2) what's EXPOSED now less what was EXPOSED before
- *
- * note that (1) is conservative, we start with the whole
- * visible region but only keep what used to be covered by
- * something -- which mean it may have been exposed.
- *
- * (2) handles areas that were not covered by anything but got
- * exposed because of a resize.
- */
- const Region newExposed = visibleRegion - coveredRegion;
- const Region oldVisibleRegion = layer->visibleRegion;
- const Region oldCoveredRegion = layer->coveredRegion;
- const Region oldExposed = oldVisibleRegion - oldCoveredRegion;
- dirty = (visibleRegion&oldCoveredRegion) | (newExposed-oldExposed);
- }
- dirty.subtractSelf(aboveOpaqueLayers);
-
- // accumulate to the screen dirty region
- outDirtyRegion.orSelf(dirty);
-
- // Update aboveOpaqueLayers for next (lower) layer
- aboveOpaqueLayers.orSelf(opaqueRegion);
-
- // Store the visible region in screen space
- layer->setVisibleRegion(visibleRegion);
- layer->setCoveredRegion(coveredRegion);
- layer->setVisibleNonTransparentRegion(
- visibleRegion.subtract(transparentRegion));
- });
-
- outOpaqueRegion = aboveOpaqueLayers;
-}
-
void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
for (const auto& [token, displayDevice] : mDisplays) {
auto display = displayDevice->getCompositionDisplay();
@@ -3329,6 +2664,8 @@
bool frameQueued = false;
bool newDataLatched = false;
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
+
// Store the set of layers that need updates. This set must not change as
// buffers are being latched, as this could result in a deadlock.
// Example: Two producers share the same command stream and:
@@ -3341,7 +2678,6 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (layer->hasReadyFrame()) {
frameQueued = true;
- const nsecs_t expectedPresentTime = getExpectedPresentTime();
if (layer->shouldPresentNow(expectedPresentTime)) {
mLayersWithQueuedFrames.push_back(layer);
} else {
@@ -3353,13 +2689,21 @@
}
});
+ // The client can continue submitting buffers for offscreen layers, but they will not
+ // be shown on screen. Therefore, we need to latch and release buffers of offscreen
+ // layers to ensure dequeueBuffer doesn't block indefinitely.
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing,
+ [&](Layer* l) { l->latchAndReleaseBuffer(); });
+ }
+
if (!mLayersWithQueuedFrames.empty()) {
// mStateLock is needed for latchBuffer as LayerRejecter::reject()
// writes to Layer current state. See also b/119481871
Mutex::Autolock lock(mStateLock);
for (auto& layer : mLayersWithQueuedFrames) {
- if (layer->latchBuffer(visibleRegions, latchTime)) {
+ if (layer->latchBuffer(visibleRegions, latchTime, expectedPresentTime)) {
mLayersPendingRefresh.push_back(layer);
}
layer->useSurfaceDamage();
@@ -3384,6 +2728,8 @@
mBootStage = BootStage::BOOTANIMATION;
}
+ mDrawingState.traverseInZOrder([&](Layer* layer) { layer->updateCloneBufferInfo(); });
+
// Only continue with the refresh if there is actually new work to do
return !mLayersWithQueuedFrames.empty() && newDataLatched;
}
@@ -3393,207 +2739,6 @@
mGeometryInvalid = true;
}
-void SurfaceFlinger::doDisplayComposition(const sp<DisplayDevice>& displayDevice,
- const Region& inDirtyRegion) {
- auto display = displayDevice->getCompositionDisplay();
- // We only need to actually compose the display if:
- // 1) It is being handled by hardware composer, which may need this to
- // keep its virtual display state machine in sync, or
- // 2) There is work to be done (the dirty region isn't empty)
- if (!displayDevice->getId() && inDirtyRegion.isEmpty()) {
- ALOGV("Skipping display composition");
- return;
- }
-
- ALOGV("doDisplayComposition");
- base::unique_fd readyFence;
- if (!doComposeSurfaces(displayDevice, Region::INVALID_REGION, &readyFence)) return;
-
- // swap buffers (presentation)
- display->getRenderSurface()->queueBuffer(std::move(readyFence));
-}
-
-bool SurfaceFlinger::doComposeSurfaces(const sp<DisplayDevice>& displayDevice,
- const Region& debugRegion, base::unique_fd* readyFence) {
- ATRACE_CALL();
- ALOGV("doComposeSurfaces");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- const auto displayId = display->getId();
- auto& renderEngine = getRenderEngine();
- const bool supportProtectedContent = renderEngine.supportsProtectedContent();
-
- const Region bounds(displayState.bounds);
- const DisplayRenderArea renderArea(displayDevice);
- const bool hasClientComposition = getHwComposer().hasClientComposition(displayId);
- ATRACE_INT("hasClientComposition", hasClientComposition);
-
- bool applyColorMatrix = false;
-
- renderengine::DisplaySettings clientCompositionDisplay;
- std::vector<renderengine::LayerSettings> clientCompositionLayers;
- sp<GraphicBuffer> buf;
- base::unique_fd fd;
-
- if (hasClientComposition) {
- ALOGV("hasClientComposition");
-
- if (displayDevice->isPrimary() && supportProtectedContent) {
- bool needsProtected = false;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- // If the layer is a protected layer, mark protected context is needed.
- if (layer->isProtected()) {
- needsProtected = true;
- break;
- }
- }
- if (needsProtected != renderEngine.isProtected()) {
- renderEngine.useProtectedContext(needsProtected);
- }
- if (needsProtected != display->getRenderSurface()->isProtected() &&
- needsProtected == renderEngine.isProtected()) {
- display->getRenderSurface()->setProtected(needsProtected);
- }
- }
-
- buf = display->getRenderSurface()->dequeueBuffer(&fd);
-
- if (buf == nullptr) {
- ALOGW("Dequeuing buffer for display [%s] failed, bailing out of "
- "client composition for this frame",
- displayDevice->getDisplayName().c_str());
- return false;
- }
-
- clientCompositionDisplay.physicalDisplay = displayState.scissor;
- clientCompositionDisplay.clip = displayState.scissor;
- const ui::Transform& displayTransform = displayState.transform;
- clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
- clientCompositionDisplay.orientation = displayState.orientation;
-
- const auto* profile = display->getDisplayColorProfile();
- Dataspace outputDataspace = Dataspace::UNKNOWN;
- if (profile->hasWideColorGamut()) {
- outputDataspace = displayState.dataspace;
- }
- clientCompositionDisplay.outputDataspace = outputDataspace;
- clientCompositionDisplay.maxLuminance =
- profile->getHdrCapabilities().getDesiredMaxLuminance();
-
- const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
- const bool skipClientColorTransform =
- getHwComposer()
- .hasDisplayCapability(displayId,
- HWC2::DisplayCapability::SkipClientColorTransform);
-
- // Compute the global color transform matrix.
- applyColorMatrix = !hasDeviceComposition && !skipClientColorTransform;
- if (applyColorMatrix) {
- clientCompositionDisplay.colorTransform = displayState.colorTransformMat;
- }
- }
-
- /*
- * and then, render the layers targeted at the framebuffer
- */
-
- ALOGV("Rendering client layers");
- bool firstLayer = true;
- Region clearRegion = Region::INVALID_REGION;
- for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
- const Region viewportRegion(displayState.viewport);
- const Region clip(viewportRegion.intersect(layer->visibleRegion));
- ALOGV("Layer: %s", layer->getName().string());
- ALOGV(" Composition type: %s", toString(layer->getCompositionType(displayDevice)).c_str());
- if (!clip.isEmpty()) {
- switch (layer->getCompositionType(displayDevice)) {
- case Hwc2::IComposerClient::Composition::CURSOR:
- case Hwc2::IComposerClient::Composition::DEVICE:
- case Hwc2::IComposerClient::Composition::SIDEBAND:
- case Hwc2::IComposerClient::Composition::SOLID_COLOR: {
- LOG_ALWAYS_FATAL_IF(!displayId);
- const Layer::State& state(layer->getDrawingState());
- if (layer->getClearClientTarget(displayDevice) && !firstLayer &&
- layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
- layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
- // never clear the very first layer since we're
- // guaranteed the FB is already cleared
- renderengine::LayerSettings layerSettings;
- Region dummyRegion;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, dummyRegion,
- supportProtectedContent, 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::IComposerClient::Composition::CLIENT: {
- renderengine::LayerSettings layerSettings;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, clearRegion,
- supportProtectedContent, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
- }
- break;
- }
- default:
- break;
- }
- } else {
- ALOGV(" Skipping for empty clip");
- }
- firstLayer = false;
- }
-
- // Perform some cleanup steps if we used client composition.
- if (hasClientComposition) {
- clientCompositionDisplay.clearRegion = clearRegion;
-
- // We boost GPU frequency here because there will be color spaces conversion
- // and it's expensive. We boost the GPU frequency so that GPU composition can
- // finish in time. We must reset GPU frequency afterwards, because high frequency
- // consumes extra battery.
- const bool expensiveRenderingExpected =
- clientCompositionDisplay.outputDataspace == Dataspace::DISPLAY_P3;
- if (expensiveRenderingExpected && displayId) {
- mPowerAdvisor.setExpensiveRenderingExpected(*displayId, true);
- }
- 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);
- }
- }
- renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
- readyFence);
- } else if (displayId) {
- mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
- }
- return true;
-}
-
-void SurfaceFlinger::drawWormhole(const Region& region) const {
- auto& engine(getRenderEngine());
- engine.fillRegionWithColor(region, 0, 0, 0, 0);
-}
-
status_t SurfaceFlinger::addClientLayer(const sp<Client>& client, const sp<IBinder>& handle,
const sp<IGraphicBufferProducer>& gbc, const sp<Layer>& lbc,
const sp<IBinder>& parentHandle,
@@ -3612,7 +2757,7 @@
}
if (mNumLayers >= MAX_LAYERS) {
- ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers,
+ ALOGE("AddClientLayer failed, mNumLayers (%zu) >= MAX_LAYERS (%zu)", mNumLayers.load(),
MAX_LAYERS);
return NO_MEMORY;
}
@@ -3636,7 +2781,7 @@
mMaxGraphicBufferProducerListSize,
"Suspected IGBP leak: %zu IGBPs (%zu max), %zu Layers",
mGraphicBufferProducerList.size(),
- mMaxGraphicBufferProducerListSize, mNumLayers);
+ mMaxGraphicBufferProducerListSize, mNumLayers.load());
}
mLayersAdded = true;
}
@@ -3662,7 +2807,7 @@
uint32_t SurfaceFlinger::setTransactionFlags(uint32_t flags,
Scheduler::TransactionStart transactionStart) {
uint32_t old = mTransactionFlags.fetch_or(flags);
- mVsyncModulator.setTransactionStart(transactionStart);
+ mVSyncModulator->setTransactionStart(transactionStart);
if ((old & flags)==0) { // wake the server up
signalTransaction();
}
@@ -3685,6 +2830,7 @@
while (!transactionQueue.empty()) {
const auto& transaction = transactionQueue.front();
if (!transactionIsReadyToBeApplied(transaction.desiredPresentTime,
+ true /* useCachedExpectedPresentTime */,
transaction.states)) {
setTransactionFlags(eTransactionFlushNeeded);
break;
@@ -3692,9 +2838,9 @@
transactions.push_back(transaction);
applyTransactionState(transaction.states, transaction.displays, transaction.flags,
mPendingInputWindowCommands, transaction.desiredPresentTime,
- transaction.buffer, transaction.callback,
- transaction.postTime, transaction.privileged,
- /*isMainThread*/ true);
+ transaction.buffer, transaction.postTime,
+ transaction.privileged, transaction.hasListenerCallbacks,
+ transaction.listenerCallbacks, /*isMainThread*/ true);
transactionQueue.pop();
flushedATransaction = true;
}
@@ -3714,31 +2860,14 @@
return !mTransactionQueues.empty();
}
-bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
- for (const ComposerState& state : states) {
- // Here we need to check that the interface we're given is indeed
- // one of our own. A malicious client could give us a nullptr
- // IInterface, or one of its own or even one of our own but a
- // different type. All these situations would cause us to crash.
- if (state.client == nullptr) {
- return true;
- }
-
- sp<IBinder> binder = IInterface::asBinder(state.client);
- if (binder == nullptr) {
- return true;
- }
-
- if (binder->queryLocalInterface(ISurfaceComposerClient::descriptor) == nullptr) {
- return true;
- }
- }
- return false;
-}
bool SurfaceFlinger::transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states) {
- nsecs_t expectedPresentTime = getExpectedPresentTime();
+ if (!useCachedExpectedPresentTime)
+ populateExpectedPresentTime();
+
+ const nsecs_t expectedPresentTime = mExpectedPresentTime.load();
// Do not present if the desiredPresentTime has not passed unless it is more than one second
// in the future. We ignore timestamps more than 1 second in the future for stability reasons.
if (desiredPresentTime >= 0 && desiredPresentTime >= expectedPresentTime &&
@@ -3758,13 +2887,11 @@
return true;
}
-void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags,
- const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime,
- const client_cache_t& uncacheBuffer,
- const std::vector<ListenerCallbacks>& listenerCallbacks) {
+void SurfaceFlinger::setTransactionState(
+ const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags,
+ const sp<IBinder>& applyToken, const InputWindowCommands& inputWindowCommands,
+ int64_t desiredPresentTime, const client_cache_t& uncacheBuffer, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks) {
ATRACE_CALL();
const int64_t postTime = systemTime();
@@ -3773,10 +2900,6 @@
Mutex::Autolock _l(mStateLock);
- if (containsAnyInvalidClientState(states)) {
- return;
- }
-
// If its TransactionQueue already has a pending TransactionState or if it is pending
auto itr = mTransactionQueues.find(applyToken);
// if this is an animation frame, wait until prior animation frame has
@@ -3793,27 +2916,28 @@
itr = mTransactionQueues.find(applyToken);
}
}
- if (itr != mTransactionQueues.end() ||
- !transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+
+ // Expected present time is computed and cached on invalidate, so it may be stale.
+ if (itr != mTransactionQueues.end() || !transactionIsReadyToBeApplied(
+ desiredPresentTime, false /* useCachedExpectedPresentTime */, states)) {
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
- uncacheBuffer, listenerCallbacks, postTime,
- privileged);
+ uncacheBuffer, postTime, privileged,
+ hasListenerCallbacks, listenerCallbacks);
setTransactionFlags(eTransactionFlushNeeded);
return;
}
applyTransactionState(states, displays, flags, inputWindowCommands, desiredPresentTime,
- uncacheBuffer, listenerCallbacks, postTime, privileged);
+ uncacheBuffer, postTime, privileged, hasListenerCallbacks,
+ listenerCallbacks);
}
-void SurfaceFlinger::applyTransactionState(const Vector<ComposerState>& states,
- const Vector<DisplayState>& displays, uint32_t flags,
- const InputWindowCommands& inputWindowCommands,
- const int64_t desiredPresentTime,
- const client_cache_t& uncacheBuffer,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- const int64_t postTime, bool privileged,
- bool isMainThread) {
+void SurfaceFlinger::applyTransactionState(
+ const Vector<ComposerState>& states, const Vector<DisplayState>& displays, uint32_t flags,
+ const InputWindowCommands& inputWindowCommands, const int64_t desiredPresentTime,
+ const client_cache_t& uncacheBuffer, const int64_t postTime, bool privileged,
+ bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
+ bool isMainThread) {
uint32_t transactionFlags = 0;
if (flags & eAnimation) {
@@ -3836,24 +2960,27 @@
transactionFlags |= setDisplayStateLocked(display);
}
- // In case the client has sent a Transaction that should receive callbacks but without any
- // SurfaceControls that should be included in the callback, send the listener and callbackIds
- // to the callback thread so it can send an empty callback
- if (!listenerCallbacks.empty()) {
- mTransactionCompletedThread.run();
- }
- for (const auto& [listener, callbackIds] : listenerCallbacks) {
- mTransactionCompletedThread.addCallback(listener, callbackIds);
+ // start and end registration for listeners w/ no surface so they can get their callback. Note
+ // that listeners with SurfaceControls will start registration during setClientStateLocked
+ // below.
+ for (const auto& listener : listenerCallbacks) {
+ mTransactionCompletedThread.startRegistration(listener);
+ mTransactionCompletedThread.endRegistration(listener);
}
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> listenerCallbacksWithSurfaces;
uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
- clientStateFlags |= setClientStateLocked(state, desiredPresentTime, listenerCallbacks,
- postTime, privileged);
+ clientStateFlags |= setClientStateLocked(state, desiredPresentTime, postTime, privileged,
+ listenerCallbacksWithSurfaces);
+ }
+
+ for (const auto& listenerCallback : listenerCallbacksWithSurfaces) {
+ mTransactionCompletedThread.endRegistration(listenerCallback);
}
// If the state doesn't require a traversal and there are callbacks, send them now
- if (!(clientStateFlags & eTraversalNeeded) && !listenerCallbacks.empty()) {
+ if (!(clientStateFlags & eTraversalNeeded) && hasListenerCallbacks) {
mTransactionCompletedThread.sendCallbacks();
}
transactionFlags |= clientStateFlags;
@@ -3981,22 +3108,30 @@
}
uint32_t SurfaceFlinger::setClientStateLocked(
- const ComposerState& composerState, int64_t desiredPresentTime,
- const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
- bool privileged) {
+ const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime,
+ bool privileged,
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks) {
const layer_state_t& s = composerState.state;
- sp<Client> client(static_cast<Client*>(composerState.client.get()));
- sp<Layer> layer(client->getLayerUser(s.surface));
+ for (auto& listener : s.listeners) {
+ // note that startRegistration will not re-register if the listener has
+ // already be registered for a prior surface control
+ mTransactionCompletedThread.startRegistration(listener);
+ listenerCallbacks.insert(listener);
+ }
+
+ sp<Layer> layer(fromHandle(s.surface));
if (layer == nullptr) {
+ for (auto& [listener, callbackIds] : s.listeners) {
+ mTransactionCompletedThread.registerUnpresentedCallbackHandle(
+ new CallbackHandle(listener, callbackIds, s.surface));
+ }
return 0;
}
uint32_t flags = 0;
const uint64_t what = s.what;
- bool geometryAppliesWithResize =
- what & layer_state_t::eGeometryAppliesWithResize;
// If we are deferring transaction, make sure to push the pending state, as otherwise the
// pending state will also be deferred.
@@ -4005,7 +3140,7 @@
}
if (what & layer_state_t::ePositionChanged) {
- if (layer->setPosition(s.x, s.y, !geometryAppliesWithResize)) {
+ if (layer->setPosition(s.x, s.y)) {
flags |= eTraversalNeeded;
}
}
@@ -4096,8 +3231,7 @@
flags |= eTraversalNeeded;
}
if (what & layer_state_t::eCropChanged_legacy) {
- if (layer->setCrop_legacy(s.crop_legacy, !geometryAppliesWithResize))
- flags |= eTraversalNeeded;
+ if (layer->setCrop_legacy(s.crop_legacy)) flags |= eTraversalNeeded;
}
if (what & layer_state_t::eCornerRadiusChanged) {
if (layer->setCornerRadius(s.cornerRadius))
@@ -4139,15 +3273,6 @@
// We don't trigger a traversal here because if no other state is
// changed, we don't want this to cause any more work
}
- if (what & layer_state_t::eReparent) {
- bool hadParent = layer->hasParent();
- if (layer->reparent(s.parentHandleForChild)) {
- if (!hadParent) {
- mCurrentState.layersSortedByZ.remove(layer);
- }
- flags |= eTransactionNeeded|eTraversalNeeded;
- }
- }
if (what & layer_state_t::eReparentChildren) {
if (layer->reparentChildren(s.reparentHandle)) {
flags |= eTransactionNeeded|eTraversalNeeded;
@@ -4208,9 +3333,22 @@
flags |= eTraversalNeeded;
}
}
+ // This has to happen after we reparent children because when we reparent to null we remove
+ // child layers from current state and remove its relative z. If the children are reparented in
+ // the same transaction, then we have to make sure we reparent the children first so we do not
+ // lose its relative z order.
+ if (what & layer_state_t::eReparent) {
+ bool hadParent = layer->hasParent();
+ if (layer->reparent(s.parentHandleForChild)) {
+ if (!hadParent) {
+ mCurrentState.layersSortedByZ.remove(layer);
+ }
+ flags |= eTransactionNeeded | eTraversalNeeded;
+ }
+ }
std::vector<sp<CallbackHandle>> callbackHandles;
- if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
- for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!s.listeners.empty())) {
+ for (auto& [listener, callbackIds] : s.listeners) {
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
}
@@ -4259,6 +3397,35 @@
return flags;
}
+status_t SurfaceFlinger::mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+ sp<IBinder>* outHandle) {
+ if (!mirrorFromHandle) {
+ return NAME_NOT_FOUND;
+ }
+
+ sp<Layer> mirrorLayer;
+ sp<Layer> mirrorFrom;
+ String8 uniqueName = getUniqueLayerName(String8("MirrorRoot"));
+
+ {
+ Mutex::Autolock _l(mStateLock);
+ mirrorFrom = fromHandle(mirrorFromHandle);
+ if (!mirrorFrom) {
+ return NAME_NOT_FOUND;
+ }
+
+ status_t result = createContainerLayer(client, uniqueName, -1, -1, 0, LayerMetadata(),
+ outHandle, &mirrorLayer);
+ if (result != NO_ERROR) {
+ return result;
+ }
+
+ mirrorLayer->mClonedChild = mirrorFrom->createClone();
+ }
+
+ return addClientLayer(client, *outHandle, nullptr, mirrorLayer, nullptr, nullptr, false);
+}
+
status_t SurfaceFlinger::createLayer(const String8& name, const sp<Client>& client, uint32_t w,
uint32_t h, PixelFormat format, uint32_t flags,
LayerMetadata metadata, sp<IBinder>* handle,
@@ -4394,8 +3561,18 @@
break;
}
- sp<BufferQueueLayer> layer = getFactory().createBufferQueueLayer(
- LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+ sp<BufferQueueLayer> layer;
+ LayerCreationArgs args =
+ LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata));
+ args.textureName = getNewTexture();
+ {
+ // Grab the SF state lock during this since it's the only safe way to access
+ // RenderEngine when creating a BufferLayerConsumer
+ // TODO: Check if this lock is still needed here
+ Mutex::Autolock lock(mStateLock);
+ layer = getFactory().createBufferQueueLayer(args);
+ }
+
status_t err = layer->setDefaultBufferProperties(w, h, format);
if (err == NO_ERROR) {
*handle = layer->getHandle();
@@ -4411,8 +3588,11 @@
uint32_t w, uint32_t h, uint32_t flags,
LayerMetadata metadata, sp<IBinder>* handle,
sp<Layer>* outLayer) {
- sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(
- LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata)));
+ LayerCreationArgs args =
+ LayerCreationArgs(this, client, name, w, h, flags, std::move(metadata));
+ args.displayDevice = getDefaultDisplayDevice();
+ args.textureName = getNewTexture();
+ sp<BufferStateLayer> layer = getFactory().createBufferStateLayer(args);
*handle = layer->getHandle();
*outLayer = layer;
@@ -4492,7 +3672,8 @@
d.width = 0;
d.height = 0;
displays.add(d);
- setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, {});
+ setTransactionState(state, displays, 0, nullptr, mPendingInputWindowCommands, -1, {}, false,
+ {});
setPowerModeInternal(display, HWC_POWER_MODE_NORMAL);
@@ -4598,7 +3779,7 @@
if (display->isPrimary()) {
mTimeStats->setPowerMode(mode);
- mRefreshRateStats.setPowerMode(mode);
+ mRefreshRateStats->setPowerMode(mode);
mScheduler->setDisplayPowerState(mode == HWC_POWER_MODE_NORMAL);
}
@@ -4649,14 +3830,10 @@
using namespace std::string_literals;
static const std::unordered_map<std::string, Dumper> dumpers = {
- {"--clear-layer-stats"s, dumper([this](std::string&) { mLayerStats.clear(); })},
- {"--disable-layer-stats"s, dumper([this](std::string&) { mLayerStats.disable(); })},
{"--display-id"s, dumper(&SurfaceFlinger::dumpDisplayIdentificationData)},
- {"--dispsync"s, dumper([this](std::string& s) {
- mScheduler->dumpPrimaryDispSync(s);
- })},
- {"--dump-layer-stats"s, dumper([this](std::string& s) { mLayerStats.dump(s); })},
- {"--enable-layer-stats"s, dumper([this](std::string&) { mLayerStats.enable(); })},
+ {"--dispsync"s,
+ dumper([this](std::string& s) { mScheduler->getPrimaryDispSync().dump(s); })},
+ {"--edid"s, argsDumper(&SurfaceFlinger::dumpRawDisplayIdentificationData)},
{"--frame-events"s, dumper(&SurfaceFlinger::dumpFrameEventsLocked)},
{"--latency"s, argsDumper(&SurfaceFlinger::dumpStatsLocked)},
{"--latency-clear"s, argsDumper(&SurfaceFlinger::clearStatsLocked)},
@@ -4669,7 +3846,8 @@
const auto flag = args.empty() ? ""s : std::string(String8(args[0]));
- if (const auto it = dumpers.find(flag); it != dumpers.end()) {
+ const auto it = dumpers.find(flag);
+ if (it != dumpers.end()) {
(it->second)(args, asProto, result);
} else if (!asProto) {
dumpAllLocked(args, result);
@@ -4679,13 +3857,17 @@
mStateLock.unlock();
}
- LayersProto layersProto = dumpProtoFromMainThread();
- if (asProto) {
- result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
- } else {
- auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- result.append(LayerProtoParser::layerTreeToString(layerTree));
- result.append("\n");
+ if (it == dumpers.end()) {
+ const LayersProto layersProto = dumpProtoFromMainThread();
+ if (asProto) {
+ result.append(layersProto.SerializeAsString());
+ } else {
+ // Dump info that we need to access from the main thread
+ const auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layerTreeToString(layerTree));
+ result.append("\n");
+ dumpOffscreenLayers(result);
+ }
}
}
write(fd, result.c_str(), result.size());
@@ -4760,24 +3942,27 @@
}
void SurfaceFlinger::dumpVSync(std::string& result) const {
+ mScheduler->dump(result);
+ StringAppendF(&result, "+ Refresh rate switching: %s\n",
+ mRefreshRateConfigs->refreshRateSwitchingSupported() ? "on" : "off");
+ StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
+
+ mRefreshRateStats->dump(result);
+ result.append("\n");
+
mPhaseOffsets->dump(result);
StringAppendF(&result,
- " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
+ " present offset: %9" PRId64 " ns\t VSYNC period: %9" PRId64 " ns\n\n",
dispSyncPresentTimeOffset, getVsyncPeriod());
- StringAppendF(&result, "Scheduler enabled.");
- StringAppendF(&result, "+ Smart 90 for video detection: %s\n\n",
- mUseSmart90ForVideo ? "on" : "off");
StringAppendF(&result, "Allowed Display Configs: ");
for (int32_t configId : mAllowedDisplayConfigs) {
- for (auto refresh : mRefreshRateConfigs.getRefreshRates()) {
- if (refresh.second && refresh.second->configId == configId) {
- StringAppendF(&result, "%dHz, ", refresh.second->fps);
- }
- }
+ StringAppendF(&result, "%" PRIu32 " Hz, ",
+ mRefreshRateConfigs->getRefreshRateFromConfigId(configId).fps);
}
StringAppendF(&result, "(config override by backdoor: %s)\n\n",
mDebugDisplayConfigSetByBackdoor ? "yes" : "no");
+
mScheduler->dump(mAppConnectionHandle, result);
}
@@ -4878,21 +4063,13 @@
}
if (!isEdid(data)) {
- result.append("unknown identification data: ");
- for (uint8_t byte : data) {
- StringAppendF(&result, "%x ", byte);
- }
- result.append("\n");
+ result.append("unknown identification data\n");
continue;
}
const auto edid = parseEdid(data);
if (!edid) {
- result.append("invalid EDID: ");
- for (uint8_t byte : data) {
- StringAppendF(&result, "%x ", byte);
- }
- result.append("\n");
+ result.append("invalid EDID\n");
continue;
}
@@ -4902,6 +4079,18 @@
}
}
+void SurfaceFlinger::dumpRawDisplayIdentificationData(const DumpArgs& args,
+ std::string& result) const {
+ hwc2_display_t hwcDisplayId;
+ uint8_t port;
+ DisplayIdentificationData data;
+
+ if (args.size() > 1 && base::ParseUint(String8(args[1]), &hwcDisplayId) &&
+ getHwComposer().getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
+ result.append(reinterpret_cast<const char*>(data.data()), data.size());
+ }
+}
+
void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
StringAppendF(&result, "Device has wide color built-in display: %d\n", hasWideColorDisplay);
StringAppendF(&result, "Device uses color management: %d\n", useColorManagement);
@@ -4940,37 +4129,53 @@
return layersProto;
}
+void SurfaceFlinger::dumpOffscreenLayersProto(LayersProto& layersProto, uint32_t traceFlags) const {
+ // Add a fake invisible root layer to the proto output and parent all the offscreen layers to
+ // it.
+ LayerProto* rootProto = layersProto.add_layers();
+ const int32_t offscreenRootLayerId = INT32_MAX - 2;
+ rootProto->set_id(offscreenRootLayerId);
+ rootProto->set_name("Offscreen Root");
+ rootProto->set_parent(-1);
+
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ // Add layer as child of the fake root
+ rootProto->add_children(offscreenLayer->sequence);
+
+ // Add layer
+ LayerProto* layerProto = layersProto.add_layers();
+ offscreenLayer->writeToProtoDrawingState(layerProto, traceFlags);
+ offscreenLayer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing,
+ traceFlags);
+ layerProto->set_parent(offscreenRootLayerId);
+
+ // Add children
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ if (layer == offscreenLayer) {
+ return;
+ }
+ LayerProto* childProto = layersProto.add_layers();
+ layer->writeToProtoDrawingState(childProto, traceFlags);
+ layer->writeToProtoCommonState(childProto, LayerVector::StateSet::Drawing, traceFlags);
+ });
+ }
+}
+
LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
LayersProto layersProto;
postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
return layersProto;
}
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
- const sp<DisplayDevice>& displayDevice) const {
- LayersProto layersProto;
-
- SizeProto* resolution = layersProto.mutable_resolution();
- resolution->set_w(displayDevice->getWidth());
- resolution->set_h(displayDevice->getHeight());
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- layersProto.set_color_mode(decodeColorMode(displayState.colorMode));
- layersProto.set_color_transform(decodeColorTransform(displayState.colorTransform));
- layersProto.set_global_transform(displayState.orientation);
-
- const auto displayId = displayDevice->getId();
- LOG_ALWAYS_FATAL_IF(!displayId);
- mDrawingState.traverseInZOrder([&](Layer* layer) {
- if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
- LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProtoCompositionState(layerProto, displayDevice);
+void SurfaceFlinger::dumpOffscreenLayers(std::string& result) {
+ result.append("Offscreen Layers:\n");
+ postMessageSync(new LambdaMessage([&]() {
+ for (Layer* offscreenLayer : mOffscreenLayers) {
+ offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
+ layer->dumpCallingUidPid(result);
+ });
}
- });
-
- return layersProto;
+ }));
}
void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) const {
@@ -5007,7 +4212,7 @@
result.append("\n\n");
colorizer.bold(result);
- result.append("VSYNC configuration:\n");
+ result.append("Scheduler:\n");
colorizer.reset(result);
dumpVSync(result);
result.append("\n");
@@ -5025,7 +4230,7 @@
* Dump the visible layer list
*/
colorizer.bold(result);
- StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers);
+ StringAppendF(&result, "Visible layers (count = %zu)\n", mNumLayers.load());
StringAppendF(&result, "GraphicBufferProducers: %zu, max %zu\n",
mGraphicBufferProducerList.size(), mMaxGraphicBufferProducerListSize);
colorizer.reset(result);
@@ -5051,6 +4256,12 @@
result.append("\n");
/*
+ * Dump CompositionEngine state
+ */
+
+ mCompositionEngine->dump(result);
+
+ /*
* Dump SurfaceFlinger global state
*/
@@ -5134,31 +4345,10 @@
result.append("\n");
}
- /**
- * Scheduler dump state.
- */
- result.append("\nScheduler state:\n");
- result.append(mScheduler->doDump() + "\n");
- StringAppendF(&result, "+ Smart video mode: %s\n\n", mUseSmart90ForVideo ? "on" : "off");
- result.append(mRefreshRateStats.doDump() + "\n");
-
result.append(mTimeStats->miniDump());
result.append("\n");
}
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
- // Note: mStateLock is held here
- for (const auto& [token, display] : mDisplays) {
- if (display->getId() == displayId) {
- return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
- }
- }
-
- ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
- static const Vector<sp<Layer>> empty;
- return empty;
-}
-
void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix;
if (mGlobalSaturationFactor != 1.0f) {
@@ -5251,7 +4441,18 @@
case SET_DISPLAY_BRIGHTNESS: {
return OK;
}
- case CAPTURE_LAYERS:
+ case CAPTURE_LAYERS: {
+ IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ // allow media to capture layer for video thumbnails
+ if ((uid != AID_GRAPHICS && uid != AID_MEDIA) &&
+ !PermissionCache::checkPermission(sReadFramebuffer, pid, uid)) {
+ ALOGE("Permission Denial: can't capture layer pid=%d, uid=%d", pid, uid);
+ return PERMISSION_DENIED;
+ }
+ return OK;
+ }
case CAPTURE_SCREEN:
case ADD_REGION_SAMPLING_LISTENER:
case REMOVE_REGION_SAMPLING_LISTENER: {
@@ -5427,13 +4628,8 @@
updateColorMatrixLocked();
return NO_ERROR;
}
- // This is an experimental interface
- // Needs to be shifted to proper binder interface when we productize
- case 1016: {
- n = data.readInt32();
- // TODO(b/113612090): Evaluate if this can be removed.
- mScheduler->setRefreshSkipCount(n);
- return NO_ERROR;
+ case 1016: { // Unused.
+ return NAME_NOT_FOUND;
}
case 1017: {
n = data.readInt32();
@@ -5527,13 +4723,13 @@
DisplayColorSetting setting = static_cast<DisplayColorSetting>(data.readInt32());
switch (setting) {
- case DisplayColorSetting::MANAGED:
+ case DisplayColorSetting::kManaged:
reply->writeBool(useColorManagement);
break;
- case DisplayColorSetting::UNMANAGED:
+ case DisplayColorSetting::kUnmanaged:
reply->writeBool(true);
break;
- case DisplayColorSetting::ENHANCED:
+ case DisplayColorSetting::kEnhanced:
reply->writeBool(display->hasRenderIntent(RenderIntent::ENHANCE));
break;
default: // vendor display color setting
@@ -5611,7 +4807,8 @@
case 1034: {
// TODO(b/129297325): expose this via developer menu option
n = data.readInt32();
- if (n && !mRefreshRateOverlay) {
+ if (n && !mRefreshRateOverlay &&
+ mRefreshRateConfigs->refreshRateSwitchingSupported()) {
RefreshRateType type;
{
std::lock_guard<std::mutex> lock(mActiveConfigLock);
@@ -5833,10 +5030,13 @@
drawLayers();
} else {
Rect bounds = getBounds();
- screenshotParentLayer = mFlinger->getFactory().createContainerLayer(
- LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
- bounds.getWidth(), bounds.getHeight(), 0,
- LayerMetadata()));
+ // In the "childrenOnly" case we reparent the children to a screenshot
+ // layer which has no properties set and which does not draw.
+ sp<ContainerLayer> screenshotParentLayer =
+ mFlinger->getFactory().createContainerLayer(
+ LayerCreationArgs(mFlinger, nullptr, String8("Screenshot Parent"),
+ bounds.getWidth(), bounds.getHeight(), 0,
+ LayerMetadata()));
ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
drawLayers();
@@ -5847,9 +5047,6 @@
const sp<Layer> mLayer;
const Rect mCrop;
- // In the "childrenOnly" case we reparent the children to a screenshot
- // layer which has no properties set and which does not draw.
- sp<ContainerLayer> screenshotParentLayer;
ui::Transform mTransform;
bool mNeedsFiltering;
@@ -6108,11 +5305,19 @@
Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- renderengine::LayerSettings layerSettings;
- bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
- false, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ const bool supportProtectedContent = false;
+ Region clip(renderArea.getBounds());
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
});
@@ -6210,15 +5415,28 @@
mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value,
display->getActiveConfig());
- // Set the highest allowed config by iterating backwards on available refresh rates
- const auto& refreshRates = mRefreshRateConfigs.getRefreshRates();
- for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
- if (iter->second && isDisplayConfigAllowed(iter->second->configId)) {
- ALOGV("switching to config %d", iter->second->configId);
- setDesiredActiveConfig(
- {iter->first, iter->second->configId, Scheduler::ConfigEvent::Changed});
- break;
+ if (mRefreshRateConfigs->refreshRateSwitchingSupported()) {
+ const auto& type = mScheduler->getPreferredRefreshRateType();
+ const auto& config = mRefreshRateConfigs->getRefreshRateFromType(type);
+ if (isDisplayConfigAllowed(config.configId)) {
+ ALOGV("switching to Scheduler preferred config %d", config.configId);
+ setDesiredActiveConfig({type, config.configId, Scheduler::ConfigEvent::Changed});
+ } else {
+ // Set the highest allowed config by iterating backwards on available refresh rates
+ const auto& refreshRates = mRefreshRateConfigs->getRefreshRateMap();
+ for (auto iter = refreshRates.crbegin(); iter != refreshRates.crend(); ++iter) {
+ if (isDisplayConfigAllowed(iter->second.configId)) {
+ ALOGV("switching to allowed config %d", iter->second.configId);
+ setDesiredActiveConfig(
+ {iter->first, iter->second.configId, Scheduler::ConfigEvent::Changed});
+ break;
+ }
+ }
}
+ } else if (!allowedConfigs.empty()) {
+ ALOGV("switching to config %d", allowedConfigs[0]);
+ setDesiredActiveConfig(
+ {RefreshRateType::DEFAULT, allowedConfigs[0], Scheduler::ConfigEvent::Changed});
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5778be6..a9a4276 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -23,12 +23,14 @@
*/
#include <android-base/thread_annotations.h>
+#include <compositionengine/OutputColorSetting.h>
#include <cutils/atomic.h>
#include <cutils/compiler.h>
#include <gui/BufferQueue.h>
#include <gui/FrameTimestamps.h>
#include <gui/ISurfaceComposer.h>
#include <gui/ISurfaceComposerClient.h>
+#include <gui/ITransactionCompletedListener.h>
#include <gui/LayerState.h>
#include <gui/OccupancyTracker.h>
#include <hardware/hwcomposer_defs.h>
@@ -52,7 +54,6 @@
#include "DisplayHardware/PowerAdvisor.h"
#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
-#include "LayerStats.h"
#include "LayerVector.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
@@ -60,6 +61,7 @@
#include "Scheduler/VSyncModulator.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceTracing.h"
+#include "TracedOrdinal.h"
#include "TransactionCompletedThread.h"
#include <atomic>
@@ -68,6 +70,7 @@
#include <map>
#include <memory>
#include <mutex>
+#include <optional>
#include <queue>
#include <set>
#include <string>
@@ -86,15 +89,18 @@
class HWComposer;
class IGraphicBufferProducer;
class IInputFlinger;
-class InjectVSyncSource;
class Layer;
class MessageBase;
class RefreshRateOverlay;
class RegionSamplingThread;
class TimeStats;
+class FrameTracer;
namespace compositionengine {
class DisplaySurface;
+class OutputLayer;
+
+struct CompositionRefreshArgs;
} // namespace compositionengine
namespace renderengine {
@@ -114,11 +120,7 @@
eTransactionMask = 0x1f,
};
-enum class DisplayColorSetting : int32_t {
- MANAGED = 0,
- UNMANAGED = 1,
- ENHANCED = 2,
-};
+using DisplayColorSetting = compositionengine::OutputColorSetting;
class SurfaceFlingerBE
{
@@ -296,22 +298,13 @@
// main thread function to enable/disable h/w composer event
void setPrimaryVsyncEnabledInternal(bool enabled);
+ void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
// called on the main thread by MessageQueue when an internal message
// is received
// TODO: this should be made accessible only to MessageQueue
void onMessageReceived(int32_t what);
- // populates the expected present time for this frame.
- // When we are in negative offsets, we perform a correction so that the
- // predicted vsync for the *next* frame is used instead.
- void populateExpectedPresentTime();
- nsecs_t getExpectedPresentTime() const { return mExpectedPresentTime; }
-
- // for debugging only
- // TODO: this should be made accessible only to HWComposer
- const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
-
renderengine::RenderEngine& getRenderEngine() const;
bool authenticateSurfaceTextureLocked(
@@ -353,9 +346,11 @@
static const size_t MAX_LAYERS = 4096;
static const int MAX_TRACING_MEMORY = 100 * 1024 * 1024; // 100MB
+protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
+private:
/* ------------------------------------------------------------------------
* Internal data structures
*/
@@ -406,6 +401,7 @@
const sp<IBinder>& applyToken,
const InputWindowCommands& inputWindowCommands,
int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
+ bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks) override;
void bootFinished() override;
bool authenticateSurfaceTexture(
@@ -554,9 +550,9 @@
void updateInputFlinger();
void updateInputWindowInfo();
void commitInputWindowCommands() REQUIRES(mStateLock);
- void executeInputWindowCommands();
void setInputWindowsFinished();
void updateCursorAsync();
+ void initScheduler(DisplayId primaryDisplayId);
/* handlePageFlip - latch a new buffer if available and compute the dirty
* region. Returns whether a new buffer has been latched, i.e., whether it
@@ -571,10 +567,10 @@
const Vector<DisplayState>& displays, uint32_t flags,
const InputWindowCommands& inputWindowCommands,
const int64_t desiredPresentTime,
- const client_cache_t& uncacheBuffer,
+ const client_cache_t& uncacheBuffer, const int64_t postTime,
+ bool privileged, bool hasListenerCallbacks,
const std::vector<ListenerCallbacks>& listenerCallbacks,
- const int64_t postTime, bool privileged, bool isMainThread = false)
- REQUIRES(mStateLock);
+ bool isMainThread = false) REQUIRES(mStateLock);
// Returns true if at least one transaction was flushed
bool flushTransactionQueues();
// Returns true if there is at least one transaction that needs to be flushed
@@ -584,19 +580,24 @@
// Can only be called from the main thread or with mStateLock held
uint32_t setTransactionFlags(uint32_t flags);
uint32_t setTransactionFlags(uint32_t flags, Scheduler::TransactionStart transactionStart);
- void latchAndReleaseBuffer(const sp<Layer>& layer);
void commitTransaction() REQUIRES(mStateLock);
void commitOffscreenLayers();
- bool containsAnyInvalidClientState(const Vector<ComposerState>& states);
bool transactionIsReadyToBeApplied(int64_t desiredPresentTime,
+ bool useCachedExpectedPresentTime,
const Vector<ComposerState>& states);
- uint32_t setClientStateLocked(const ComposerState& composerState, int64_t desiredPresentTime,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- int64_t postTime, bool privileged) REQUIRES(mStateLock);
uint32_t setDisplayStateLocked(const DisplayState& s) REQUIRES(mStateLock);
uint32_t addInputWindowCommands(const InputWindowCommands& inputWindowCommands)
REQUIRES(mStateLock);
+protected:
+ virtual uint32_t setClientStateLocked(
+ const ComposerState& composerState, int64_t desiredPresentTime, int64_t postTime,
+ bool privileged,
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash>& listenerCallbacks)
+ REQUIRES(mStateLock);
+ virtual void commitTransactionLocked();
+
+private:
/* ------------------------------------------------------------------------
* Layer management
*/
@@ -622,6 +623,9 @@
uint32_t h, uint32_t flags, LayerMetadata metadata,
sp<IBinder>* outHandle, sp<Layer>* outLayer);
+ status_t mirrorLayer(const sp<Client>& client, const sp<IBinder>& mirrorFromHandle,
+ sp<IBinder>* outHandle);
+
String8 getUniqueLayerName(const String8& name);
// called when all clients have released all their references to
@@ -749,53 +753,15 @@
* Compositing
*/
void invalidateHwcGeometry();
- void computeVisibleRegions(const sp<const DisplayDevice>& display, Region& dirtyRegion,
- Region& opaqueRegion);
- void preComposition();
void postComposition();
void getCompositorTiming(CompositorTiming* compositorTiming);
void updateCompositorTiming(const DisplayStatInfo& stats, nsecs_t compositeTime,
std::shared_ptr<FenceTime>& presentFenceTime);
void setCompositorTimingSnapped(const DisplayStatInfo& stats,
nsecs_t compositeToPresentLatency);
- void rebuildLayerStacks();
- ui::Dataspace getBestDataspace(const sp<DisplayDevice>& display, ui::Dataspace* outHdrDataSpace,
- bool* outIsHdrClientComposition) const;
-
- // Returns the appropriate ColorMode, Dataspace and RenderIntent for the
- // DisplayDevice. The function only returns the supported ColorMode,
- // Dataspace and RenderIntent.
- void pickColorMode(const sp<DisplayDevice>& display, ui::ColorMode* outMode,
- ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
-
- void calculateWorkingSet();
- /*
- * beginFrame - This function handles any pre-frame processing that needs to be
- * prior to any CompositionInfo handling and is not dependent on data in
- * CompositionInfo
- */
- void beginFrame(const sp<DisplayDevice>& display);
- /* prepareFrame - This function will call into the DisplayDevice to prepare a
- * frame after CompositionInfo has been programmed. This provides a mechanism
- * to prepare the hardware composer
- */
- void prepareFrame(const sp<DisplayDevice>& display);
- void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
- void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
- void logLayerStats();
- void doDisplayComposition(const sp<DisplayDevice>& display, const Region& dirtyRegion);
-
- // 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();
- void drawWormhole(const Region& region) const;
/* ------------------------------------------------------------------------
* Display management
@@ -819,7 +785,13 @@
// the desired refresh rate.
void setRefreshRateTo(RefreshRateType, Scheduler::ConfigEvent event) REQUIRES(mStateLock);
- bool isDisplayConfigAllowed(int32_t configId) REQUIRES(mStateLock);
+ bool isDisplayConfigAllowed(int32_t configId) const REQUIRES(mStateLock);
+
+ bool previousFrameMissed(int graceTimeMs = 0);
+
+ // Populates the expected present time for this frame. For negative offsets, performs a
+ // correction using the predicted vsync for the next frame instead.
+ void populateExpectedPresentTime();
/*
* Display identification
@@ -849,9 +821,6 @@
return hwcDisplayId ? getHwComposer().toPhysicalDisplayId(*hwcDisplayId) : std::nullopt;
}
- bool previousFrameMissed(int graceTimeMs = 0);
- void setVsyncEnabledInHWC(DisplayId displayId, HWC2::Vsync enabled);
-
/*
* Debugging & dumpsys
*/
@@ -900,12 +869,15 @@
std::vector<OccupancyTracker::Segment>&& history);
void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const;
+ void dumpRawDisplayIdentificationData(const DumpArgs&, std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ void dumpOffscreenLayersProto(LayersProto& layersProto,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
EXCLUDES(mStateLock);
+ void dumpOffscreenLayers(std::string& result) EXCLUDES(mStateLock);
void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
- LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
bool isLayerTripleBufferingDisabled() const {
return this->mLayerTripleBufferingDisabled;
@@ -966,13 +938,6 @@
// constant members (no synchronization needed for access)
const nsecs_t mBootTime = systemTime();
bool mGpuToCpuSupported = false;
- std::unique_ptr<EventThread> mInjectorEventThread;
- std::unique_ptr<InjectVSyncSource> mVSyncInjector;
-
- // Calculates correct offsets.
- VSyncModulator mVsyncModulator;
- // Keeps track of all available phase offsets for different refresh types.
- const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
// Can only accessed from the main thread, these members
// don't need synchronization
@@ -1027,8 +992,8 @@
SurfaceTracing mTracing{*this};
bool mTracingEnabled = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
- LayerStats mLayerStats;
const std::shared_ptr<TimeStats> mTimeStats;
+ const std::unique_ptr<FrameTracer> mFrameTracer;
bool mUseHwcVirtualDisplays = false;
std::atomic<uint32_t> mFrameMissedCount = 0;
std::atomic<uint32_t> mHwcFrameMissedCount = 0;
@@ -1058,47 +1023,42 @@
uint32_t mTexturePoolSize = 0;
std::vector<uint32_t> mTexturePool;
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& strongPointer) const {
- return std::hash<IBinder*>{}(strongPointer.get());
- }
- };
struct TransactionState {
TransactionState(const Vector<ComposerState>& composerStates,
const Vector<DisplayState>& displayStates, uint32_t transactionFlags,
int64_t desiredPresentTime, const client_cache_t& uncacheBuffer,
- const std::vector<ListenerCallbacks>& listenerCallbacks, int64_t postTime,
- bool privileged)
+ int64_t postTime, bool privileged, bool hasListenerCallbacks,
+ std::vector<ListenerCallbacks> listenerCallbacks)
: states(composerStates),
displays(displayStates),
flags(transactionFlags),
desiredPresentTime(desiredPresentTime),
buffer(uncacheBuffer),
- callback(listenerCallbacks),
postTime(postTime),
- privileged(privileged) {}
+ privileged(privileged),
+ hasListenerCallbacks(hasListenerCallbacks),
+ listenerCallbacks(listenerCallbacks) {}
Vector<ComposerState> states;
Vector<DisplayState> displays;
uint32_t flags;
const int64_t desiredPresentTime;
client_cache_t buffer;
- std::vector<ListenerCallbacks> callback;
const int64_t postTime;
bool privileged;
+ bool hasListenerCallbacks;
+ std::vector<ListenerCallbacks> listenerCallbacks;
};
- std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IBinderHash> mTransactionQueues;
+ std::unordered_map<sp<IBinder>, std::queue<TransactionState>, IListenerHash> mTransactionQueues;
/* ------------------------------------------------------------------------
* Feature prototyping
*/
- bool mInjectVSyncs = false;
-
// Static screen stats
bool mHasPoweredOff = false;
- size_t mNumLayers = 0;
+ std::atomic<size_t> mNumLayers = 0;
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
@@ -1112,7 +1072,7 @@
static bool useVrFlinger;
std::thread::id mMainThreadId = std::this_thread::get_id();
- DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
+ DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::kEnhanced;
// Color mode forced by setting persist.sys.sf.color_mode, it must:
// 1. not be NATIVE color mode, NATIVE color mode means no forced color mode;
@@ -1135,11 +1095,19 @@
*/
bool mUseSmart90ForVideo = false;
std::unique_ptr<Scheduler> mScheduler;
- sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
- sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+ scheduler::ConnectionHandle mAppConnectionHandle;
+ scheduler::ConnectionHandle mSfConnectionHandle;
- scheduler::RefreshRateConfigs mRefreshRateConfigs;
- scheduler::RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, *mTimeStats};
+ // Stores phase offsets configured per refresh rate.
+ const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
+
+ // Optional to defer construction until scheduler connections are created.
+ std::optional<scheduler::VSyncModulator> mVSyncModulator;
+
+ std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
+
+ std::atomic<nsecs_t> mExpectedPresentTime = 0;
// All configs are allowed if the set is empty.
using DisplayConfigs = std::set<int32_t>;
@@ -1154,7 +1122,8 @@
ActiveConfigInfo mDesiredActiveConfig GUARDED_BY(mActiveConfigLock);
// below flags are set by main thread only
- bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
+ TracedOrdinal<bool> mDesiredActiveConfigChanged
+ GUARDED_BY(mActiveConfigLock) = {"DesiredActiveConfigChanged", false};
bool mCheckPendingFence = false;
bool mLumaSampling = true;
@@ -1194,8 +1163,6 @@
// Flags to capture the state of Vsync in HWC
HWC2::Vsync mHWCVsyncState = HWC2::Vsync::Disable;
HWC2::Vsync mHWCVsyncPendingState = HWC2::Vsync::Disable;
-
- nsecs_t mExpectedPresentTime;
};
} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index e425b2a..4ddc132 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -35,7 +35,6 @@
#include "Scheduler/MessageQueue.h"
#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/Scheduler.h"
-#include "TimeStats/TimeStats.h"
namespace android::surfaceflinger {
@@ -45,19 +44,13 @@
Factory() = default;
~Factory() = default;
- std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework,
- int64_t dispSyncPresentTimeOffset) override {
- // Note: We create a local temporary with the real DispSync implementation
- // type temporarily so we can initialize it with the configured values,
- // before storing it for more generic use using the interface type.
- auto primaryDispSync = std::make_unique<android::impl::DispSync>(name);
- primaryDispSync->init(hasSyncFramework, dispSyncPresentTimeOffset);
- return primaryDispSync;
+ std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) override {
+ return std::make_unique<android::impl::DispSync>(name, hasSyncFramework);
}
std::unique_ptr<EventControlThread> createEventControlThread(
- std::function<void(bool)> setVSyncEnabled) override {
- return std::make_unique<android::impl::EventControlThread>(setVSyncEnabled);
+ SetVSyncEnabled setVSyncEnabled) override {
+ return std::make_unique<android::impl::EventControlThread>(std::move(setVSyncEnabled));
}
std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) override {
@@ -74,9 +67,9 @@
}
std::unique_ptr<Scheduler> createScheduler(
- std::function<void(bool)> callback,
- const scheduler::RefreshRateConfigs& refreshRateConfig) override {
- return std::make_unique<Scheduler>(callback, refreshRateConfig);
+ SetVSyncEnabled setVSyncEnabled,
+ const scheduler::RefreshRateConfigs& configs) override {
+ return std::make_unique<Scheduler>(std::move(setVSyncEnabled), configs);
}
std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(
@@ -129,10 +122,6 @@
sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) override {
return new ColorLayer(args);
}
-
- std::shared_ptr<TimeStats> createTimeStats() override {
- return std::make_shared<android::impl::TimeStats>();
- }
};
static Factory factory;
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index c2bc808..3fd4de8 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -44,7 +44,6 @@
class StartPropertySetThread;
class SurfaceFlinger;
class SurfaceInterceptor;
-class TimeStats;
struct DisplayDeviceCreationArgs;
struct LayerCreationArgs;
@@ -55,7 +54,9 @@
namespace scheduler {
class PhaseOffsets;
+class RefreshRateConfigs;
} // namespace scheduler
+
namespace surfaceflinger {
class NativeWindowSurface;
@@ -64,16 +65,15 @@
// of each interface.
class Factory {
public:
- virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework,
- int64_t dispSyncPresentTimeOffset) = 0;
- virtual std::unique_ptr<EventControlThread> createEventControlThread(
- std::function<void(bool)> setVSyncEnabled) = 0;
+ using SetVSyncEnabled = std::function<void(bool)>;
+
+ virtual std::unique_ptr<DispSync> createDispSync(const char* name, bool hasSyncFramework) = 0;
+ virtual std::unique_ptr<EventControlThread> createEventControlThread(SetVSyncEnabled) = 0;
virtual std::unique_ptr<HWComposer> createHWComposer(const std::string& serviceName) = 0;
virtual std::unique_ptr<MessageQueue> createMessageQueue() = 0;
virtual std::unique_ptr<scheduler::PhaseOffsets> createPhaseOffsets() = 0;
- virtual std::unique_ptr<Scheduler> createScheduler(
- std::function<void(bool)> callback,
- const scheduler::RefreshRateConfigs& refreshRateConfig) = 0;
+ virtual std::unique_ptr<Scheduler> createScheduler(SetVSyncEnabled,
+ const scheduler::RefreshRateConfigs&) = 0;
virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
@@ -95,8 +95,6 @@
virtual sp<ColorLayer> createColorLayer(const LayerCreationArgs& args) = 0;
virtual sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) = 0;
- virtual std::shared_ptr<TimeStats> createTimeStats() = 0;
-
protected:
~Factory() = default;
};
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 768074a..b4716eb 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -226,6 +226,14 @@
return static_cast<int64_t>(defaultValue);
}
+bool refresh_rate_switching(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::refresh_rate_switching();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
int32_t set_idle_timer_ms(int32_t defaultValue) {
auto temp = SurfaceFlingerProperties::set_idle_timer_ms();
if (temp.has_value()) {
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 5f88322..e394cca 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -73,6 +73,8 @@
int64_t color_space_agnostic_dataspace(
android::hardware::graphics::common::V1_2::Dataspace defaultValue);
+bool refresh_rate_switching(bool defaultValue);
+
int32_t set_idle_timer_ms(int32_t defaultValue);
int32_t set_touch_timer_ms(int32_t defaultValue);
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 7bfe033..a02d14c 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -116,7 +116,14 @@
layer->mCurrentState.frameNumber_legacy);
}
addOverrideScalingModeLocked(transaction, layerId, layer->getEffectiveScalingMode());
- addFlagsLocked(transaction, layerId, layer->mCurrentState.flags);
+ addFlagsLocked(transaction, layerId, layer->mCurrentState.flags,
+ layer_state_t::eLayerHidden | layer_state_t::eLayerOpaque |
+ layer_state_t::eLayerSecure);
+ addReparentLocked(transaction, layerId, getLayerIdFromWeakRef(layer->mCurrentParent));
+ addDetachChildrenLocked(transaction, layerId, layer->isLayerDetached());
+ addRelativeParentLocked(transaction, layerId,
+ getLayerIdFromWeakRef(layer->mCurrentState.zOrderRelativeOf),
+ layer->mCurrentState.z);
}
void SurfaceInterceptor::addInitialDisplayStateLocked(Increment* increment,
@@ -150,7 +157,7 @@
return NO_ERROR;
}
-const sp<const Layer> SurfaceInterceptor::getLayer(const wp<const IBinder>& weakHandle) {
+const sp<const Layer> SurfaceInterceptor::getLayer(const wp<const IBinder>& weakHandle) const {
const sp<const IBinder>& handle(weakHandle.promote());
const auto layerHandle(static_cast<const Layer::Handle*>(handle.get()));
const sp<const Layer> layer(layerHandle->owner.promote());
@@ -158,14 +165,31 @@
return layer;
}
-const std::string SurfaceInterceptor::getLayerName(const sp<const Layer>& layer) {
+const std::string SurfaceInterceptor::getLayerName(const sp<const Layer>& layer) const {
return layer->getName().string();
}
-int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) {
+int32_t SurfaceInterceptor::getLayerId(const sp<const Layer>& layer) const {
return layer->sequence;
}
+int32_t SurfaceInterceptor::getLayerIdFromWeakRef(const wp<const Layer>& layer) const {
+ if (layer == nullptr) {
+ return -1;
+ }
+ auto strongLayer = layer.promote();
+ return strongLayer == nullptr ? -1 : getLayerId(strongLayer);
+}
+
+int32_t SurfaceInterceptor::getLayerIdFromHandle(const sp<const IBinder>& handle) const {
+ if (handle == nullptr) {
+ return -1;
+ }
+ const auto layerHandle(static_cast<const Layer::Handle*>(handle.get()));
+ const sp<const Layer> layer(layerHandle->owner.promote());
+ return layer == nullptr ? -1 : getLayerId(layer);
+}
+
Increment* SurfaceInterceptor::createTraceIncrementLocked() {
Increment* increment(mTrace.add_increment());
increment->set_time_stamp(systemTime());
@@ -252,24 +276,23 @@
}
}
-void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerId,
- uint8_t flags)
-{
+void SurfaceInterceptor::addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags,
+ uint8_t mask) {
// There can be multiple flags changed
- if (flags & layer_state_t::eLayerHidden) {
+ if (mask & layer_state_t::eLayerHidden) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
HiddenFlagChange* flagChange(change->mutable_hidden_flag());
- flagChange->set_hidden_flag(true);
+ flagChange->set_hidden_flag(flags & layer_state_t::eLayerHidden);
}
- if (flags & layer_state_t::eLayerOpaque) {
+ if (mask & layer_state_t::eLayerOpaque) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
OpaqueFlagChange* flagChange(change->mutable_opaque_flag());
- flagChange->set_opaque_flag(true);
+ flagChange->set_opaque_flag(flags & layer_state_t::eLayerOpaque);
}
- if (flags & layer_state_t::eLayerSecure) {
+ if (mask & layer_state_t::eLayerSecure) {
SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
SecureFlagChange* flagChange(change->mutable_secure_flag());
- flagChange->set_secure_flag(true);
+ flagChange->set_secure_flag(flags & layer_state_t::eLayerSecure);
}
}
@@ -320,6 +343,35 @@
overrideChange->set_override_scaling_mode(overrideScalingMode);
}
+void SurfaceInterceptor::addReparentLocked(Transaction* transaction, int32_t layerId,
+ int32_t parentId) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ ReparentChange* overrideChange(change->mutable_reparent());
+ overrideChange->set_parent_id(parentId);
+}
+
+void SurfaceInterceptor::addReparentChildrenLocked(Transaction* transaction, int32_t layerId,
+ int32_t parentId) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ ReparentChildrenChange* overrideChange(change->mutable_reparent_children());
+ overrideChange->set_parent_id(parentId);
+}
+
+void SurfaceInterceptor::addDetachChildrenLocked(Transaction* transaction, int32_t layerId,
+ bool detached) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ DetachChildrenChange* overrideChange(change->mutable_detach_children());
+ overrideChange->set_detach_children(detached);
+}
+
+void SurfaceInterceptor::addRelativeParentLocked(Transaction* transaction, int32_t layerId,
+ int32_t parentId, int z) {
+ SurfaceChange* change(createSurfaceChangeLocked(transaction, layerId));
+ RelativeParentChange* overrideChange(change->mutable_relative_parent());
+ overrideChange->set_relative_parent_id(parentId);
+ overrideChange->set_z(z);
+}
+
void SurfaceInterceptor::addSurfaceChangesLocked(Transaction* transaction,
const layer_state_t& state)
{
@@ -351,7 +403,7 @@
addTransparentRegionLocked(transaction, layerId, state.transparentRegion);
}
if (state.what & layer_state_t::eFlagsChanged) {
- addFlagsLocked(transaction, layerId, state.flags);
+ addFlagsLocked(transaction, layerId, state.flags, state.mask);
}
if (state.what & layer_state_t::eLayerStackChanged) {
addLayerStackLocked(transaction, layerId, state.layerStack);
@@ -380,6 +432,19 @@
if (state.what & layer_state_t::eOverrideScalingModeChanged) {
addOverrideScalingModeLocked(transaction, layerId, state.overrideScalingMode);
}
+ if (state.what & layer_state_t::eReparent) {
+ addReparentLocked(transaction, layerId, getLayerIdFromHandle(state.parentHandleForChild));
+ }
+ if (state.what & layer_state_t::eReparentChildren) {
+ addReparentChildrenLocked(transaction, layerId, getLayerIdFromHandle(state.reparentHandle));
+ }
+ if (state.what & layer_state_t::eDetachChildren) {
+ addDetachChildrenLocked(transaction, layerId, true);
+ }
+ if (state.what & layer_state_t::eRelativeLayerChanged) {
+ addRelativeParentLocked(transaction, layerId,
+ getLayerIdFromHandle(state.relativeLayerHandle), state.z);
+ }
}
void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 563a44c..6858c4d 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -39,8 +39,14 @@
struct DisplayDeviceState;
struct DisplayState;
struct layer_state_t;
+using Transaction = surfaceflinger::Transaction;
+using Trace = surfaceflinger::Trace;
+using Rectangle = surfaceflinger::Rectangle;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Increment = surfaceflinger::Increment;
+using DisplayChange = surfaceflinger::DisplayChange;
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
class SurfaceInterceptor {
public:
@@ -116,9 +122,11 @@
void addInitialDisplayStateLocked(Increment* increment, const DisplayDeviceState& display);
status_t writeProtoFileLocked();
- const sp<const Layer> getLayer(const wp<const IBinder>& weakHandle);
- const std::string getLayerName(const sp<const Layer>& layer);
- int32_t getLayerId(const sp<const Layer>& layer);
+ const sp<const Layer> getLayer(const wp<const IBinder>& weakHandle) const;
+ const std::string getLayerName(const sp<const Layer>& layer) const;
+ int32_t getLayerId(const sp<const Layer>& layer) const;
+ int32_t getLayerIdFromWeakRef(const wp<const Layer>& layer) const;
+ int32_t getLayerIdFromHandle(const sp<const IBinder>& weakHandle) const;
Increment* createTraceIncrementLocked();
void addSurfaceCreationLocked(Increment* increment, const sp<const Layer>& layer);
@@ -141,7 +149,7 @@
const layer_state_t::matrix22_t& matrix);
void addTransparentRegionLocked(Transaction* transaction, int32_t layerId,
const Region& transRegion);
- void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags);
+ void addFlagsLocked(Transaction* transaction, int32_t layerId, uint8_t flags, uint8_t mask);
void addLayerStackLocked(Transaction* transaction, int32_t layerId, uint32_t layerStack);
void addCropLocked(Transaction* transaction, int32_t layerId, const Rect& rect);
void addCornerRadiusLocked(Transaction* transaction, int32_t layerId, float cornerRadius);
@@ -153,6 +161,11 @@
void addTransactionLocked(Increment* increment, const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays,
const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags);
+ void addReparentLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
+ void addReparentChildrenLocked(Transaction* transaction, int32_t layerId, int32_t parentId);
+ void addDetachChildrenLocked(Transaction* transaction, int32_t layerId, bool detached);
+ void addRelativeParentLocked(Transaction* transaction, int32_t layerId, int32_t parentId,
+ int z);
// Add display transactions to the trace
DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
@@ -176,6 +189,7 @@
};
} // namespace impl
+
} // namespace android
#endif // ANDROID_SURFACEINTERCEPTOR_H
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index 9053f2c..eb26cd0 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -163,6 +163,7 @@
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
+ mFlinger.dumpOffscreenLayersProto(layers);
entry.mutable_layers()->Swap(&layers);
return entry;
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 4773307..18524f0 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -61,7 +61,7 @@
void setTraceFlags(uint32_t flags);
private:
- static constexpr auto kDefaultBufferCapInByte = 100_MB;
+ static constexpr auto kDefaultBufferCapInByte = 5_MB;
static constexpr auto kDefaultFileName = "/data/misc/wmtrace/layers_trace.pb";
class LayersTraceBuffer { // ring buffer
diff --git a/services/surfaceflinger/TimeStats/Android.bp b/services/surfaceflinger/TimeStats/Android.bp
new file mode 100644
index 0000000..2080a38
--- /dev/null
+++ b/services/surfaceflinger/TimeStats/Android.bp
@@ -0,0 +1,12 @@
+cc_library_static {
+ name: "libtimestats",
+ defaults: ["surfaceflinger_defaults"],
+ srcs: [
+ "TimeStats.cpp",
+ ],
+ export_include_dirs: ["."],
+ shared_libs: [
+ "libtimestats_proto",
+ "libui",
+ ],
+}
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index c97a19b..3df8360 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -34,6 +34,14 @@
namespace impl {
+TimeStats::TimeStats() {
+ // Temporarily enable TimeStats by default. Telemetry is disabled while
+ // we move onto statsd, so TimeStats is currently not exercised at all
+ // during testing.
+ // TODO: remove this.
+ enable();
+}
+
void TimeStats::parseArgs(bool asProto, const Vector<String16>& args, std::string& result) {
ATRACE_CALL();
@@ -72,8 +80,10 @@
std::string result = "TimeStats miniDump:\n";
std::lock_guard<std::mutex> lock(mMutex);
- android::base::StringAppendF(&result, "Number of tracked layers is %zu\n",
+ android::base::StringAppendF(&result, "Number of layers currently being tracked is %zu\n",
mTimeStatsTracker.size());
+ android::base::StringAppendF(&result, "Number of layers in the stats pool is %zu\n",
+ mTimeStats.stats.size());
return result;
}
@@ -173,8 +183,8 @@
ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
- const std::string& layerName = layerRecord.layerName;
if (prevTimeRecord.ready) {
+ const std::string& layerName = layerRecord.layerName;
if (!mTimeStats.stats.count(layerName)) {
mTimeStats.stats[layerName].layerName = layerName;
mTimeStats.stats[layerName].packageName = getPackageName(layerName);
@@ -220,18 +230,6 @@
timeRecords[0].frameTime.frameNumber, presentToPresentMs);
timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
}
-
- // Output additional trace points to track frame time.
- ATRACE_INT64(("TimeStats-Post - " + layerName).c_str(), timeRecords[0].frameTime.postTime);
- ATRACE_INT64(("TimeStats-Acquire - " + layerName).c_str(),
- timeRecords[0].frameTime.acquireTime);
- ATRACE_INT64(("TimeStats-Latch - " + layerName).c_str(),
- timeRecords[0].frameTime.latchTime);
- ATRACE_INT64(("TimeStats-Desired - " + layerName).c_str(),
- timeRecords[0].frameTime.desiredTime);
- ATRACE_INT64(("TimeStats-Present - " + layerName).c_str(),
- timeRecords[0].frameTime.presentTime);
-
prevTimeRecord = timeRecords[0];
timeRecords.pop_front();
layerRecord.waitData--;
@@ -262,6 +260,9 @@
postTime);
std::lock_guard<std::mutex> lock(mMutex);
+ if (!mTimeStats.stats.count(layerName) && mTimeStats.stats.size() >= MAX_NUM_LAYER_STATS) {
+ return;
+ }
if (!mTimeStatsTracker.count(layerID) && mTimeStatsTracker.size() < MAX_NUM_LAYER_RECORDS &&
layerNameIsValid(layerName)) {
mTimeStatsTracker[layerID].layerName = layerName;
@@ -414,13 +415,9 @@
}
void TimeStats::onDestroy(int32_t layerID) {
- if (!mEnabled.load()) return;
-
ATRACE_CALL();
ALOGV("[%d]-onDestroy", layerID);
-
std::lock_guard<std::mutex> lock(mMutex);
- if (!mTimeStatsTracker.count(layerID)) return;
mTimeStatsTracker.erase(layerID);
}
@@ -613,7 +610,7 @@
if (asProto) {
ALOGD("Dumping TimeStats as proto");
SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
- result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
+ result.append(timeStatsProto.SerializeAsString());
} else {
ALOGD("Dumping TimeStats as text");
result.append(mTimeStats.toString(maxLayers));
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 2bcb568..1313132 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -16,13 +16,10 @@
#pragma once
+#include <hardware/hwcomposer_defs.h>
#include <timestatsproto/TimeStatsHelper.h>
#include <timestatsproto/TimeStatsProtoHeader.h>
-
-#include <hardware/hwcomposer_defs.h>
-
#include <ui/FenceTime.h>
-
#include <utils/String16.h>
#include <utils/Vector.h>
@@ -109,7 +106,7 @@
};
public:
- TimeStats() = default;
+ TimeStats();
void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) override;
bool isEnabled() override;
@@ -161,6 +158,7 @@
GlobalRecord mGlobalRecord;
static const size_t MAX_NUM_LAYER_RECORDS = 200;
+ static const size_t MAX_NUM_LAYER_STATS = 200;
};
} // namespace impl
diff --git a/services/surfaceflinger/TracedOrdinal.h b/services/surfaceflinger/TracedOrdinal.h
new file mode 100644
index 0000000..c145a39
--- /dev/null
+++ b/services/surfaceflinger/TracedOrdinal.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+#include <android-base/stringprintf.h>
+#include <utils/Trace.h>
+#include <cmath>
+#include <string>
+
+template <typename T>
+class TracedOrdinal {
+public:
+ static_assert(std::is_same<bool, T>() || (std::is_signed<T>() && std::is_integral<T>()),
+ "Type is not supported. Please test it with systrace before adding "
+ "it to the list.");
+
+ TracedOrdinal(const std::string& name, T initialValue)
+ : mName(name),
+ mNameNegative(android::base::StringPrintf("%sNegative", name.c_str())),
+ mHasGoneNegative(std::signbit(initialValue)),
+ mData(initialValue) {
+ trace();
+ }
+
+ operator T() const { return mData; }
+
+ TracedOrdinal& operator=(T other) {
+ mData = other;
+ mHasGoneNegative = mHasGoneNegative || std::signbit(mData);
+ trace();
+ return *this;
+ }
+
+private:
+ void trace() {
+ if (!std::signbit(mData)) {
+ ATRACE_INT64(mName.c_str(), int64_t(mData));
+ if (mHasGoneNegative) {
+ ATRACE_INT64(mNameNegative.c_str(), 0);
+ }
+ } else {
+ ATRACE_INT64(mNameNegative.c_str(), -int64_t(mData));
+ ATRACE_INT64(mName.c_str(), 0);
+ }
+ }
+
+ const std::string mName;
+ const std::string mNameNegative;
+ bool mHasGoneNegative;
+ T mData;
+};
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index fd466de..92e59d7 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -24,7 +24,6 @@
#include <cinttypes>
#include <binder/IInterface.h>
-#include <gui/ITransactionCompletedListener.h>
#include <utils/RefBase.h>
namespace android {
@@ -58,7 +57,7 @@
{
std::lock_guard lock(mMutex);
for (const auto& [listener, transactionStats] : mCompletedTransactions) {
- IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient);
+ listener->unlinkToDeath(mDeathRecipient);
}
}
}
@@ -75,27 +74,59 @@
mThread = std::thread(&TransactionCompletedThread::threadMain, this);
}
-status_t TransactionCompletedThread::addCallback(const sp<ITransactionCompletedListener>& listener,
- const std::vector<CallbackId>& callbackIds) {
+status_t TransactionCompletedThread::startRegistration(const ListenerCallbacks& listenerCallbacks) {
+ // begin running if not already running
+ run();
std::lock_guard lock(mMutex);
if (!mRunning) {
ALOGE("cannot add callback because the callback thread isn't running");
return BAD_VALUE;
}
- if (mCompletedTransactions.count(listener) == 0) {
- status_t err = IInterface::asBinder(listener)->linkToDeath(mDeathRecipient);
- if (err != NO_ERROR) {
- ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
- return err;
+ auto [itr, inserted] = mRegisteringTransactions.insert(listenerCallbacks);
+ auto& [listener, callbackIds] = listenerCallbacks;
+
+ if (inserted) {
+ if (mCompletedTransactions.count(listener) == 0) {
+ status_t err = listener->linkToDeath(mDeathRecipient);
+ if (err != NO_ERROR) {
+ ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
+ return err;
+ }
}
+ auto& transactionStatsDeque = mCompletedTransactions[listener];
+ transactionStatsDeque.emplace_back(callbackIds);
}
- auto& transactionStatsDeque = mCompletedTransactions[listener];
- transactionStatsDeque.emplace_back(callbackIds);
return NO_ERROR;
}
+status_t TransactionCompletedThread::endRegistration(const ListenerCallbacks& listenerCallbacks) {
+ std::lock_guard lock(mMutex);
+ if (!mRunning) {
+ ALOGE("cannot add callback because the callback thread isn't running");
+ return BAD_VALUE;
+ }
+
+ auto itr = mRegisteringTransactions.find(listenerCallbacks);
+ if (itr == mRegisteringTransactions.end()) {
+ ALOGE("cannot end a registration that does not exist");
+ return BAD_VALUE;
+ }
+
+ mRegisteringTransactions.erase(itr);
+
+ return NO_ERROR;
+}
+
+bool TransactionCompletedThread::isRegisteringTransaction(
+ const sp<IBinder>& transactionListener, const std::vector<CallbackId>& callbackIds) {
+ ListenerCallbacks listenerCallbacks(transactionListener, callbackIds);
+
+ auto itr = mRegisteringTransactions.find(listenerCallbacks);
+ return itr != mRegisteringTransactions.end();
+}
+
status_t TransactionCompletedThread::registerPendingCallbackHandle(
const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
@@ -105,7 +136,7 @@
}
// If we can't find the transaction stats something has gone wrong. The client should call
- // addCallback before trying to register a pending callback handle.
+ // startRegistration before trying to register a pending callback handle.
TransactionStats* transactionStats;
status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
if (err != NO_ERROR) {
@@ -117,7 +148,7 @@
return NO_ERROR;
}
-status_t TransactionCompletedThread::addPresentedCallbackHandles(
+status_t TransactionCompletedThread::finalizePendingCallbackHandles(
const std::deque<sp<CallbackHandle>>& handles) {
std::lock_guard lock(mMutex);
if (!mRunning) {
@@ -158,7 +189,7 @@
return NO_ERROR;
}
-status_t TransactionCompletedThread::addUnpresentedCallbackHandle(
+status_t TransactionCompletedThread::registerUnpresentedCallbackHandle(
const sp<CallbackHandle>& handle) {
std::lock_guard lock(mMutex);
if (!mRunning) {
@@ -170,8 +201,8 @@
}
status_t TransactionCompletedThread::findTransactionStats(
- const sp<ITransactionCompletedListener>& listener,
- const std::vector<CallbackId>& callbackIds, TransactionStats** outTransactionStats) {
+ const sp<IBinder>& listener, const std::vector<CallbackId>& callbackIds,
+ TransactionStats** outTransactionStats) {
auto& transactionStatsDeque = mCompletedTransactions[listener];
// Search back to front because the most recent transactions are at the back of the deque
@@ -189,7 +220,7 @@
status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
// If we can't find the transaction stats something has gone wrong. The client should call
- // addCallback before trying to add a presnted callback handle.
+ // startRegistration before trying to add a callback handle.
TransactionStats* transactionStats;
status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
if (err != NO_ERROR) {
@@ -239,6 +270,13 @@
while (transactionStatsItr != transactionStatsDeque.end()) {
auto& transactionStats = *transactionStatsItr;
+ // If this transaction is still registering, it is not safe to send a callback
+ // because there could be surface controls that haven't been added to
+ // transaction stats or mPendingTransactions.
+ if (isRegisteringTransaction(listener, transactionStats.callbackIds)) {
+ break;
+ }
+
// If we are still waiting on the callback handles for this transaction, stop
// here because all transaction callbacks for the same listener must come in order
auto pendingTransactions = mPendingTransactions.find(listener);
@@ -262,10 +300,16 @@
// If the listener has completed transactions
if (!listenerStats.transactionStats.empty()) {
// If the listener is still alive
- if (IInterface::asBinder(listener)->isBinderAlive()) {
- // Send callback
- listenerStats.listener->onTransactionCompleted(listenerStats);
- IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient);
+ if (listener->isBinderAlive()) {
+ // Send callback. The listener stored in listenerStats
+ // comes from the cross-process setTransactionState call to
+ // SF. This MUST be an ITransactionCompletedListener. We
+ // keep it as an IBinder due to consistency reasons: if we
+ // interface_cast at the IPC boundary when reading a Parcel,
+ // we get pointers that compare unequal in the SF process.
+ interface_cast<ITransactionCompletedListener>(listenerStats.listener)
+ ->onTransactionCompleted(listenerStats);
+ listener->unlinkToDeath(mDeathRecipient);
}
completedTransactionsItr = mCompletedTransactions.erase(completedTransactionsItr);
} else {
@@ -297,7 +341,7 @@
// -----------------------------------------------------------------------
-CallbackHandle::CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
+CallbackHandle::CallbackHandle(const sp<IBinder>& transactionListener,
const std::vector<CallbackId>& ids, const sp<IBinder>& sc)
: listener(transactionListener), callbackIds(ids), surfaceControl(sc) {}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index e849f71..a85ad1e 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -21,6 +21,7 @@
#include <mutex>
#include <thread>
#include <unordered_map>
+#include <unordered_set>
#include <android-base/thread_annotations.h>
@@ -30,24 +31,12 @@
namespace android {
-struct CallbackIdsHash {
- // CallbackId vectors have several properties that let us get away with this simple hash.
- // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
- // empty we can still hash 0.
- // 2) CallbackId vectors for the same listener either are identical or contain none of the
- // same members. It is sufficient to just check the first CallbackId in the vectors. If
- // they match, they are the same. If they do not match, they are not the same.
- std::size_t operator()(const std::vector<CallbackId>& callbackIds) const {
- return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front());
- }
-};
-
class CallbackHandle : public RefBase {
public:
- CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
- const std::vector<CallbackId>& ids, const sp<IBinder>& sc);
+ CallbackHandle(const sp<IBinder>& transactionListener, const std::vector<CallbackId>& ids,
+ const sp<IBinder>& sc);
- sp<ITransactionCompletedListener> listener;
+ sp<IBinder> listener;
std::vector<CallbackId> callbackIds;
wp<IBinder> surfaceControl;
@@ -64,10 +53,12 @@
void run();
// Adds listener and callbackIds in case there are no SurfaceControls that are supposed
- // to be included in the callback. This functions should be call before attempting to add any
- // callback handles.
- status_t addCallback(const sp<ITransactionCompletedListener>& transactionListener,
- const std::vector<CallbackId>& callbackIds);
+ // to be included in the callback. This functions should be call before attempting to register
+ // any callback handles.
+ status_t startRegistration(const ListenerCallbacks& listenerCallbacks);
+ // Ends the registration. After this is called, no more CallbackHandles will be registered.
+ // It is safe to send a callback if the Transaction doesn't have any Pending callback handles.
+ status_t endRegistration(const ListenerCallbacks& listenerCallbacks);
// Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
// that needs to be latched and presented this frame. This function should be called once the
@@ -76,11 +67,11 @@
// presented.
status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
// Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
- status_t addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
+ status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
- status_t addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
+ status_t registerUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
void addPresentFence(const sp<Fence>& presentFence);
@@ -89,7 +80,10 @@
private:
void threadMain();
- status_t findTransactionStats(const sp<ITransactionCompletedListener>& listener,
+ bool isRegisteringTransaction(const sp<IBinder>& transactionListener,
+ const std::vector<CallbackId>& callbackIds) REQUIRES(mMutex);
+
+ status_t findTransactionStats(const sp<IBinder>& listener,
const std::vector<CallbackId>& callbackIds,
TransactionStats** outTransactionStats) REQUIRES(mMutex);
@@ -106,13 +100,6 @@
};
sp<ThreadDeathRecipient> mDeathRecipient;
- struct ITransactionCompletedListenerHash {
- std::size_t operator()(const sp<ITransactionCompletedListener>& listener) const {
- return std::hash<IBinder*>{}((listener) ? IInterface::asBinder(listener).get()
- : nullptr);
- }
- };
-
// Protects the creation and destruction of mThread
std::mutex mThreadMutex;
@@ -121,13 +108,16 @@
std::mutex mMutex;
std::condition_variable_any mConditionVariable;
+ std::unordered_set<ListenerCallbacks, ListenerCallbacksHash> mRegisteringTransactions
+ GUARDED_BY(mMutex);
+
std::unordered_map<
- sp<ITransactionCompletedListener>,
+ sp<IBinder>,
std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
- ITransactionCompletedListenerHash>
+ IListenerHash>
mPendingTransactions GUARDED_BY(mMutex);
- std::unordered_map<sp<ITransactionCompletedListener>, std::deque<TransactionStats>,
- ITransactionCompletedListenerHash>
+
+ std::unordered_map<sp<IBinder>, std::deque<TransactionStats>, IListenerHash>
mCompletedTransactions GUARDED_BY(mMutex);
bool mRunning GUARDED_BY(mMutex) = false;
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index d3381e5..ef488bd 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -37,16 +37,6 @@
return lhs->id < rhs->id;
}
-const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
- const LayersProto& layersProto) {
- LayerGlobal layerGlobal;
- layerGlobal.resolution = {layersProto.resolution().w(), layersProto.resolution().h()};
- layerGlobal.colorMode = layersProto.color_mode();
- layerGlobal.colorTransform = layersProto.color_transform();
- layerGlobal.globalTransform = layersProto.global_transform();
- return layerGlobal;
-}
-
LayerProtoParser::LayerTree LayerProtoParser::generateLayerTree(const LayersProto& layersProto) {
LayerTree layerTree;
layerTree.allLayers = generateLayerList(layersProto);
@@ -114,10 +104,6 @@
layer.bufferTransform = generateTransform(layerProto.buffer_transform());
layer.queuedFrames = layerProto.queued_frames();
layer.refreshPending = layerProto.refresh_pending();
- layer.hwcFrame = generateRect(layerProto.hwc_frame());
- layer.hwcCrop = generateFloatRect(layerProto.hwc_crop());
- layer.hwcTransform = layerProto.hwc_transform();
- layer.hwcCompositionType = layerProto.hwc_composition_type();
layer.isProtected = layerProto.is_protected();
layer.cornerRadius = layerProto.corner_radius();
for (const auto& entry : layerProto.metadata()) {
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index d1b2b1f..54e02ca 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -108,10 +108,6 @@
Transform bufferTransform;
int32_t queuedFrames;
bool refreshPending;
- LayerProtoParser::Rect hwcFrame;
- LayerProtoParser::FloatRect hwcCrop;
- int32_t hwcTransform;
- int32_t hwcCompositionType;
bool isProtected;
float cornerRadius;
LayerMetadata metadata;
@@ -119,14 +115,6 @@
std::string to_string() const;
};
- class LayerGlobal {
- public:
- int2 resolution;
- std::string colorMode;
- std::string colorTransform;
- int32_t globalTransform;
- };
-
class LayerTree {
public:
// all layers in LayersProto and in the original order
@@ -136,7 +124,6 @@
std::vector<Layer*> topLevelLayers;
};
- static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
static LayerTree generateLayerTree(const LayersProto& layersProto);
static std::string layerTreeToString(const LayerTree& layerTree);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index b097505..c7fbff3 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,10 +7,6 @@
// Contains a list of all layers.
message LayersProto {
repeated LayerProto layers = 1;
- SizeProto resolution = 2;
- string color_mode = 3;
- string color_transform = 4;
- int32 global_transform = 5;
}
// Information about each layer.
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index 56ab4e3..51b20cb 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -15,7 +15,7 @@
module: "android.sysprop.SurfaceFlingerProperties"
owner: Platform
-# The following two propertiess define (respectively):
+# The following two properties define (respectively):
#
# - The phase offset between hardware vsync and when apps are woken up by the
# Choreographer callback
@@ -301,9 +301,18 @@
prop_name: "ro.surface_flinger.display_primary_white"
}
-# setIdleTimerMs indicates what is considered a timeout in milliseconds for Scheduler. This value is
-# used by the Scheduler to trigger inactivity callbacks that will switch the display to a lower
-# refresh rate. Setting this property to 0 means there is no timer.
+# refreshRateSwitching indicates whether SurfaceFlinger should use refresh rate
+# switching on the device, e.g. to switch between 60 and 90 Hz. The settings
+# below that are related to refresh rate switching will only have an effect if
+# refresh_rate_switching is enabled.
+prop {
+ api_name: "refresh_rate_switching"
+ type: Boolean
+ scope: System
+ access: Readonly
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+}
+
prop {
api_name: "set_idle_timer_ms"
type: Integer
diff --git a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
index b66e56e..2d52507 100644
--- a/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
+++ b/services/surfaceflinger/sysprop/api/SurfaceFlingerProperties-current.txt
@@ -73,6 +73,10 @@
enum_values: "ORIENTATION_0|ORIENTATION_90|ORIENTATION_180|ORIENTATION_270"
}
prop {
+ api_name: "refresh_rate_switching"
+ prop_name: "ro.surface_flinger.refresh_rate_switching"
+ }
+ prop {
api_name: "running_without_sync_framework"
prop_name: "ro.surface_flinger.running_without_sync_framework"
}
diff --git a/services/surfaceflinger/tests/Android.bp b/services/surfaceflinger/tests/Android.bp
index 53a3611..d021fc2 100644
--- a/services/surfaceflinger/tests/Android.bp
+++ b/services/surfaceflinger/tests/Android.bp
@@ -19,10 +19,21 @@
srcs: [
"BufferGenerator.cpp",
"Credentials_test.cpp",
+ "DereferenceSurfaceControl_test.cpp",
+ "DisplayActiveConfig_test.cpp",
"InvalidHandles_test.cpp",
+ "LayerCallback_test.cpp",
+ "LayerRenderTypeTransaction_test.cpp",
+ "LayerTransaction_test.cpp",
+ "LayerTypeAndRenderTypeTransaction_test.cpp",
+ "LayerTypeTransaction_test.cpp",
+ "LayerUpdate_test.cpp",
+ "MirrorLayer_test.cpp",
+ "MultiDisplayLayerBounds_test.cpp",
+ "RelativeZ_test.cpp",
+ "SetGeometry_test.cpp",
"Stress_test.cpp",
"SurfaceInterceptor_test.cpp",
- "Transaction_test.cpp",
"VirtualDisplay_test.cpp",
],
data: ["SurfaceFlinger_test.filter"],
@@ -43,13 +54,55 @@
"libui",
"libutils",
]
+}
+cc_defaults {
+ name: "ipc_defaults",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+}
+
+cc_test {
+ name: "IPC_test",
+ defaults: ["ipc_defaults"],
+ test_suites: ["device-tests"],
+ srcs: [
+ "BufferGenerator.cpp",
+ "IPC_test.cpp",
+ ],
+ cppflags: [
+ "-Wall",
+ "-Werror",
+ "-Wformat",
+ "-Wthread-safety",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+ shared_libs: [
+ "libandroid",
+ "libbinder",
+ "libcutils",
+ "libEGL",
+ "libGLESv2",
+ "libgui",
+ "liblayers_proto",
+ "liblog",
+ "libprotobuf-cpp-full",
+ "libtimestats_proto",
+ "libui",
+ "libutils",
+ ],
+ cpp_std: "experimental",
+ gnu_extensions: false,
}
subdirs = [
"fakehwc",
"hwc2",
"unittests",
+ "utils",
"vsync",
"waitforvsync",
]
diff --git a/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
new file mode 100644
index 0000000..0cef0d1
--- /dev/null
+++ b/services/surfaceflinger/tests/DereferenceSurfaceControl_test.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class DereferenceSurfaceControlTest : public LayerTransactionTest {
+protected:
+ void SetUp() override {
+ LayerTransactionTest::SetUp();
+ bgLayer = createLayer("BG layer", 20, 20);
+ fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
+ fgLayer = createLayer("FG layer", 20, 20);
+ fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
+ Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
+ {
+ SCOPED_TRACE("before anything");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+ }
+ }
+ void TearDown() override {
+ LayerTransactionTest::TearDown();
+ bgLayer = 0;
+ fgLayer = 0;
+ }
+
+ sp<SurfaceControl> bgLayer;
+ sp<SurfaceControl> fgLayer;
+};
+
+TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
+ fgLayer = nullptr;
+ {
+ SCOPED_TRACE("after setting null");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
+ }
+}
+
+TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
+ auto transaction = Transaction().show(fgLayer);
+ fgLayer = nullptr;
+ {
+ SCOPED_TRACE("after setting null");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/DisplayActiveConfig_test.cpp b/services/surfaceflinger/tests/DisplayActiveConfig_test.cpp
new file mode 100644
index 0000000..2e3b760
--- /dev/null
+++ b/services/surfaceflinger/tests/DisplayActiveConfig_test.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <thread>
+#include "LayerTransactionTest.h"
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class DisplayActiveConfigTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
+ SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &mDisplayconfigs);
+ EXPECT_GT(mDisplayconfigs.size(), 0);
+
+ // set display power to on to make sure config can be changed
+ SurfaceComposerClient::setDisplayPowerMode(mDisplayToken, HWC_POWER_MODE_NORMAL);
+ }
+
+ sp<IBinder> mDisplayToken;
+ Vector<DisplayInfo> mDisplayconfigs;
+};
+
+TEST_F(DisplayActiveConfigTest, allConfigsAllowed) {
+ std::vector<int32_t> allowedConfigs;
+
+ // Add all configs to the allowed configs
+ for (int i = 0; i < mDisplayconfigs.size(); i++) {
+ allowedConfigs.push_back(i);
+ }
+
+ status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
+ EXPECT_EQ(res, NO_ERROR);
+
+ std::vector<int32_t> outConfigs;
+ res = SurfaceComposerClient::getAllowedDisplayConfigs(mDisplayToken, &outConfigs);
+ EXPECT_EQ(res, NO_ERROR);
+ EXPECT_EQ(allowedConfigs, outConfigs);
+}
+
+TEST_F(DisplayActiveConfigTest, changeAllowedConfig) {
+ // we need at least 2 configs available for this test
+ if (mDisplayconfigs.size() <= 1) return;
+
+ int activeConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
+
+ // We want to set the allowed config to everything but the active config
+ std::vector<int32_t> allowedConfigs;
+ for (int i = 0; i < mDisplayconfigs.size(); i++) {
+ if (i != activeConfig) {
+ allowedConfigs.push_back(i);
+ }
+ }
+
+ status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
+ EXPECT_EQ(res, NO_ERROR);
+
+ // Allow some time for the config change
+ std::this_thread::sleep_for(200ms);
+
+ int newActiveConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
+ EXPECT_NE(activeConfig, newActiveConfig);
+
+ // Make sure the new config is part of allowed config
+ EXPECT_TRUE(std::find(allowedConfigs.begin(), allowedConfigs.end(), newActiveConfig) !=
+ allowedConfigs.end());
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/IPC_test.cpp b/services/surfaceflinger/tests/IPC_test.cpp
new file mode 100644
index 0000000..8a756a6
--- /dev/null
+++ b/services/surfaceflinger/tests/IPC_test.cpp
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IInterface.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <limits>
+
+#include <ui/DisplayInfo.h>
+
+#include <utils/String8.h>
+
+#include "BufferGenerator.h"
+#include "utils/CallbackUtils.h"
+#include "utils/ColorUtils.h"
+#include "utils/TransactionUtils.h"
+
+namespace android {
+
+namespace test {
+
+using Transaction = SurfaceComposerClient::Transaction;
+using CallbackInfo = SurfaceComposerClient::CallbackInfo;
+using TCLHash = SurfaceComposerClient::TCLHash;
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class TransactionHelper : public Transaction {
+public:
+ size_t getNumListeners() { return mListenerCallbacks.size(); }
+
+ std::unordered_map<sp<ITransactionCompletedListener>, CallbackInfo, TCLHash>
+ getListenerCallbacks() {
+ return mListenerCallbacks;
+ }
+};
+
+class IPCTestUtils {
+public:
+ static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false);
+ static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence);
+};
+
+class IIPCTest : public IInterface {
+public:
+ DECLARE_META_INTERFACE(IPCTest)
+ enum class Tag : uint32_t {
+ SetDeathToken = IBinder::FIRST_CALL_TRANSACTION,
+ InitClient,
+ CreateTransaction,
+ MergeAndApply,
+ VerifyCallbacks,
+ CleanUp,
+ Last,
+ };
+
+ virtual status_t setDeathToken(sp<IBinder>& token) = 0;
+
+ virtual status_t initClient() = 0;
+
+ virtual status_t createTransaction(TransactionHelper* outTransaction, uint32_t width,
+ uint32_t height) = 0;
+
+ virtual status_t mergeAndApply(TransactionHelper transaction) = 0;
+
+ virtual status_t verifyCallbacks() = 0;
+
+ virtual status_t cleanUp() = 0;
+};
+
+class BpIPCTest : public SafeBpInterface<IIPCTest> {
+public:
+ explicit BpIPCTest(const sp<IBinder>& impl) : SafeBpInterface<IIPCTest>(impl, "BpIPCTest") {}
+
+ status_t setDeathToken(sp<IBinder>& token) {
+ return callRemote<decltype(&IIPCTest::setDeathToken)>(Tag::SetDeathToken, token);
+ }
+
+ status_t initClient() { return callRemote<decltype(&IIPCTest::initClient)>(Tag::InitClient); }
+
+ status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) {
+ return callRemote<decltype(&IIPCTest::createTransaction)>(Tag::CreateTransaction,
+ transaction, width, height);
+ }
+
+ status_t mergeAndApply(TransactionHelper transaction) {
+ return callRemote<decltype(&IIPCTest::mergeAndApply)>(Tag::MergeAndApply, transaction);
+ }
+
+ status_t verifyCallbacks() {
+ return callRemote<decltype(&IIPCTest::verifyCallbacks)>(Tag::VerifyCallbacks);
+ }
+
+ status_t cleanUp() { return callRemote<decltype(&IIPCTest::cleanUp)>(Tag::CleanUp); }
+};
+
+IMPLEMENT_META_INTERFACE(IPCTest, "android.gfx.tests.IIPCTest")
+
+class onTestDeath : public IBinder::DeathRecipient {
+public:
+ void binderDied(const wp<IBinder>& /*who*/) override {
+ ALOGE("onTestDeath::binderDied, exiting");
+ exit(0);
+ }
+};
+
+sp<onTestDeath> getDeathToken() {
+ static sp<onTestDeath> token = new onTestDeath;
+ return token;
+}
+
+class BnIPCTest : public SafeBnInterface<IIPCTest> {
+public:
+ BnIPCTest() : SafeBnInterface("BnIPCTest") {}
+
+ status_t setDeathToken(sp<IBinder>& token) override {
+ return token->linkToDeath(getDeathToken());
+ }
+
+ status_t initClient() override {
+ mClient = new SurfaceComposerClient;
+ auto err = mClient->initCheck();
+ return err;
+ }
+
+ status_t createTransaction(TransactionHelper* transaction, uint32_t width, uint32_t height) {
+ if (transaction == nullptr) {
+ ALOGE("Error in createTransaction: transaction is nullptr");
+ return BAD_VALUE;
+ }
+ mSurfaceControl = mClient->createSurface(String8("parentProcessSurface"), 0, 0,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+ sp<GraphicBuffer> gb;
+ sp<Fence> fence;
+ int err = IPCTestUtils::getBuffer(&gb, &fence);
+ if (err != NO_ERROR) return err;
+
+ TransactionUtils::fillGraphicBufferColor(gb,
+ {0, 0, static_cast<int32_t>(width),
+ static_cast<int32_t>(height)},
+ Color::RED);
+ transaction->setLayerStack(mSurfaceControl, 0)
+ .setLayer(mSurfaceControl, std::numeric_limits<int32_t>::max())
+ .setFrame(mSurfaceControl, Rect(0, 0, width, height))
+ .setBuffer(mSurfaceControl, gb)
+ .setAcquireFence(mSurfaceControl, fence)
+ .show(mSurfaceControl)
+ .addTransactionCompletedCallback(mCallbackHelper.function,
+ mCallbackHelper.getContext());
+ return NO_ERROR;
+ }
+
+ status_t mergeAndApply(TransactionHelper /*transaction*/) {
+ // transaction.apply();
+ return NO_ERROR;
+ }
+
+ status_t verifyCallbacks() {
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, mSurfaceControl);
+ EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(mCallbackHelper, expected, true));
+ return NO_ERROR;
+ }
+
+ status_t cleanUp() {
+ if (mClient) mClient->dispose();
+ mSurfaceControl = nullptr;
+ IPCThreadState::self()->stopProcess();
+ return NO_ERROR;
+ }
+
+ status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t /*flags*/) override {
+ EXPECT_GE(code, IBinder::FIRST_CALL_TRANSACTION);
+ EXPECT_LT(code, static_cast<uint32_t>(IIPCTest::Tag::Last));
+ switch (static_cast<IIPCTest::Tag>(code)) {
+ case IIPCTest::Tag::SetDeathToken:
+ return callLocal(data, reply, &IIPCTest::setDeathToken);
+ case IIPCTest::Tag::InitClient:
+ return callLocal(data, reply, &IIPCTest::initClient);
+ case IIPCTest::Tag::CreateTransaction:
+ return callLocal(data, reply, &IIPCTest::createTransaction);
+ case IIPCTest::Tag::MergeAndApply:
+ return callLocal(data, reply, &IIPCTest::mergeAndApply);
+ case IIPCTest::Tag::VerifyCallbacks:
+ return callLocal(data, reply, &IIPCTest::verifyCallbacks);
+ case IIPCTest::Tag::CleanUp:
+ return callLocal(data, reply, &IIPCTest::cleanUp);
+ default:
+ return UNKNOWN_ERROR;
+ }
+ }
+
+private:
+ sp<SurfaceComposerClient> mClient;
+ sp<SurfaceControl> mSurfaceControl;
+ CallbackHelper mCallbackHelper;
+};
+
+class IPCTest : public ::testing::Test {
+public:
+ IPCTest() : mDeathRecipient(new BBinder), mRemote(initRemoteService()) {
+ ProcessState::self()->startThreadPool();
+ }
+ void SetUp() {
+ mClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mPrimaryDisplay = mClient->getInternalDisplayToken();
+ DisplayInfo info;
+ mClient->getDisplayInfo(mPrimaryDisplay, &info);
+ mDisplayWidth = info.w;
+ mDisplayHeight = info.h;
+
+ Transaction setupTransaction;
+ setupTransaction.setDisplayLayerStack(mPrimaryDisplay, 0);
+ setupTransaction.apply();
+ }
+
+protected:
+ sp<IIPCTest> initRemoteService();
+
+ sp<IBinder> mDeathRecipient;
+ sp<IIPCTest> mRemote;
+ sp<SurfaceComposerClient> mClient;
+ sp<IBinder> mPrimaryDisplay;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+ sp<SurfaceControl> sc;
+};
+
+status_t IPCTestUtils::getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+ static BufferGenerator bufferGenerator;
+ return bufferGenerator.get(outBuffer, outFence);
+}
+
+void IPCTestUtils::waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState) {
+ CallbackData callbackData;
+ ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+}
+
+sp<IIPCTest> IPCTest::initRemoteService() {
+ static std::mutex mMutex;
+ static sp<IIPCTest> remote;
+ const String16 serviceName("IPCTest");
+
+ std::unique_lock<decltype(mMutex)> lock;
+ if (remote == nullptr) {
+ pid_t forkPid = fork();
+ EXPECT_NE(forkPid, -1);
+
+ if (forkPid == 0) {
+ sp<IIPCTest> nativeService = new BnIPCTest;
+ if (!nativeService) {
+ ALOGE("null service...");
+ }
+ status_t err = defaultServiceManager()->addService(serviceName,
+ IInterface::asBinder(nativeService));
+ if (err != NO_ERROR) {
+ ALOGE("failed to add service: %d", err);
+ }
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+ [&]() { exit(0); }();
+ }
+ sp<IBinder> binder = defaultServiceManager()->getService(serviceName);
+ remote = interface_cast<IIPCTest>(binder);
+ remote->setDeathToken(mDeathRecipient);
+ }
+ return remote;
+}
+
+TEST_F(IPCTest, MergeBasic) {
+ CallbackHelper helper1;
+ sc = mClient->createSurface(String8("parentProcessSurface"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceBufferState,
+ /*parent*/ nullptr);
+ sp<GraphicBuffer> gb;
+ sp<Fence> fence;
+ int err = IPCTestUtils::getBuffer(&gb, &fence);
+ ASSERT_EQ(NO_ERROR, err);
+ TransactionUtils::fillGraphicBufferColor(gb,
+ {0, 0, static_cast<int32_t>(mDisplayWidth),
+ static_cast<int32_t>(mDisplayHeight)},
+ Color::RED);
+
+ Transaction transaction;
+ transaction.setLayerStack(sc, 0)
+ .setLayer(sc, std::numeric_limits<int32_t>::max() - 1)
+ .setBuffer(sc, gb)
+ .setAcquireFence(sc, fence)
+ .show(sc)
+ .addTransactionCompletedCallback(helper1.function, helper1.getContext());
+
+ TransactionHelper remote;
+ mRemote->initClient();
+ mRemote->createTransaction(&remote, mDisplayWidth / 2, mDisplayHeight / 2);
+ ASSERT_EQ(1, remote.getNumListeners());
+ auto remoteListenerCallbacks = remote.getListenerCallbacks();
+ auto remoteCallback = remoteListenerCallbacks.begin();
+ auto remoteCallbackInfo = remoteCallback->second;
+ auto remoteListenerScs = remoteCallbackInfo.surfaceControls;
+ ASSERT_EQ(1, remoteCallbackInfo.callbackIds.size());
+ ASSERT_EQ(1, remoteListenerScs.size());
+
+ sp<SurfaceControl> remoteSc = *(remoteListenerScs.begin());
+ transaction.merge(std::move(remote));
+ transaction.apply();
+
+ sleep(1);
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, sc);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, remoteSc);
+ EXPECT_NO_FATAL_FAILURE(IPCTestUtils::waitForCallback(helper1, expected, true));
+
+ mRemote->verifyCallbacks();
+ mRemote->cleanUp();
+}
+
+} // namespace test
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerCallback_test.cpp b/services/surfaceflinger/tests/LayerCallback_test.cpp
new file mode 100644
index 0000000..7a5ed48
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerCallback_test.cpp
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+#include "utils/CallbackUtils.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerCallbackTest : public LayerTransactionTest {
+public:
+ virtual sp<SurfaceControl> createBufferStateLayer() {
+ return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
+ }
+
+ static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
+ const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
+ bool setBackgroundColor = false) {
+ if (layer) {
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ if (setBuffer) {
+ int err = getBuffer(&buffer, &fence);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transaction.setBuffer(layer, buffer);
+ transaction.setAcquireFence(layer, fence);
+ }
+
+ if (setBackgroundColor) {
+ transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
+ ui::Dataspace::UNKNOWN);
+ }
+ }
+
+ transaction.addTransactionCompletedCallback(callbackHelper->function,
+ callbackHelper->getContext());
+ return NO_ERROR;
+ }
+
+ static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
+ bool finalState = false) {
+ CallbackData callbackData;
+ ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
+ EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
+
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+
+ static void waitForCallbacks(CallbackHelper& helper,
+ const std::vector<ExpectedResult>& expectedResults,
+ bool finalState = false) {
+ for (const auto& expectedResult : expectedResults) {
+ waitForCallback(helper, expectedResult);
+ }
+ if (finalState) {
+ ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
+ }
+ }
+};
+
+TEST_F(LayerCallbackTest, BufferColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferNoColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, false, false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, BufferNoColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, true, false);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoBufferColor) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, NoStateChange) {
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, OffScreen) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeBufferNoColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeNoBufferColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2, false, true);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+TEST_F(LayerCallbackTest, Merge_SameCallback) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction1, &callback, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_SameLayer) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ ExpectedResult expected;
+
+ if (i == 0) {
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ } else {
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ }
+
+ transaction.apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ for (size_t i = 0; i < 10; i++) {
+ if (i == 0) {
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ } else {
+ int err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expected;
+ expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
+ : ExpectedResult::Transaction::NOT_PRESENTED,
+ layer,
+ (i == 0) ? ExpectedResult::Buffer::ACQUIRED
+ : ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
+ ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+ for (size_t i = 0; i < 10; i++) {
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
+ ExpectedResult::Buffer::ACQUIRED,
+ (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
+ : ExpectedResult::PreviousBuffer::RELEASED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
+ }
+ ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
+ ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ err = fillTransaction(transaction1, &callback1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.merge(std::move(transaction1)).apply();
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
+ sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
+ client2(new SurfaceComposerClient);
+
+ ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
+ ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
+
+ sp<SurfaceControl> layer1, layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
+ ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction transaction1, transaction2;
+ CallbackHelper callback1, callback2;
+
+ // Normal call to set up test
+ int err = fillTransaction(transaction1, &callback1, layer1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2, layer2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ ExpectedResult expected;
+ expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+ expected.reset();
+
+ // Test
+ err = fillTransaction(transaction1, &callback1);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+ err = fillTransaction(transaction2, &callback2);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
+
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::UNKNOWN);
+
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+
+ err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.apply();
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ // Normal call to set up test
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ ExpectedResult expectedResult;
+ expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
+
+ // Test
+ std::vector<ExpectedResult> expectedResults(50);
+ for (auto& expected : expectedResults) {
+ expected.reset();
+ expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
+ ExpectedResult::Buffer::NOT_ACQUIRED);
+
+ err = fillTransaction(transaction, &callback);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
+ }
+ EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(time);
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms after the first frame
+ time += (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+ expected2.addExpectedPresentTime(time);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback1;
+ int err = fillTransaction(transaction, &callback1, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the future
+ nsecs_t time = systemTime() + (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected1;
+ expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected1.addExpectedPresentTime(time);
+
+ CallbackHelper callback2;
+ err = fillTransaction(transaction, &callback2, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 33ms before the previous frame
+ time -= (33.3 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected2;
+ expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
+ ExpectedResult::Buffer::ACQUIRED,
+ ExpectedResult::PreviousBuffer::RELEASED);
+
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
+}
+
+TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
+
+ Transaction transaction;
+ CallbackHelper callback;
+ int err = fillTransaction(transaction, &callback, layer);
+ if (err) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ // Try to present 100ms in the past
+ nsecs_t time = systemTime() - (100 * 1e6);
+
+ transaction.setDesiredPresentTime(time);
+ transaction.apply();
+
+ ExpectedResult expected;
+ expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
+ expected.addExpectedPresentTime(systemTime());
+ EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
new file mode 100644
index 0000000..a48f553
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -0,0 +1,1834 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferItemConsumer.h>
+#include <thread>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerRenderTypeTransactionTest : public LayerTransactionTest,
+ public ::testing::WithParamInterface<RenderPath> {
+public:
+ LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
+ void setRelativeZBasicHelper(uint32_t layerType);
+ void setRelativeZGroupHelper(uint32_t layerType);
+ void setAlphaBasicHelper(uint32_t layerType);
+ void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
+ Color finalColor);
+
+protected:
+ LayerRenderPathTestHarness mHarness;
+};
+
+INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("default position");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = getScreenCapture();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ Transaction().setPosition(layer, 5, 10).apply();
+ {
+ SCOPED_TRACE("new position");
+ const Rect rect(5, 10, 37, 42);
+ auto shot = getScreenCapture();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // GLES requires only 4 bits of subpixel precision during rasterization
+ // XXX GLES composition does not match HWC composition due to precision
+ // loss (b/69315223)
+ const float epsilon = 1.0f / 16.0f;
+ Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
+ {
+ SCOPED_TRACE("rounding down");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
+ {
+ SCOPED_TRACE("rounding up");
+ getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setPosition(layer, -32, -32).apply();
+ {
+ SCOPED_TRACE("negative coordinates");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+
+ Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
+ {
+ SCOPED_TRACE("positive coordinates");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // partially out of bounds
+ Transaction().setPosition(layer, -30, -30).apply();
+ {
+ SCOPED_TRACE("negative coordinates");
+ getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
+ }
+
+ Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
+ {
+ SCOPED_TRACE("positive coordinates");
+ getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
+ mDisplayHeight),
+ Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setPosition is applied immediately by default, with or without resize
+ // pending
+ Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ const Rect rect(5, 10, 37, 42);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+ {
+ SCOPED_TRACE("resize applied");
+ getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setSize(layer, 64, 64).apply();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ const Rect rect(0, 0, 32, 32);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+ {
+ SCOPED_TRACE("resize applied");
+ auto shot = getScreenCapture();
+ const Rect rect(0, 0, 64, 64);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
+ Transaction()
+ .setSize(layer, 64, 64)
+ .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
+}
+
+void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ Transaction()
+ .setPosition(layerG, 16, 16)
+ .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ Transaction()
+ .setFrame(layerR, Rect(0, 0, 32, 32))
+ .setFrame(layerG, Rect(16, 16, 48, 48))
+ .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .apply();
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+ {
+ SCOPED_TRACE("layerG above");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+ shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
+ }
+
+ Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
+ {
+ SCOPED_TRACE("layerG below");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ sp<SurfaceControl> layerB;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
+
+ // layerR = 0, layerG = layerR + 3, layerB = 2
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ Transaction()
+ .setPosition(layerG, 8, 8)
+ .setRelativeLayer(layerG, layerR->getHandle(), 3)
+ .setPosition(layerB, 16, 16)
+ .setLayer(layerB, mLayerZBase + 2)
+ .apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ Transaction()
+ .setFrame(layerR, Rect(0, 0, 32, 32))
+ .setFrame(layerG, Rect(8, 8, 40, 40))
+ .setRelativeLayer(layerG, layerR->getHandle(), 3)
+ .setFrame(layerB, Rect(16, 16, 48, 48))
+ .setLayer(layerB, mLayerZBase + 2)
+ .apply();
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+
+ {
+ SCOPED_TRACE("(layerR < layerG) < layerB");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+ shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
+ shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+ }
+
+ // layerR = 4, layerG = layerR + 3, layerB = 2
+ Transaction().setLayer(layerR, mLayerZBase + 4).apply();
+ {
+ SCOPED_TRACE("layerB < (layerR < layerG)");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
+ shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
+ shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+ }
+
+ // layerR = 4, layerG = layerR - 3, layerB = 2
+ Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
+ {
+ SCOPED_TRACE("layerB < (layerG < layerR)");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
+ shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
+ }
+
+ // restore to absolute z
+ // layerR = 4, layerG = 0, layerB = 2
+ Transaction().setLayer(layerG, mLayerZBase).apply();
+ {
+ SCOPED_TRACE("layerG < layerB < layerR");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
+ }
+
+ // layerR should not affect layerG anymore
+ // layerR = 1, layerG = 0, layerB = 2
+ Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+ {
+ SCOPED_TRACE("layerG < layerR < layerB");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
+ shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
+ const Rect top(0, 0, 32, 16);
+ const Rect bottom(0, 16, 32, 32);
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+
+ ANativeWindow_Buffer buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::RED));
+ // setTransparentRegionHint always applies to the following buffer
+ Transaction().setTransparentRegionHint(layer, Region(top)).apply();
+ ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
+ {
+ SCOPED_TRACE("top transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+ {
+ SCOPED_TRACE("transparent region hint pending");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, top, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
+ {
+ SCOPED_TRACE("bottom transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::RED);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) {
+ const Rect top(0, 0, 32, 16);
+ const Rect bottom(0, 16, 32, 32);
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
+ ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::RED));
+ Transaction()
+ .setTransparentRegionHint(layer, Region(top))
+ .setBuffer(layer, buffer)
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .apply();
+ {
+ SCOPED_TRACE("top transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::RED);
+ }
+
+ Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
+ {
+ SCOPED_TRACE("transparent region hint intermediate");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::BLACK);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ ASSERT_NO_FATAL_FAILURE(TransactionUtils::fillGraphicBufferColor(buffer, top, Color::RED));
+ ASSERT_NO_FATAL_FAILURE(
+ TransactionUtils::fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
+ Transaction().setBuffer(layer, buffer).apply();
+ {
+ SCOPED_TRACE("bottom transparent");
+ auto shot = getScreenCapture();
+ shot->expectColor(top, Color::RED);
+ shot->expectColor(bottom, Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layerTransparent;
+ sp<SurfaceControl> layerR;
+ ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+
+ // check that transparent region hint is bound by the layer size
+ Transaction()
+ .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+ .setPosition(layerR, 16, 16)
+ .setLayer(layerR, mLayerZBase + 1)
+ .apply();
+ ASSERT_NO_FATAL_FAILURE(
+ fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
+ sp<SurfaceControl> layerTransparent;
+ sp<SurfaceControl> layerR;
+ ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(
+ layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ // check that transparent region hint is bound by the layer size
+ Transaction()
+ .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
+ .setFrame(layerR, Rect(16, 16, 48, 48))
+ .setLayer(layerR, mLayerZBase + 1)
+ .apply();
+ ASSERT_NO_FATAL_FAILURE(
+ fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
+ getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
+}
+
+void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
+ sp<SurfaceControl> layer1;
+ sp<SurfaceControl> layer2;
+ ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
+
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ Transaction()
+ .setAlpha(layer1, 0.25f)
+ .setAlpha(layer2, 0.75f)
+ .setPosition(layer2, 16, 0)
+ .setLayer(layer2, mLayerZBase + 1)
+ .apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ Transaction()
+ .setAlpha(layer1, 0.25f)
+ .setAlpha(layer2, 0.75f)
+ .setFrame(layer1, Rect(0, 0, 32, 32))
+ .setFrame(layer2, Rect(16, 0, 48, 32))
+ .setLayer(layer2, mLayerZBase + 1)
+ .apply();
+ break;
+ default:
+ ASSERT_FALSE(true) << "Unsupported layer type";
+ }
+ {
+ auto shot = getScreenCapture();
+ uint8_t r = 16; // 64 * 0.25f
+ uint8_t g = 48; // 64 * 0.75f
+ shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
+ shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
+
+ r /= 4; // r * (1.0f - 0.75f)
+ shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
+ ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
+ ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const Color expected = {15, 51, 85, 255};
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction().setColor(colorLayer, color).apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
+ }
+}
+
+// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
+// BLUE: prior background color
+// GREEN: final background color
+// BLACK: no color or fill
+void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
+ bool bufferFill, float alpha,
+ Color finalColor) {
+ sp<SurfaceControl> layer;
+ int32_t width = 500;
+ int32_t height = 500;
+
+ Color fillColor = Color::RED;
+ Color priorBgColor = Color::BLUE;
+ Color expectedColor = Color::BLACK;
+ switch (layerType) {
+ case ISurfaceComposerClient::eFXSurfaceColor:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
+ Transaction()
+ .setCrop_legacy(layer, Rect(0, 0, width, height))
+ .setColor(layer, half3(1.0f, 0, 0))
+ .apply();
+ expectedColor = fillColor;
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
+ if (bufferFill) {
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
+ expectedColor = fillColor;
+ }
+ Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
+ break;
+ default:
+ GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
+ return;
+ }
+
+ if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
+ .apply();
+ if (!bufferFill) {
+ expectedColor = priorBgColor;
+ }
+ }
+
+ {
+ SCOPED_TRACE("default before setting background color layer");
+ screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
+ }
+ Transaction()
+ .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
+ .apply();
+
+ {
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, width, height), finalColor);
+ shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = true;
+ float alpha = 1.0f;
+ Color finalColor = Color::RED;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 1.0f;
+ Color finalColor = Color::GREEN;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
+ bool priorColor = false;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest,
+ SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
+ bool priorColor = true;
+ bool bufferFill = false;
+ float alpha = 0;
+ Color finalColor = Color::BLACK;
+ ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
+ priorColor, bufferFill, alpha, finalColor));
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
+ .apply();
+
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const float alpha = 0.25f;
+ const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction()
+ .setColor(colorLayer, color)
+ .setAlpha(colorLayer, alpha)
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
+ sp<SurfaceControl> bufferLayer;
+ sp<SurfaceControl> parentLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
+ const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
+ const float alpha = 0.25f;
+ const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
+ // this is handwavy, but the precision loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+ Transaction()
+ .reparent(colorLayer, parentLayer->getHandle())
+ .setColor(colorLayer, color)
+ .setAlpha(parentLayer, alpha)
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
+ tolerance);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
+ {
+ SCOPED_TRACE("IDENTITY");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
+ {
+ SCOPED_TRACE("FLIP_H");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
+ Color::WHITE, Color::BLUE);
+ }
+
+ Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
+ {
+ SCOPED_TRACE("FLIP_V");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
+ Color::RED, Color::GREEN);
+ }
+
+ Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
+ {
+ SCOPED_TRACE("ROT_90");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
+ Color::WHITE, Color::GREEN);
+ }
+
+ Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
+ {
+ SCOPED_TRACE("SCALE");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction()
+ .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .apply();
+ {
+ SCOPED_TRACE("IDENTITY");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
+ {
+ SCOPED_TRACE("FLIP_H");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
+ {
+ SCOPED_TRACE("FLIP_V");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
+ {
+ SCOPED_TRACE("ROT_90");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+
+ Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
+ {
+ SCOPED_TRACE("SCALE");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ const float rot = M_SQRT1_2; // 45 degrees
+ const float trans = M_SQRT2 * 16.0f;
+ Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
+
+ auto shot = getScreenCapture();
+ // check a 8x8 region inside each color
+ auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
+ const int32_t halfL = 4;
+ return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
+ };
+ const int32_t unit = int32_t(trans / 2);
+ shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
+ shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
+ shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
+ shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setMatrix is applied after any pending resize, unlike setPosition
+ Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ const Rect rect(0, 0, 32, 32);
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
+ {
+ SCOPED_TRACE("resize applied");
+ const Rect rect(0, 0, 128, 128);
+ getScreenCapture()->expectColor(rect, Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
+ Transaction()
+ .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+ .setSize(layer, 64, 64)
+ .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+ .apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ // XXX SCALE_CROP is not respected; calling setSize and
+ // setOverrideScalingMode in separate transactions does not work
+ // (b/69315456)
+ Transaction()
+ .setSize(layer, 64, 16)
+ .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
+ .apply();
+ {
+ SCOPED_TRACE("SCALE_TO_WINDOW");
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE, true /* filtered */);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+ const Rect crop(8, 8, 24, 24);
+
+ Transaction().setCrop_legacy(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(crop, Color::RED);
+ shot->expectBorder(crop, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+ const Rect crop(8, 8, 24, 24);
+
+ Transaction().setCrop(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("empty rect");
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("empty rect");
+ Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
+
+ Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
+
+ Transaction().setBuffer(layer, buffer).apply();
+
+ // Partially out of bounds in the negative (upper left) direction
+ Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply();
+ {
+ SCOPED_TRACE("out of bounds, negative (upper left) direction");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ }
+
+ // Partially out of bounds in the positive (lower right) direction
+ Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply();
+ {
+ SCOPED_TRACE("out of bounds, positive (lower right) direction");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ }
+
+ // Fully out of buffer space bounds
+ Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
+ {
+ SCOPED_TRACE("Fully out of bounds");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
+ shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
+ shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ const Point position(32, 32);
+ const Rect crop(8, 8, 24, 24);
+ Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(crop + position, Color::RED);
+ shot->expectBorder(crop + position, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ const Rect frame(32, 32, 64, 64);
+ const Rect crop(8, 8, 24, 24);
+ Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(frame, Color::RED);
+ shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // crop_legacy is affected by matrix
+ Transaction()
+ .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
+ .setCrop_legacy(layer, Rect(8, 8, 24, 24))
+ .apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ // setCrop_legacy is applied immediately by default, with or without resize pending
+ Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
+ {
+ SCOPED_TRACE("resize pending");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
+ shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
+ {
+ SCOPED_TRACE("resize applied");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
+ shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+ const Rect frame(8, 8, 24, 24);
+
+ Transaction().setFrame(layer, frame).apply();
+ auto shot = getScreenCapture();
+ shot->expectColor(frame, Color::RED);
+ shot->expectBorder(frame, Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("empty rect");
+ Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ {
+ SCOPED_TRACE("negative rect");
+ Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
+
+ // A parentless layer will default to a frame with the same size as the buffer
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
+ sp<SurfaceControl> parent, child;
+ ASSERT_NO_FATAL_FAILURE(
+ parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+ Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+ ASSERT_NO_FATAL_FAILURE(
+ child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+ Transaction().reparent(child, parent->getHandle()).apply();
+
+ // A layer will default to the frame of its parent
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
+ sp<SurfaceControl> parent, child;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
+
+ ASSERT_NO_FATAL_FAILURE(
+ child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+
+ Transaction().reparent(child, parent->getHandle()).apply();
+
+ // A layer will default to the frame of its parent
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+ Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply();
+
+ std::this_thread::sleep_for(500ms);
+
+ Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
+ shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
+ sp<SurfaceControl> parent, child;
+ ASSERT_NO_FATAL_FAILURE(
+ parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ ASSERT_NO_FATAL_FAILURE(
+ child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+ Transaction().reparent(child, parent->getHandle()).apply();
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
+ Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
+ Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
+ shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 1");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 2");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
+
+ {
+ SCOPED_TRACE("set buffer 3");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
+ sp<SurfaceControl> layer1;
+ ASSERT_NO_FATAL_FAILURE(
+ layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<SurfaceControl> layer2;
+ ASSERT_NO_FATAL_FAILURE(
+ layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
+
+ Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
+ {
+ SCOPED_TRACE("set layer 1 buffer red");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
+
+ Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
+ {
+ SCOPED_TRACE("set layer 2 buffer blue");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
+ shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
+ {
+ SCOPED_TRACE("set layer 1 buffer green");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+ shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+ shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+ }
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32));
+
+ {
+ SCOPED_TRACE("set layer 2 buffer white");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
+ shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
+ shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 10> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 70> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
+
+ std::array<sp<GraphicBuffer>, 65> buffers;
+
+ size_t idx = 0;
+ for (auto& buffer : buffers) {
+ buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ Color color = colors[idx % colors.size()];
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
+ idx++;
+ }
+
+ // Set each buffer twice. The first time adds it to the cache, the second time tests that the
+ // cache is working.
+ idx = 0;
+ for (auto& buffer : buffers) {
+ for (int i = 0; i < 2; i++) {
+ Transaction().setBuffer(layer, buffer).apply();
+
+ Color color = colors[idx % colors.size()];
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+ }
+ if (idx == 0) {
+ buffers[0].clear();
+ }
+ idx++;
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
+ .apply();
+
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
+ Color::GREEN, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
+ .apply();
+
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
+ Color::BLUE, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
+ Color::BLUE, Color::WHITE));
+
+ Transaction()
+ .setFrame(layer, Rect(0, 0, 32, 32))
+ .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
+ .apply();
+
+ getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
+ Color::GREEN, true /* filtered */);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ Transaction transaction;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ sp<Fence> fence;
+ if (getBuffer(nullptr, &fence) != NO_ERROR) {
+ GTEST_SUCCEED() << "test not supported";
+ return;
+ }
+
+ Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+
+ status_t status = fence->wait(1000);
+ ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
+ std::this_thread::sleep_for(200ms);
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ sp<Fence> fence = Fence::NO_FENCE;
+
+ Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Transaction().setBuffer(layer, buffer).setDataspace(layer, ui::Dataspace::UNKNOWN).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ HdrMetadata hdrMetadata;
+ hdrMetadata.validTypes = 0;
+ Transaction().setBuffer(layer, buffer).setHdrMetadata(layer, hdrMetadata).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Region region;
+ region.set(32, 32);
+ Transaction().setBuffer(layer, buffer).setSurfaceDamageRegion(layer, region).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
+
+ Transaction().setBuffer(layer, buffer).setApi(layer, NATIVE_WINDOW_API_CPU).apply();
+
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
+ shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(colorLayer =
+ createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor));
+ Transaction()
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(colorLayer, mLayerZBase + 1)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+ half3 expected = color;
+ mat3 matrix;
+ matrix[0][0] = 0.3;
+ matrix[1][0] = 0.59;
+ matrix[2][0] = 0.11;
+ matrix[0][1] = 0.3;
+ matrix[1][1] = 0.59;
+ matrix[2][1] = 0.11;
+ matrix[0][2] = 0.3;
+ matrix[1][2] = 0.59;
+ matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
+ Transaction().setColor(colorLayer, color).setColorTransform(colorLayer, matrix, vec3()).apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
+ sp<SurfaceControl> parentLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer));
+ ASSERT_NO_FATAL_FAILURE(
+ colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+
+ Transaction()
+ .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+ half3 expected = color;
+ mat3 matrix;
+ matrix[0][0] = 0.3;
+ matrix[1][0] = 0.59;
+ matrix[2][0] = 0.11;
+ matrix[0][1] = 0.3;
+ matrix[1][1] = 0.59;
+ matrix[2][1] = 0.11;
+ matrix[0][2] = 0.3;
+ matrix[1][2] = 0.59;
+ matrix[2][2] = 0.11;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrix);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
+ Transaction()
+ .setColor(colorLayer, color)
+ .setColorTransform(parentLayer, matrix, vec3())
+ .apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ }
+}
+
+TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
+ sp<SurfaceControl> parentLayer;
+ sp<SurfaceControl> colorLayer;
+ ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer));
+ ASSERT_NO_FATAL_FAILURE(
+ colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
+
+ Transaction()
+ .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
+ .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
+ .setLayer(parentLayer, mLayerZBase + 1)
+ .apply();
+ {
+ SCOPED_TRACE("default color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
+ half3 expected = color;
+ mat3 matrixChild;
+ matrixChild[0][0] = 0.3;
+ matrixChild[1][0] = 0.59;
+ matrixChild[2][0] = 0.11;
+ matrixChild[0][1] = 0.3;
+ matrixChild[1][1] = 0.59;
+ matrixChild[2][1] = 0.11;
+ matrixChild[0][2] = 0.3;
+ matrixChild[1][2] = 0.59;
+ matrixChild[2][2] = 0.11;
+ mat3 matrixParent;
+ matrixParent[0][0] = 0.2;
+ matrixParent[1][0] = 0.4;
+ matrixParent[2][0] = 0.10;
+ matrixParent[0][1] = 0.2;
+ matrixParent[1][1] = 0.4;
+ matrixParent[2][1] = 0.10;
+ matrixParent[0][2] = 0.2;
+ matrixParent[1][2] = 0.4;
+ matrixParent[2][2] = 0.10;
+
+ // degamma before applying the matrix
+ if (mColorManagementUsed) {
+ ColorTransformHelper::DegammaColor(expected);
+ }
+
+ ColorTransformHelper::applyMatrix(expected, matrixChild);
+ ColorTransformHelper::applyMatrix(expected, matrixParent);
+
+ if (mColorManagementUsed) {
+ ColorTransformHelper::GammaColor(expected);
+ }
+
+ const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
+ uint8_t(expected.b * 255), 255};
+
+ // this is handwavy, but the precison loss scaled by 255 (8-bit per
+ // channel) should be less than one
+ const uint8_t tolerance = 1;
+
+ Transaction()
+ .setColor(colorLayer, color)
+ .setColorTransform(parentLayer, matrixParent, vec3())
+ .setColorTransform(colorLayer, matrixChild, vec3())
+ .apply();
+ {
+ SCOPED_TRACE("new color");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
+ }
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTransactionTest.h b/services/surfaceflinger/tests/LayerTransactionTest.h
new file mode 100644
index 0000000..7edddb6
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTransactionTest.h
@@ -0,0 +1,296 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_LAYER_TRANSACTION_TEST_H
+#define ANDROID_LAYER_TRANSACTION_TEST_H
+
+#include <gtest/gtest.h>
+
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <hardware/hwcomposer_defs.h>
+#include <private/gui/ComposerService.h>
+
+#include <ui/DisplayInfo.h>
+
+#include "BufferGenerator.h"
+#include "utils/ScreenshotUtils.h"
+#include "utils/TransactionUtils.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTransactionTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mClient = new SurfaceComposerClient;
+ ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
+
+ ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
+ }
+
+ virtual void TearDown() {
+ mBlackBgSurface = 0;
+ mClient->dispose();
+ mClient = 0;
+ }
+
+ virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0, SurfaceControl* parent = nullptr) {
+ auto layer =
+ createSurface(client, name, width, height, PIXEL_FORMAT_RGBA_8888, flags, parent);
+
+ Transaction t;
+ t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
+
+ status_t error = t.apply();
+ if (error != NO_ERROR) {
+ ADD_FAILURE() << "failed to initialize SurfaceControl";
+ layer.clear();
+ }
+
+ return layer;
+ }
+
+ virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
+ const char* name, uint32_t width, uint32_t height,
+ PixelFormat format, uint32_t flags,
+ SurfaceControl* parent = nullptr) {
+ auto layer = client->createSurface(String8(name), width, height, format, flags, parent);
+ EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
+ return layer;
+ }
+
+ virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0, SurfaceControl* parent = nullptr) {
+ return createLayer(mClient, name, width, height, flags, parent);
+ }
+
+ sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
+ SurfaceControl* parent = nullptr) {
+ auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, parent);
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
+ t.setAlpha(colorLayer, color.a / 255.0f);
+ });
+ return colorLayer;
+ }
+
+ ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
+ // wait for previous transactions (such as setSize) to complete
+ Transaction().apply(true);
+
+ ANativeWindow_Buffer buffer = {};
+ EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
+
+ return buffer;
+ }
+
+ void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
+ ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
+
+ // wait for the newly posted buffer to be latched
+ waitForLayerBuffers();
+ }
+
+ virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
+ ANativeWindow_Buffer buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ TransactionUtils::fillANativeWindowBufferColor(buffer,
+ Rect(0, 0, bufferWidth, bufferHeight),
+ color);
+ postBufferQueueLayerBuffer(layer);
+ }
+
+ virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight),
+ color);
+ Transaction().setBuffer(layer, buffer).apply();
+ }
+
+ void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
+ int32_t bufferWidth, int32_t bufferHeight) {
+ switch (mLayerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
+ break;
+ default:
+ ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+ }
+ }
+
+ void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
+ int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
+ const Color& topRight, const Color& bottomLeft,
+ const Color& bottomRight) {
+ switch (mLayerType) {
+ case ISurfaceComposerClient::eFXSurfaceBufferQueue:
+ fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+ bottomLeft, bottomRight);
+ break;
+ case ISurfaceComposerClient::eFXSurfaceBufferState:
+ fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
+ bottomLeft, bottomRight);
+ break;
+ default:
+ ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
+ }
+ }
+
+ virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+ int32_t bufferHeight, const Color& topLeft,
+ const Color& topRight, const Color& bottomLeft,
+ const Color& bottomRight) {
+ ANativeWindow_Buffer buffer;
+ ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
+ ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+ const int32_t halfW = bufferWidth / 2;
+ const int32_t halfH = bufferHeight / 2;
+ TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+ TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
+ topRight);
+ TransactionUtils::fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
+ bottomLeft);
+ TransactionUtils::fillANativeWindowBufferColor(buffer,
+ Rect(halfW, halfH, bufferWidth,
+ bufferHeight),
+ bottomRight);
+
+ postBufferQueueLayerBuffer(layer);
+ }
+
+ virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+ int32_t bufferHeight, const Color& topLeft,
+ const Color& topRight, const Color& bottomLeft,
+ const Color& bottomRight) {
+ sp<GraphicBuffer> buffer =
+ new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
+ BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
+ BufferUsage::COMPOSER_OVERLAY,
+ "test");
+
+ ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
+
+ const int32_t halfW = bufferWidth / 2;
+ const int32_t halfH = bufferHeight / 2;
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH),
+ topRight);
+ TransactionUtils::fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight),
+ bottomLeft);
+ TransactionUtils::fillGraphicBufferColor(buffer,
+ Rect(halfW, halfH, bufferWidth, bufferHeight),
+ bottomRight);
+
+ Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
+ }
+
+ std::unique_ptr<ScreenCapture> screenshot() {
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ return screenshot;
+ }
+
+ void asTransaction(const std::function<void(Transaction&)>& exec) {
+ Transaction t;
+ exec(t);
+ t.apply(true);
+ }
+
+ static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
+ static BufferGenerator bufferGenerator;
+ return bufferGenerator.get(outBuffer, outFence);
+ }
+
+ sp<SurfaceComposerClient> mClient;
+
+ sp<IBinder> mDisplay;
+ uint32_t mDisplayWidth;
+ uint32_t mDisplayHeight;
+ uint32_t mDisplayLayerStack;
+ Rect mDisplayRect = Rect::INVALID_RECT;
+
+ // leave room for ~256 layers
+ const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
+
+ sp<SurfaceControl> mBlackBgSurface;
+ bool mColorManagementUsed;
+
+private:
+ void SetUpDisplay() {
+ mDisplay = mClient->getInternalDisplayToken();
+ ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
+
+ // get display width/height
+ DisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
+ mDisplayWidth = info.w;
+ mDisplayHeight = info.h;
+ mDisplayRect =
+ Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
+
+ // After a new buffer is queued, SurfaceFlinger is notified and will
+ // latch the new buffer on next vsync. Let's heuristically wait for 3
+ // vsyncs.
+ mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
+
+ mDisplayLayerStack = 0;
+
+ mBlackBgSurface =
+ createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+
+ // set layer stack (b/68888219)
+ Transaction t;
+ t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
+ t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
+ t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
+ t.setColor(mBlackBgSurface, half3{0, 0, 0});
+ t.setLayer(mBlackBgSurface, mLayerZBase);
+ t.apply();
+ }
+
+ void waitForLayerBuffers() {
+ // Request an empty transaction to get applied synchronously to ensure the buffer is
+ // latched.
+ Transaction().apply(true);
+ usleep(mBufferPostDelay);
+ }
+
+ int32_t mBufferPostDelay;
+
+ friend class LayerRenderPathTestHarness;
+};
+} // namespace android
+
+#endif
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
new file mode 100644
index 0000000..35c51e1
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <private/android_filesystem_config.h>
+#include <thread>
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<GraphicBuffer> outBuffer;
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+ .apply(true);
+ ASSERT_EQ(PERMISSION_DENIED,
+ composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ UIDFaker f(AID_SYSTEM);
+
+ // By default the system can capture screenshots with secure layers but they
+ // will be blacked out
+ ASSERT_EQ(NO_ERROR, composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ {
+ SCOPED_TRACE("as system");
+ auto shot = screenshot();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+
+ // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
+ // to receive them...we are expected to take care with the results.
+ bool outCapturedSecureLayers;
+ ASSERT_EQ(NO_ERROR,
+ composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
+ ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
+ 0, false, ISurfaceComposer::eRotateNone, true));
+ ASSERT_EQ(true, outCapturedSecureLayers);
+ ScreenCapture sc(outBuffer);
+ sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ Transaction().setTransformToDisplayInverse(layer, false).apply();
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32));
+
+ Transaction().setTransformToDisplayInverse(layer, true).apply();
+}
+
+TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(
+ layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
+
+ // verify this doesn't cause a crash
+ Transaction().setSidebandStream(layer, nullptr).apply();
+}
+
+TEST_F(LayerTransactionTest, ReparentToSelf) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
+ Transaction().reparent(layer, layer->getHandle()).apply();
+
+ {
+ // We expect the transaction to be silently dropped, but for SurfaceFlinger
+ // to still be functioning.
+ SCOPED_TRACE("after reparent to self");
+ const Rect rect(0, 0, 32, 32);
+ auto shot = screenshot();
+ shot->expectColor(rect, Color::RED);
+ shot->expectBorder(rect, Color::BLACK);
+ }
+}
+
+// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
+// the dropped buffer's damage region into the next buffer's damage region. If
+// we don't do this, we'll report an incorrect damage region to hardware
+// composer, resulting in broken rendering. This test checks the BufferQueue
+// case.
+//
+// Unfortunately, we don't currently have a way to inspect the damage region
+// SurfaceFlinger sends to hardware composer from a test, so this test requires
+// the dev to manually watch the device's screen during the test to spot broken
+// rendering. Because the results can't be automatically verified, this test is
+// marked disabled.
+TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
+ const int width = mDisplayWidth;
+ const int height = mDisplayHeight;
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
+ const auto producer = layer->getIGraphicBufferProducer();
+ const sp<IProducerListener> dummyListener(new DummyProducerListener);
+ IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
+ ASSERT_EQ(OK,
+ producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
+
+ std::map<int, sp<GraphicBuffer>> slotMap;
+ auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
+ ASSERT_NE(nullptr, buf);
+ const auto iter = slotMap.find(slot);
+ ASSERT_NE(slotMap.end(), iter);
+ *buf = iter->second;
+ };
+
+ auto dequeue = [&](int* outSlot) {
+ ASSERT_NE(nullptr, outSlot);
+ *outSlot = -1;
+ int slot;
+ sp<Fence> fence;
+ uint64_t age;
+ FrameEventHistoryDelta timestamps;
+ const status_t dequeueResult =
+ producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
+ GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ &age, ×tamps);
+ if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+ sp<GraphicBuffer> newBuf;
+ ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
+ ASSERT_NE(nullptr, newBuf.get());
+ slotMap[slot] = newBuf;
+ } else {
+ ASSERT_EQ(OK, dequeueResult);
+ }
+ *outSlot = slot;
+ };
+
+ auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
+ IGraphicBufferProducer::QueueBufferInput input(
+ /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
+ /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
+ /*transform=*/0, Fence::NO_FENCE);
+ input.setSurfaceDamage(damage);
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
+ };
+
+ auto fillAndPostBuffers = [&](const Color& color) {
+ int slot1;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
+ int slot2;
+ ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
+
+ sp<GraphicBuffer> buf1;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
+ sp<GraphicBuffer> buf2;
+ ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
+ TransactionUtils::fillGraphicBufferColor(buf1, Rect(width, height), color);
+ TransactionUtils::fillGraphicBufferColor(buf2, Rect(width, height), color);
+
+ const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
+ ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
+ ASSERT_NO_FATAL_FAILURE(
+ queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
+ displayTime));
+ };
+
+ const auto startTime = systemTime();
+ const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
+ int colorIndex = 0;
+ while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
+ ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
+ std::this_thread::sleep_for(1s);
+ }
+
+ ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
new file mode 100644
index 0000000..daeff17
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferItemConsumer.h>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTypeAndRenderTypeTransactionTest
+ : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
+public:
+ LayerTypeAndRenderTypeTransactionTest()
+ : LayerTypeTransactionHarness(std::get<0>(GetParam())),
+ mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ return mRenderPathHarness.getScreenCapture();
+ }
+
+protected:
+ LayerRenderPathTestHarness mRenderPathHarness;
+};
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
+ ::testing::Combine(
+ ::testing::Values(
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
+ ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
+ // cannot test robustness against invalid sizes (zero or really huge)
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction().setLayer(layerR, mLayerZBase + 1).apply();
+ {
+ SCOPED_TRACE("layerR");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ Transaction().setLayer(layerG, mLayerZBase + 2).apply();
+ {
+ SCOPED_TRACE("layerG");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction()
+ .setPosition(layerG, 16, 16)
+ .setRelativeLayer(layerG, layerR->getHandle(), 1)
+ .apply();
+
+ layerG.clear();
+ // layerG should have been removed
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
+ {
+ SCOPED_TRACE("layer hidden");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+
+ Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
+ {
+ SCOPED_TRACE("layer shown");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
+ const Color translucentRed = {100, 0, 0, 100};
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction()
+ .setLayer(layerR, mLayerZBase + 1)
+ .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+ .apply();
+ {
+ SCOPED_TRACE("layerR opaque");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
+ }
+
+ Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
+ {
+ SCOPED_TRACE("layerR translucent");
+ const uint8_t g = uint8_t(255 - translucentRed.a);
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+
+ Transaction()
+ .reparent(layerR, parent->getHandle())
+ .reparent(layerG, parent->getHandle())
+ .apply();
+ Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
+ {
+ SCOPED_TRACE("layerR");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+
+ Transaction().setLayer(layerR, -3).apply();
+ {
+ SCOPED_TRACE("layerG");
+ auto shot = getScreenCapture();
+ shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
+ const Color color = {64, 0, 0, 255};
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
+
+ Transaction().setAlpha(layer, 2.0f).apply();
+ {
+ SCOPED_TRACE("clamped to 1.0f");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
+ }
+
+ Transaction().setAlpha(layer, -1.0f).apply();
+ {
+ SCOPED_TRACE("clamped to 0.0f");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
+ sp<SurfaceControl> layer;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
+
+ Transaction()
+ .setCornerRadius(layer, cornerRadius)
+ .setCrop_legacy(layer, Rect(0, 0, size, size))
+ .apply();
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ // Transparent corners
+ shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+ shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
+ sp<SurfaceControl> parent;
+ sp<SurfaceControl> child;
+ const uint8_t size = 64;
+ const uint8_t testArea = 4;
+ const float cornerRadius = 20.0f;
+ ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
+ ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
+
+ Transaction()
+ .setCornerRadius(parent, cornerRadius)
+ .setCrop_legacy(parent, Rect(0, 0, size, size))
+ .reparent(child, parent->getHandle())
+ .setPosition(child, 0, size / 2)
+ .apply();
+ {
+ const uint8_t bottom = size - 1;
+ const uint8_t right = size - 1;
+ auto shot = getScreenCapture();
+ // Top edge of child should not have rounded corners because it's translated in the parent
+ shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
+ Color::GREEN);
+ // But bottom edges should have been clipped according to parent bounds
+ shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
+ shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
+ }
+}
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
+ sp<SurfaceControl> bufferLayer;
+ ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
+
+ // color is ignored
+ Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+}
+
+TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+ Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
+ {
+ SCOPED_TRACE("non-existing layer stack");
+ getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
+ }
+
+ Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
+ {
+ SCOPED_TRACE("original layer stack");
+ getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
+ }
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
new file mode 100644
index 0000000..42ec34a
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerTypeTransaction_test.cpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/BufferItemConsumer.h>
+#include "TransactionTestHarnesses.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
+ public ::testing::WithParamInterface<uint32_t> {
+public:
+ LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
+};
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+INSTANTIATE_TEST_CASE_P(
+ LayerTypeTransactionTests, LayerTypeTransactionTest,
+ ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
+ static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
+
+TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceContainer);
+ Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
+ sp<SurfaceControl> layerR;
+ sp<SurfaceControl> layerG;
+ sp<SurfaceControl> layerB;
+ ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
+ ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
+
+ Transaction().reparent(layerB, parent->getHandle()).apply();
+
+ // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
+ Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
+
+ std::unique_ptr<ScreenCapture> screenshot;
+ // only layerB is in this range
+ sp<IBinder> parentHandle = parent->getHandle();
+ ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
+ screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
+}
+
+TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ sp<SurfaceControl> childLayer;
+ ASSERT_NO_FATAL_FAILURE(
+ childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ parent.get()));
+ Transaction()
+ .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
+ .setColor(parent, half3{0.0f, 0.0f, 0.0f})
+ .show(childLayer)
+ .show(parent)
+ .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
+ .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
+ .apply();
+
+ Transaction()
+ .setRelativeLayer(childLayer, parent->getHandle(), -1)
+ .setLayer(childLayer, 1)
+ .apply();
+
+ {
+ SCOPED_TRACE("setLayer above");
+ // Set layer should get applied and place the child above.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
+ }
+
+ Transaction()
+ .setLayer(childLayer, 1)
+ .setRelativeLayer(childLayer, parent->getHandle(), -1)
+ .apply();
+
+ {
+ SCOPED_TRACE("setRelative below");
+ // Set relative layer should get applied and place the child below.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
+ sp<SurfaceControl> parent =
+ LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor);
+ sp<SurfaceControl> relativeParent =
+ LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor);
+
+ sp<SurfaceControl> childLayer;
+ ASSERT_NO_FATAL_FAILURE(
+ childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
+ 0 /* buffer height */,
+ ISurfaceComposerClient::eFXSurfaceColor,
+ parent.get()));
+ Transaction()
+ .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
+ .setColor(parent, half3{0.0f, 0.0f, 0.0f})
+ .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f})
+ .show(childLayer)
+ .show(parent)
+ .show(relativeParent)
+ .setLayer(parent, mLayerZBase - 1)
+ .setLayer(relativeParent, mLayerZBase)
+ .apply();
+
+ Transaction().setRelativeLayer(childLayer, relativeParent->getHandle(), 1).apply();
+
+ {
+ SCOPED_TRACE("setLayer above");
+ // Set layer should get applied and place the child above.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
+ }
+
+ Transaction().hide(relativeParent).apply();
+
+ {
+ SCOPED_TRACE("hide relative parent");
+ // The relative should no longer be visible.
+ std::unique_ptr<ScreenCapture> screenshot;
+ ScreenCapture::captureScreen(&screenshot);
+ screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
+ }
+}
+
+TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+ ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
+
+ sp<ISurfaceComposer> composer = ComposerService::getComposerService();
+ sp<GraphicBuffer> outBuffer;
+ Transaction()
+ .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
+ .apply(true);
+ ASSERT_EQ(PERMISSION_DENIED,
+ composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+
+ Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
+ ASSERT_EQ(NO_ERROR, composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
+}
+TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
+ sp<SurfaceControl> layer;
+ ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
+
+ sp<IBinder> handle = layer->getHandle();
+ ASSERT_TRUE(handle != nullptr);
+
+ FrameStats frameStats;
+ mClient->getLayerFrameStats(handle, &frameStats);
+
+ ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/LayerUpdate_test.cpp b/services/surfaceflinger/tests/LayerUpdate_test.cpp
new file mode 100644
index 0000000..73f563d
--- /dev/null
+++ b/services/surfaceflinger/tests/LayerUpdate_test.cpp
@@ -0,0 +1,1655 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class LayerUpdateTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ DisplayInfo info;
+ ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
+
+ ssize_t displayWidth = info.w;
+ ssize_t displayHeight = info.h;
+
+ // Background surface
+ mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth, displayHeight, 0);
+ ASSERT_TRUE(mBGSurfaceControl != nullptr);
+ ASSERT_TRUE(mBGSurfaceControl->isValid());
+ TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
+
+ // Foreground surface
+ mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0);
+
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+
+ // Synchronization surface
+ mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0);
+ ASSERT_TRUE(mSyncSurfaceControl != nullptr);
+ ASSERT_TRUE(mSyncSurfaceControl->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+
+ t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
+
+ t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .show(mFGSurfaceControl);
+
+ t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
+ .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
+ .show(mSyncSurfaceControl);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mBGSurfaceControl = 0;
+ mFGSurfaceControl = 0;
+ mSyncSurfaceControl = 0;
+ }
+
+ void waitForPostedBuffers() {
+ // Since the sync surface is in synchronous mode (i.e. double buffered)
+ // posting three buffers to it should ensure that at least two
+ // SurfaceFlinger::handlePageFlip calls have been made, which should
+ // guaranteed that a buffer posted to another Surface has been retired.
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ }
+
+ sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mFGSurfaceControl;
+
+ // This surface is used to ensure that the buffers posted to
+ // mFGSurfaceControl have been picked up by SurfaceFlinger.
+ sp<SurfaceControl> mSyncSurfaceControl;
+};
+
+TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
+ TransactionUtils::fillSurfaceRGBA8(relative, 10, 10, 10);
+ waitForPostedBuffers();
+
+ Transaction{}
+ .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
+ .setPosition(relative, 64, 64)
+ .apply();
+
+ {
+ // The relative should be on top of the FG control.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(64, 64, 10, 10, 10);
+ }
+ Transaction{}.detachChildren(mFGSurfaceControl).apply();
+
+ {
+ // Nothing should change at this point.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(64, 64, 10, 10, 10);
+ }
+
+ Transaction{}.hide(relative).apply();
+
+ {
+ // Ensure that the relative was actually hidden, rather than
+ // being left in the detached but visible state.
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(64, 64);
+ }
+}
+
+class GeometryLatchingTest : public LayerUpdateTest {
+protected:
+ void EXPECT_INITIAL_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // We find the leading edge of the FG surface.
+ sc->expectFGColor(127, 127);
+ sc->expectBGColor(128, 128);
+ }
+
+ void lockAndFillFGBuffer() {
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false);
+ }
+
+ void unlockFGBuffer() {
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ waitForPostedBuffers();
+ }
+
+ void completeFGResize() {
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+ }
+ void restoreInitialState() {
+ asTransaction([&](Transaction& t) {
+ t.setSize(mFGSurfaceControl, 64, 64);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
+ });
+
+ EXPECT_INITIAL_STATE("After restoring initial state");
+ }
+ std::unique_ptr<ScreenCapture> sc;
+};
+
+class CropLatchingTest : public GeometryLatchingTest {
+protected:
+ void EXPECT_CROPPED_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // The edge should be moved back one pixel by our crop.
+ sc->expectFGColor(126, 126);
+ sc->expectBGColor(127, 127);
+ sc->expectBGColor(128, 128);
+ }
+
+ void EXPECT_RESIZE_STATE(const char* trace) {
+ SCOPED_TRACE(trace);
+ ScreenCapture::captureScreen(&sc);
+ // The FG is now resized too 128,128 at 64,64
+ sc->expectFGColor(64, 64);
+ sc->expectFGColor(191, 191);
+ sc->expectBGColor(192, 192);
+ }
+};
+
+TEST_F(LayerUpdateTest, DeferredTransactionTest) {
+ std::unique_ptr<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before anything");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->expectFGColor(96, 96);
+ sc->expectBGColor(160, 160);
+ }
+
+ // set up two deferred transactions on different frames
+ asTransaction([&](Transaction& t) {
+ t.setAlpha(mFGSurfaceControl, 0.75);
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber());
+ });
+
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 128, 128);
+ t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
+ mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
+ });
+
+ {
+ SCOPED_TRACE("before any trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->expectFGColor(96, 96);
+ sc->expectBGColor(160, 160);
+ }
+
+ // should trigger the first deferred transaction, but not the second one
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ {
+ SCOPED_TRACE("after first trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->checkPixel(96, 96, 162, 63, 96);
+ sc->expectBGColor(160, 160);
+ }
+
+ // should show up immediately since it's not deferred
+ asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
+
+ // trigger the second deferred transaction
+ TransactionUtils::fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+ {
+ SCOPED_TRACE("after second trigger");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(32, 32);
+ sc->expectBGColor(96, 96);
+ sc->expectFGColor(160, 160);
+ }
+}
+
+TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ sp<SurfaceControl> childNoBuffer =
+ createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
+ PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
+ TransactionUtils::fillSurfaceRGBA8(childBuffer, 200, 200, 200);
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
+ .show(childNoBuffer)
+ .show(childBuffer)
+ .apply(true);
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectChildColor(73, 73);
+ sc->expectFGColor(74, 74);
+ }
+ SurfaceComposerClient::Transaction{}
+ .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
+ .apply(true);
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectChildColor(73, 73);
+ sc->expectChildColor(74, 74);
+ }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactions) {
+ std::unique_ptr<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before move");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(0, 12);
+ sc->expectFGColor(75, 75);
+ sc->expectBGColor(145, 145);
+ }
+
+ Transaction t1, t2;
+ t1.setPosition(mFGSurfaceControl, 128, 128);
+ t2.setPosition(mFGSurfaceControl, 0, 0);
+ // We expect that the position update from t2 now
+ // overwrites the position update from t1.
+ t1.merge(std::move(t2));
+ t1.apply();
+
+ {
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(1, 1);
+ }
+}
+
+TEST_F(LayerUpdateTest, MergingTransactionFlags) {
+ Transaction().hide(mFGSurfaceControl).apply();
+ std::unique_ptr<ScreenCapture> sc;
+ {
+ SCOPED_TRACE("before merge");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectBGColor(0, 12);
+ sc->expectBGColor(75, 75);
+ sc->expectBGColor(145, 145);
+ }
+
+ Transaction t1, t2;
+ t1.show(mFGSurfaceControl);
+ t2.setFlags(mFGSurfaceControl, 0 /* flags */, layer_state_t::eLayerSecure /* mask */);
+ t1.merge(std::move(t2));
+ t1.apply();
+
+ {
+ SCOPED_TRACE("after merge");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectFGColor(75, 75);
+ }
+}
+
+class ChildLayerTest : public LayerUpdateTest {
+protected:
+ void SetUp() override {
+ LayerUpdateTest::SetUp();
+ mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ SCOPED_TRACE("before anything");
+ mCapture = screenshot();
+ mCapture->expectChildColor(64, 64);
+ }
+ }
+ void TearDown() override {
+ LayerUpdateTest::TearDown();
+ mChild = 0;
+ }
+
+ sp<SurfaceControl> mChild;
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ChildLayerTest, ChildLayerPositioning) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground should now be at 0, 0
+ mCapture->expectFGColor(0, 0);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(10, 10);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(20, 20);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerCropping) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(4, 4);
+ mCapture->expectBGColor(5, 5);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerConstraints) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 63, 63);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(0, 0);
+ // Last pixel in foreground should now be the child.
+ mCapture->expectChildColor(63, 63);
+ // But the child should be constrained and the next pixel
+ // must be the background
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerScaling) {
+ asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
+
+ // Find the boundary between the parent and child
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
+
+ // The boundary should be twice as far from the origin now.
+ // The pixels from the last test should all be child now
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ mCapture->expectChildColor(19, 19);
+ mCapture->expectFGColor(20, 20);
+ }
+}
+
+// A child with a scale transform should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 0, 0);
+ });
+
+ // Find the boundary between the parent and child.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
+
+ // The child should fill its parent bounds and be cropped by it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerAlpha) {
+ TransactionUtils::fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
+ TransactionUtils::fillSurfaceRGBA8(mChild, 0, 254, 0);
+ waitForPostedBuffers();
+
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ // Unblended child color
+ mCapture->checkPixel(0, 0, 0, 254, 0);
+ }
+
+ asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
+
+ {
+ mCapture = screenshot();
+ // Child and BG blended.
+ mCapture->checkPixel(0, 0, 127, 127, 0);
+ }
+
+ asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
+
+ {
+ mCapture = screenshot();
+ // Child and BG blended.
+ mCapture->checkPixel(0, 0, 95, 64, 95);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentChildren) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ {
+ SCOPED_TRACE("Grandchild visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 111, 111, 111);
+ }
+
+ mChild.clear();
+
+ {
+ SCOPED_TRACE("After destroying child");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->expectFGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.reparent(mGrandChild, mFGSurfaceControl->getHandle()); });
+
+ {
+ SCOPED_TRACE("After reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 111, 111, 111);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildrenRelativeZSurvivesParentDestruction) {
+ sp<SurfaceControl> mGrandChild =
+ createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ TransactionUtils::fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
+
+ // draw grand child behind the foreground surface
+ asTransaction([&](Transaction& t) {
+ t.setRelativeLayer(mGrandChild, mFGSurfaceControl->getHandle(), -1);
+ });
+
+ {
+ SCOPED_TRACE("Child visible");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 200, 200, 200);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.reparent(mChild, nullptr);
+ t.reparentChildren(mChild, mFGSurfaceControl->getHandle());
+ });
+
+ {
+ SCOPED_TRACE("foreground visible reparenting grandchild");
+ ScreenCapture::captureScreen(&mCapture);
+ mCapture->checkPixel(64, 64, 195, 63, 63);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+ asTransaction([&](Transaction& t) { t.hide(mChild); });
+
+ // Since the child has the same client as the parent, it will not get
+ // detached and will be hidden.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectFGColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+ sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> mChildNewClient =
+ createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(mChildNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
+
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ t.show(mChildNewClient);
+ t.setPosition(mChildNewClient, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
+
+ asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+ Transaction()
+ .hide(mChild)
+ .show(childNewClient)
+ .setPosition(childNewClient, 10, 10)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ Transaction().detachChildren(mFGSurfaceControl).apply();
+ Transaction().hide(childNewClient).apply();
+
+ // Nothing should have changed.
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectChildColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+
+ sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
+ fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
+ 32);
+ Transaction()
+ .setLayer(newParentSurface, INT32_MAX - 1)
+ .show(newParentSurface)
+ .setPosition(newParentSurface, 20, 20)
+ .reparent(childNewClient, newParentSurface->getHandle())
+ .apply();
+ {
+ mCapture = screenshot();
+ // Child is now hidden.
+ mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
+ }
+}
+TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
+ sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> childNewClient =
+ newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ ASSERT_TRUE(childNewClient != nullptr);
+ ASSERT_TRUE(childNewClient->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(childNewClient, 200, 200, 200);
+
+ Transaction()
+ .hide(mChild)
+ .show(childNewClient)
+ .setPosition(childNewClient, 10, 10)
+ .setPosition(mFGSurfaceControl, 64, 64)
+ .apply();
+
+ {
+ mCapture = screenshot();
+ Rect rect = Rect(74, 74, 84, 84);
+ mCapture->expectBorder(rect, Color{195, 63, 63, 255});
+ mCapture->expectColor(rect, Color{200, 200, 200, 255});
+ }
+
+ Transaction()
+ .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber())
+ .apply();
+ Transaction().detachChildren(mFGSurfaceControl).apply();
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
+
+ // BufferLayer can still dequeue buffers even though there's a detached layer with a
+ // deferred transaction.
+ {
+ SCOPED_TRACE("new buffer");
+ mCapture = screenshot();
+ Rect rect = Rect(74, 74, 84, 84);
+ mCapture->expectBorder(rect, Color::RED);
+ mCapture->expectColor(rect, Color{200, 200, 200, 255});
+ }
+}
+
+TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ // We've positioned the child in the top left.
+ mCapture->expectChildColor(0, 0);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // We cause scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ {
+ mCapture = screenshot();
+ // We've positioned the child in the top left.
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(10, 10);
+ mCapture->expectChildColor(19, 29);
+ // And now it should be scaled all the way to 20x30
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
+// Regression test for b/37673612
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ // We've positioned the child in the top left.
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
+ }
+ // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
+ // the WM specified state size.
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ {
+ // The child should still be in the same place and not have any strange scaling as in
+ // b/37673612.
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectFGColor(10, 10);
+ }
+}
+
+// A child with a buffer transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 100, 100);
+ });
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should be cropped by the new parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(99, 63);
+ mCapture->expectFGColor(100, 63);
+ mCapture->expectBGColor(128, 64);
+ }
+}
+
+// A child with a scale transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 200, 200);
+ });
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Set a scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ // Child should inherit its parents scale but should be cropped by its parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(127, 127);
+ mCapture->expectBGColor(128, 128);
+ }
+}
+
+// Regression test for b/127368943
+// Child should ignore the buffer transform but apply parent scale transform.
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ mCapture->expectFGColor(10, 15);
+ }
+
+ // Change the size of the foreground to 128 * 64 so we can test rotation as well.
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ t.setSize(mFGSurfaceControl, 128, 64);
+ });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
+ // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 32, 64);
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should ignore the buffer transform but apply the 2.0 scale from parent.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(19, 29);
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
+TEST_F(ChildLayerTest, Bug36858924) {
+ // Destroy the child layer
+ mChild.clear();
+
+ // Now recreate it as hidden
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
+
+ // Show the child layer in a deferred transaction
+ asTransaction([&](Transaction& t) {
+ t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
+ mFGSurfaceControl->getSurface()->getNextFrameNumber());
+ t.show(mChild);
+ });
+
+ // Render the foreground surface a few times
+ //
+ // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
+ // frame because SurfaceFlinger would never process the deferred transaction and would therefore
+ // never acquire/release the first buffer
+ ALOGI("Filling 1");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
+ ALOGI("Filling 2");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
+ ALOGI("Filling 3");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
+ ALOGI("Filling 4");
+ TransactionUtils::fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
+}
+
+TEST_F(ChildLayerTest, Reparent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+
+ asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectFGColor(64, 64);
+ // In reparenting we should have exposed the entire foreground surface.
+ mCapture->expectFGColor(74, 74);
+ // And the child layer should now begin at 10, 10 (since the BG
+ // layer is at (0, 0)).
+ mCapture->expectBGColor(9, 9);
+ mCapture->expectChildColor(10, 10);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentToNoParent) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 10, 10);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // But 10 pixels in we should see the child surface
+ mCapture->expectChildColor(74, 74);
+ // And 10 more pixels we should be back to the foreground surface
+ mCapture->expectFGColor(84, 84);
+ }
+ asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
+ {
+ mCapture = screenshot();
+ // The surface should now be offscreen.
+ mCapture->expectFGColor(64, 64);
+ mCapture->expectFGColor(74, 74);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, ReparentFromNoParent) {
+ sp<SurfaceControl> newSurface = createLayer(String8("New Surface"), 10, 10, 0);
+ ASSERT_TRUE(newSurface != nullptr);
+ ASSERT_TRUE(newSurface->isValid());
+
+ TransactionUtils::fillSurfaceRGBA8(newSurface, 63, 195, 63);
+ asTransaction([&](Transaction& t) {
+ t.hide(mChild);
+ t.show(newSurface);
+ t.setPosition(newSurface, 10, 10);
+ t.setLayer(newSurface, INT32_MAX - 2);
+ t.setPosition(mFGSurfaceControl, 64, 64);
+ });
+
+ {
+ mCapture = screenshot();
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // At 10, 10 we should see the new surface
+ mCapture->checkPixel(10, 10, 63, 195, 63);
+ }
+
+ asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
+
+ {
+ mCapture = screenshot();
+ // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
+ // mFGSurface, putting it at 74, 74.
+ mCapture->expectFGColor(64, 64);
+ mCapture->checkPixel(74, 74, 63, 195, 63);
+ mCapture->expectFGColor(84, 84);
+ }
+}
+
+TEST_F(ChildLayerTest, NestedChildren) {
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
+ TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+ {
+ mCapture = screenshot();
+ // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
+ // which begins at 64, 64
+ mCapture->checkPixel(64, 64, 50, 50, 50);
+ }
+}
+
+TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
+ sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 128, 128, 0);
+ TransactionUtils::fillSurfaceRGBA8(relative, 255, 255, 255);
+
+ Transaction t;
+ t.setLayer(relative, INT32_MAX)
+ .setRelativeLayer(mChild, relative->getHandle(), 1)
+ .setPosition(mFGSurfaceControl, 0, 0)
+ .apply(true);
+
+ // We expect that the child should have been elevated above our
+ // INT_MAX layer even though it's not a child of it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->checkPixel(10, 10, 255, 255, 255);
+ }
+}
+
+class BoundlessLayerTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+// Verify setting a size on a buffer layer has no effect.
+TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
+ sp<SurfaceControl> bufferLayer =
+ createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ ASSERT_TRUE(bufferLayer->isValid());
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
+ asTransaction([&](Transaction& t) { t.show(bufferLayer); });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
+ // Buffer layer should not extend past buffer bounds
+ mCapture->expectFGColor(95, 95);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
+// which will crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
+// a crop which will be used to crop the color layer.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
+ sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(cropLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(cropLayer);
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // 5 pixels from the foreground we should see the child surface
+ mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
+ // 10 pixels from the foreground we should be back to the foreground surface
+ mCapture->expectFGColor(74, 74);
+ }
+}
+
+// Verify for boundless layer with no children, their transforms have no effect.
+TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(colorLayer, 320, 320);
+ t.setMatrix(colorLayer, 2, 0, 0, 2);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless layer with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> boundlessLayerRightShift =
+ createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayerRightShift->isValid());
+ sp<SurfaceControl> boundlessLayerDownShift =
+ createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, boundlessLayerRightShift.get());
+ ASSERT_TRUE(boundlessLayerDownShift->isValid());
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setPosition(boundlessLayerRightShift, 32, 0);
+ t.show(boundlessLayerRightShift);
+ t.setPosition(boundlessLayerDownShift, 0, 32);
+ t.show(boundlessLayerDownShift);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectFGColor(64, 64);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify child layers do not get clipped if they temporarily move into the negative
+// coordinate space as the result of an intermediate transformation.
+TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
+ sp<SurfaceControl> boundlessLayer =
+ mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ 0 /* flags */, mFGSurfaceControl.get());
+ ASSERT_TRUE(boundlessLayer != nullptr);
+ ASSERT_TRUE(boundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
+ ASSERT_TRUE(colorLayer != nullptr);
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ // shift child layer off bounds. If this layer was not boundless, we will
+ // expect the child layer to be cropped.
+ t.setPosition(boundlessLayer, 32, 32);
+ t.show(boundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ // undo shift by parent
+ t.setPosition(colorLayer, -32, -32);
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(129, 129);
+ }
+}
+
+// Verify for boundless root layers with children, their transforms have an effect.
+TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
+ sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
+ PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
+ ASSERT_TRUE(rootBoundlessLayer->isValid());
+ sp<SurfaceControl> colorLayer =
+ createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
+ ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
+
+ ASSERT_TRUE(colorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
+ t.setPosition(rootBoundlessLayer, 32, 32);
+ t.show(rootBoundlessLayer);
+ t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
+ t.setColor(colorLayer, half3{0, 0, 0});
+ t.show(colorLayer);
+ t.hide(mFGSurfaceControl);
+ });
+ {
+ mCapture = screenshot();
+ // Top left of background must now be visible
+ mCapture->expectBGColor(0, 0);
+ // Top left of foreground must now be visible
+ mCapture->expectBGColor(31, 31);
+ // Foreground Surface bounds must be color layer
+ mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
+ // Color layer should not extend past foreground bounds
+ mCapture->expectBGColor(97, 97);
+ }
+}
+
+class ScreenCaptureTest : public LayerUpdateTest {
+protected:
+ std::unique_ptr<ScreenCapture> mCapture;
+};
+
+TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
+ auto bgHandle = mBGSurfaceControl->getHandle();
+ ScreenCapture::captureLayers(&mCapture, bgHandle);
+ mCapture->expectBGColor(0, 0);
+ // Doesn't capture FG layer which is at 64, 64
+ mCapture->expectBGColor(64, 64);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ // Captures mFGSurfaceControl layer and its child.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ // Captures mFGSurfaceControl's child
+ ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .show(child2)
+ .setLayer(child, 1)
+ .setLayer(child2, 2)
+ .apply(true);
+
+ // Child2 would be visible but its excluded, so we should see child1 color instead.
+ ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+// Like the last test but verifies that children are also exclude.
+TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+ sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, child2.get());
+ TransactionUtils::fillSurfaceRGBA8(child2, 200, 0, 200);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .show(child2)
+ .show(child3)
+ .setLayer(child, 1)
+ .setLayer(child2, 2)
+ .apply(true);
+
+ // Child2 would be visible but its excluded, so we should see child1 color instead.
+ ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->checkPixel(0, 0, 200, 200, 200);
+}
+
+TEST_F(ScreenCaptureTest, CaptureTransparent) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(child).apply(true);
+
+ auto childHandle = child->getHandle();
+
+ // Captures child
+ ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
+ mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
+ // Area outside of child's bounds is transparent.
+ mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
+}
+
+TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ ASSERT_NE(nullptr, child.get()) << "failed to create surface";
+ sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ // Set relative layer above fg layer so should be shown above when computing all layers.
+ .setRelativeLayer(relative, fgHandle, 1)
+ .show(relative)
+ .apply(true);
+
+ // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ TransactionUtils::fillSurfaceRGBA8(relative, 100, 100, 100);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ // Set relative layer below fg layer but relative to child layer so it should be shown
+ // above child layer.
+ .setLayer(relative, -1)
+ .setRelativeLayer(relative, child->getHandle(), 1)
+ .show(relative)
+ .apply(true);
+
+ // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
+ // relative value should be taken into account, placing it above child layer.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ // Relative layer is showing on top of child layer
+ mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
+}
+
+// In the following tests we verify successful skipping of a parent layer,
+// so we use the same verification logic and only change how we mutate
+// the parent layer to verify that various properties are ignored.
+class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
+public:
+ void SetUp() override {
+ LayerUpdateTest::SetUp();
+
+ mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ SurfaceComposerClient::Transaction().show(mChild).apply(true);
+ }
+
+ void verify(std::function<void()> verifyStartingState) {
+ // Verify starting state before a screenshot is taken.
+ verifyStartingState();
+
+ // Verify child layer does not inherit any of the properties of its
+ // parent when its screenshot is captured.
+ auto fgHandle = mFGSurfaceControl->getHandle();
+ ScreenCapture::captureChildLayers(&mCapture, fgHandle);
+ mCapture->checkPixel(10, 10, 0, 0, 0);
+ mCapture->expectChildColor(0, 0);
+
+ // Verify all assumptions are still true after the screenshot is taken.
+ verifyStartingState();
+ }
+
+ std::unique_ptr<ScreenCapture> mCapture;
+ sp<SurfaceControl> mChild;
+};
+
+// Regression test b/76099859
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
+ SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
+
+ // Even though the parent is hidden we should still capture the child.
+
+ // Before and after reparenting, verify child is properly hidden
+ // when rendering full-screen.
+ verify([&] { screenshot()->expectBGColor(64, 64); });
+}
+
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
+ SurfaceComposerClient::Transaction()
+ .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
+ .apply(true);
+
+ // Even though the parent is cropped out we should still capture the child.
+
+ // Before and after reparenting, verify child is cropped by parent.
+ verify([&] { screenshot()->expectBGColor(65, 65); });
+}
+
+// Regression test b/124372894
+TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
+ SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
+
+ // We should not inherit the parent scaling.
+
+ // Before and after reparenting, verify child is properly scaled.
+ verify([&] { screenshot()->expectChildColor(80, 80); });
+}
+
+TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
+ auto fgHandle = mFGSurfaceControl->getHandle();
+
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
+
+ TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .setPosition(grandchild, 5, 5)
+ .show(grandchild)
+ .apply(true);
+
+ // Captures mFGSurfaceControl, its child, and the grandchild.
+ ScreenCapture::captureLayers(&mCapture, fgHandle);
+ mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(0, 0);
+ mCapture->checkPixel(5, 5, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureChildOnly) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ auto childHandle = child->getHandle();
+
+ SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
+
+ // Captures only the child layer, and not the parent.
+ ScreenCapture::captureLayers(&mCapture, childHandle);
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+}
+
+TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
+ sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
+ PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+ TransactionUtils::fillSurfaceRGBA8(child, 200, 200, 200);
+ auto childHandle = child->getHandle();
+
+ sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
+ PIXEL_FORMAT_RGBA_8888, 0, child.get());
+ TransactionUtils::fillSurfaceRGBA8(grandchild, 50, 50, 50);
+
+ SurfaceComposerClient::Transaction()
+ .show(child)
+ .setPosition(grandchild, 5, 5)
+ .show(grandchild)
+ .apply(true);
+
+ auto grandchildHandle = grandchild->getHandle();
+
+ // Captures only the grandchild.
+ ScreenCapture::captureLayers(&mCapture, grandchildHandle);
+ mCapture->checkPixel(0, 0, 50, 50, 50);
+ mCapture->checkPixel(4, 4, 50, 50, 50);
+}
+
+TEST_F(ScreenCaptureTest, CaptureCrop) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+ PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
+
+ SurfaceComposerClient::Transaction()
+ .setLayer(redLayer, INT32_MAX - 1)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+ mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+ // red area below the blue area
+ mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+ // red area to the right of the blue area
+ mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+ const Rect crop = Rect(0, 0, 30, 30);
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
+ // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
+ // area visible.
+ mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureSize) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+ sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
+ PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
+
+ SurfaceComposerClient::Transaction()
+ .setLayer(redLayer, INT32_MAX - 1)
+ .show(redLayer)
+ .show(blueLayer)
+ .apply(true);
+
+ auto redLayerHandle = redLayer->getHandle();
+
+ // Capturing full screen should have both red and blue are visible.
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle);
+ mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
+ // red area below the blue area
+ mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
+ // red area to the right of the blue area
+ mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
+
+ ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
+ // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
+ mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
+ // red area below the blue area
+ mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
+ // red area to the right of the blue area
+ mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
+ mCapture->checkPixel(30, 30, 0, 0, 0);
+}
+
+TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
+ sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
+
+ ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
+
+ auto redLayerHandle = redLayer->getHandle();
+ redLayer.clear();
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+
+ // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/MirrorLayer_test.cpp b/services/surfaceflinger/tests/MirrorLayer_test.cpp
new file mode 100644
index 0000000..0bcac1a
--- /dev/null
+++ b/services/surfaceflinger/tests/MirrorLayer_test.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class MirrorLayerTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ mParentLayer = createColorLayer("Parent layer", Color::RED);
+ mChildLayer = createColorLayer("Child layer", Color::GREEN, mParentLayer.get());
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mParentLayer, INT32_MAX - 2).show(mParentLayer);
+ t.setCrop_legacy(mChildLayer, Rect(0, 0, 400, 400)).show(mChildLayer);
+ t.setPosition(mChildLayer, 50, 50);
+ t.setFlags(mParentLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ t.setFlags(mChildLayer, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mParentLayer = 0;
+ mChildLayer = 0;
+ }
+
+ sp<SurfaceControl> mParentLayer;
+ sp<SurfaceControl> mChildLayer;
+};
+
+TEST_F(MirrorLayerTest, MirrorColorLayer) {
+ sp<SurfaceControl> grandchild =
+ createColorLayer("Grandchild layer", Color::BLUE, mChildLayer.get());
+ Transaction()
+ .setFlags(grandchild, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
+ .setCrop_legacy(grandchild, Rect(0, 0, 200, 200))
+ .show(grandchild)
+ .apply();
+
+ // Mirror mChildLayer
+ sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ ASSERT_NE(mirrorLayer, nullptr);
+
+ // Add mirrorLayer as child of mParentLayer so it's shown on the display
+ Transaction()
+ .reparent(mirrorLayer, mParentLayer->getHandle())
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ // Set color to white on grandchild layer.
+ Transaction().setColor(grandchild, half3{1, 1, 1}).apply();
+ {
+ SCOPED_TRACE("Updated Grandchild Layer Color");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ // Set color to black on child layer.
+ Transaction().setColor(mChildLayer, half3{0, 0, 0}).apply();
+ {
+ SCOPED_TRACE("Updated Child Layer Color");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+
+ // Remove grandchild layer
+ Transaction().reparent(grandchild, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed Grandchild Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLACK);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+
+ // Remove child layer
+ Transaction().reparent(mChildLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed Child Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+ }
+
+ // Add grandchild layer to offscreen layer
+ Transaction().reparent(grandchild, mChildLayer->getHandle()).apply();
+ {
+ SCOPED_TRACE("Added Grandchild Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::RED);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::RED);
+ }
+
+ // Add child layer
+ Transaction().reparent(mChildLayer, mParentLayer->getHandle()).apply();
+ {
+ SCOPED_TRACE("Added Child Layer");
+ auto shot = screenshot();
+ // Grandchild mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::BLACK);
+ }
+}
+
+TEST_F(MirrorLayerTest, MirrorBufferLayer) {
+ sp<SurfaceControl> bufferQueueLayer =
+ createLayer("BufferQueueLayer", 200, 200, 0, mChildLayer.get());
+ fillBufferQueueLayerColor(bufferQueueLayer, Color::BLUE, 200, 200);
+ Transaction().show(bufferQueueLayer).apply();
+
+ sp<SurfaceControl> mirrorLayer = mClient->mirrorSurface(mChildLayer.get());
+ Transaction()
+ .reparent(mirrorLayer, mParentLayer->getHandle())
+ .setPosition(mirrorLayer, 500, 500)
+ .show(mirrorLayer)
+ .apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ fillBufferQueueLayerColor(bufferQueueLayer, Color::WHITE, 200, 200);
+ {
+ SCOPED_TRACE("Update BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ Transaction().reparent(bufferQueueLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed BufferQueueLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ sp<SurfaceControl> bufferStateLayer =
+ createLayer("BufferStateLayer", 200, 200, ISurfaceComposerClient::eFXSurfaceBufferState,
+ mChildLayer.get());
+ fillBufferStateLayerColor(bufferStateLayer, Color::BLUE, 200, 200);
+ Transaction().setFrame(bufferStateLayer, Rect(0, 0, 200, 200)).show(bufferStateLayer).apply();
+
+ {
+ SCOPED_TRACE("Initial Mirror BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::BLUE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ fillBufferStateLayerColor(bufferStateLayer, Color::WHITE, 200, 200);
+ {
+ SCOPED_TRACE("Update BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::WHITE);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+
+ Transaction().reparent(bufferStateLayer, nullptr).apply();
+ {
+ SCOPED_TRACE("Removed BufferStateLayer");
+ auto shot = screenshot();
+ // Buffer mirror
+ shot->expectColor(Rect(550, 550, 750, 750), Color::GREEN);
+ // Child mirror
+ shot->expectColor(Rect(750, 750, 950, 950), Color::GREEN);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
new file mode 100644
index 0000000..066c9aa
--- /dev/null
+++ b/services/surfaceflinger/tests/MultiDisplayLayerBounds_test.cpp
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
+
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&mProducer, &consumer);
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
+ }
+
+ virtual void TearDown() {
+ SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
+ LayerTransactionTest::TearDown();
+ mColorLayer = 0;
+ }
+
+ void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
+ mVirtualDisplay =
+ SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
+ asTransaction([&](Transaction& t) {
+ t.setDisplaySurface(mVirtualDisplay, mProducer);
+ t.setDisplayLayerStack(mVirtualDisplay, layerStack);
+ t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
+ Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
+ });
+ }
+
+ void createColorLayer(uint32_t layerStack) {
+ mColorLayer =
+ createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
+ PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
+ ASSERT_TRUE(mColorLayer != nullptr);
+ ASSERT_TRUE(mColorLayer->isValid());
+ asTransaction([&](Transaction& t) {
+ t.setLayerStack(mColorLayer, layerStack);
+ t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
+ t.setLayer(mColorLayer, INT32_MAX - 2);
+ t.setColor(mColorLayer,
+ half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
+ mExpectedColor.b / 255.0f});
+ t.show(mColorLayer);
+ });
+ }
+
+ DisplayInfo mMainDisplayInfo;
+ sp<IBinder> mMainDisplay;
+ sp<IBinder> mVirtualDisplay;
+ sp<IGraphicBufferProducer> mProducer;
+ sp<SurfaceControl> mColorLayer;
+ Color mExpectedColor = {63, 63, 195, 255};
+};
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
+ createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
+ createColorLayer(1 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer does not render on main display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ // Verify color layer renders correctly on virtual display.
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0});
+}
+
+TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
+ // Create a display and set its layer stack to the main display's layer stack so
+ // the contents of the main display are mirrored on to the virtual display.
+
+ // Assumption here is that the new mirrored display has the same viewport as the
+ // primary display that it is mirroring.
+ createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
+ createColorLayer(0 /* layerStack */);
+
+ asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
+
+ // Verify color layer renders correctly on main display and it is mirrored on the
+ // virtual display.
+ std::unique_ptr<ScreenCapture> sc;
+ ScreenCapture::captureScreen(&sc, mMainDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+
+ ScreenCapture::captureScreen(&sc, mVirtualDisplay);
+ sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
+ sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/RelativeZ_test.cpp b/services/surfaceflinger/tests/RelativeZ_test.cpp
new file mode 100644
index 0000000..8549db2
--- /dev/null
+++ b/services/surfaceflinger/tests/RelativeZ_test.cpp
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+::testing::Environment* const binderEnv =
+ ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
+
+class RelativeZTest : public LayerTransactionTest {
+protected:
+ virtual void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ const auto display = SurfaceComposerClient::getInternalDisplayToken();
+ ASSERT_FALSE(display == nullptr);
+
+ // Back layer
+ mBackgroundLayer = createColorLayer("Background layer", Color::RED);
+
+ // Front layer
+ mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
+
+ asTransaction([&](Transaction& t) {
+ t.setDisplayLayerStack(display, 0);
+ t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
+ t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
+ });
+ }
+
+ virtual void TearDown() {
+ LayerTransactionTest::TearDown();
+ mBackgroundLayer = 0;
+ mForegroundLayer = 0;
+ }
+
+ sp<SurfaceControl> mBackgroundLayer;
+ sp<SurfaceControl> mForegroundLayer;
+};
+
+// When a layer is reparented offscreen, remove relative z order if the relative parent
+// is still onscreen so that the layer is not drawn.
+TEST_F(RelativeZTest, LayerRemoved) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Child layer (WHITE) (relative to foregroud layer)
+ // Foregroud layer (GREEN)
+ sp<SurfaceControl> childLayer =
+ createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
+
+ Transaction{}
+ .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
+ .show(childLayer)
+ .apply();
+
+ {
+ // The childLayer should be in front of the FG control.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, nullptr).apply();
+
+ // Background layer (RED)
+ // Child layer (WHITE)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
+
+ {
+ // The relative z info for child layer should be reset, leaving FG control on top.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+}
+
+// When a layer is reparented offscreen, preseve relative z order if the relative parent
+// is also offscreen. Regression test b/132613412
+TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
+ std::unique_ptr<ScreenCapture> sc;
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1 (WHITE)
+ // child level 2a (BLUE)
+ // child level 3 (GREEN) (relative to child level 2b)
+ // child level 2b (BLACK)
+ sp<SurfaceControl> childLevel1 =
+ createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
+ sp<SurfaceControl> childLevel2a =
+ createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
+ sp<SurfaceControl> childLevel2b =
+ createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
+ sp<SurfaceControl> childLevel3 =
+ createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
+
+ Transaction{}
+ .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
+ .show(childLevel2a)
+ .show(childLevel2b)
+ .show(childLevel3)
+ .apply();
+
+ {
+ // The childLevel3 should be in front of childLevel2b.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ Transaction{}.reparent(childLevel1, nullptr).apply();
+
+ // Background layer (RED)
+ // Foregroud layer (GREEN)
+ // child level 1 (WHITE)
+ // child level 2 back (BLUE)
+ // child level 3 (GREEN) (relative to child level 2b)
+ // child level 2 front (BLACK)
+ Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
+
+ {
+ // Nothing should change at this point since relative z info was preserved.
+ ScreenCapture::captureScreen(&sc);
+ sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
+ }
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/SetGeometry_test.cpp b/services/surfaceflinger/tests/SetGeometry_test.cpp
new file mode 100644
index 0000000..dca06ec
--- /dev/null
+++ b/services/surfaceflinger/tests/SetGeometry_test.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LayerTransactionTest.h"
+
+namespace android {
+
+class SetGeometryTest : public LayerTransactionTest {
+protected:
+ void SetUp() {
+ LayerTransactionTest::SetUp();
+ ASSERT_EQ(NO_ERROR, mClient->initCheck());
+
+ mLayer = createLayer("Layer", mLayerWidth, mLayerHeight);
+ fillBufferQueueLayerColor(mLayer, Color::RED, mLayerWidth, mLayerHeight);
+ asTransaction([&](Transaction& t) { t.setLayer(mLayer, INT32_MAX - 1).show(mLayer); });
+
+ {
+ SCOPED_TRACE("init");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(Rect(0, 0, mLayerWidth, mLayerHeight), Color::RED);
+ sc->expectBorder(Rect(0, 0, mLayerWidth, mLayerHeight), Color::BLACK);
+ }
+ }
+
+ void TearDown() {
+ LayerTransactionTest::TearDown();
+ sc = 0;
+ mLayer = 0;
+ }
+
+ std::unique_ptr<ScreenCapture> sc;
+ sp<SurfaceControl> mLayer;
+ const int mLayerWidth = 100;
+ const int mLayerHeight = 200;
+};
+
+TEST_F(SetGeometryTest, SourceAtZeroNoScale) {
+ Rect source = Rect(0, 0, 30, 30);
+ Rect dest = Rect(60, 60, 90, 90);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("geometry applied");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+TEST_F(SetGeometryTest, SourceNotAtZero) {
+ Rect source = Rect(40, 40, 70, 70);
+ Rect dest = Rect(60, 60, 90, 90);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("geometry applied");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+TEST_F(SetGeometryTest, Scale) {
+ Rect source = Rect(0, 0, 100, 200);
+ Rect dest = Rect(0, 0, 200, 400);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+
+ {
+ SCOPED_TRACE("Scaled by 2");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+
+ dest = Rect(0, 0, 50, 100);
+ Transaction{}.setGeometry(mLayer, source, dest, 0).apply();
+ {
+ SCOPED_TRACE("Scaled by .5");
+ ScreenCapture::captureScreen(&sc);
+ sc->expectColor(dest, Color::RED);
+ sc->expectBorder(dest, Color::BLACK);
+ }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 6b4634a..b196684 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
{
"presubmit": {
- "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*"
+ "filter": "CredentialsTest.*:SurfaceFlingerStress.*:SurfaceInterceptorTest.*:LayerTransactionTest.*:LayerTypeTransactionTest.*:LayerUpdateTest.*:GeometryLatchingTest.*:CropLatchingTest.*:ChildLayerTest.*:ScreenCaptureTest.*:ScreenCaptureChildOnlyTest.*:DereferenceSurfaceControlTest.*:BoundlessLayerTest.*:MultiDisplayLayerBoundsTest.*:InvalidHandleTest.*:VirtualDisplayTest.*:RelativeZTest.*:SetGeometryTest.*"
}
}
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index 5cc946a..59e9c00 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -36,6 +36,9 @@
namespace android {
using Transaction = SurfaceComposerClient::Transaction;
+using SurfaceChange = surfaceflinger::SurfaceChange;
+using Trace = surfaceflinger::Trace;
+using Increment = surfaceflinger::Increment;
constexpr int32_t SCALING_UPDATE = 1;
constexpr uint32_t BUFFER_UPDATES = 18;
@@ -43,18 +46,21 @@
constexpr uint32_t SIZE_UPDATE = 134;
constexpr uint32_t STACK_UPDATE = 1;
constexpr uint64_t DEFERRED_UPDATE = 0;
+constexpr int32_t RELATIVE_Z = 42;
constexpr float ALPHA_UPDATE = 0.29f;
constexpr float CORNER_RADIUS_UPDATE = 0.2f;
constexpr float POSITION_UPDATE = 121;
const Rect CROP_UPDATE(16, 16, 32, 32);
const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
-constexpr auto TEST_SURFACE_NAME = "BG Interceptor Test Surface";
-constexpr auto UNIQUE_TEST_SURFACE_NAME = "BG Interceptor Test Surface#0";
+constexpr auto TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface";
+constexpr auto TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface";
+constexpr auto UNIQUE_TEST_BG_SURFACE_NAME = "BG Interceptor Test Surface#0";
+constexpr auto UNIQUE_TEST_FG_SURFACE_NAME = "FG Interceptor Test Surface#0";
constexpr auto LAYER_NAME = "Layer Create and Delete Test";
constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
-constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
+constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
// Fill an RGBA_8888 formatted surface with a single color.
static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b) {
@@ -136,12 +142,15 @@
void TearDown() override {
mComposerClient->dispose();
mBGSurfaceControl.clear();
+ mFGSurfaceControl.clear();
mComposerClient.clear();
}
sp<SurfaceComposerClient> mComposerClient;
sp<SurfaceControl> mBGSurfaceControl;
+ sp<SurfaceControl> mFGSurfaceControl;
int32_t mBGLayerId;
+ int32_t mFGLayerId;
public:
using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
@@ -177,6 +186,10 @@
bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
+ bool reparentUpdateFound(const SurfaceChange& change, bool found);
+ bool relativeParentUpdateFound(const SurfaceChange& change, bool found);
+ bool detachChildrenUpdateFound(const SurfaceChange& change, bool found);
+ bool reparentChildrenUpdateFound(const SurfaceChange& change, bool found);
bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
// Find all of the updates in the single trace
@@ -209,6 +222,10 @@
void opaqueFlagUpdate(Transaction&);
void secureFlagUpdate(Transaction&);
void deferredTransactionUpdate(Transaction&);
+ void reparentUpdate(Transaction&);
+ void relativeParentUpdate(Transaction&);
+ void detachChildrenUpdate(Transaction&);
+ void reparentChildrenUpdate(Transaction&);
void surfaceCreation(Transaction&);
void displayCreation(Transaction&);
void displayDeletion(Transaction&);
@@ -250,21 +267,30 @@
ssize_t displayHeight = info.h;
// Background surface
- mBGSurfaceControl = mComposerClient->createSurface(
- String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
- PIXEL_FORMAT_RGBA_8888, 0);
+ mBGSurfaceControl = mComposerClient->createSurface(String8(TEST_BG_SURFACE_NAME), displayWidth,
+ displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
ASSERT_TRUE(mBGSurfaceControl != nullptr);
ASSERT_TRUE(mBGSurfaceControl->isValid());
+ // Foreground surface
+ mFGSurfaceControl = mComposerClient->createSurface(String8(TEST_FG_SURFACE_NAME), displayWidth,
+ displayHeight, PIXEL_FORMAT_RGBA_8888, 0);
+ ASSERT_TRUE(mFGSurfaceControl != nullptr);
+ ASSERT_TRUE(mFGSurfaceControl->isValid());
+
Transaction t;
t.setDisplayLayerStack(display, 0);
- ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
- .show(mBGSurfaceControl)
- .apply());
+ ASSERT_EQ(NO_ERROR,
+ t.setLayer(mBGSurfaceControl, INT_MAX - 3)
+ .show(mBGSurfaceControl)
+ .setLayer(mFGSurfaceControl, INT_MAX - 3)
+ .show(mFGSurfaceControl)
+ .apply());
}
void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
- mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME);
+ mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_BG_SURFACE_NAME);
+ mFGLayerId = getSurfaceId(trace, UNIQUE_TEST_FG_SURFACE_NAME);
}
void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
@@ -364,6 +390,22 @@
DEFERRED_UPDATE);
}
+void SurfaceInterceptorTest::reparentUpdate(Transaction& t) {
+ t.reparent(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+}
+
+void SurfaceInterceptorTest::relativeParentUpdate(Transaction& t) {
+ t.setRelativeLayer(mBGSurfaceControl, mFGSurfaceControl->getHandle(), RELATIVE_Z);
+}
+
+void SurfaceInterceptorTest::detachChildrenUpdate(Transaction& t) {
+ t.detachChildren(mBGSurfaceControl);
+}
+
+void SurfaceInterceptorTest::reparentChildrenUpdate(Transaction& t) {
+ t.reparentChildren(mBGSurfaceControl, mFGSurfaceControl->getHandle());
+}
+
void SurfaceInterceptorTest::displayCreation(Transaction&) {
sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, true);
SurfaceComposerClient::destroyDisplay(testDisplay);
@@ -389,6 +431,10 @@
runInTransaction(&SurfaceInterceptorTest::opaqueFlagUpdate);
runInTransaction(&SurfaceInterceptorTest::secureFlagUpdate);
runInTransaction(&SurfaceInterceptorTest::deferredTransactionUpdate);
+ runInTransaction(&SurfaceInterceptorTest::reparentUpdate);
+ runInTransaction(&SurfaceInterceptorTest::reparentChildrenUpdate);
+ runInTransaction(&SurfaceInterceptorTest::detachChildrenUpdate);
+ runInTransaction(&SurfaceInterceptorTest::relativeParentUpdate);
}
void SurfaceInterceptorTest::surfaceCreation(Transaction&) {
@@ -569,6 +615,46 @@
return foundDeferred;
}
+bool SurfaceInterceptorTest::reparentUpdateFound(const SurfaceChange& change, bool found) {
+ bool hasId(change.reparent().parent_id() == mFGLayerId);
+ if (hasId && !found) {
+ found = true;
+ } else if (hasId && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::relativeParentUpdateFound(const SurfaceChange& change, bool found) {
+ bool hasId(change.relative_parent().relative_parent_id() == mFGLayerId);
+ if (hasId && !found) {
+ found = true;
+ } else if (hasId && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::detachChildrenUpdateFound(const SurfaceChange& change, bool found) {
+ bool detachChildren(change.detach_children().detach_children());
+ if (detachChildren && !found) {
+ found = true;
+ } else if (detachChildren && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
+bool SurfaceInterceptorTest::reparentChildrenUpdateFound(const SurfaceChange& change, bool found) {
+ bool hasId(change.reparent_children().parent_id() == mFGLayerId);
+ if (hasId && !found) {
+ found = true;
+ } else if (hasId && found) {
+ []() { FAIL(); }();
+ }
+ return found;
+}
+
bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
SurfaceChange::SurfaceChangeCase changeCase) {
bool foundUpdate = false;
@@ -620,6 +706,18 @@
case SurfaceChange::SurfaceChangeCase::kDeferredTransaction:
foundUpdate = deferredTransactionUpdateFound(change, foundUpdate);
break;
+ case SurfaceChange::SurfaceChangeCase::kReparent:
+ foundUpdate = reparentUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kReparentChildren:
+ foundUpdate = reparentChildrenUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kRelativeParent:
+ foundUpdate = relativeParentUpdateFound(change, foundUpdate);
+ break;
+ case SurfaceChange::SurfaceChangeCase::kDetachChildren:
+ foundUpdate = detachChildrenUpdateFound(change, foundUpdate);
+ break;
case SurfaceChange::SurfaceChangeCase::SURFACECHANGE_NOT_SET:
break;
}
@@ -644,6 +742,10 @@
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kOpaqueFlag));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSecureFlag));
ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDeferredTransaction));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparent));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kReparentChildren));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kRelativeParent));
+ ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kDetachChildren));
}
bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
@@ -798,6 +900,26 @@
SurfaceChange::SurfaceChangeCase::kDeferredTransaction);
}
+TEST_F(SurfaceInterceptorTest, InterceptReparentUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::reparentUpdate,
+ SurfaceChange::SurfaceChangeCase::kReparent);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptReparentChildrenUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::reparentChildrenUpdate,
+ SurfaceChange::SurfaceChangeCase::kReparentChildren);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptRelativeParentUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::relativeParentUpdate,
+ SurfaceChange::SurfaceChangeCase::kRelativeParent);
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptDetachChildrenUpdateWorks) {
+ captureTest(&SurfaceInterceptorTest::detachChildrenUpdate,
+ SurfaceChange::SurfaceChangeCase::kDetachChildren);
+}
+
TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
captureTest(&SurfaceInterceptorTest::runAllUpdates,
&SurfaceInterceptorTest::assertAllUpdatesFound);
@@ -861,5 +983,4 @@
ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
}
-
}
diff --git a/services/surfaceflinger/tests/TransactionTestHarnesses.h b/services/surfaceflinger/tests/TransactionTestHarnesses.h
new file mode 100644
index 0000000..8fdcde4
--- /dev/null
+++ b/services/surfaceflinger/tests/TransactionTestHarnesses.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#ifndef ANDROID_TRANSACTION_TEST_HARNESSES
+#define ANDROID_TRANSACTION_TEST_HARNESSES
+
+/*#include <algorithm>
+#include <chrono>
+#include <cinttypes>
+#include <functional>
+#include <limits>
+#include <ostream>
+
+#include <android/native_window.h>
+
+#include <binder/ProcessState.h>
+#include <gui/BufferItemConsumer.h>
+#include <gui/IProducerListener.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/LayerState.h>
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+#include <hardware/hwcomposer_defs.h>
+#include <private/android_filesystem_config.h>
+#include <private/gui/ComposerService.h>
+
+#include <ui/DisplayInfo.h>
+
+#include <math.h>
+#include <math/vec3.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "BufferGenerator.h"
+*/
+#include "LayerTransactionTest.h"
+/*#include "utils/CallbackUtils.h"
+#include "utils/ColorUtils.h"
+#include "utils/ScreenshotUtils.h"
+#include "utils/TransactionUtils.h"
+*/
+namespace android {
+
+using android::hardware::graphics::common::V1_1::BufferUsage;
+
+class LayerRenderPathTestHarness {
+public:
+ LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
+ : mDelegate(delegate), mRenderPath(renderPath) {}
+
+ std::unique_ptr<ScreenCapture> getScreenCapture() {
+ switch (mRenderPath) {
+ case RenderPath::SCREENSHOT:
+ return mDelegate->screenshot();
+ case RenderPath::VIRTUAL_DISPLAY:
+
+ const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
+ DisplayInfo mainDisplayInfo;
+ SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
+
+ sp<IBinder> vDisplay;
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ sp<BufferItemConsumer> itemConsumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ consumer->setConsumerName(String8("Virtual disp consumer"));
+ consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
+
+ itemConsumer = new BufferItemConsumer(consumer,
+ // Sample usage bits from screenrecord
+ GRALLOC_USAGE_HW_VIDEO_ENCODER |
+ GRALLOC_USAGE_SW_READ_OFTEN);
+
+ vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
+ false /*secure*/);
+
+ SurfaceComposerClient::Transaction t;
+ t.setDisplaySurface(vDisplay, producer);
+ t.setDisplayLayerStack(vDisplay, 0);
+ t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
+ Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
+ Rect(mainDisplayInfo.w, mainDisplayInfo.h));
+ t.apply();
+ SurfaceComposerClient::Transaction().apply(true);
+ BufferItem item;
+ itemConsumer->acquireBuffer(&item, 0, true);
+ auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
+ itemConsumer->releaseBuffer(item);
+ SurfaceComposerClient::destroyDisplay(vDisplay);
+ return sc;
+ }
+ }
+
+protected:
+ LayerTransactionTest* mDelegate;
+ RenderPath mRenderPath;
+};
+
+class LayerTypeTransactionHarness : public LayerTransactionTest {
+public:
+ LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
+
+ sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
+ uint32_t flags = 0, SurfaceControl* parent = nullptr) {
+ // if the flags already have a layer type specified, return an error
+ if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
+ return nullptr;
+ }
+ return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType, parent);
+ }
+
+ void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
+ int32_t bufferHeight) {
+ ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
+ bufferWidth, bufferHeight));
+ }
+
+ void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
+ int32_t bufferHeight, const Color& topLeft, const Color& topRight,
+ const Color& bottomLeft, const Color& bottomRight) {
+ ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
+ bufferWidth, bufferHeight,
+ topLeft, topRight,
+ bottomLeft, bottomRight));
+ }
+
+protected:
+ uint32_t mLayerType;
+};
+} // namespace android
+#endif
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
deleted file mode 100644
index c93e15e..0000000
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ /dev/null
@@ -1,6156 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <algorithm>
-#include <chrono>
-#include <cinttypes>
-#include <functional>
-#include <limits>
-#include <ostream>
-#include <thread>
-
-#include <gtest/gtest.h>
-
-#include <android/native_window.h>
-
-#include <binder/ProcessState.h>
-#include <gui/BufferItemConsumer.h>
-#include <gui/IProducerListener.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/LayerState.h>
-#include <gui/Surface.h>
-#include <gui/SurfaceComposerClient.h>
-#include <hardware/hwcomposer_defs.h>
-#include <private/android_filesystem_config.h>
-#include <private/gui/ComposerService.h>
-
-#include <ui/ColorSpace.h>
-#include <ui/DisplayInfo.h>
-#include <ui/Rect.h>
-#include <utils/String8.h>
-
-#include <math.h>
-#include <math/vec3.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "BufferGenerator.h"
-
-namespace android {
-
-namespace {
-
-struct Color {
- uint8_t r;
- uint8_t g;
- uint8_t b;
- uint8_t a;
-
- static const Color RED;
- static const Color GREEN;
- static const Color BLUE;
- static const Color WHITE;
- static const Color BLACK;
- static const Color TRANSPARENT;
-};
-
-const Color Color::RED{255, 0, 0, 255};
-const Color Color::GREEN{0, 255, 0, 255};
-const Color Color::BLUE{0, 0, 255, 255};
-const Color Color::WHITE{255, 255, 255, 255};
-const Color Color::BLACK{0, 0, 0, 255};
-const Color Color::TRANSPARENT{0, 0, 0, 0};
-
-using android::hardware::graphics::common::V1_1::BufferUsage;
-using namespace std::chrono_literals;
-
-std::ostream& operator<<(std::ostream& os, const Color& color) {
- os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
- return os;
-}
-
-// Fill a region with the specified color.
-void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
- const Color& color) {
- Rect r(0, 0, buffer.width, buffer.height);
- if (!r.intersect(rect, &r)) {
- return;
- }
-
- int32_t width = r.right - r.left;
- int32_t height = r.bottom - r.top;
-
- for (int32_t row = 0; row < height; row++) {
- uint8_t* dst =
- static_cast<uint8_t*>(buffer.bits) + (buffer.stride * (r.top + row) + r.left) * 4;
- for (int32_t column = 0; column < width; column++) {
- dst[0] = color.r;
- dst[1] = color.g;
- dst[2] = color.b;
- dst[3] = color.a;
- dst += 4;
- }
- }
-}
-
-// Fill a region with the specified color.
-void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect, const Color& color) {
- Rect r(0, 0, buffer->width, buffer->height);
- if (!r.intersect(rect, &r)) {
- return;
- }
-
- int32_t width = r.right - r.left;
- int32_t height = r.bottom - r.top;
-
- uint8_t* pixels;
- buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- reinterpret_cast<void**>(&pixels));
-
- for (int32_t row = 0; row < height; row++) {
- uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
- for (int32_t column = 0; column < width; column++) {
- dst[0] = color.r;
- dst[1] = color.g;
- dst[2] = color.b;
- dst[3] = color.a;
- dst += 4;
- }
- }
- buffer->unlock();
-}
-
-// Check if a region has the specified color.
-void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels, const Rect& rect,
- const Color& color, uint8_t tolerance) {
- int32_t x = rect.left;
- int32_t y = rect.top;
- int32_t width = rect.right - rect.left;
- int32_t height = rect.bottom - rect.top;
-
- int32_t bufferWidth = int32_t(outBuffer->getWidth());
- int32_t bufferHeight = int32_t(outBuffer->getHeight());
- if (x + width > bufferWidth) {
- x = std::min(x, bufferWidth);
- width = bufferWidth - x;
- }
- if (y + height > bufferHeight) {
- y = std::min(y, bufferHeight);
- height = bufferHeight - y;
- }
-
- auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
- uint8_t tmp = a >= b ? a - b : b - a;
- return tmp <= tolerance;
- };
- for (int32_t j = 0; j < height; j++) {
- const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
- for (int32_t i = 0; i < width; i++) {
- const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
- EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
- << "pixel @ (" << x + i << ", " << y + j << "): "
- << "expected (" << color << "), "
- << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
- src += 4;
- }
- }
-}
-
-} // anonymous namespace
-
-using Transaction = SurfaceComposerClient::Transaction;
-
-// Fill an RGBA_8888 formatted surface with a single color.
-static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
- bool unlock = true) {
- ANativeWindow_Buffer outBuffer;
- sp<Surface> s = sc->getSurface();
- ASSERT_TRUE(s != nullptr);
- ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
- uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
- for (int y = 0; y < outBuffer.height; y++) {
- for (int x = 0; x < outBuffer.width; x++) {
- uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
- pixel[0] = r;
- pixel[1] = g;
- pixel[2] = b;
- pixel[3] = 255;
- }
- }
- if (unlock) {
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- }
-}
-
-// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
-// individual pixel values for testing purposes.
-class ScreenCapture : public RefBase {
-public:
- static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
- captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
- }
-
- static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
- const auto sf = ComposerService::getComposerService();
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- static void captureChildLayersExcluding(
- std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
- std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
- ASSERT_EQ(NO_ERROR,
- sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
- ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
- 1.0f, true));
- *sc = std::make_unique<ScreenCapture>(outBuffer);
- }
-
- void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
- ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
- expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
- }
-
- void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
- ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
- const bool leftBorder = rect.left > 0;
- const bool topBorder = rect.top > 0;
- const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
- const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
-
- if (topBorder) {
- Rect top(rect.left, rect.top - 1, rect.right, rect.top);
- if (leftBorder) {
- top.left -= 1;
- }
- if (rightBorder) {
- top.right += 1;
- }
- expectColor(top, color, tolerance);
- }
- if (leftBorder) {
- Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
- expectColor(left, color, tolerance);
- }
- if (rightBorder) {
- Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
- expectColor(right, color, tolerance);
- }
- if (bottomBorder) {
- Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
- if (leftBorder) {
- bottom.left -= 1;
- }
- if (rightBorder) {
- bottom.right += 1;
- }
- expectColor(bottom, color, tolerance);
- }
- }
-
- void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
- const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
- uint8_t tolerance = 0) {
- ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
-
- const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
- const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
- // avoid checking borders due to unspecified filtering behavior
- const int32_t offsetX = filtered ? 2 : 0;
- const int32_t offsetY = filtered ? 2 : 0;
- expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
- tolerance);
- expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
- tolerance);
- expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
- tolerance);
- expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
- bottomRight, tolerance);
- }
-
- void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
- ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
- const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
- if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
- String8 err(String8::format("pixel @ (%3d, %3d): "
- "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
- x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
- EXPECT_EQ(String8(), err) << err.string();
- }
- }
-
- void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
-
- void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
-
- void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
-
- explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
- mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
- }
-
- ~ScreenCapture() { mOutBuffer->unlock(); }
-
-private:
- sp<GraphicBuffer> mOutBuffer;
- uint8_t* mPixels = nullptr;
-};
-
-class LayerTransactionTest : public ::testing::Test {
-protected:
- void SetUp() override {
- mClient = new SurfaceComposerClient;
- ASSERT_EQ(NO_ERROR, mClient->initCheck()) << "failed to create SurfaceComposerClient";
-
- ASSERT_NO_FATAL_FAILURE(SetUpDisplay());
-
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- ASSERT_NO_FATAL_FAILURE(sf->getColorManagement(&mColorManagementUsed));
- }
-
- virtual void TearDown() {
- mBlackBgSurface = 0;
- mClient->dispose();
- mClient = 0;
- }
-
- virtual sp<SurfaceControl> createLayer(const sp<SurfaceComposerClient>& client,
- const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr) {
- auto layer =
- createSurface(client, name, width, height, PIXEL_FORMAT_RGBA_8888, flags, parent);
-
- Transaction t;
- t.setLayerStack(layer, mDisplayLayerStack).setLayer(layer, mLayerZBase);
-
- status_t error = t.apply();
- if (error != NO_ERROR) {
- ADD_FAILURE() << "failed to initialize SurfaceControl";
- layer.clear();
- }
-
- return layer;
- }
-
- virtual sp<SurfaceControl> createSurface(const sp<SurfaceComposerClient>& client,
- const char* name, uint32_t width, uint32_t height,
- PixelFormat format, uint32_t flags,
- SurfaceControl* parent = nullptr) {
- auto layer = client->createSurface(String8(name), width, height, format, flags, parent);
- EXPECT_NE(nullptr, layer.get()) << "failed to create SurfaceControl";
- return layer;
- }
-
- virtual sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr) {
- return createLayer(mClient, name, width, height, flags, parent);
- }
-
- sp<SurfaceControl> createColorLayer(const char* name, const Color& color,
- SurfaceControl* parent = nullptr) {
- auto colorLayer = createSurface(mClient, name, 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, parent);
- asTransaction([&](Transaction& t) {
- t.setColor(colorLayer, half3{color.r / 255.0f, color.g / 255.0f, color.b / 255.0f});
- t.setAlpha(colorLayer, color.a / 255.0f);
- });
- return colorLayer;
- }
-
- ANativeWindow_Buffer getBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
- // wait for previous transactions (such as setSize) to complete
- Transaction().apply(true);
-
- ANativeWindow_Buffer buffer = {};
- EXPECT_EQ(NO_ERROR, layer->getSurface()->lock(&buffer, nullptr));
-
- return buffer;
- }
-
- void postBufferQueueLayerBuffer(const sp<SurfaceControl>& layer) {
- ASSERT_EQ(NO_ERROR, layer->getSurface()->unlockAndPost());
-
- // wait for the newly posted buffer to be latched
- waitForLayerBuffers();
- }
-
- virtual void fillBufferQueueLayerColor(const sp<SurfaceControl>& layer, const Color& color,
- int32_t bufferWidth, int32_t bufferHeight) {
- ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
- fillANativeWindowBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
- postBufferQueueLayerBuffer(layer);
- }
-
- virtual void fillBufferStateLayerColor(const sp<SurfaceControl>& layer, const Color& color,
- int32_t bufferWidth, int32_t bufferHeight) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, bufferWidth, bufferHeight), color);
- Transaction().setBuffer(layer, buffer).apply();
- }
-
- void fillLayerColor(uint32_t mLayerType, const sp<SurfaceControl>& layer, const Color& color,
- int32_t bufferWidth, int32_t bufferHeight) {
- switch (mLayerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- fillBufferQueueLayerColor(layer, color, bufferWidth, bufferHeight);
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- fillBufferStateLayerColor(layer, color, bufferWidth, bufferHeight);
- break;
- default:
- ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
- }
- }
-
- void fillLayerQuadrant(uint32_t mLayerType, const sp<SurfaceControl>& layer,
- int32_t bufferWidth, int32_t bufferHeight, const Color& topLeft,
- const Color& topRight, const Color& bottomLeft,
- const Color& bottomRight) {
- switch (mLayerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- fillBufferQueueLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
- bottomLeft, bottomRight);
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- fillBufferStateLayerQuadrant(layer, bufferWidth, bufferHeight, topLeft, topRight,
- bottomLeft, bottomRight);
- break;
- default:
- ASSERT_TRUE(false) << "unsupported layer type: " << mLayerType;
- }
- }
-
- virtual void fillBufferQueueLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
- int32_t bufferHeight, const Color& topLeft,
- const Color& topRight, const Color& bottomLeft,
- const Color& bottomRight) {
- ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
- ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
-
- const int32_t halfW = bufferWidth / 2;
- const int32_t halfH = bufferHeight / 2;
- fillANativeWindowBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
- fillANativeWindowBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
- fillANativeWindowBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
- fillANativeWindowBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight),
- bottomRight);
-
- postBufferQueueLayerBuffer(layer);
- }
-
- virtual void fillBufferStateLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
- int32_t bufferHeight, const Color& topLeft,
- const Color& topRight, const Color& bottomLeft,
- const Color& bottomRight) {
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(bufferWidth, bufferHeight, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- ASSERT_TRUE(bufferWidth % 2 == 0 && bufferHeight % 2 == 0);
-
- const int32_t halfW = bufferWidth / 2;
- const int32_t halfH = bufferHeight / 2;
- fillGraphicBufferColor(buffer, Rect(0, 0, halfW, halfH), topLeft);
- fillGraphicBufferColor(buffer, Rect(halfW, 0, bufferWidth, halfH), topRight);
- fillGraphicBufferColor(buffer, Rect(0, halfH, halfW, bufferHeight), bottomLeft);
- fillGraphicBufferColor(buffer, Rect(halfW, halfH, bufferWidth, bufferHeight), bottomRight);
-
- Transaction().setBuffer(layer, buffer).setSize(layer, bufferWidth, bufferHeight).apply();
- }
-
- std::unique_ptr<ScreenCapture> screenshot() {
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- return screenshot;
- }
-
- void asTransaction(const std::function<void(Transaction&)>& exec) {
- Transaction t;
- exec(t);
- t.apply(true);
- }
-
- static status_t getBuffer(sp<GraphicBuffer>* outBuffer, sp<Fence>* outFence) {
- static BufferGenerator bufferGenerator;
- return bufferGenerator.get(outBuffer, outFence);
- }
-
- sp<SurfaceComposerClient> mClient;
-
- sp<IBinder> mDisplay;
- uint32_t mDisplayWidth;
- uint32_t mDisplayHeight;
- uint32_t mDisplayLayerStack;
- Rect mDisplayRect = Rect::INVALID_RECT;
-
- // leave room for ~256 layers
- const int32_t mLayerZBase = std::numeric_limits<int32_t>::max() - 256;
-
- sp<SurfaceControl> mBlackBgSurface;
- bool mColorManagementUsed;
-
-private:
- void SetUpDisplay() {
- mDisplay = mClient->getInternalDisplayToken();
- ASSERT_FALSE(mDisplay == nullptr) << "failed to get display";
-
- // get display width/height
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(mDisplay, &info));
- mDisplayWidth = info.w;
- mDisplayHeight = info.h;
- mDisplayRect =
- Rect(static_cast<int32_t>(mDisplayWidth), static_cast<int32_t>(mDisplayHeight));
-
- // After a new buffer is queued, SurfaceFlinger is notified and will
- // latch the new buffer on next vsync. Let's heuristically wait for 3
- // vsyncs.
- mBufferPostDelay = int32_t(1e6 / info.fps) * 3;
-
- mDisplayLayerStack = 0;
-
- mBlackBgSurface =
- createSurface(mClient, "BaseSurface", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
-
- // set layer stack (b/68888219)
- Transaction t;
- t.setDisplayLayerStack(mDisplay, mDisplayLayerStack);
- t.setCrop_legacy(mBlackBgSurface, Rect(0, 0, mDisplayWidth, mDisplayHeight));
- t.setLayerStack(mBlackBgSurface, mDisplayLayerStack);
- t.setColor(mBlackBgSurface, half3{0, 0, 0});
- t.setLayer(mBlackBgSurface, mLayerZBase);
- t.apply();
- }
-
- void waitForLayerBuffers() {
- // Request an empty transaction to get applied synchronously to ensure the buffer is
- // latched.
- Transaction().apply(true);
- usleep(mBufferPostDelay);
- }
-
- int32_t mBufferPostDelay;
-
- friend class LayerRenderPathTestHarness;
-};
-enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
-
-class LayerRenderPathTestHarness {
-public:
- LayerRenderPathTestHarness(LayerTransactionTest* delegate, RenderPath renderPath)
- : mDelegate(delegate), mRenderPath(renderPath) {}
-
- std::unique_ptr<ScreenCapture> getScreenCapture() {
- switch (mRenderPath) {
- case RenderPath::SCREENSHOT:
- return mDelegate->screenshot();
- case RenderPath::VIRTUAL_DISPLAY:
-
- const auto mainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- DisplayInfo mainDisplayInfo;
- SurfaceComposerClient::getDisplayInfo(mainDisplay, &mainDisplayInfo);
-
- sp<IBinder> vDisplay;
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- sp<BufferItemConsumer> itemConsumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
-
- consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mainDisplayInfo.w, mainDisplayInfo.h);
-
- itemConsumer = new BufferItemConsumer(consumer,
- // Sample usage bits from screenrecord
- GRALLOC_USAGE_HW_VIDEO_ENCODER |
- GRALLOC_USAGE_SW_READ_OFTEN);
-
- vDisplay = SurfaceComposerClient::createDisplay(String8("VirtualDisplay"),
- false /*secure*/);
-
- SurfaceComposerClient::Transaction t;
- t.setDisplaySurface(vDisplay, producer);
- t.setDisplayLayerStack(vDisplay, 0);
- t.setDisplayProjection(vDisplay, mainDisplayInfo.orientation,
- Rect(mainDisplayInfo.viewportW, mainDisplayInfo.viewportH),
- Rect(mainDisplayInfo.w, mainDisplayInfo.h));
- t.apply();
- SurfaceComposerClient::Transaction().apply(true);
- BufferItem item;
- itemConsumer->acquireBuffer(&item, 0, true);
- auto sc = std::make_unique<ScreenCapture>(item.mGraphicBuffer);
- itemConsumer->releaseBuffer(item);
- SurfaceComposerClient::destroyDisplay(vDisplay);
- return sc;
- }
- }
-
-protected:
- LayerTransactionTest* mDelegate;
- RenderPath mRenderPath;
-};
-
-class LayerTypeTransactionHarness : public LayerTransactionTest {
-public:
- LayerTypeTransactionHarness(uint32_t layerType) : mLayerType(layerType) {}
-
- sp<SurfaceControl> createLayer(const char* name, uint32_t width, uint32_t height,
- uint32_t flags = 0, SurfaceControl* parent = nullptr) {
- // if the flags already have a layer type specified, return an error
- if (flags & ISurfaceComposerClient::eFXSurfaceMask) {
- return nullptr;
- }
- return LayerTransactionTest::createLayer(name, width, height, flags | mLayerType, parent);
- }
-
- void fillLayerColor(const sp<SurfaceControl>& layer, const Color& color, int32_t bufferWidth,
- int32_t bufferHeight) {
- ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerColor(mLayerType, layer, color,
- bufferWidth, bufferHeight));
- }
-
- void fillLayerQuadrant(const sp<SurfaceControl>& layer, int32_t bufferWidth,
- int32_t bufferHeight, const Color& topLeft, const Color& topRight,
- const Color& bottomLeft, const Color& bottomRight) {
- ASSERT_NO_FATAL_FAILURE(LayerTransactionTest::fillLayerQuadrant(mLayerType, layer,
- bufferWidth, bufferHeight,
- topLeft, topRight,
- bottomLeft, bottomRight));
- }
-
-protected:
- uint32_t mLayerType;
-};
-
-class LayerTypeTransactionTest : public LayerTypeTransactionHarness,
- public ::testing::WithParamInterface<uint32_t> {
-public:
- LayerTypeTransactionTest() : LayerTypeTransactionHarness(GetParam()) {}
-};
-
-class LayerTypeAndRenderTypeTransactionTest
- : public LayerTypeTransactionHarness,
- public ::testing::WithParamInterface<std::tuple<uint32_t, RenderPath>> {
-public:
- LayerTypeAndRenderTypeTransactionTest()
- : LayerTypeTransactionHarness(std::get<0>(GetParam())),
- mRenderPathHarness(LayerRenderPathTestHarness(this, std::get<1>(GetParam()))) {}
-
- std::unique_ptr<ScreenCapture> getScreenCapture() {
- return mRenderPathHarness.getScreenCapture();
- }
-
-protected:
- LayerRenderPathTestHarness mRenderPathHarness;
-};
-
-// Environment for starting up binder threads. This is required for testing
-// virtual displays, as BufferQueue parameters may be queried over binder.
-class BinderEnvironment : public ::testing::Environment {
-public:
- void SetUp() override { ProcessState::self()->startThreadPool(); }
-};
-
-::testing::Environment* const binderEnv =
- ::testing::AddGlobalTestEnvironment(new BinderEnvironment());
-
-class LayerRenderTypeTransactionTest : public LayerTransactionTest,
- public ::testing::WithParamInterface<RenderPath> {
-public:
- LayerRenderTypeTransactionTest() : mHarness(LayerRenderPathTestHarness(this, GetParam())) {}
-
- std::unique_ptr<ScreenCapture> getScreenCapture() { return mHarness.getScreenCapture(); }
- void setRelativeZBasicHelper(uint32_t layerType);
- void setRelativeZGroupHelper(uint32_t layerType);
- void setAlphaBasicHelper(uint32_t layerType);
- void setBackgroundColorHelper(uint32_t layerType, bool priorColor, bool bufferFill, float alpha,
- Color finalColor);
-
-protected:
- LayerRenderPathTestHarness mHarness;
-};
-
-INSTANTIATE_TEST_CASE_P(
- LayerTypeAndRenderTypeTransactionTests, LayerTypeAndRenderTypeTransactionTest,
- ::testing::Combine(
- ::testing::Values(
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)),
- ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT)));
-
-INSTANTIATE_TEST_CASE_P(LayerRenderTypeTransactionTests, LayerRenderTypeTransactionTest,
- ::testing::Values(RenderPath::VIRTUAL_DISPLAY, RenderPath::SCREENSHOT));
-
-INSTANTIATE_TEST_CASE_P(
- LayerTypeTransactionTests, LayerTypeTransactionTest,
- ::testing::Values(static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferQueue),
- static_cast<uint32_t>(ISurfaceComposerClient::eFXSurfaceBufferState)));
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("default position");
- const Rect rect(0, 0, 32, 32);
- auto shot = getScreenCapture();
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- Transaction().setPosition(layer, 5, 10).apply();
- {
- SCOPED_TRACE("new position");
- const Rect rect(5, 10, 37, 42);
- auto shot = getScreenCapture();
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionRounding_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // GLES requires only 4 bits of subpixel precision during rasterization
- // XXX GLES composition does not match HWC composition due to precision
- // loss (b/69315223)
- const float epsilon = 1.0f / 16.0f;
- Transaction().setPosition(layer, 0.5f - epsilon, 0.5f - epsilon).apply();
- {
- SCOPED_TRACE("rounding down");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setPosition(layer, 0.5f + epsilon, 0.5f + epsilon).apply();
- {
- SCOPED_TRACE("rounding up");
- getScreenCapture()->expectColor(Rect(1, 1, 33, 33), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setPosition(layer, -32, -32).apply();
- {
- SCOPED_TRACE("negative coordinates");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-
- Transaction().setPosition(layer, mDisplayWidth, mDisplayHeight).apply();
- {
- SCOPED_TRACE("positive coordinates");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionPartiallyOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // partially out of bounds
- Transaction().setPosition(layer, -30, -30).apply();
- {
- SCOPED_TRACE("negative coordinates");
- getScreenCapture()->expectColor(Rect(0, 0, 2, 2), Color::RED);
- }
-
- Transaction().setPosition(layer, mDisplayWidth - 2, mDisplayHeight - 2).apply();
- {
- SCOPED_TRACE("positive coordinates");
- getScreenCapture()->expectColor(Rect(mDisplayWidth - 2, mDisplayHeight - 2, mDisplayWidth,
- mDisplayHeight),
- Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setPosition is applied immediately by default, with or without resize
- // pending
- Transaction().setPosition(layer, 5, 10).setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(5, 10, 37, 42);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // request setPosition to be applied with the next resize
- Transaction().setPosition(layer, 5, 10).setGeometryAppliesWithResize(layer).apply();
- {
- SCOPED_TRACE("new position pending");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setPosition(layer, 15, 20).apply();
- {
- SCOPED_TRACE("pending new position modified");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // finally resize and latch the buffer
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("new position applied");
- getScreenCapture()->expectColor(Rect(15, 20, 79, 84), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetPositionWithNextResizeScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setPosition is not immediate even with SCALE_TO_WINDOW override
- Transaction()
- .setPosition(layer, 5, 10)
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("new position pending");
- getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("new position applied");
- getScreenCapture()->expectColor(Rect(5, 10, 69, 74), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 32, 32);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 64, 64);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetSizeInvalid) {
- // cannot test robustness against invalid sizes (zero or really huge)
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSizeWithScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setSize is immediate with SCALE_TO_WINDOW, unlike setPosition
- Transaction()
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 64, 64), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZBasic) {
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction().setLayer(layerR, mLayerZBase + 1).apply();
- {
- SCOPED_TRACE("layerR");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setLayer(layerG, mLayerZBase + 2).apply();
- {
- SCOPED_TRACE("layerG");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetZNegative) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer);
- Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction()
- .reparent(layerR, parent->getHandle())
- .reparent(layerG, parent->getHandle())
- .apply();
- Transaction().setLayer(layerR, -1).setLayer(layerG, -2).apply();
- {
- SCOPED_TRACE("layerR");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setLayer(layerR, -3).apply();
- {
- SCOPED_TRACE("layerG");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::GREEN);
- }
-}
-
-void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
-
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setPosition(layerG, 16, 16)
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setFrame(layerR, Rect(0, 0, 32, 32))
- .setFrame(layerG, Rect(16, 16, 48, 48))
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
- break;
- default:
- ASSERT_FALSE(true) << "Unsupported layer type";
- }
- {
- SCOPED_TRACE("layerG above");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectColor(Rect(16, 16, 48, 48), Color::GREEN);
- }
-
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).apply();
- {
- SCOPED_TRACE("layerG below");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectColor(Rect(32, 32, 48, 48), Color::GREEN);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferQueue) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZBasic_BufferState) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeTransactionTest, SetRelativeZNegative) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer);
- Transaction().setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight)).apply();
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- sp<SurfaceControl> layerB;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test B", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerB, Color::BLUE, 32, 32));
-
- Transaction()
- .reparent(layerB, parent->getHandle())
- .apply();
-
- // layerR = mLayerZBase, layerG = layerR - 1, layerB = -2
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -1).setLayer(layerB, -2).apply();
-
- std::unique_ptr<ScreenCapture> screenshot;
- // only layerB is in this range
- sp<IBinder> parentHandle = parent->getHandle();
- ScreenCapture::captureLayers(&screenshot, parentHandle, Rect(0, 0, 32, 32));
- screenshot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
-}
-
-TEST_P(LayerTypeTransactionTest, SetLayerAndRelative) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
-
- sp<SurfaceControl> childLayer;
- ASSERT_NO_FATAL_FAILURE(
- childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
- parent.get()));
- Transaction()
- .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
- .setColor(parent, half3{0.0f, 0.0f, 0.0f})
- .show(childLayer)
- .show(parent)
- .setCrop_legacy(parent, Rect(0, 0, mDisplayWidth, mDisplayHeight))
- .setCrop_legacy(childLayer, Rect(0, 0, 20, 30))
- .apply();
-
- Transaction()
- .setRelativeLayer(childLayer, parent->getHandle(), -1)
- .setLayer(childLayer, 1)
- .apply();
-
- {
- SCOPED_TRACE("setLayer above");
- // Set layer should get applied and place the child above.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
- }
-
- Transaction()
- .setLayer(childLayer, 1)
- .setRelativeLayer(childLayer, parent->getHandle(), -1)
- .apply();
-
- {
- SCOPED_TRACE("setRelative below");
- // Set relative layer should get applied and place the child below.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeTransactionTest, HideRelativeParentHidesLayer) {
- sp<SurfaceControl> parent =
- LayerTransactionTest::createLayer("Parent", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor);
- sp<SurfaceControl> relativeParent =
- LayerTransactionTest::createLayer("RelativeParent", 0 /* buffer width */,
- 0 /* buffer height */, ISurfaceComposerClient::eFXSurfaceColor);
-
- sp<SurfaceControl> childLayer;
- ASSERT_NO_FATAL_FAILURE(
- childLayer = LayerTransactionTest::createLayer("childLayer", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor,
- parent.get()));
- Transaction()
- .setColor(childLayer, half3{1.0f, 0.0f, 0.0f})
- .setColor(parent, half3{0.0f, 0.0f, 0.0f})
- .setColor(relativeParent, half3{0.0f, 1.0f, 0.0f})
- .show(childLayer)
- .show(parent)
- .show(relativeParent)
- .setLayer(parent, mLayerZBase - 1)
- .setLayer(relativeParent, mLayerZBase)
- .apply();
-
- Transaction()
- .setRelativeLayer(childLayer, relativeParent->getHandle(), 1)
- .apply();
-
- {
- SCOPED_TRACE("setLayer above");
- // Set layer should get applied and place the child above.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::RED);
- }
-
- Transaction()
- .hide(relativeParent)
- .apply();
-
- {
- SCOPED_TRACE("hide relative parent");
- // The relative should no longer be visible.
- std::unique_ptr<ScreenCapture> screenshot;
- ScreenCapture::captureScreen(&screenshot);
- screenshot->expectColor(Rect(0, 0, 20, 30), Color::BLACK);
- }
-}
-
-void LayerRenderTypeTransactionTest::setRelativeZGroupHelper(uint32_t layerType) {
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- sp<SurfaceControl> layerB;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerG, Color::GREEN, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerB = createLayer("test", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layerB, Color::BLUE, 32, 32));
-
- // layerR = 0, layerG = layerR + 3, layerB = 2
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setPosition(layerG, 8, 8)
- .setRelativeLayer(layerG, layerR->getHandle(), 3)
- .setPosition(layerB, 16, 16)
- .setLayer(layerB, mLayerZBase + 2)
- .apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setFrame(layerR, Rect(0, 0, 32, 32))
- .setFrame(layerG, Rect(8, 8, 40, 40))
- .setRelativeLayer(layerG, layerR->getHandle(), 3)
- .setFrame(layerB, Rect(16, 16, 48, 48))
- .setLayer(layerB, mLayerZBase + 2)
- .apply();
- break;
- default:
- ASSERT_FALSE(true) << "Unsupported layer type";
- }
-
- {
- SCOPED_TRACE("(layerR < layerG) < layerB");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
- shot->expectColor(Rect(8, 8, 16, 16), Color::GREEN);
- shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
- }
-
- // layerR = 4, layerG = layerR + 3, layerB = 2
- Transaction().setLayer(layerR, mLayerZBase + 4).apply();
- {
- SCOPED_TRACE("layerB < (layerR < layerG)");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 8, 8), Color::RED);
- shot->expectColor(Rect(8, 8, 40, 40), Color::GREEN);
- shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
- }
-
- // layerR = 4, layerG = layerR - 3, layerB = 2
- Transaction().setRelativeLayer(layerG, layerR->getHandle(), -3).apply();
- {
- SCOPED_TRACE("layerB < (layerG < layerR)");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectColor(Rect(32, 32, 40, 40), Color::GREEN);
- shot->expectColor(Rect(40, 40, 48, 48), Color::BLUE);
- }
-
- // restore to absolute z
- // layerR = 4, layerG = 0, layerB = 2
- Transaction().setLayer(layerG, mLayerZBase).apply();
- {
- SCOPED_TRACE("layerG < layerB < layerR");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectColor(Rect(32, 32, 48, 48), Color::BLUE);
- }
-
- // layerR should not affect layerG anymore
- // layerR = 1, layerG = 0, layerB = 2
- Transaction().setLayer(layerR, mLayerZBase + 1).apply();
- {
- SCOPED_TRACE("layerG < layerR < layerB");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectColor(Rect(16, 16, 48, 48), Color::BLUE);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferQueue) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetRelativeZGroup_BufferState) {
- ASSERT_NO_FATAL_FAILURE(setRelativeZGroupHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetRelativeZBug64572777) {
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
-
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction()
- .setPosition(layerG, 16, 16)
- .setRelativeLayer(layerG, layerR->getHandle(), 1)
- .apply();
-
- layerG.clear();
- // layerG should have been removed
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsHidden) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setFlags(layer, layer_state_t::eLayerHidden, layer_state_t::eLayerHidden).apply();
- {
- SCOPED_TRACE("layer hidden");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-
- Transaction().setFlags(layer, 0, layer_state_t::eLayerHidden).apply();
- {
- SCOPED_TRACE("layer shown");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetFlagsOpaque) {
- const Color translucentRed = {100, 0, 0, 100};
- sp<SurfaceControl> layerR;
- sp<SurfaceControl> layerG;
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerR, translucentRed, 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerG = createLayer("test G", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerG, Color::GREEN, 32, 32));
-
- Transaction()
- .setLayer(layerR, mLayerZBase + 1)
- .setFlags(layerR, layer_state_t::eLayerOpaque, layer_state_t::eLayerOpaque)
- .apply();
- {
- SCOPED_TRACE("layerR opaque");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, 0, 0, 255});
- }
-
- Transaction().setFlags(layerR, 0, layer_state_t::eLayerOpaque).apply();
- {
- SCOPED_TRACE("layerR translucent");
- const uint8_t g = uint8_t(255 - translucentRed.a);
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {100, g, 0, 255});
- }
-}
-
-TEST_P(LayerTypeTransactionTest, SetFlagsSecure) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- sp<GraphicBuffer> outBuffer;
- Transaction()
- .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
- .apply(true);
- ASSERT_EQ(PERMISSION_DENIED,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
- Transaction().setFlags(layer, 0, layer_state_t::eLayerSecure).apply(true);
- ASSERT_EQ(NO_ERROR,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-}
-
-/** RAII Wrapper around get/seteuid */
-class UIDFaker {
- uid_t oldId;
-public:
- UIDFaker(uid_t uid) {
- oldId = geteuid();
- seteuid(uid);
- }
- ~UIDFaker() {
- seteuid(oldId);
- }
-};
-
-TEST_F(LayerTransactionTest, SetFlagsSecureEUidSystem) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- sp<ISurfaceComposer> composer = ComposerService::getComposerService();
- sp<GraphicBuffer> outBuffer;
- Transaction()
- .setFlags(layer, layer_state_t::eLayerSecure, layer_state_t::eLayerSecure)
- .apply(true);
- ASSERT_EQ(PERMISSION_DENIED,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
- UIDFaker f(AID_SYSTEM);
-
- // By default the system can capture screenshots with secure layers but they
- // will be blacked out
- ASSERT_EQ(NO_ERROR,
- composer->captureScreen(mDisplay, &outBuffer, Rect(), 0, 0, false));
-
- {
- SCOPED_TRACE("as system");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- // Here we pass captureSecureLayers = true and since we are AID_SYSTEM we should be able
- // to receive them...we are expected to take care with the results.
- bool outCapturedSecureLayers;
- ASSERT_EQ(NO_ERROR,
- composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
- ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
- 0, false, ISurfaceComposer::eRotateNone, true));
- ASSERT_EQ(true, outCapturedSecureLayers);
- ScreenCapture sc(outBuffer);
- sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferQueue) {
- const Rect top(0, 0, 32, 16);
- const Rect bottom(0, 16, 32, 32);
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-
- ANativeWindow_Buffer buffer;
- ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
- ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::TRANSPARENT));
- ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::RED));
- // setTransparentRegionHint always applies to the following buffer
- Transaction().setTransparentRegionHint(layer, Region(top)).apply();
- ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
- {
- SCOPED_TRACE("top transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::RED);
- }
-
- Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
- {
- SCOPED_TRACE("transparent region hint pending");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::RED);
- }
-
- ASSERT_NO_FATAL_FAILURE(buffer = getBufferQueueLayerBuffer(layer));
- ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, top, Color::RED));
- ASSERT_NO_FATAL_FAILURE(fillANativeWindowBufferColor(buffer, bottom, Color::TRANSPARENT));
- ASSERT_NO_FATAL_FAILURE(postBufferQueueLayerBuffer(layer));
- {
- SCOPED_TRACE("bottom transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::RED);
- shot->expectColor(bottom, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintBasic_BufferState) {
- const Rect top(0, 0, 32, 16);
- const Rect bottom(0, 16, 32, 32);
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::TRANSPARENT));
- ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::RED));
- Transaction()
- .setTransparentRegionHint(layer, Region(top))
- .setBuffer(layer, buffer)
- .setFrame(layer, Rect(0, 0, 32, 32))
- .apply();
- {
- SCOPED_TRACE("top transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::RED);
- }
-
- Transaction().setTransparentRegionHint(layer, Region(bottom)).apply();
- {
- SCOPED_TRACE("transparent region hint intermediate");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::BLACK);
- shot->expectColor(bottom, Color::BLACK);
- }
-
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
-
- ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, top, Color::RED));
- ASSERT_NO_FATAL_FAILURE(fillGraphicBufferColor(buffer, bottom, Color::TRANSPARENT));
- Transaction().setBuffer(layer, buffer).apply();
- {
- SCOPED_TRACE("bottom transparent");
- auto shot = getScreenCapture();
- shot->expectColor(top, Color::RED);
- shot->expectColor(bottom, Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layerTransparent;
- sp<SurfaceControl> layerR;
- ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
- ASSERT_NO_FATAL_FAILURE(layerR = createLayer("test R", 32, 32));
-
- // check that transparent region hint is bound by the layer size
- Transaction()
- .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
- .setPosition(layerR, 16, 16)
- .setLayer(layerR, mLayerZBase + 1)
- .apply();
- ASSERT_NO_FATAL_FAILURE(
- fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layerR, Color::RED, 32, 32));
- getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransparentRegionHintOutOfBounds_BufferState) {
- sp<SurfaceControl> layerTransparent;
- sp<SurfaceControl> layerR;
- ASSERT_NO_FATAL_FAILURE(layerTransparent = createLayer("test transparent", 32, 32));
- ASSERT_NO_FATAL_FAILURE(
- layerR = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- // check that transparent region hint is bound by the layer size
- Transaction()
- .setTransparentRegionHint(layerTransparent, Region(mDisplayRect))
- .setFrame(layerR, Rect(16, 16, 48, 48))
- .setLayer(layerR, mLayerZBase + 1)
- .apply();
- ASSERT_NO_FATAL_FAILURE(
- fillBufferQueueLayerColor(layerTransparent, Color::TRANSPARENT, 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layerR, Color::RED, 32, 32));
- getScreenCapture()->expectColor(Rect(16, 16, 48, 48), Color::RED);
-}
-
-void LayerRenderTypeTransactionTest::setAlphaBasicHelper(uint32_t layerType) {
- sp<SurfaceControl> layer1;
- sp<SurfaceControl> layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer("test 1", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer("test 2", 32, 32, layerType));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer1, {64, 0, 0, 255}, 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layerType, layer2, {0, 64, 0, 255}, 32, 32));
-
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- Transaction()
- .setAlpha(layer1, 0.25f)
- .setAlpha(layer2, 0.75f)
- .setPosition(layer2, 16, 0)
- .setLayer(layer2, mLayerZBase + 1)
- .apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- Transaction()
- .setAlpha(layer1, 0.25f)
- .setAlpha(layer2, 0.75f)
- .setFrame(layer1, Rect(0, 0, 32, 32))
- .setFrame(layer2, Rect(16, 0, 48, 32))
- .setLayer(layer2, mLayerZBase + 1)
- .apply();
- break;
- default:
- ASSERT_FALSE(true) << "Unsupported layer type";
- }
- {
- auto shot = getScreenCapture();
- uint8_t r = 16; // 64 * 0.25f
- uint8_t g = 48; // 64 * 0.75f
- shot->expectColor(Rect(0, 0, 16, 32), {r, 0, 0, 255});
- shot->expectColor(Rect(32, 0, 48, 32), {0, g, 0, 255});
-
- r /= 4; // r * (1.0f - 0.75f)
- shot->expectColor(Rect(16, 0, 32, 32), {r, g, 0, 255});
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferQueue) {
- ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetAlphaBasic_BufferState) {
- ASSERT_NO_FATAL_FAILURE(setAlphaBasicHelper(ISurfaceComposerClient::eFXSurfaceBufferState));
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetAlphaClamped) {
- const Color color = {64, 0, 0, 255};
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, color, 32, 32));
-
- Transaction().setAlpha(layer, 2.0f).apply();
- {
- SCOPED_TRACE("clamped to 1.0f");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), color);
- }
-
- Transaction().setAlpha(layer, -1.0f).apply();
- {
- SCOPED_TRACE("clamped to 0.0f");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadius) {
- sp<SurfaceControl> layer;
- const uint8_t size = 64;
- const uint8_t testArea = 4;
- const float cornerRadius = 20.0f;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", size, size));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, size, size));
-
- Transaction()
- .setCornerRadius(layer, cornerRadius)
- .apply();
- {
- const uint8_t bottom = size - 1;
- const uint8_t right = size - 1;
- auto shot = getScreenCapture();
- // Transparent corners
- shot->expectColor(Rect(0, 0, testArea, testArea), Color::BLACK);
- shot->expectColor(Rect(size - testArea, 0, right, testArea), Color::BLACK);
- shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
- shot->expectColor(Rect(size - testArea, bottom - testArea, right, bottom), Color::BLACK);
- }
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetCornerRadiusChildCrop) {
- sp<SurfaceControl> parent;
- sp<SurfaceControl> child;
- const uint8_t size = 64;
- const uint8_t testArea = 4;
- const float cornerRadius = 20.0f;
- ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", size, size));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, size, size));
- ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size / 2));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size / 2));
-
- Transaction()
- .setCornerRadius(parent, cornerRadius)
- .reparent(child, parent->getHandle())
- .setPosition(child, 0, size / 2)
- .apply();
- {
- const uint8_t bottom = size - 1;
- const uint8_t right = size - 1;
- auto shot = getScreenCapture();
- // Top edge of child should not have rounded corners because it's translated in the parent
- shot->expectColor(Rect(0, size / 2, right, static_cast<int>(bottom - cornerRadius)),
- Color::GREEN);
- // But bottom edges should have been clipped according to parent bounds
- shot->expectColor(Rect(0, bottom - testArea, testArea, bottom), Color::BLACK);
- shot->expectColor(Rect(right - testArea, bottom - testArea, right, bottom), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorBasic) {
- sp<SurfaceControl> bufferLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
-
- Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(colorLayer, mLayerZBase + 1)
- .apply();
-
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
- const Color expected = {15, 51, 85, 255};
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
- Transaction().setColor(colorLayer, color).apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expected, tolerance);
- }
-}
-
-// RED: Color layer base color and BufferQueueLayer/BufferStateLayer fill
-// BLUE: prior background color
-// GREEN: final background color
-// BLACK: no color or fill
-void LayerRenderTypeTransactionTest::setBackgroundColorHelper(uint32_t layerType, bool priorColor,
- bool bufferFill, float alpha,
- Color finalColor) {
- sp<SurfaceControl> layer;
- int32_t width = 500;
- int32_t height = 500;
-
- Color fillColor = Color::RED;
- Color priorBgColor = Color::BLUE;
- Color expectedColor = Color::BLACK;
- switch (layerType) {
- case ISurfaceComposerClient::eFXSurfaceColor:
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 0, 0, layerType));
- Transaction()
- .setCrop_legacy(layer, Rect(0, 0, width, height))
- .setColor(layer, half3(1.0f, 0, 0))
- .apply();
- expectedColor = fillColor;
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferQueue:
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
- if (bufferFill) {
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, fillColor, width, height));
- expectedColor = fillColor;
- }
- Transaction().setCrop_legacy(layer, Rect(0, 0, width, height)).apply();
- break;
- case ISurfaceComposerClient::eFXSurfaceBufferState:
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height, layerType));
- if (bufferFill) {
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, fillColor, width, height));
- expectedColor = fillColor;
- }
- Transaction().setFrame(layer, Rect(0, 0, width, height)).apply();
- break;
- default:
- GTEST_FAIL() << "Unknown layer type in setBackgroundColorHelper";
- return;
- }
-
- if (priorColor && layerType != ISurfaceComposerClient::eFXSurfaceColor) {
- Transaction()
- .setBackgroundColor(layer, half3(0, 0, 1.0f), 1.0f, ui::Dataspace::UNKNOWN)
- .apply();
- if (!bufferFill) {
- expectedColor = priorBgColor;
- }
- }
-
- {
- SCOPED_TRACE("default before setting background color layer");
- screenshot()->expectColor(Rect(0, 0, width, height), expectedColor);
- }
- Transaction()
- .setBackgroundColor(layer, half3(0, 1.0f, 0), alpha, ui::Dataspace::UNKNOWN)
- .apply();
-
- {
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, width, height), finalColor);
- shot->expectBorder(Rect(0, 0, width, height), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_Color_NoEffect) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceColor,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_BufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoBufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBackgroundColor_BufferQueue_BufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoBufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_NoPriorColor_ZeroAlpha_NoEffect) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferQueue_PriorColor_ZeroAlpha_DeleteBackground) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferQueue,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_BufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = true;
- float alpha = 1.0f;
- Color finalColor = Color::RED;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_NoBufferFill_NoPriorColor_Basic) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_NoBufferFill_PriorColor_Basic) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 1.0f;
- Color finalColor = Color::GREEN;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_NoPriorColor_ZeroAlpha_NoEffect) {
- bool priorColor = false;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest,
- SetBackgroundColor_BufferState_PriorColor_ZeroAlpha_DeleteBackground) {
- bool priorColor = true;
- bool bufferFill = false;
- float alpha = 0;
- Color finalColor = Color::BLACK;
- ASSERT_NO_FATAL_FAILURE(setBackgroundColorHelper(ISurfaceComposerClient::eFXSurfaceBufferState,
- priorColor, bufferFill, alpha, finalColor));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorClamped) {
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setColor(colorLayer, half3(2.0f, -1.0f, 0.0f))
- .apply();
-
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorWithAlpha) {
- sp<SurfaceControl> bufferLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
-
- const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
- const float alpha = 0.25f;
- const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
- Transaction()
- .setColor(colorLayer, color)
- .setAlpha(colorLayer, alpha)
- .setLayer(colorLayer, mLayerZBase + 1)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorWithParentAlpha_Bug74220420) {
- sp<SurfaceControl> bufferLayer;
- sp<SurfaceControl> parentLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test bg", 32, 32));
- ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parentWithAlpha", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::RED, 32, 32));
- ASSERT_NO_FATAL_FAILURE(colorLayer = createLayer("childWithColor", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction().setCrop_legacy(colorLayer, Rect(0, 0, 32, 32)).apply();
- const half3 color(15.0f / 255.0f, 51.0f / 255.0f, 85.0f / 255.0f);
- const float alpha = 0.25f;
- const ubyte3 expected((vec3(color) * alpha + vec3(1.0f, 0.0f, 0.0f) * (1.0f - alpha)) * 255.0f);
- // this is handwavy, but the precision loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
- Transaction()
- .reparent(colorLayer, parentLayer->getHandle())
- .setColor(colorLayer, color)
- .setAlpha(parentLayer, alpha)
- .setLayer(parentLayer, mLayerZBase + 1)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), {expected.r, expected.g, expected.b, 255},
- tolerance);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetColorWithBuffer) {
- sp<SurfaceControl> bufferLayer;
- ASSERT_NO_FATAL_FAILURE(bufferLayer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(bufferLayer, Color::RED, 32, 32));
-
- // color is ignored
- Transaction().setColor(bufferLayer, half3(0.0f, 1.0f, 0.0f)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
-}
-
-TEST_P(LayerTypeAndRenderTypeTransactionTest, SetLayerStackBasic) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setLayerStack(layer, mDisplayLayerStack + 1).apply();
- {
- SCOPED_TRACE("non-existing layer stack");
- getScreenCapture()->expectColor(mDisplayRect, Color::BLACK);
- }
-
- Transaction().setLayerStack(layer, mDisplayLayerStack).apply();
- {
- SCOPED_TRACE("original layer stack");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("IDENTITY");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).setPosition(layer, 32, 0).apply();
- {
- SCOPED_TRACE("FLIP_H");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED,
- Color::WHITE, Color::BLUE);
- }
-
- Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).setPosition(layer, 0, 32).apply();
- {
- SCOPED_TRACE("FLIP_V");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE,
- Color::RED, Color::GREEN);
- }
-
- Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).setPosition(layer, 32, 0).apply();
- {
- SCOPED_TRACE("ROT_90");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED,
- Color::WHITE, Color::GREEN);
- }
-
- Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("SCALE");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 64), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE, true /* filtered */);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- Transaction()
- .setMatrix(layer, 1.0f, 0.0f, 0.0f, 1.0f)
- .setFrame(layer, Rect(0, 0, 32, 32))
- .apply();
- {
- SCOPED_TRACE("IDENTITY");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, -1.0f, 0.0f, 0.0f, 1.0f).apply();
- {
- SCOPED_TRACE("FLIP_H");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, 1.0f, 0.0f, 0.0f, -1.0f).apply();
- {
- SCOPED_TRACE("FLIP_V");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, 0.0f, 1.0f, -1.0f, 0.0f).apply();
- {
- SCOPED_TRACE("ROT_90");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-
- Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).apply();
- {
- SCOPED_TRACE("SCALE");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixRot45_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- const float rot = M_SQRT1_2; // 45 degrees
- const float trans = M_SQRT2 * 16.0f;
- Transaction().setMatrix(layer, rot, rot, -rot, rot).setPosition(layer, trans, 0).apply();
-
- auto shot = getScreenCapture();
- // check a 8x8 region inside each color
- auto get8x8Rect = [](int32_t centerX, int32_t centerY) {
- const int32_t halfL = 4;
- return Rect(centerX - halfL, centerY - halfL, centerX + halfL, centerY + halfL);
- };
- const int32_t unit = int32_t(trans / 2);
- shot->expectColor(get8x8Rect(2 * unit, 1 * unit), Color::RED);
- shot->expectColor(get8x8Rect(3 * unit, 2 * unit), Color::GREEN);
- shot->expectColor(get8x8Rect(1 * unit, 2 * unit), Color::BLUE);
- shot->expectColor(get8x8Rect(2 * unit, 3 * unit), Color::WHITE);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setMatrix is applied after any pending resize, unlike setPosition
- Transaction().setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f).setSize(layer, 64, 64).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- const Rect rect(0, 0, 32, 32);
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 64, 64));
- {
- SCOPED_TRACE("resize applied");
- const Rect rect(0, 0, 128, 128);
- getScreenCapture()->expectColor(rect, Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetMatrixWithScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setMatrix is immediate with SCALE_TO_WINDOW, unlike setPosition
- Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setSize(layer, 64, 64)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- getScreenCapture()->expectColor(Rect(0, 0, 128, 128), Color::RED);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetOverrideScalingModeBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- // XXX SCALE_CROP is not respected; calling setSize and
- // setOverrideScalingMode in separate transactions does not work
- // (b/69315456)
- Transaction()
- .setSize(layer, 64, 16)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .apply();
- {
- SCOPED_TRACE("SCALE_TO_WINDOW");
- getScreenCapture()->expectQuadrant(Rect(0, 0, 64, 16), Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE, true /* filtered */);
- }
-}
-
-TEST_P(LayerTypeTransactionTest, RefreshRateIsInitialized) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
-
- sp<IBinder> handle = layer->getHandle();
- ASSERT_TRUE(handle != nullptr);
-
- FrameStats frameStats;
- mClient->getLayerFrameStats(handle, &frameStats);
-
- ASSERT_GT(frameStats.refreshPeriodNano, static_cast<nsecs_t>(0));
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- const Rect crop(8, 8, 24, 24);
-
- Transaction().setCrop_legacy(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(crop, Color::RED);
- shot->expectBorder(crop, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- const Rect crop(8, 8, 24, 24);
-
- Transaction().setCrop(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("empty rect");
- Transaction().setCrop_legacy(layer, Rect(8, 8, 8, 8)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setCrop_legacy(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropEmpty_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("empty rect");
- Transaction().setCrop(layer, Rect(8, 8, 8, 8)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setCrop(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- Transaction().setCrop_legacy(layer, Rect(-128, -64, 128, 64)).apply();
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::RED);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropOutOfBounds_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 64, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 16), Color::BLUE);
- fillGraphicBufferColor(buffer, Rect(0, 16, 32, 64), Color::RED);
-
- Transaction().setFrame(layer, Rect(0, 0, 64, 64)).apply();
-
- Transaction().setBuffer(layer, buffer).apply();
-
- // Partially out of bounds in the negative (upper left) direction
- Transaction().setCrop(layer, Rect(-128, -128, 32, 16)).apply();
- {
- SCOPED_TRACE("out of bounds, negative (upper left) direction");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
- }
-
- // Partially out of bounds in the positive (lower right) direction
- Transaction().setCrop(layer, Rect(0, 16, 128, 128)).apply();
- {
- SCOPED_TRACE("out of bounds, positive (lower right) direction");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
- }
-
- // Fully out of buffer space bounds
- Transaction().setCrop(layer, Rect(-128, -128, -1, -1)).apply();
- {
- SCOPED_TRACE("Fully out of bounds");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 16), Color::BLUE);
- shot->expectColor(Rect(0, 16, 64, 64), Color::RED);
- shot->expectBorder(Rect(0, 0, 64, 64), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- const Point position(32, 32);
- const Rect crop(8, 8, 24, 24);
- Transaction().setPosition(layer, position.x, position.y).setCrop_legacy(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(crop + position, Color::RED);
- shot->expectBorder(crop + position, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithTranslation_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- const Rect frame(32, 32, 64, 64);
- const Rect crop(8, 8, 24, 24);
- Transaction().setFrame(layer, frame).setCrop(layer, crop).apply();
- auto shot = getScreenCapture();
- shot->expectColor(frame, Color::RED);
- shot->expectBorder(frame, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithScale_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // crop_legacy is affected by matrix
- Transaction()
- .setMatrix(layer, 2.0f, 0.0f, 0.0f, 2.0f)
- .setCrop_legacy(layer, Rect(8, 8, 24, 24))
- .apply();
- auto shot = getScreenCapture();
- shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
- shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setCrop_legacy is applied immediately by default, with or without resize pending
- Transaction().setCrop_legacy(layer, Rect(8, 8, 24, 24)).setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(8, 8, 24, 24), Color::RED);
- shot->expectBorder(Rect(8, 8, 24, 24), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("resize applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(8, 8, 16, 16), Color::RED);
- shot->expectBorder(Rect(8, 8, 16, 16), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResize_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // request setCrop_legacy to be applied with the next resize
- Transaction()
- .setCrop_legacy(layer, Rect(8, 8, 24, 24))
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("waiting for next resize");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setCrop_legacy(layer, Rect(4, 4, 12, 12)).apply();
- {
- SCOPED_TRACE("pending crop modified");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- Transaction().setSize(layer, 16, 16).apply();
- {
- SCOPED_TRACE("resize pending");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::RED);
- }
-
- // finally resize
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- {
- SCOPED_TRACE("new crop applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetCropWithNextResizeScaleToWindow_BufferQueue) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
-
- // setCrop_legacy is not immediate even with SCALE_TO_WINDOW override
- Transaction()
- .setCrop_legacy(layer, Rect(4, 4, 12, 12))
- .setSize(layer, 16, 16)
- .setOverrideScalingMode(layer, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW)
- .setGeometryAppliesWithResize(layer)
- .apply();
- {
- SCOPED_TRACE("new crop pending");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 16, 16), Color::RED);
- shot->expectBorder(Rect(0, 0, 16, 16), Color::BLACK);
- }
-
- // XXX crop is never latched without other geometry change (b/69315677)
- Transaction().setPosition(layer, 1, 0).setGeometryAppliesWithResize(layer).apply();
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 16, 16));
- Transaction().setPosition(layer, 0, 0).apply();
- {
- SCOPED_TRACE("new crop applied");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(4, 4, 12, 12), Color::RED);
- shot->expectBorder(Rect(4, 4, 12, 12), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- const Rect frame(8, 8, 24, 24);
-
- Transaction().setFrame(layer, frame).apply();
- auto shot = getScreenCapture();
- shot->expectColor(frame, Color::RED);
- shot->expectBorder(frame, Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameEmpty_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("empty rect");
- Transaction().setFrame(layer, Rect(8, 8, 8, 8)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- {
- SCOPED_TRACE("negative rect");
- Transaction().setFrame(layer, Rect(8, 8, 0, 0)).apply();
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultParentless_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 10, 10));
-
- // A parentless layer will default to a frame with the same size as the buffer
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBSParent_BufferState) {
- sp<SurfaceControl> parent, child;
- ASSERT_NO_FATAL_FAILURE(
- parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
- Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
-
- ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-
- Transaction().reparent(child, parent->getHandle()).apply();
-
- // A layer will default to the frame of its parent
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameDefaultBQParent_BufferState) {
- sp<SurfaceControl> parent, child;
- ASSERT_NO_FATAL_FAILURE(parent = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(parent, Color::RED, 32, 32));
-
- ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
-
- Transaction().reparent(child, parent->getHandle()).apply();
-
- // A layer will default to the frame of its parent
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameUpdate_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
- Transaction().setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- std::this_thread::sleep_for(500ms);
-
- Transaction().setFrame(layer, Rect(16, 16, 48, 48)).apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(16, 16, 48, 48), Color::RED);
- shot->expectBorder(Rect(16, 16, 48, 48), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFrameOutsideBounds_BufferState) {
- sp<SurfaceControl> parent, child;
- ASSERT_NO_FATAL_FAILURE(
- parent = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(
- child = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
- Transaction().reparent(child, parent->getHandle()).apply();
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(parent, Color::RED, 32, 32));
- Transaction().setFrame(parent, Rect(0, 0, 32, 32)).apply();
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(child, Color::BLUE, 10, 10));
- Transaction().setFrame(child, Rect(0, 16, 32, 32)).apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 16), Color::RED);
- shot->expectColor(Rect(0, 16, 32, 32), Color::BLUE);
- shot->expectBorder(Rect(0, 0, 32, 32), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleBuffers_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("set buffer 1");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::BLUE, 32, 32));
-
- {
- SCOPED_TRACE("set buffer 2");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLUE);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::RED, 32, 32));
-
- {
- SCOPED_TRACE("set buffer 3");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferMultipleLayers_BufferState) {
- sp<SurfaceControl> layer1;
- ASSERT_NO_FATAL_FAILURE(
- layer1 = createLayer("test", 64, 64, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<SurfaceControl> layer2;
- ASSERT_NO_FATAL_FAILURE(
- layer2 = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::RED, 64, 64));
-
- Transaction().setFrame(layer1, Rect(0, 0, 64, 64)).apply();
- {
- SCOPED_TRACE("set layer 1 buffer red");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 64, 64), Color::RED);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::BLUE, 32, 32));
-
- Transaction().setFrame(layer2, Rect(0, 0, 32, 32)).apply();
- {
- SCOPED_TRACE("set layer 2 buffer blue");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectColor(Rect(0, 32, 64, 64), Color::RED);
- shot->expectColor(Rect(0, 32, 32, 64), Color::RED);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer1, Color::GREEN, 64, 64));
- {
- SCOPED_TRACE("set layer 1 buffer green");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::BLUE);
- shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
- shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
- }
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer2, Color::WHITE, 32, 32));
-
- {
- SCOPED_TRACE("set layer 2 buffer white");
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, 32, 32), Color::WHITE);
- shot->expectColor(Rect(0, 32, 64, 64), Color::GREEN);
- shot->expectColor(Rect(0, 32, 32, 64), Color::GREEN);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
- std::array<sp<GraphicBuffer>, 10> buffers;
-
- size_t idx = 0;
- for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- Color color = colors[idx % colors.size()];
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
- idx++;
- }
-
- // Set each buffer twice. The first time adds it to the cache, the second time tests that the
- // cache is working.
- idx = 0;
- for (auto& buffer : buffers) {
- for (int i = 0; i < 2; i++) {
- Transaction().setBuffer(layer, buffer).apply();
-
- Color color = colors[idx % colors.size()];
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
- idx++;
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_LeastRecentlyUsed_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
- std::array<sp<GraphicBuffer>, 70> buffers;
-
- size_t idx = 0;
- for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- Color color = colors[idx % colors.size()];
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
- idx++;
- }
-
- // Set each buffer twice. The first time adds it to the cache, the second time tests that the
- // cache is working.
- idx = 0;
- for (auto& buffer : buffers) {
- for (int i = 0; i < 2; i++) {
- Transaction().setBuffer(layer, buffer).apply();
-
- Color color = colors[idx % colors.size()];
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
- idx++;
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetBufferCaching_DestroyedBuffer_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- std::array<Color, 4> colors = {Color::RED, Color::BLUE, Color::WHITE, Color::GREEN};
-
- std::array<sp<GraphicBuffer>, 65> buffers;
-
- size_t idx = 0;
- for (auto& buffer : buffers) {
- buffer = new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- Color color = colors[idx % colors.size()];
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), color);
- idx++;
- }
-
- // Set each buffer twice. The first time adds it to the cache, the second time tests that the
- // cache is working.
- idx = 0;
- for (auto& buffer : buffers) {
- for (int i = 0; i < 2; i++) {
- Transaction().setBuffer(layer, buffer).apply();
-
- Color color = colors[idx % colors.size()];
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), color);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
- }
- if (idx == 0) {
- buffers[0].clear();
- }
- idx++;
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransformRotate90_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setTransform(layer, NATIVE_WINDOW_TRANSFORM_ROT_90)
- .apply();
-
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::RED, Color::WHITE,
- Color::GREEN, true /* filtered */);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipH_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_H)
- .apply();
-
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::GREEN, Color::RED, Color::WHITE,
- Color::BLUE, true /* filtered */);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetTransformFlipV_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerQuadrant(layer, 32, 32, Color::RED, Color::GREEN,
- Color::BLUE, Color::WHITE));
-
- Transaction()
- .setFrame(layer, Rect(0, 0, 32, 32))
- .setTransform(layer, NATIVE_WINDOW_TRANSFORM_FLIP_V)
- .apply();
-
- getScreenCapture()->expectQuadrant(Rect(0, 0, 32, 32), Color::BLUE, Color::WHITE, Color::RED,
- Color::GREEN, true /* filtered */);
-}
-
-TEST_F(LayerTransactionTest, SetTransformToDisplayInverse_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction().setTransformToDisplayInverse(layer, false).apply();
-
- ASSERT_NO_FATAL_FAILURE(fillBufferStateLayerColor(layer, Color::GREEN, 32, 32));
-
- Transaction().setTransformToDisplayInverse(layer, true).apply();
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFenceBasic_BufferState) {
- sp<SurfaceControl> layer;
- Transaction transaction;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- sp<Fence> fence;
- if (getBuffer(nullptr, &fence) != NO_ERROR) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- Transaction().setBuffer(layer, buffer).setAcquireFence(layer, fence).apply();
-
- status_t status = fence->wait(1000);
- ASSERT_NE(static_cast<status_t>(Fence::Status::Unsignaled), status);
- std::this_thread::sleep_for(200ms);
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetFenceNull_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- sp<Fence> fence = Fence::NO_FENCE;
-
- Transaction()
- .setBuffer(layer, buffer)
- .setAcquireFence(layer, fence)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetDataspaceBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- Transaction()
- .setBuffer(layer, buffer)
- .setDataspace(layer, ui::Dataspace::UNKNOWN)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetHdrMetadataBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- HdrMetadata hdrMetadata;
- hdrMetadata.validTypes = 0;
- Transaction()
- .setBuffer(layer, buffer)
- .setHdrMetadata(layer, hdrMetadata)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetSurfaceDamageRegionBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- Region region;
- region.set(32, 32);
- Transaction()
- .setBuffer(layer, buffer)
- .setSurfaceDamageRegion(layer, region)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetApiBasic_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- sp<GraphicBuffer> buffer =
- new GraphicBuffer(32, 32, PIXEL_FORMAT_RGBA_8888, 1,
- BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN |
- BufferUsage::COMPOSER_OVERLAY,
- "test");
- fillGraphicBufferColor(buffer, Rect(0, 0, 32, 32), Color::RED);
-
- Transaction()
- .setBuffer(layer, buffer)
- .setApi(layer, NATIVE_WINDOW_API_CPU)
- .apply();
-
- auto shot = getScreenCapture();
- shot->expectColor(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::RED);
- shot->expectBorder(Rect(0, 0, mDisplayWidth, mDisplayHeight), Color::BLACK);
-}
-
-TEST_F(LayerTransactionTest, SetSidebandStreamNull_BufferState) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(
- layer = createLayer("test", 32, 32, ISurfaceComposerClient::eFXSurfaceBufferState));
-
- // verify this doesn't cause a crash
- Transaction().setSidebandStream(layer, nullptr).apply();
-}
-
-TEST_F(LayerTransactionTest, ReparentToSelf) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(layer, Color::RED, 32, 32));
- Transaction().reparent(layer, layer->getHandle()).apply();
-
- {
- // We expect the transaction to be silently dropped, but for SurfaceFlinger
- // to still be functioning.
- SCOPED_TRACE("after reparent to self");
- const Rect rect(0, 0, 32, 32);
- auto shot = screenshot();
- shot->expectColor(rect, Color::RED);
- shot->expectBorder(rect, Color::BLACK);
- }
-}
-
-class ColorTransformHelper {
-public:
- static void DegammaColorSingle(half& s) {
- if (s <= 0.03928f)
- s = s / 12.92f;
- else
- s = pow((s + 0.055f) / 1.055f, 2.4f);
- }
-
- static void DegammaColor(half3& color) {
- DegammaColorSingle(color.r);
- DegammaColorSingle(color.g);
- DegammaColorSingle(color.b);
- }
-
- static void GammaColorSingle(half& s) {
- if (s <= 0.0031308f) {
- s = s * 12.92f;
- } else {
- s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
- }
- }
-
- static void GammaColor(half3& color) {
- GammaColorSingle(color.r);
- GammaColorSingle(color.g);
- GammaColorSingle(color.b);
- }
-
- static void applyMatrix(half3& color, const mat3& mat) {
- half3 ret = half3(0);
-
- for (int i = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++) {
- ret[i] = ret[i] + color[j] * mat[j][i];
- }
- }
- color = ret;
- }
-};
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformBasic) {
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(colorLayer =
- createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor));
- Transaction()
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(colorLayer, mLayerZBase + 1)
- .apply();
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- half3 expected = color;
- mat3 matrix;
- matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
- matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
- matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
-
- // degamma before applying the matrix
- if (mColorManagementUsed) {
- ColorTransformHelper::DegammaColor(expected);
- }
-
- ColorTransformHelper::applyMatrix(expected, matrix);
-
- if (mColorManagementUsed) {
- ColorTransformHelper::GammaColor(expected);
- }
-
- const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
- uint8_t(expected.b * 255), 255};
-
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
-
- Transaction().setColor(colorLayer, color)
- .setColorTransform(colorLayer, matrix, vec3()).apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnParent) {
- sp<SurfaceControl> parentLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer));
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
-
- Transaction()
- .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(parentLayer, mLayerZBase + 1)
- .apply();
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- half3 expected = color;
- mat3 matrix;
- matrix[0][0] = 0.3; matrix[1][0] = 0.59; matrix[2][0] = 0.11;
- matrix[0][1] = 0.3; matrix[1][1] = 0.59; matrix[2][1] = 0.11;
- matrix[0][2] = 0.3; matrix[1][2] = 0.59; matrix[2][2] = 0.11;
-
- // degamma before applying the matrix
- if (mColorManagementUsed) {
- ColorTransformHelper::DegammaColor(expected);
- }
-
- ColorTransformHelper::applyMatrix(expected, matrix);
-
- if (mColorManagementUsed) {
- ColorTransformHelper::GammaColor(expected);
- }
-
- const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
- uint8_t(expected.b * 255), 255};
-
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
-
- Transaction()
- .setColor(colorLayer, color)
- .setColorTransform(parentLayer, matrix, vec3())
- .apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
- }
-}
-
-TEST_P(LayerRenderTypeTransactionTest, SetColorTransformOnChildAndParent) {
- sp<SurfaceControl> parentLayer;
- sp<SurfaceControl> colorLayer;
- ASSERT_NO_FATAL_FAILURE(parentLayer = createLayer("parent", 0 /* buffer width */,
- 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceContainer));
- ASSERT_NO_FATAL_FAILURE(
- colorLayer = createLayer("test", 0 /* buffer width */, 0 /* buffer height */,
- ISurfaceComposerClient::eFXSurfaceColor, parentLayer.get()));
-
- Transaction()
- .setCrop_legacy(parentLayer, Rect(0, 0, 100, 100))
- .setCrop_legacy(colorLayer, Rect(0, 0, 32, 32))
- .setLayer(parentLayer, mLayerZBase + 1)
- .apply();
- {
- SCOPED_TRACE("default color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), Color::BLACK);
- }
-
- const half3 color(50.0f / 255.0f, 100.0f / 255.0f, 150.0f / 255.0f);
- half3 expected = color;
- mat3 matrixChild;
- matrixChild[0][0] = 0.3; matrixChild[1][0] = 0.59; matrixChild[2][0] = 0.11;
- matrixChild[0][1] = 0.3; matrixChild[1][1] = 0.59; matrixChild[2][1] = 0.11;
- matrixChild[0][2] = 0.3; matrixChild[1][2] = 0.59; matrixChild[2][2] = 0.11;
- mat3 matrixParent;
- matrixParent[0][0] = 0.2; matrixParent[1][0] = 0.4; matrixParent[2][0] = 0.10;
- matrixParent[0][1] = 0.2; matrixParent[1][1] = 0.4; matrixParent[2][1] = 0.10;
- matrixParent[0][2] = 0.2; matrixParent[1][2] = 0.4; matrixParent[2][2] = 0.10;
-
- // degamma before applying the matrix
- if (mColorManagementUsed) {
- ColorTransformHelper::DegammaColor(expected);
- }
-
- ColorTransformHelper::applyMatrix(expected, matrixChild);
- ColorTransformHelper::applyMatrix(expected, matrixParent);
-
- if (mColorManagementUsed) {
- ColorTransformHelper::GammaColor(expected);
- }
-
- const Color expectedColor = {uint8_t(expected.r * 255), uint8_t(expected.g * 255),
- uint8_t(expected.b * 255), 255};
-
- // this is handwavy, but the precison loss scaled by 255 (8-bit per
- // channel) should be less than one
- const uint8_t tolerance = 1;
-
- Transaction()
- .setColor(colorLayer, color)
- .setColorTransform(parentLayer, matrixParent, vec3())
- .setColorTransform(colorLayer, matrixChild, vec3())
- .apply();
- {
- SCOPED_TRACE("new color");
- getScreenCapture()->expectColor(Rect(0, 0, 32, 32), expectedColor, tolerance);
- }
-}
-
-struct CallbackData {
- CallbackData() = default;
- CallbackData(nsecs_t time, const sp<Fence>& fence,
- const std::vector<SurfaceControlStats>& stats)
- : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
-
- nsecs_t latchTime;
- sp<Fence> presentFence;
- std::vector<SurfaceControlStats> surfaceControlStats;
-};
-
-class ExpectedResult {
-public:
- enum Transaction {
- NOT_PRESENTED = 0,
- PRESENTED,
- };
-
- enum Buffer {
- NOT_ACQUIRED = 0,
- ACQUIRED,
- };
-
- enum PreviousBuffer {
- NOT_RELEASED = 0,
- RELEASED,
- UNKNOWN,
- };
-
- void reset() {
- mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
- mExpectedSurfaceResults.clear();
- }
-
- void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
- ExpectedResult::Buffer bufferResult = ACQUIRED,
- ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
- mTransactionResult = transactionResult;
- mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
- std::forward_as_tuple(bufferResult, previousBufferResult));
- }
-
- void addSurfaces(ExpectedResult::Transaction transactionResult,
- const std::vector<sp<SurfaceControl>>& layers,
- ExpectedResult::Buffer bufferResult = ACQUIRED,
- ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
- for (const auto& layer : layers) {
- addSurface(transactionResult, layer, bufferResult, previousBufferResult);
- }
- }
-
- void addExpectedPresentTime(nsecs_t expectedPresentTime) {
- mExpectedPresentTime = expectedPresentTime;
- }
-
- void verifyCallbackData(const CallbackData& callbackData) const {
- const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
- if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
- ASSERT_GE(latchTime, 0) << "bad latch time";
- ASSERT_NE(presentFence, nullptr);
- if (mExpectedPresentTime >= 0) {
- ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
- ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
- // if the panel is running at 30 hz, at the worst case, our expected time just
- // misses vsync and we have to wait another 33.3ms
- ASSERT_LE(presentFence->getSignalTime(),
- mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
- }
- } else {
- ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
- ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
- }
-
- ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
- << "wrong number of surfaces";
-
- for (const auto& stats : surfaceControlStats) {
- ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
-
- const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
- ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
- << "unexpected surface control";
- expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
- }
- }
-
-private:
- class ExpectedSurfaceResult {
- public:
- ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
- ExpectedResult::PreviousBuffer previousBufferResult)
- : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
-
- void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
- nsecs_t latchTime) const {
- const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
-
- ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
- << "bad acquire time";
- ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
-
- if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
- ASSERT_NE(previousReleaseFence, nullptr)
- << "failed to set release prev buffer fence";
- } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
- ASSERT_EQ(previousReleaseFence, nullptr)
- << "should not have set released prev buffer fence";
- }
- }
-
- private:
- ExpectedResult::Buffer mBufferResult;
- ExpectedResult::PreviousBuffer mPreviousBufferResult;
- };
-
- struct SCHash {
- std::size_t operator()(const sp<SurfaceControl>& sc) const {
- return std::hash<IBinder*>{}(sc->getHandle().get());
- }
- };
- ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
- nsecs_t mExpectedPresentTime = -1;
- std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
-};
-
-class CallbackHelper {
-public:
- static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
- const std::vector<SurfaceControlStats>& stats) {
- if (!callbackContext) {
- ALOGE("failed to get callback context");
- }
- CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
- std::lock_guard lock(helper->mMutex);
- helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
- helper->mConditionVariable.notify_all();
- }
-
- void getCallbackData(CallbackData* outData) {
- std::unique_lock lock(mMutex);
-
- if (mCallbackDataQueue.empty()) {
- ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
- std::cv_status::timeout)
- << "did not receive callback";
- }
-
- *outData = std::move(mCallbackDataQueue.front());
- mCallbackDataQueue.pop();
- }
-
- void verifyFinalState() {
- // Wait to see if there are extra callbacks
- std::this_thread::sleep_for(500ms);
-
- std::lock_guard lock(mMutex);
- EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
- mCallbackDataQueue = {};
- }
-
- void* getContext() { return static_cast<void*>(this); }
-
- std::mutex mMutex;
- std::condition_variable mConditionVariable;
- std::queue<CallbackData> mCallbackDataQueue;
-};
-
-class LayerCallbackTest : public LayerTransactionTest {
-public:
- virtual sp<SurfaceControl> createBufferStateLayer() {
- return createLayer(mClient, "test", 0, 0, ISurfaceComposerClient::eFXSurfaceBufferState);
- }
-
- static int fillTransaction(Transaction& transaction, CallbackHelper* callbackHelper,
- const sp<SurfaceControl>& layer = nullptr, bool setBuffer = true,
- bool setBackgroundColor = false) {
- if (layer) {
- sp<GraphicBuffer> buffer;
- sp<Fence> fence;
- if (setBuffer) {
- int err = getBuffer(&buffer, &fence);
- if (err != NO_ERROR) {
- return err;
- }
-
- transaction.setBuffer(layer, buffer);
- transaction.setAcquireFence(layer, fence);
- }
-
- if (setBackgroundColor) {
- transaction.setBackgroundColor(layer, /*color*/ half3(1.0f, 0, 0), /*alpha*/ 1.0f,
- ui::Dataspace::UNKNOWN);
- }
- }
-
- transaction.addTransactionCompletedCallback(callbackHelper->function,
- callbackHelper->getContext());
- return NO_ERROR;
- }
-
- static void waitForCallback(CallbackHelper& helper, const ExpectedResult& expectedResult,
- bool finalState = false) {
- CallbackData callbackData;
- ASSERT_NO_FATAL_FAILURE(helper.getCallbackData(&callbackData));
- EXPECT_NO_FATAL_FAILURE(expectedResult.verifyCallbackData(callbackData));
-
- if (finalState) {
- ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
- }
- }
-
- static void waitForCallbacks(CallbackHelper& helper,
- const std::vector<ExpectedResult>& expectedResults,
- bool finalState = false) {
- for (const auto& expectedResult : expectedResults) {
- waitForCallback(helper, expectedResult);
- }
- if (finalState) {
- ASSERT_NO_FATAL_FAILURE(helper.verifyFinalState());
- }
- }
-};
-
-TEST_F(LayerCallbackTest, BufferColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, true, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoBufferNoColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, false, false);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, BufferNoColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, true, false);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoBufferColor) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, NoStateChange) {
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, OffScreen) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(-100, -100, 100, 100)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeBufferNoColor) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeNoBufferColor) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MergeOneBufferOneColor) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2, false, true);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer1);
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer2,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-TEST_F(LayerCallbackTest, Merge_SameCallback) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback;
- int err = fillTransaction(transaction1, &callback, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, Merge_SameLayer) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, Merge_DifferentClients) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
-
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- for (size_t i = 0; i < 10; i++) {
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
- : ExpectedResult::PreviousBuffer::RELEASED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_NoStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- for (size_t i = 0; i < 10; i++) {
- ExpectedResult expected;
-
- if (i == 0) {
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- } else {
- int err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- }
-
- transaction.apply();
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SameStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- for (size_t i = 0; i < 10; i++) {
- if (i == 0) {
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- } else {
- int err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expected;
- expected.addSurface((i == 0) ? ExpectedResult::Transaction::PRESENTED
- : ExpectedResult::Transaction::NOT_PRESENTED,
- layer,
- (i == 0) ? ExpectedResult::Buffer::ACQUIRED
- : ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, i == 0));
- }
- ASSERT_NO_FATAL_FAILURE(callback.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge) {
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createBufferStateLayer());
- ASSERT_NO_FATAL_FAILURE(layer2 = createBufferStateLayer());
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- for (size_t i = 0; i < 10; i++) {
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
- ExpectedResult::Buffer::ACQUIRED,
- (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
- : ExpectedResult::PreviousBuffer::RELEASED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
- ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
- for (size_t i = 0; i < 10; i++) {
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2},
- ExpectedResult::Buffer::ACQUIRED,
- (i == 0) ? ExpectedResult::PreviousBuffer::NOT_RELEASED
- : ExpectedResult::PreviousBuffer::RELEASED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected));
- }
- ASSERT_NO_FATAL_FAILURE(callback1.verifyFinalState());
- ASSERT_NO_FATAL_FAILURE(callback2.verifyFinalState());
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_NoStateChange) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
-
- // Normal call to set up test
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
- expected.reset();
-
- // Test
- err = fillTransaction(transaction1, &callback1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.merge(std::move(transaction1)).apply();
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_Merge_DifferentClients_SameStateChange) {
- sp<SurfaceComposerClient> client1(new SurfaceComposerClient),
- client2(new SurfaceComposerClient);
-
- ASSERT_EQ(NO_ERROR, client1->initCheck()) << "failed to create SurfaceComposerClient";
- ASSERT_EQ(NO_ERROR, client2->initCheck()) << "failed to create SurfaceComposerClient";
-
- sp<SurfaceControl> layer1, layer2;
- ASSERT_NO_FATAL_FAILURE(layer1 = createLayer(client1, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
- ASSERT_NO_FATAL_FAILURE(layer2 = createLayer(client2, "test", 0, 0,
- ISurfaceComposerClient::eFXSurfaceBufferState));
-
- Transaction transaction1, transaction2;
- CallbackHelper callback1, callback2;
-
- // Normal call to set up test
- int err = fillTransaction(transaction1, &callback1, layer1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2, layer2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction1.setFrame(layer1, Rect(0, 0, 32, 32));
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- ExpectedResult expected;
- expected.addSurfaces(ExpectedResult::Transaction::PRESENTED, {layer1, layer2});
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
- expected.reset();
-
- // Test
- err = fillTransaction(transaction1, &callback1);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
- err = fillTransaction(transaction2, &callback2);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction2.setFrame(layer2, Rect(32, 32, 64, 64)).merge(std::move(transaction1)).apply();
-
- expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer2,
- ExpectedResult::Buffer::NOT_ACQUIRED);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- std::vector<ExpectedResult> expectedResults(50);
- for (auto& expected : expectedResults) {
- expected.reset();
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- ExpectedResult::PreviousBuffer::UNKNOWN);
-
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
- }
- EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_NoStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- // Normal call to set up test
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-
- // Test
- std::vector<ExpectedResult> expectedResults(50);
- for (auto& expected : expectedResults) {
- expected.reset();
-
- err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.apply();
- }
- EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, MultipleTransactions_SingleFrame_SameStateChange) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- // Normal call to set up test
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
-
- ExpectedResult expectedResult;
- expectedResult.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expectedResult, true));
-
- // Test
- std::vector<ExpectedResult> expectedResults(50);
- for (auto& expected : expectedResults) {
- expected.reset();
- expected.addSurface(ExpectedResult::Transaction::NOT_PRESENTED, layer,
- ExpectedResult::Buffer::NOT_ACQUIRED);
-
- err = fillTransaction(transaction, &callback);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- transaction.setFrame(layer, Rect(0, 0, 32, 32)).apply();
- }
- EXPECT_NO_FATAL_FAILURE(waitForCallbacks(callback, expectedResults, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected.addExpectedPresentTime(time);
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_Multiple) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback1;
- int err = fillTransaction(transaction, &callback1, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected1;
- expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected1.addExpectedPresentTime(time);
-
- CallbackHelper callback2;
- err = fillTransaction(transaction, &callback2, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 33ms after the first frame
- time += (33.3 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected2;
- expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- ExpectedResult::PreviousBuffer::RELEASED);
- expected2.addExpectedPresentTime(time);
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_OutOfOrder) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback1;
- int err = fillTransaction(transaction, &callback1, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the future
- nsecs_t time = systemTime() + (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected1;
- expected1.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected1.addExpectedPresentTime(time);
-
- CallbackHelper callback2;
- err = fillTransaction(transaction, &callback2, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 33ms before the previous frame
- time -= (33.3 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected2;
- expected2.addSurface(ExpectedResult::Transaction::PRESENTED, layer,
- ExpectedResult::Buffer::ACQUIRED,
- ExpectedResult::PreviousBuffer::RELEASED);
-
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback1, expected1, true));
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback2, expected2, true));
-}
-
-TEST_F(LayerCallbackTest, DesiredPresentTime_Past) {
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createBufferStateLayer());
-
- Transaction transaction;
- CallbackHelper callback;
- int err = fillTransaction(transaction, &callback, layer);
- if (err) {
- GTEST_SUCCEED() << "test not supported";
- return;
- }
-
- // Try to present 100ms in the past
- nsecs_t time = systemTime() - (100 * 1e6);
-
- transaction.setDesiredPresentTime(time);
- transaction.apply();
-
- ExpectedResult expected;
- expected.addSurface(ExpectedResult::Transaction::PRESENTED, layer);
- expected.addExpectedPresentTime(systemTime());
- EXPECT_NO_FATAL_FAILURE(waitForCallback(callback, expected, true));
-}
-
-class LayerUpdateTest : public LayerTransactionTest {
-protected:
- virtual void SetUp() {
- LayerTransactionTest::SetUp();
- ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
- ASSERT_FALSE(display == nullptr);
-
- DisplayInfo info;
- ASSERT_EQ(NO_ERROR, SurfaceComposerClient::getDisplayInfo(display, &info));
-
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
-
- // Background surface
- mBGSurfaceControl = createLayer(String8("BG Test Surface"), displayWidth,
- displayHeight, 0);
- ASSERT_TRUE(mBGSurfaceControl != nullptr);
- ASSERT_TRUE(mBGSurfaceControl->isValid());
- fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
-
- // Foreground surface
- mFGSurfaceControl = createLayer(String8("FG Test Surface"), 64, 64, 0);
-
- ASSERT_TRUE(mFGSurfaceControl != nullptr);
- ASSERT_TRUE(mFGSurfaceControl->isValid());
-
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
-
- // Synchronization surface
- mSyncSurfaceControl = createLayer(String8("Sync Test Surface"), 1, 1, 0);
- ASSERT_TRUE(mSyncSurfaceControl != nullptr);
- ASSERT_TRUE(mSyncSurfaceControl->isValid());
-
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
-
- asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
-
- t.setLayer(mBGSurfaceControl, INT32_MAX - 2).show(mBGSurfaceControl);
-
- t.setLayer(mFGSurfaceControl, INT32_MAX - 1)
- .setPosition(mFGSurfaceControl, 64, 64)
- .show(mFGSurfaceControl);
-
- t.setLayer(mSyncSurfaceControl, INT32_MAX - 1)
- .setPosition(mSyncSurfaceControl, displayWidth - 2, displayHeight - 2)
- .show(mSyncSurfaceControl);
- });
- }
-
- virtual void TearDown() {
- LayerTransactionTest::TearDown();
- mBGSurfaceControl = 0;
- mFGSurfaceControl = 0;
- mSyncSurfaceControl = 0;
- }
-
- void waitForPostedBuffers() {
- // Since the sync surface is in synchronous mode (i.e. double buffered)
- // posting three buffers to it should ensure that at least two
- // SurfaceFlinger::handlePageFlip calls have been made, which should
- // guaranteed that a buffer posted to another Surface has been retired.
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- }
-
-
- sp<SurfaceControl> mBGSurfaceControl;
- sp<SurfaceControl> mFGSurfaceControl;
-
- // This surface is used to ensure that the buffers posted to
- // mFGSurfaceControl have been picked up by SurfaceFlinger.
- sp<SurfaceControl> mSyncSurfaceControl;
-};
-
-TEST_F(LayerUpdateTest, RelativesAreNotDetached) {
-
- std::unique_ptr<ScreenCapture> sc;
-
- sp<SurfaceControl> relative = createLayer(String8("relativeTestSurface"), 10, 10, 0);
- fillSurfaceRGBA8(relative, 10, 10, 10);
- waitForPostedBuffers();
-
- Transaction{}
- .setRelativeLayer(relative, mFGSurfaceControl->getHandle(), 1)
- .setPosition(relative, 64, 64)
- .apply();
-
- {
- // The relative should be on top of the FG control.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(64, 64, 10, 10, 10);
- }
- Transaction{}.detachChildren(mFGSurfaceControl).apply();
-
- {
- // Nothing should change at this point.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(64, 64, 10, 10, 10);
- }
-
- Transaction{}.hide(relative).apply();
-
- {
- // Ensure that the relative was actually hidden, rather than
- // being left in the detached but visible state.
- ScreenCapture::captureScreen(&sc);
- sc->expectFGColor(64, 64);
- }
-}
-
-class GeometryLatchingTest : public LayerUpdateTest {
-protected:
- void EXPECT_INITIAL_STATE(const char* trace) {
- SCOPED_TRACE(trace);
- ScreenCapture::captureScreen(&sc);
- // We find the leading edge of the FG surface.
- sc->expectFGColor(127, 127);
- sc->expectBGColor(128, 128);
- }
-
- void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63, false); }
-
- void unlockFGBuffer() {
- sp<Surface> s = mFGSurfaceControl->getSurface();
- ASSERT_EQ(NO_ERROR, s->unlockAndPost());
- waitForPostedBuffers();
- }
-
- void completeFGResize() {
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
- }
- void restoreInitialState() {
- asTransaction([&](Transaction& t) {
- t.setSize(mFGSurfaceControl, 64, 64);
- t.setPosition(mFGSurfaceControl, 64, 64);
- t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 64, 64));
- });
-
- EXPECT_INITIAL_STATE("After restoring initial state");
- }
- std::unique_ptr<ScreenCapture> sc;
-};
-
-class CropLatchingTest : public GeometryLatchingTest {
-protected:
- void EXPECT_CROPPED_STATE(const char* trace) {
- SCOPED_TRACE(trace);
- ScreenCapture::captureScreen(&sc);
- // The edge should be moved back one pixel by our crop.
- sc->expectFGColor(126, 126);
- sc->expectBGColor(127, 127);
- sc->expectBGColor(128, 128);
- }
-
- void EXPECT_RESIZE_STATE(const char* trace) {
- SCOPED_TRACE(trace);
- ScreenCapture::captureScreen(&sc);
- // The FG is now resized too 128,128 at 64,64
- sc->expectFGColor(64, 64);
- sc->expectFGColor(191, 191);
- sc->expectBGColor(192, 192);
- }
-};
-
-TEST_F(LayerUpdateTest, DeferredTransactionTest) {
- std::unique_ptr<ScreenCapture> sc;
- {
- SCOPED_TRACE("before anything");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectFGColor(96, 96);
- sc->expectBGColor(160, 160);
- }
-
- // set up two deferred transactions on different frames
- asTransaction([&](Transaction& t) {
- t.setAlpha(mFGSurfaceControl, 0.75);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber());
- });
-
- asTransaction([&](Transaction& t) {
- t.setPosition(mFGSurfaceControl, 128, 128);
- t.deferTransactionUntil_legacy(mFGSurfaceControl, mSyncSurfaceControl->getHandle(),
- mSyncSurfaceControl->getSurface()->getNextFrameNumber() + 1);
- });
-
- {
- SCOPED_TRACE("before any trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectFGColor(96, 96);
- sc->expectBGColor(160, 160);
- }
-
- // should trigger the first deferred transaction, but not the second one
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- {
- SCOPED_TRACE("after first trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->checkPixel(96, 96, 162, 63, 96);
- sc->expectBGColor(160, 160);
- }
-
- // should show up immediately since it's not deferred
- asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 1.0); });
-
- // trigger the second deferred transaction
- fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
- {
- SCOPED_TRACE("after second trigger");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(32, 32);
- sc->expectBGColor(96, 96);
- sc->expectFGColor(160, 160);
- }
-}
-
-TEST_F(LayerUpdateTest, LayerWithNoBuffersResizesImmediately) {
- std::unique_ptr<ScreenCapture> sc;
-
- sp<SurfaceControl> childNoBuffer =
- createSurface(mClient, "Bufferless child", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- sp<SurfaceControl> childBuffer = createSurface(mClient, "Buffered child", 20, 20,
- PIXEL_FORMAT_RGBA_8888, 0, childNoBuffer.get());
- fillSurfaceRGBA8(childBuffer, 200, 200, 200);
- SurfaceComposerClient::Transaction{}
- .setCrop_legacy(childNoBuffer, Rect(0, 0, 10, 10))
- .show(childNoBuffer)
- .show(childBuffer)
- .apply(true);
- {
- ScreenCapture::captureScreen(&sc);
- sc->expectChildColor(73, 73);
- sc->expectFGColor(74, 74);
- }
- SurfaceComposerClient::Transaction{}
- .setCrop_legacy(childNoBuffer, Rect(0, 0, 20, 20))
- .apply(true);
- {
- ScreenCapture::captureScreen(&sc);
- sc->expectChildColor(73, 73);
- sc->expectChildColor(74, 74);
- }
-}
-
-TEST_F(LayerUpdateTest, MergingTransactions) {
- std::unique_ptr<ScreenCapture> sc;
- {
- SCOPED_TRACE("before move");
- ScreenCapture::captureScreen(&sc);
- sc->expectBGColor(0, 12);
- sc->expectFGColor(75, 75);
- sc->expectBGColor(145, 145);
- }
-
- Transaction t1, t2;
- t1.setPosition(mFGSurfaceControl, 128, 128);
- t2.setPosition(mFGSurfaceControl, 0, 0);
- // We expect that the position update from t2 now
- // overwrites the position update from t1.
- t1.merge(std::move(t2));
- t1.apply();
-
- {
- ScreenCapture::captureScreen(&sc);
- sc->expectFGColor(1, 1);
- }
-}
-
-class ChildLayerTest : public LayerUpdateTest {
-protected:
- void SetUp() override {
- LayerUpdateTest::SetUp();
- mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- SCOPED_TRACE("before anything");
- mCapture = screenshot();
- mCapture->expectChildColor(64, 64);
- }
- }
- void TearDown() override {
- LayerUpdateTest::TearDown();
- mChild = 0;
- }
-
- sp<SurfaceControl> mChild;
- std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(ChildLayerTest, ChildLayerPositioning) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
-
- {
- mCapture = screenshot();
- // Top left of foreground should now be at 0, 0
- mCapture->expectFGColor(0, 0);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(10, 10);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(20, 20);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerCropping) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 5, 5));
- });
-
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(4, 4);
- mCapture->expectBGColor(5, 5);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerConstraints) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setPosition(mChild, 63, 63);
- });
-
- {
- mCapture = screenshot();
- mCapture->expectFGColor(0, 0);
- // Last pixel in foreground should now be the child.
- mCapture->expectChildColor(63, 63);
- // But the child should be constrained and the next pixel
- // must be the background
- mCapture->expectBGColor(64, 64);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerScaling) {
- asTransaction([&](Transaction& t) { t.setPosition(mFGSurfaceControl, 0, 0); });
-
- // Find the boundary between the parent and child
- {
- mCapture = screenshot();
- mCapture->expectChildColor(9, 9);
- mCapture->expectFGColor(10, 10);
- }
-
- asTransaction([&](Transaction& t) { t.setMatrix(mFGSurfaceControl, 2.0, 0, 0, 2.0); });
-
- // The boundary should be twice as far from the origin now.
- // The pixels from the last test should all be child now
- {
- mCapture = screenshot();
- mCapture->expectChildColor(9, 9);
- mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 19);
- mCapture->expectFGColor(20, 20);
- }
-}
-
-// A child with a scale transform should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
- asTransaction([&](Transaction& t) {
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setPosition(mChild, 0, 0);
- });
-
- // Find the boundary between the parent and child.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 9);
- mCapture->expectFGColor(10, 10);
- }
-
- asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
-
- // The child should fill its parent bounds and be cropped by it.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerAlpha) {
- fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
- fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
- fillSurfaceRGBA8(mChild, 0, 254, 0);
- waitForPostedBuffers();
-
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // Unblended child color
- mCapture->checkPixel(0, 0, 0, 254, 0);
- }
-
- asTransaction([&](Transaction& t) { t.setAlpha(mChild, 0.5); });
-
- {
- mCapture = screenshot();
- // Child and BG blended.
- mCapture->checkPixel(0, 0, 127, 127, 0);
- }
-
- asTransaction([&](Transaction& t) { t.setAlpha(mFGSurfaceControl, 0.5); });
-
- {
- mCapture = screenshot();
- // Child and BG blended.
- mCapture->checkPixel(0, 0, 95, 64, 95);
- }
-}
-
-TEST_F(ChildLayerTest, ReparentChildren) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) {
- t.reparentChildren(mFGSurfaceControl, mBGSurfaceControl->getHandle());
- });
-
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- // In reparenting we should have exposed the entire foreground surface.
- mCapture->expectFGColor(74, 74);
- // And the child layer should now begin at 10, 10 (since the BG
- // layer is at (0, 0)).
- mCapture->expectBGColor(9, 9);
- mCapture->expectChildColor(10, 10);
- }
-}
-
-TEST_F(ChildLayerTest, ChildrenSurviveParentDestruction) {
- sp<SurfaceControl> mGrandChild =
- createSurface(mClient, "Grand Child", 10, 10, PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
- fillSurfaceRGBA8(mGrandChild, 111, 111, 111);
-
- {
- SCOPED_TRACE("Grandchild visible");
- ScreenCapture::captureScreen(&mCapture);
- mCapture->checkPixel(64, 64, 111, 111, 111);
- }
-
- mChild.clear();
-
- {
- SCOPED_TRACE("After destroying child");
- ScreenCapture::captureScreen(&mCapture);
- mCapture->expectFGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) {
- t.reparent(mGrandChild, mFGSurfaceControl->getHandle());
- });
-
- {
- SCOPED_TRACE("After reparenting grandchild");
- ScreenCapture::captureScreen(&mCapture);
- mCapture->checkPixel(64, 64, 111, 111, 111);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenSameClient) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
-
- asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
- asTransaction([&](Transaction& t) { t.hide(mChild); });
-
- // Since the child has the same client as the parent, it will not get
- // detached and will be hidden.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectFGColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
- sp<SurfaceComposerClient> mNewComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> mChildNewClient =
- createSurface(mNewComposerClient, "New Child Test Surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(mChildNewClient->isValid());
-
- fillSurfaceRGBA8(mChildNewClient, 200, 200, 200);
-
- asTransaction([&](Transaction& t) {
- t.hide(mChild);
- t.show(mChildNewClient);
- t.setPosition(mChildNewClient, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.detachChildren(mFGSurfaceControl); });
-
- asTransaction([&](Transaction& t) { t.hide(mChildNewClient); });
-
- // Nothing should have changed.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, DetachChildrenThenAttach) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
-
- fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
- Transaction()
- .hide(mChild)
- .show(childNewClient)
- .setPosition(childNewClient, 10, 10)
- .setPosition(mFGSurfaceControl, 64, 64)
- .apply();
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- Transaction().detachChildren(mFGSurfaceControl).apply();
- Transaction().hide(childNewClient).apply();
-
- // Nothing should have changed.
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- mCapture->expectChildColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-
- sp<SurfaceControl> newParentSurface = createLayer(String8("New Parent Surface"), 32, 32, 0);
- fillLayerColor(ISurfaceComposerClient::eFXSurfaceBufferQueue, newParentSurface, Color::RED, 32,
- 32);
- Transaction()
- .setLayer(newParentSurface, INT32_MAX - 1)
- .show(newParentSurface)
- .setPosition(newParentSurface, 20, 20)
- .reparent(childNewClient, newParentSurface->getHandle())
- .apply();
- {
- mCapture = screenshot();
- // Child is now hidden.
- mCapture->expectColor(Rect(20, 20, 52, 52), Color::RED);
- }
-}
-TEST_F(ChildLayerTest, DetachChildrenWithDeferredTransaction) {
- sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
- sp<SurfaceControl> childNewClient =
- newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- ASSERT_TRUE(childNewClient != nullptr);
- ASSERT_TRUE(childNewClient->isValid());
-
- fillSurfaceRGBA8(childNewClient, 200, 200, 200);
-
- Transaction()
- .hide(mChild)
- .show(childNewClient)
- .setPosition(childNewClient, 10, 10)
- .setPosition(mFGSurfaceControl, 64, 64)
- .apply();
-
- {
- mCapture = screenshot();
- Rect rect = Rect(74, 74, 84, 84);
- mCapture->expectBorder(rect, Color{195, 63, 63, 255});
- mCapture->expectColor(rect, Color{200, 200, 200, 255});
- }
-
- Transaction()
- .deferTransactionUntil_legacy(childNewClient, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber())
- .apply();
- Transaction().detachChildren(mFGSurfaceControl).apply();
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(mFGSurfaceControl, Color::RED, 32, 32));
-
- // BufferLayer can still dequeue buffers even though there's a detached layer with a
- // deferred transaction.
- {
- SCOPED_TRACE("new buffer");
- mCapture = screenshot();
- Rect rect = Rect(74, 74, 84, 84);
- mCapture->expectBorder(rect, Color::RED);
- mCapture->expectColor(rect, Color{200, 200, 200, 255});
- }
-}
-
-TEST_F(ChildLayerTest, ChildrenInheritNonTransformScalingFromParent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- // But it's only 10x15.
- mCapture->expectFGColor(10, 15);
- }
-
- asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // We cause scaling by 2.
- t.setSize(mFGSurfaceControl, 128, 128);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 29);
- // And now it should be scaled all the way to 20x30
- mCapture->expectFGColor(20, 30);
- }
-}
-
-// Regression test for b/37673612
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransform) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- // We've positioned the child in the top left.
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 14);
- // But it's only 10x15.
- mCapture->expectFGColor(10, 15);
- }
- // We set things up as in b/37673612 so that there is a mismatch between the buffer size and
- // the WM specified state size.
- asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- {
- // The child should still be in the same place and not have any strange scaling as in
- // b/37673612.
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectFGColor(10, 10);
- }
-}
-
-// A child with a buffer transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setSize(mChild, 100, 100);
- });
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- mCapture = screenshot();
-
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- // Apply a 90 transform on the buffer.
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 64, 128);
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- // The child should be cropped by the new parent bounds.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(99, 63);
- mCapture->expectFGColor(100, 63);
- mCapture->expectBGColor(128, 64);
- }
-}
-
-// A child with a scale transform from its parents should be cropped by its parent bounds.
-TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- t.setSize(mChild, 200, 200);
- });
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- {
- mCapture = screenshot();
-
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(63, 63);
- mCapture->expectBGColor(64, 64);
- }
-
- asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- // Set a scaling by 2.
- t.setSize(mFGSurfaceControl, 128, 128);
- });
-
- // Child should inherit its parents scale but should be cropped by its parent bounds.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(127, 127);
- mCapture->expectBGColor(128, 128);
- }
-}
-
-// Regression test for b/127368943
-// Child should ignore the buffer transform but apply parent scale transform.
-TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 0, 0);
- t.setPosition(mFGSurfaceControl, 0, 0);
- });
-
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 14);
- mCapture->expectFGColor(10, 15);
- }
-
- // Change the size of the foreground to 128 * 64 so we can test rotation as well.
- asTransaction([&](Transaction& t) {
- t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- t.setSize(mFGSurfaceControl, 128, 64);
- });
- sp<Surface> s = mFGSurfaceControl->getSurface();
- auto anw = static_cast<ANativeWindow*>(s.get());
- // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
- // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
- native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
- native_window_set_buffers_dimensions(anw, 32, 64);
- fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
- waitForPostedBuffers();
-
- // The child should ignore the buffer transform but apply the 2.0 scale from parent.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(19, 29);
- mCapture->expectFGColor(20, 30);
- }
-}
-
-TEST_F(ChildLayerTest, Bug36858924) {
- // Destroy the child layer
- mChild.clear();
-
- // Now recreate it as hidden
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eHidden, mFGSurfaceControl.get());
-
- // Show the child layer in a deferred transaction
- asTransaction([&](Transaction& t) {
- t.deferTransactionUntil_legacy(mChild, mFGSurfaceControl->getHandle(),
- mFGSurfaceControl->getSurface()->getNextFrameNumber());
- t.show(mChild);
- });
-
- // Render the foreground surface a few times
- //
- // Prior to the bugfix for b/36858924, this would usually hang while trying to fill the third
- // frame because SurfaceFlinger would never process the deferred transaction and would therefore
- // never acquire/release the first buffer
- ALOGI("Filling 1");
- fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
- ALOGI("Filling 2");
- fillSurfaceRGBA8(mFGSurfaceControl, 0, 0, 255);
- ALOGI("Filling 3");
- fillSurfaceRGBA8(mFGSurfaceControl, 255, 0, 0);
- ALOGI("Filling 4");
- fillSurfaceRGBA8(mFGSurfaceControl, 0, 255, 0);
-}
-
-TEST_F(ChildLayerTest, Reparent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
-
- asTransaction([&](Transaction& t) { t.reparent(mChild, mBGSurfaceControl->getHandle()); });
-
- {
- mCapture = screenshot();
- mCapture->expectFGColor(64, 64);
- // In reparenting we should have exposed the entire foreground surface.
- mCapture->expectFGColor(74, 74);
- // And the child layer should now begin at 10, 10 (since the BG
- // layer is at (0, 0)).
- mCapture->expectBGColor(9, 9);
- mCapture->expectChildColor(10, 10);
- }
-}
-
-TEST_F(ChildLayerTest, ReparentToNoParent) {
- asTransaction([&](Transaction& t) {
- t.show(mChild);
- t.setPosition(mChild, 10, 10);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // But 10 pixels in we should see the child surface
- mCapture->expectChildColor(74, 74);
- // And 10 more pixels we should be back to the foreground surface
- mCapture->expectFGColor(84, 84);
- }
- asTransaction([&](Transaction& t) { t.reparent(mChild, nullptr); });
- {
- mCapture = screenshot();
- // The surface should now be offscreen.
- mCapture->expectFGColor(64, 64);
- mCapture->expectFGColor(74, 74);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, ReparentFromNoParent) {
- sp<SurfaceControl> newSurface = createLayer(String8("New Surface"), 10, 10, 0);
- ASSERT_TRUE(newSurface != nullptr);
- ASSERT_TRUE(newSurface->isValid());
-
- fillSurfaceRGBA8(newSurface, 63, 195, 63);
- asTransaction([&](Transaction& t) {
- t.hide(mChild);
- t.show(newSurface);
- t.setPosition(newSurface, 10, 10);
- t.setLayer(newSurface, INT32_MAX - 2);
- t.setPosition(mFGSurfaceControl, 64, 64);
- });
-
- {
- mCapture = screenshot();
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // At 10, 10 we should see the new surface
- mCapture->checkPixel(10, 10, 63, 195, 63);
- }
-
- asTransaction([&](Transaction& t) { t.reparent(newSurface, mFGSurfaceControl->getHandle()); });
-
- {
- mCapture = screenshot();
- // newSurface will now be a child of mFGSurface so it will be 10, 10 offset from
- // mFGSurface, putting it at 74, 74.
- mCapture->expectFGColor(64, 64);
- mCapture->checkPixel(74, 74, 63, 195, 63);
- mCapture->expectFGColor(84, 84);
- }
-}
-
-TEST_F(ChildLayerTest, NestedChildren) {
- sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mChild.get());
- fillSurfaceRGBA8(grandchild, 50, 50, 50);
-
- {
- mCapture = screenshot();
- // Expect the grandchild to begin at 64, 64 because it's a child of mChild layer
- // which begins at 64, 64
- mCapture->checkPixel(64, 64, 50, 50, 50);
- }
-}
-
-TEST_F(ChildLayerTest, ChildLayerRelativeLayer) {
- sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 128, 128, 0);
- fillSurfaceRGBA8(relative, 255, 255, 255);
-
- Transaction t;
- t.setLayer(relative, INT32_MAX)
- .setRelativeLayer(mChild, relative->getHandle(), 1)
- .setPosition(mFGSurfaceControl, 0, 0)
- .apply(true);
-
- // We expect that the child should have been elevated above our
- // INT_MAX layer even though it's not a child of it.
- {
- mCapture = screenshot();
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 9);
- mCapture->checkPixel(10, 10, 255, 255, 255);
- }
-}
-
-class BoundlessLayerTest : public LayerUpdateTest {
-protected:
- std::unique_ptr<ScreenCapture> mCapture;
-};
-
-// Verify setting a size on a buffer layer has no effect.
-TEST_F(BoundlessLayerTest, BufferLayerIgnoresSize) {
- sp<SurfaceControl> bufferLayer =
- createSurface(mClient, "BufferLayer", 45, 45, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- ASSERT_TRUE(bufferLayer->isValid());
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(bufferLayer, Color::BLACK, 30, 30));
- asTransaction([&](Transaction& t) { t.show(bufferLayer); });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 94, 94), Color::BLACK);
- // Buffer layer should not extend past buffer bounds
- mCapture->expectFGColor(95, 95);
- }
-}
-
-// Verify a boundless color layer will fill its parent bounds. The parent has a buffer size
-// which will crop the color layer.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentBufferBounds) {
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify a boundless color layer will fill its parent bounds. The parent has no buffer but has
-// a crop which will be used to crop the color layer.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerFillsParentCropBounds) {
- sp<SurfaceControl> cropLayer = createSurface(mClient, "CropLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(cropLayer->isValid());
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, cropLayer.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setCrop_legacy(cropLayer, Rect(5, 5, 10, 10));
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(cropLayer);
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // 5 pixels from the foreground we should see the child surface
- mCapture->expectColor(Rect(69, 69, 74, 74), Color::BLACK);
- // 10 pixels from the foreground we should be back to the foreground surface
- mCapture->expectFGColor(74, 74);
- }
-}
-
-// Verify for boundless layer with no children, their transforms have no effect.
-TEST_F(BoundlessLayerTest, BoundlessColorLayerTransformHasNoEffect) {
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, mFGSurfaceControl.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setPosition(colorLayer, 320, 320);
- t.setMatrix(colorLayer, 2, 0, 0, 2);
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify for boundless layer with children, their transforms have an effect.
-TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerCanSetTransform) {
- sp<SurfaceControl> boundlessLayerRightShift =
- createSurface(mClient, "BoundlessLayerRightShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(boundlessLayerRightShift->isValid());
- sp<SurfaceControl> boundlessLayerDownShift =
- createSurface(mClient, "BoundlessLayerLeftShift", 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, boundlessLayerRightShift.get());
- ASSERT_TRUE(boundlessLayerDownShift->isValid());
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayerDownShift.get());
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setPosition(boundlessLayerRightShift, 32, 0);
- t.show(boundlessLayerRightShift);
- t.setPosition(boundlessLayerDownShift, 0, 32);
- t.show(boundlessLayerDownShift);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Top left of foreground must now be visible
- mCapture->expectFGColor(64, 64);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(96, 96, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify child layers do not get clipped if they temporarily move into the negative
-// coordinate space as the result of an intermediate transformation.
-TEST_F(BoundlessLayerTest, IntermediateBoundlessLayerDoNotCrop) {
- sp<SurfaceControl> boundlessLayer =
- mClient->createSurface(String8("BoundlessLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- 0 /* flags */, mFGSurfaceControl.get());
- ASSERT_TRUE(boundlessLayer != nullptr);
- ASSERT_TRUE(boundlessLayer->isValid());
- sp<SurfaceControl> colorLayer =
- mClient->createSurface(String8("ColorLayer"), 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, boundlessLayer.get());
- ASSERT_TRUE(colorLayer != nullptr);
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- // shift child layer off bounds. If this layer was not boundless, we will
- // expect the child layer to be cropped.
- t.setPosition(boundlessLayer, 32, 32);
- t.show(boundlessLayer);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
- // undo shift by parent
- t.setPosition(colorLayer, -32, -32);
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(64, 64, 128, 128), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(129, 129);
- }
-}
-
-// Verify for boundless root layers with children, their transforms have an effect.
-TEST_F(BoundlessLayerTest, RootBoundlessLayerCanSetTransform) {
- sp<SurfaceControl> rootBoundlessLayer = createSurface(mClient, "RootBoundlessLayer", 0, 0,
- PIXEL_FORMAT_RGBA_8888, 0 /* flags */);
- ASSERT_TRUE(rootBoundlessLayer->isValid());
- sp<SurfaceControl> colorLayer =
- createSurface(mClient, "ColorLayer", 0, 0, PIXEL_FORMAT_RGBA_8888,
- ISurfaceComposerClient::eFXSurfaceColor, rootBoundlessLayer.get());
-
- ASSERT_TRUE(colorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setLayer(rootBoundlessLayer, INT32_MAX - 1);
- t.setPosition(rootBoundlessLayer, 32, 32);
- t.show(rootBoundlessLayer);
- t.setCrop_legacy(colorLayer, Rect(0, 0, 64, 64));
- t.setColor(colorLayer, half3{0, 0, 0});
- t.show(colorLayer);
- t.hide(mFGSurfaceControl);
- });
- {
- mCapture = screenshot();
- // Top left of background must now be visible
- mCapture->expectBGColor(0, 0);
- // Top left of foreground must now be visible
- mCapture->expectBGColor(31, 31);
- // Foreground Surface bounds must be color layer
- mCapture->expectColor(Rect(32, 32, 96, 96), Color::BLACK);
- // Color layer should not extend past foreground bounds
- mCapture->expectBGColor(97, 97);
- }
-}
-
-class ScreenCaptureTest : public LayerUpdateTest {
-protected:
- std::unique_ptr<ScreenCapture> mCapture;
-};
-
-TEST_F(ScreenCaptureTest, CaptureSingleLayer) {
- auto bgHandle = mBGSurfaceControl->getHandle();
- ScreenCapture::captureLayers(&mCapture, bgHandle);
- mCapture->expectBGColor(0, 0);
- // Doesn't capture FG layer which is at 64, 64
- mCapture->expectBGColor(64, 64);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerWithChild) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(child).apply(true);
-
- // Captures mFGSurfaceControl layer and its child.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerChildOnly) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(child).apply(true);
-
- // Captures mFGSurfaceControl's child
- ScreenCapture::captureChildLayers(&mCapture, fgHandle);
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureLayerExclude) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child2, 200, 0, 200);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- .show(child2)
- .setLayer(child, 1)
- .setLayer(child2, 2)
- .apply(true);
-
- // Child2 would be visible but its excluded, so we should see child1 color instead.
- ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->checkPixel(0, 0, 200, 200, 200);
-}
-
-// Like the last test but verifies that children are also exclude.
-TEST_F(ScreenCaptureTest, CaptureLayerExcludeTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- sp<SurfaceControl> child2 = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child2, 200, 0, 200);
- sp<SurfaceControl> child3 = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, child2.get());
- fillSurfaceRGBA8(child2, 200, 0, 200);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- .show(child2)
- .show(child3)
- .setLayer(child, 1)
- .setLayer(child2, 2)
- .apply(true);
-
- // Child2 would be visible but its excluded, so we should see child1 color instead.
- ScreenCapture::captureChildLayersExcluding(&mCapture, fgHandle, {child2->getHandle()});
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->checkPixel(0, 0, 200, 200, 200);
-}
-
-TEST_F(ScreenCaptureTest, CaptureTransparent) {
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
-
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(child).apply(true);
-
- auto childHandle = child->getHandle();
-
- // Captures child
- ScreenCapture::captureLayers(&mCapture, childHandle, {0, 0, 10, 20});
- mCapture->expectColor(Rect(0, 0, 9, 9), {200, 200, 200, 255});
- // Area outside of child's bounds is transparent.
- mCapture->expectColor(Rect(0, 10, 9, 19), {0, 0, 0, 0});
-}
-
-TEST_F(ScreenCaptureTest, DontCaptureRelativeOutsideTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- ASSERT_NE(nullptr, child.get()) << "failed to create surface";
- sp<SurfaceControl> relative = createLayer(String8("Relative surface"), 10, 10, 0);
- fillSurfaceRGBA8(child, 200, 200, 200);
- fillSurfaceRGBA8(relative, 100, 100, 100);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- // Set relative layer above fg layer so should be shown above when computing all layers.
- .setRelativeLayer(relative, fgHandle, 1)
- .show(relative)
- .apply(true);
-
- // Captures mFGSurfaceControl layer and its child. Relative layer shouldn't be captured.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- mCapture->expectChildColor(0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureRelativeInTree) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- sp<SurfaceControl> relative = createSurface(mClient, "Relative surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- fillSurfaceRGBA8(relative, 100, 100, 100);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- // Set relative layer below fg layer but relative to child layer so it should be shown
- // above child layer.
- .setLayer(relative, -1)
- .setRelativeLayer(relative, child->getHandle(), 1)
- .show(relative)
- .apply(true);
-
- // Captures mFGSurfaceControl layer and its children. Relative layer is a child of fg so its
- // relative value should be taken into account, placing it above child layer.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- // Relative layer is showing on top of child layer
- mCapture->expectColor(Rect(0, 0, 9, 9), {100, 100, 100, 255});
-}
-
-// In the following tests we verify successful skipping of a parent layer,
-// so we use the same verification logic and only change how we mutate
-// the parent layer to verify that various properties are ignored.
-class ScreenCaptureChildOnlyTest : public LayerUpdateTest {
-public:
- void SetUp() override {
- LayerUpdateTest::SetUp();
-
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
- mFGSurfaceControl.get());
- fillSurfaceRGBA8(mChild, 200, 200, 200);
-
- SurfaceComposerClient::Transaction().show(mChild).apply(true);
- }
-
- void verify(std::function<void()> verifyStartingState) {
- // Verify starting state before a screenshot is taken.
- verifyStartingState();
-
- // Verify child layer does not inherit any of the properties of its
- // parent when its screenshot is captured.
- auto fgHandle = mFGSurfaceControl->getHandle();
- ScreenCapture::captureChildLayers(&mCapture, fgHandle);
- mCapture->checkPixel(10, 10, 0, 0, 0);
- mCapture->expectChildColor(0, 0);
-
- // Verify all assumptions are still true after the screenshot is taken.
- verifyStartingState();
- }
-
- std::unique_ptr<ScreenCapture> mCapture;
- sp<SurfaceControl> mChild;
-};
-
-// Regression test b/76099859
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentVisibility) {
-
- SurfaceComposerClient::Transaction().hide(mFGSurfaceControl).apply(true);
-
- // Even though the parent is hidden we should still capture the child.
-
- // Before and after reparenting, verify child is properly hidden
- // when rendering full-screen.
- verify([&] { screenshot()->expectBGColor(64, 64); });
-}
-
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresParentCrop) {
- SurfaceComposerClient::Transaction()
- .setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 1, 1))
- .apply(true);
-
- // Even though the parent is cropped out we should still capture the child.
-
- // Before and after reparenting, verify child is cropped by parent.
- verify([&] { screenshot()->expectBGColor(65, 65); });
-}
-
-// Regression test b/124372894
-TEST_F(ScreenCaptureChildOnlyTest, CaptureLayerIgnoresTransform) {
- SurfaceComposerClient::Transaction().setMatrix(mFGSurfaceControl, 2, 0, 0, 2).apply(true);
-
- // We should not inherit the parent scaling.
-
- // Before and after reparenting, verify child is properly scaled.
- verify([&] { screenshot()->expectChildColor(80, 80); });
-}
-
-
-TEST_F(ScreenCaptureTest, CaptureLayerWithGrandchild) {
- auto fgHandle = mFGSurfaceControl->getHandle();
-
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
-
- sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
- PIXEL_FORMAT_RGBA_8888, 0, child.get());
-
- fillSurfaceRGBA8(grandchild, 50, 50, 50);
- SurfaceComposerClient::Transaction()
- .show(child)
- .setPosition(grandchild, 5, 5)
- .show(grandchild)
- .apply(true);
-
- // Captures mFGSurfaceControl, its child, and the grandchild.
- ScreenCapture::captureLayers(&mCapture, fgHandle);
- mCapture->expectFGColor(10, 10);
- mCapture->expectChildColor(0, 0);
- mCapture->checkPixel(5, 5, 50, 50, 50);
-}
-
-TEST_F(ScreenCaptureTest, CaptureChildOnly) {
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- auto childHandle = child->getHandle();
-
- SurfaceComposerClient::Transaction().setPosition(child, 5, 5).show(child).apply(true);
-
- // Captures only the child layer, and not the parent.
- ScreenCapture::captureLayers(&mCapture, childHandle);
- mCapture->expectChildColor(0, 0);
- mCapture->expectChildColor(9, 9);
-}
-
-TEST_F(ScreenCaptureTest, CaptureGrandchildOnly) {
- sp<SurfaceControl> child = createSurface(mClient, "Child surface", 10, 10,
- PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
- fillSurfaceRGBA8(child, 200, 200, 200);
- auto childHandle = child->getHandle();
-
- sp<SurfaceControl> grandchild = createSurface(mClient, "Grandchild surface", 5, 5,
- PIXEL_FORMAT_RGBA_8888, 0, child.get());
- fillSurfaceRGBA8(grandchild, 50, 50, 50);
-
- SurfaceComposerClient::Transaction()
- .show(child)
- .setPosition(grandchild, 5, 5)
- .show(grandchild)
- .apply(true);
-
- auto grandchildHandle = grandchild->getHandle();
-
- // Captures only the grandchild.
- ScreenCapture::captureLayers(&mCapture, grandchildHandle);
- mCapture->checkPixel(0, 0, 50, 50, 50);
- mCapture->checkPixel(4, 4, 50, 50, 50);
-}
-
-TEST_F(ScreenCaptureTest, CaptureCrop) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
- sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
- PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
-
- SurfaceComposerClient::Transaction()
- .setLayer(redLayer, INT32_MAX - 1)
- .show(redLayer)
- .show(blueLayer)
- .apply(true);
-
- auto redLayerHandle = redLayer->getHandle();
-
- // Capturing full screen should have both red and blue are visible.
- ScreenCapture::captureLayers(&mCapture, redLayerHandle);
- mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
- // red area below the blue area
- mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
- // red area to the right of the blue area
- mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
-
- const Rect crop = Rect(0, 0, 30, 30);
- ScreenCapture::captureLayers(&mCapture, redLayerHandle, crop);
- // Capturing the cropped screen, cropping out the shown red area, should leave only the blue
- // area visible.
- mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
- mCapture->checkPixel(30, 30, 0, 0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureSize) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
- sp<SurfaceControl> blueLayer = createSurface(mClient, "Blue surface", 30, 30,
- PIXEL_FORMAT_RGBA_8888, 0, redLayer.get());
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(blueLayer, Color::BLUE, 30, 30));
-
- SurfaceComposerClient::Transaction()
- .setLayer(redLayer, INT32_MAX - 1)
- .show(redLayer)
- .show(blueLayer)
- .apply(true);
-
- auto redLayerHandle = redLayer->getHandle();
-
- // Capturing full screen should have both red and blue are visible.
- ScreenCapture::captureLayers(&mCapture, redLayerHandle);
- mCapture->expectColor(Rect(0, 0, 29, 29), Color::BLUE);
- // red area below the blue area
- mCapture->expectColor(Rect(0, 30, 59, 59), Color::RED);
- // red area to the right of the blue area
- mCapture->expectColor(Rect(30, 0, 59, 59), Color::RED);
-
- ScreenCapture::captureLayers(&mCapture, redLayerHandle, Rect::EMPTY_RECT, 0.5);
- // Capturing the downsized area (30x30) should leave both red and blue but in a smaller area.
- mCapture->expectColor(Rect(0, 0, 14, 14), Color::BLUE);
- // red area below the blue area
- mCapture->expectColor(Rect(0, 15, 29, 29), Color::RED);
- // red area to the right of the blue area
- mCapture->expectColor(Rect(15, 0, 29, 29), Color::RED);
- mCapture->checkPixel(30, 30, 0, 0, 0);
-}
-
-TEST_F(ScreenCaptureTest, CaptureInvalidLayer) {
- sp<SurfaceControl> redLayer = createLayer(String8("Red surface"), 60, 60, 0);
-
- ASSERT_NO_FATAL_FAILURE(fillBufferQueueLayerColor(redLayer, Color::RED, 60, 60));
-
- auto redLayerHandle = redLayer->getHandle();
- redLayer.clear();
- SurfaceComposerClient::Transaction().apply(true);
-
- sp<GraphicBuffer> outBuffer;
-
- // Layer was deleted so captureLayers should fail with NAME_NOT_FOUND
- sp<ISurfaceComposer> sf(ComposerService::getComposerService());
- ASSERT_EQ(NAME_NOT_FOUND, sf->captureLayers(redLayerHandle, &outBuffer, Rect::EMPTY_RECT, 1.0));
-}
-
-
-class DereferenceSurfaceControlTest : public LayerTransactionTest {
-protected:
- void SetUp() override {
- LayerTransactionTest::SetUp();
- bgLayer = createLayer("BG layer", 20, 20);
- fillBufferQueueLayerColor(bgLayer, Color::RED, 20, 20);
- fgLayer = createLayer("FG layer", 20, 20);
- fillBufferQueueLayerColor(fgLayer, Color::BLUE, 20, 20);
- Transaction().setLayer(fgLayer, mLayerZBase + 1).apply();
- {
- SCOPED_TRACE("before anything");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
- }
- }
- void TearDown() override {
- LayerTransactionTest::TearDown();
- bgLayer = 0;
- fgLayer = 0;
- }
-
- sp<SurfaceControl> bgLayer;
- sp<SurfaceControl> fgLayer;
-};
-
-TEST_F(DereferenceSurfaceControlTest, LayerNotInTransaction) {
- fgLayer = nullptr;
- {
- SCOPED_TRACE("after setting null");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 20, 20), Color::RED);
- }
-}
-
-TEST_F(DereferenceSurfaceControlTest, LayerInTransaction) {
- auto transaction = Transaction().show(fgLayer);
- fgLayer = nullptr;
- {
- SCOPED_TRACE("after setting null");
- auto shot = screenshot();
- shot->expectColor(Rect(0, 0, 20, 20), Color::BLUE);
- }
-}
-
-class MultiDisplayLayerBoundsTest : public LayerTransactionTest {
-protected:
- virtual void SetUp() {
- LayerTransactionTest::SetUp();
- ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
- mMainDisplay = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayInfo(mMainDisplay, &mMainDisplayInfo);
-
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&mProducer, &consumer);
- consumer->setConsumerName(String8("Virtual disp consumer"));
- consumer->setDefaultBufferSize(mMainDisplayInfo.w, mMainDisplayInfo.h);
- }
-
- virtual void TearDown() {
- SurfaceComposerClient::destroyDisplay(mVirtualDisplay);
- LayerTransactionTest::TearDown();
- mColorLayer = 0;
- }
-
- void createDisplay(const Rect& layerStackRect, uint32_t layerStack) {
- mVirtualDisplay =
- SurfaceComposerClient::createDisplay(String8("VirtualDisplay"), false /*secure*/);
- asTransaction([&](Transaction& t) {
- t.setDisplaySurface(mVirtualDisplay, mProducer);
- t.setDisplayLayerStack(mVirtualDisplay, layerStack);
- t.setDisplayProjection(mVirtualDisplay, mMainDisplayInfo.orientation, layerStackRect,
- Rect(mMainDisplayInfo.w, mMainDisplayInfo.h));
- });
- }
-
- void createColorLayer(uint32_t layerStack) {
- mColorLayer =
- createSurface(mClient, "ColorLayer", 0 /* buffer width */, 0 /* buffer height */,
- PIXEL_FORMAT_RGBA_8888, ISurfaceComposerClient::eFXSurfaceColor);
- ASSERT_TRUE(mColorLayer != nullptr);
- ASSERT_TRUE(mColorLayer->isValid());
- asTransaction([&](Transaction& t) {
- t.setLayerStack(mColorLayer, layerStack);
- t.setCrop_legacy(mColorLayer, Rect(0, 0, 30, 40));
- t.setLayer(mColorLayer, INT32_MAX - 2);
- t.setColor(mColorLayer,
- half3{mExpectedColor.r / 255.0f, mExpectedColor.g / 255.0f,
- mExpectedColor.b / 255.0f});
- t.show(mColorLayer);
- });
- }
-
- DisplayInfo mMainDisplayInfo;
- sp<IBinder> mMainDisplay;
- sp<IBinder> mVirtualDisplay;
- sp<IGraphicBufferProducer> mProducer;
- sp<SurfaceControl> mColorLayer;
- Color mExpectedColor = {63, 63, 195, 255};
-};
-
-TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInVirtualDisplay) {
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 1 /* layerStack */);
- createColorLayer(1 /* layerStack */);
-
- asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
-
- // Verify color layer does not render on main display.
- std::unique_ptr<ScreenCapture> sc;
- ScreenCapture::captureScreen(&sc, mMainDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), {0, 0, 0, 255});
- sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-
- // Verify color layer renders correctly on virtual display.
- ScreenCapture::captureScreen(&sc, mVirtualDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
- sc->expectColor(Rect(1, 1, 9, 9), {0, 0, 0, 0});
-}
-
-TEST_F(MultiDisplayLayerBoundsTest, RenderLayerInMirroredVirtualDisplay) {
- // Create a display and set its layer stack to the main display's layer stack so
- // the contents of the main display are mirrored on to the virtual display.
-
- // Assumption here is that the new mirrored display has the same viewport as the
- // primary display that it is mirroring.
- createDisplay({mMainDisplayInfo.viewportW, mMainDisplayInfo.viewportH}, 0 /* layerStack */);
- createColorLayer(0 /* layerStack */);
-
- asTransaction([&](Transaction& t) { t.setPosition(mColorLayer, 10, 10); });
-
- // Verify color layer renders correctly on main display and it is mirrored on the
- // virtual display.
- std::unique_ptr<ScreenCapture> sc;
- ScreenCapture::captureScreen(&sc, mMainDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
- sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-
- ScreenCapture::captureScreen(&sc, mVirtualDisplay);
- sc->expectColor(Rect(10, 10, 40, 50), mExpectedColor);
- sc->expectColor(Rect(0, 0, 9, 9), {0, 0, 0, 255});
-}
-
-class DisplayActiveConfigTest : public ::testing::Test {
-protected:
- void SetUp() override {
- mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
- SurfaceComposerClient::getDisplayConfigs(mDisplayToken, &mDisplayconfigs);
- EXPECT_GT(mDisplayconfigs.size(), 0);
-
- // set display power to on to make sure config can be changed
- SurfaceComposerClient::setDisplayPowerMode(mDisplayToken, HWC_POWER_MODE_NORMAL);
- }
-
- sp<IBinder> mDisplayToken;
- Vector<DisplayInfo> mDisplayconfigs;
-};
-
-TEST_F(DisplayActiveConfigTest, allConfigsAllowed) {
- std::vector<int32_t> allowedConfigs;
-
- // Add all configs to the allowed configs
- for (int i = 0; i < mDisplayconfigs.size(); i++) {
- allowedConfigs.push_back(i);
- }
-
- status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
- EXPECT_EQ(res, NO_ERROR);
-
- std::vector<int32_t> outConfigs;
- res = SurfaceComposerClient::getAllowedDisplayConfigs(mDisplayToken, &outConfigs);
- EXPECT_EQ(res, NO_ERROR);
- EXPECT_EQ(allowedConfigs, outConfigs);
-}
-
-TEST_F(DisplayActiveConfigTest, changeAllowedConfig) {
- // we need at least 2 configs available for this test
- if (mDisplayconfigs.size() <= 1) return;
-
- int activeConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
-
- // We want to set the allowed config to everything but the active config
- std::vector<int32_t> allowedConfigs;
- for (int i = 0; i < mDisplayconfigs.size(); i++) {
- if (i != activeConfig) {
- allowedConfigs.push_back(i);
- }
- }
-
- status_t res = SurfaceComposerClient::setAllowedDisplayConfigs(mDisplayToken, allowedConfigs);
- EXPECT_EQ(res, NO_ERROR);
-
- // Allow some time for the config change
- std::this_thread::sleep_for(200ms);
-
- int newActiveConfig = SurfaceComposerClient::getActiveConfig(mDisplayToken);
- EXPECT_NE(activeConfig, newActiveConfig);
-
- // Make sure the new config is part of allowed config
- EXPECT_TRUE(std::find(allowedConfigs.begin(), allowedConfigs.end(), newActiveConfig) !=
- allowedConfigs.end());
-}
-
-class RelativeZTest : public LayerTransactionTest {
-protected:
- virtual void SetUp() {
- LayerTransactionTest::SetUp();
- ASSERT_EQ(NO_ERROR, mClient->initCheck());
-
- const auto display = SurfaceComposerClient::getInternalDisplayToken();
- ASSERT_FALSE(display == nullptr);
-
- // Back layer
- mBackgroundLayer = createColorLayer("Background layer", Color::RED);
-
- // Front layer
- mForegroundLayer = createColorLayer("Foreground layer", Color::GREEN);
-
- asTransaction([&](Transaction& t) {
- t.setDisplayLayerStack(display, 0);
- t.setLayer(mBackgroundLayer, INT32_MAX - 2).show(mBackgroundLayer);
- t.setLayer(mForegroundLayer, INT32_MAX - 1).show(mForegroundLayer);
- });
- }
-
- virtual void TearDown() {
- LayerTransactionTest::TearDown();
- mBackgroundLayer = 0;
- mForegroundLayer = 0;
- }
-
- sp<SurfaceControl> mBackgroundLayer;
- sp<SurfaceControl> mForegroundLayer;
-};
-
-// When a layer is reparented offscreen, remove relative z order if the relative parent
-// is still onscreen so that the layer is not drawn.
-TEST_F(RelativeZTest, LayerRemoved) {
- std::unique_ptr<ScreenCapture> sc;
-
- // Background layer (RED)
- // Child layer (WHITE) (relative to foregroud layer)
- // Foregroud layer (GREEN)
- sp<SurfaceControl> childLayer =
- createColorLayer("Child layer", Color::BLUE, mBackgroundLayer.get());
-
- Transaction{}
- .setRelativeLayer(childLayer, mForegroundLayer->getHandle(), 1)
- .show(childLayer)
- .apply();
-
- {
- // The childLayer should be in front of the FG control.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::BLUE.r, Color::BLUE.g, Color::BLUE.b);
- }
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- Transaction{}.reparent(childLayer, nullptr).apply();
-
- // Background layer (RED)
- // Child layer (WHITE)
- // Foregroud layer (GREEN)
- Transaction{}.reparent(childLayer, mBackgroundLayer->getHandle()).apply();
-
- {
- // The relative z info for child layer should be reset, leaving FG control on top.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
- }
-}
-
-// When a layer is reparented offscreen, preseve relative z order if the relative parent
-// is also offscreen. Regression test b/132613412
-TEST_F(RelativeZTest, LayerRemovedOffscreenRelativeParent) {
- std::unique_ptr<ScreenCapture> sc;
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- // child level 1 (WHITE)
- // child level 2a (BLUE)
- // child level 3 (GREEN) (relative to child level 2b)
- // child level 2b (BLACK)
- sp<SurfaceControl> childLevel1 =
- createColorLayer("child level 1", Color::WHITE, mForegroundLayer.get());
- sp<SurfaceControl> childLevel2a =
- createColorLayer("child level 2a", Color::BLUE, childLevel1.get());
- sp<SurfaceControl> childLevel2b =
- createColorLayer("child level 2b", Color::BLACK, childLevel1.get());
- sp<SurfaceControl> childLevel3 =
- createColorLayer("child level 3", Color::GREEN, childLevel2a.get());
-
- Transaction{}
- .setRelativeLayer(childLevel3, childLevel2b->getHandle(), 1)
- .show(childLevel2a)
- .show(childLevel2b)
- .show(childLevel3)
- .apply();
-
- {
- // The childLevel3 should be in front of childLevel2b.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
- }
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- Transaction{}.reparent(childLevel1, nullptr).apply();
-
- // Background layer (RED)
- // Foregroud layer (GREEN)
- // child level 1 (WHITE)
- // child level 2 back (BLUE)
- // child level 3 (GREEN) (relative to child level 2b)
- // child level 2 front (BLACK)
- Transaction{}.reparent(childLevel1, mForegroundLayer->getHandle()).apply();
-
- {
- // Nothing should change at this point since relative z info was preserved.
- ScreenCapture::captureScreen(&sc);
- sc->checkPixel(1, 1, Color::GREEN.r, Color::GREEN.g, Color::GREEN.b);
- }
-}
-
-// This test ensures that when we drop an app buffer in SurfaceFlinger, we merge
-// the dropped buffer's damage region into the next buffer's damage region. If
-// we don't do this, we'll report an incorrect damage region to hardware
-// composer, resulting in broken rendering. This test checks the BufferQueue
-// case.
-//
-// Unfortunately, we don't currently have a way to inspect the damage region
-// SurfaceFlinger sends to hardware composer from a test, so this test requires
-// the dev to manually watch the device's screen during the test to spot broken
-// rendering. Because the results can't be automatically verified, this test is
-// marked disabled.
-TEST_F(LayerTransactionTest, DISABLED_BufferQueueLayerMergeDamageRegionWhenDroppingBuffers) {
- const int width = mDisplayWidth;
- const int height = mDisplayHeight;
- sp<SurfaceControl> layer;
- ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", width, height));
- const auto producer = layer->getIGraphicBufferProducer();
- const sp<IProducerListener> dummyListener(new DummyProducerListener);
- IGraphicBufferProducer::QueueBufferOutput queueBufferOutput;
- ASSERT_EQ(OK,
- producer->connect(dummyListener, NATIVE_WINDOW_API_CPU, true, &queueBufferOutput));
-
- std::map<int, sp<GraphicBuffer>> slotMap;
- auto slotToBuffer = [&](int slot, sp<GraphicBuffer>* buf) {
- ASSERT_NE(nullptr, buf);
- const auto iter = slotMap.find(slot);
- ASSERT_NE(slotMap.end(), iter);
- *buf = iter->second;
- };
-
- auto dequeue = [&](int* outSlot) {
- ASSERT_NE(nullptr, outSlot);
- *outSlot = -1;
- int slot;
- sp<Fence> fence;
- uint64_t age;
- FrameEventHistoryDelta timestamps;
- const status_t dequeueResult =
- producer->dequeueBuffer(&slot, &fence, width, height, PIXEL_FORMAT_RGBA_8888,
- GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
- &age, ×tamps);
- if (dequeueResult == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
- sp<GraphicBuffer> newBuf;
- ASSERT_EQ(OK, producer->requestBuffer(slot, &newBuf));
- ASSERT_NE(nullptr, newBuf.get());
- slotMap[slot] = newBuf;
- } else {
- ASSERT_EQ(OK, dequeueResult);
- }
- *outSlot = slot;
- };
-
- auto queue = [&](int slot, const Region& damage, nsecs_t displayTime) {
- IGraphicBufferProducer::QueueBufferInput input(
- /*timestamp=*/displayTime, /*isAutoTimestamp=*/false, HAL_DATASPACE_UNKNOWN,
- /*crop=*/Rect::EMPTY_RECT, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW,
- /*transform=*/0, Fence::NO_FENCE);
- input.setSurfaceDamage(damage);
- IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK, producer->queueBuffer(slot, input, &output));
- };
-
- auto fillAndPostBuffers = [&](const Color& color) {
- int slot1;
- ASSERT_NO_FATAL_FAILURE(dequeue(&slot1));
- int slot2;
- ASSERT_NO_FATAL_FAILURE(dequeue(&slot2));
-
- sp<GraphicBuffer> buf1;
- ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot1, &buf1));
- sp<GraphicBuffer> buf2;
- ASSERT_NO_FATAL_FAILURE(slotToBuffer(slot2, &buf2));
- fillGraphicBufferColor(buf1, Rect(width, height), color);
- fillGraphicBufferColor(buf2, Rect(width, height), color);
-
- const auto displayTime = systemTime() + milliseconds_to_nanoseconds(100);
- ASSERT_NO_FATAL_FAILURE(queue(slot1, Region::INVALID_REGION, displayTime));
- ASSERT_NO_FATAL_FAILURE(
- queue(slot2, Region(Rect(width / 3, height / 3, 2 * width / 3, 2 * height / 3)),
- displayTime));
- };
-
- const auto startTime = systemTime();
- const std::array<Color, 3> colors = {Color::RED, Color::GREEN, Color::BLUE};
- int colorIndex = 0;
- while (nanoseconds_to_seconds(systemTime() - startTime) < 10) {
- ASSERT_NO_FATAL_FAILURE(fillAndPostBuffers(colors[colorIndex++ % colors.size()]));
- std::this_thread::sleep_for(1s);
- }
-
- ASSERT_EQ(OK, producer->disconnect(NATIVE_WINDOW_API_CPU));
-}
-
-} // namespace android
diff --git a/services/surfaceflinger/tests/fakehwc/Android.bp b/services/surfaceflinger/tests/fakehwc/Android.bp
index 2feff45..9d74761 100644
--- a/services/surfaceflinger/tests/fakehwc/Android.bp
+++ b/services/surfaceflinger/tests/fakehwc/Android.bp
@@ -10,8 +10,10 @@
],
shared_libs: [
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.1-resources",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"android.hardware.power@1.3",
"libbase",
"libbinder",
@@ -29,8 +31,11 @@
"libutils",
],
static_libs: [
+ "libcompositionengine",
"libgmock",
+ "libperfetto_client_experimental",
"librenderengine",
+ "libtimestats",
"libtrace_proto",
],
header_libs: [
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
index 51956ec..4d21468 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerUtils.cpp
@@ -167,7 +167,9 @@
}
// TODO: Try registering the mock as the default service instead.
property_set("debug.sf.hwc_service_name", "mock");
- // This allows the SurfaceFlinger to load a HIDL service not listed in manifest files.
+
+ // This allows tests/SF to register/load a HIDL service not listed in manifest files.
+ setenv("TREBLE_TESTING_OVERRIDE", "true", true);
property_set("debug.sf.treble_testing_override", "true");
}
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index a892a2a..c949d7c 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -171,7 +171,7 @@
mMockComposer = new MockComposerClient;
sp<ComposerClient> client = new ComposerClient(mMockComposer);
mFakeService = new FakeComposerService(client);
- (void)mFakeService->registerAsService("mock");
+ ASSERT_EQ(android::OK, mFakeService->registerAsService("mock"));
android::hardware::ProcessState::self()->startThreadPool();
android::ProcessState::self()->startThreadPool();
@@ -1331,16 +1331,6 @@
restoreInitialState();
- // Now we repeat with setGeometryAppliesWithResize
- // and verify the position DOESN'T latch.
- {
- TransactionScope ts(*sFakeComposer);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setSize(mFGSurfaceControl, 32, 32);
- ts.setPosition(mFGSurfaceControl, 100, 100);
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
completeFGResize();
auto referenceFrame2 = mBaseFrame;
@@ -1365,14 +1355,6 @@
restoreInitialState();
- {
- TransactionScope ts(*sFakeComposer);
- ts.setSize(mFGSurfaceControl, 128, 128);
- ts.setGeometryAppliesWithResize(mFGSurfaceControl);
- ts.setCrop_legacy(mFGSurfaceControl, Rect(0, 0, 63, 63));
- }
- EXPECT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
-
completeFGResize();
auto referenceFrame2 = mBaseFrame;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f842d61..8d98af6 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -36,13 +36,13 @@
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
"CachingTest.cpp",
- "CompositionTest.cpp",
+ "CompositionTest.cpp",
"DispSyncSourceTest.cpp",
"DisplayIdentificationTest.cpp",
"DisplayTransactionTest.cpp",
"EventControlThreadTest.cpp",
"EventThreadTest.cpp",
- "IdleTimerTest.cpp",
+ "OneShotTimerTest.cpp",
"LayerHistoryTest.cpp",
"LayerMetadataTest.cpp",
"SchedulerTest.cpp",
@@ -51,6 +51,7 @@
"RefreshRateStatsTest.cpp",
"RegionSamplingTest.cpp",
"TimeStatsTest.cpp",
+ "FrameTracerTest.cpp",
"mock/DisplayHardware/MockComposer.cpp",
"mock/DisplayHardware/MockDisplay.cpp",
"mock/DisplayHardware/MockPowerAdvisor.cpp",
@@ -63,13 +64,20 @@
"mock/MockNativeWindowSurface.cpp",
"mock/MockSurfaceInterceptor.cpp",
"mock/MockTimeStats.cpp",
+ "mock/MockFrameTracer.cpp",
"mock/system/window/MockNativeWindow.cpp",
],
static_libs: [
"libgmock",
"libcompositionengine",
"libcompositionengine_mocks",
+ "libperfetto_client_experimental",
"librenderengine_mocks",
+ "libtimestats",
+ "perfetto_trace_protos",
+ ],
+ shared_libs: [
+ "libsurfaceflinger",
],
header_libs: [
"libsurfaceflinger_headers",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 4f8ed1a..b6fa2a6 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -34,7 +34,6 @@
#include "ColorLayer.h"
#include "Layer.h"
-#include "TestableScheduler.h"
#include "TestableSurfaceFlinger.h"
#include "mock/DisplayHardware/MockComposer.h"
#include "mock/MockDispSync.h"
@@ -95,10 +94,6 @@
mFlinger.mutableEventQueue().reset(mMessageQueue);
setupScheduler();
- EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
- EXPECT_CALL(*mPrimaryDispSync, getPeriod())
- .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
- EXPECT_CALL(*mPrimaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_WIDTH, _))
.WillRepeatedly(DoAll(SetArgPointee<1>(DEFAULT_DISPLAY_WIDTH), Return(0)));
EXPECT_CALL(*mNativeWindow, query(NATIVE_WINDOW_HEIGHT, _))
@@ -125,15 +120,31 @@
}
void setupScheduler() {
- mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
- mScheduler->mutableEventControlThread().reset(mEventControlThread);
- mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
- EXPECT_CALL(*mEventThread.get(), registerDisplayEventConnection(_));
- sp<Scheduler::ConnectionHandle> connectionHandle =
- mScheduler->addConnection(std::move(mEventThread));
- mFlinger.mutableSfConnectionHandle() = std::move(connectionHandle);
+ auto eventThread = std::make_unique<mock::EventThread>();
+ auto sfEventThread = std::make_unique<mock::EventThread>();
- mFlinger.mutableScheduler().reset(mScheduler);
+ EXPECT_CALL(*eventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*eventThread, createEventConnection(_, _))
+ .WillOnce(Return(
+ new EventThreadConnection(eventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ EXPECT_CALL(*sfEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*sfEventThread, createEventConnection(_, _))
+ .WillOnce(Return(
+ new EventThreadConnection(sfEventThread.get(), ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ auto primaryDispSync = std::make_unique<mock::DispSync>();
+
+ EXPECT_CALL(*primaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+ EXPECT_CALL(*primaryDispSync, getPeriod())
+ .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+ EXPECT_CALL(*primaryDispSync, expectedPresentTime()).WillRepeatedly(Return(0));
+
+ mFlinger.setupScheduler(std::move(primaryDispSync),
+ std::make_unique<mock::EventControlThread>(),
+ std::move(eventThread), std::move(sfEventThread));
}
void setupForceGeometryDirty() {
@@ -157,7 +168,6 @@
std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
- TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
sp<DisplayDevice> mDisplay;
sp<DisplayDevice> mExternalDisplay;
@@ -168,13 +178,9 @@
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
- std::unique_ptr<mock::EventThread> mEventThread = std::make_unique<mock::EventThread>();
- mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
-
Hwc2::mock::Composer* mComposer = nullptr;
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -296,18 +302,12 @@
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
.Times(1);
- EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).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();
- }));
EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
@@ -341,11 +341,21 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
.Times(1);
}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+ }
+
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1);
+ }
+
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
@@ -419,6 +429,8 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
@@ -507,7 +519,7 @@
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
bool ignoredRecomputeVisibleRegions;
- layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+ layer->latchBuffer(ignoredRecomputeVisibleRegions, 0, 0);
Mock::VerifyAndClear(test->mRenderEngine);
}
@@ -602,6 +614,12 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so gtet the back layer.
+ if (layerSettings.empty()) {
+ ADD_FAILURE() << "layerSettings was not expected to be empty in "
+ "setupREBufferCompositionCommonCallExpectations "
+ "verification lambda";
+ return NO_ERROR;
+ }
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, Not(IsNull()));
EXPECT_THAT(layer.source.buffer.fence, Not(IsNull()));
@@ -645,6 +663,12 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ if (layerSettings.empty()) {
+ ADD_FAILURE()
+ << "layerSettings was not expected to be empty in "
+ "setupREColorCompositionCallExpectations verification lambda";
+ return NO_ERROR;
+ }
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, IsNull());
EXPECT_EQ(half3(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
@@ -715,6 +739,12 @@
displaySettings.clip);
// screen capture adds an additional color layer as an alpha
// prefill, so get the back layer.
+ if (layerSettings.empty()) {
+ ADD_FAILURE() << "layerSettings was not expected to be empty in "
+ "setupInsecureREBufferCompositionCommonCallExpectations "
+ "verification lambda";
+ return NO_ERROR;
+ }
renderengine::LayerSettings layer = layerSettings.back();
EXPECT_THAT(layer.source.buffer.buffer, IsNull());
EXPECT_EQ(half3(0.0f, 0.0f, 0.0f), layer.source.solidColor);
@@ -774,7 +804,6 @@
layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
layer->computeBounds(FloatRect(0, 0, 100, 100), ui::Transform());
- layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
return layer;
}
@@ -783,19 +812,13 @@
EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
.WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
- std::vector<std::unique_ptr<compositionengine::OutputLayer>> outputLayers;
- outputLayers.emplace_back(test->mDisplay->getCompositionDisplay()
- ->getOrCreateOutputLayer(DEFAULT_DISPLAY_ID,
- layer->getCompositionLayer(),
- layer));
-
- test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(std::move(outputLayers));
+ auto outputLayer = test->mDisplay->getCompositionDisplay()
+ ->injectOutputLayerForTest(layer->getCompositionLayer(), layer);
+ outputLayer->editState().visibleRegion = Region(Rect(0, 0, 100, 100));
+ outputLayer->editState().outputSpaceVisibleRegion = Region(Rect(0, 0, 100, 100));
Mock::VerifyAndClear(test->mComposer);
- Vector<sp<Layer>> layers;
- layers.add(layer);
- test->mDisplay->setVisibleLayersSortedByZ(layers);
test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
}
@@ -803,8 +826,7 @@
EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
.WillOnce(Return(Error::NONE));
- test->mDisplay->getCompositionDisplay()->setOutputLayersOrderedByZ(
- std::vector<std::unique_ptr<compositionengine::OutputLayer>>());
+ test->mDisplay->getCompositionDisplay()->clearOutputLayers();
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
}
};
@@ -856,11 +878,14 @@
FlingerLayerType layer =
Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
- return new BufferQueueLayer(
- LayerCreationArgs(test->mFlinger.mFlinger.get(), sp<Client>(),
- String8("test-layer"), LayerProperties::WIDTH,
- LayerProperties::HEIGHT,
- LayerProperties::LAYER_FLAGS, LayerMetadata()));
+ sp<Client> client;
+ String8 name("test-layer");
+ LayerCreationArgs args =
+ LayerCreationArgs(test->mFlinger.mFlinger.get(), client, name,
+ LayerProperties::WIDTH, LayerProperties::HEIGHT,
+ LayerProperties::LAYER_FLAGS, LayerMetadata());
+ args.textureName = test->mFlinger.mutableTexturePool().back();
+ return new BufferQueueLayer(args);
});
LayerProperties::setupLayerState(test, layer);
@@ -986,14 +1011,25 @@
template <typename Case>
static void setupCallExpectations(CompositionTest* test) {
Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcClientCompositionCallExpectations(test);
Case::Display::setupRECompositionCallExpectations(test);
Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
};
-struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant {
static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
- layer->forceClientComposition(test->mDisplay);
+ const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay);
+ LOG_FATAL_IF(!outputLayer);
+ outputLayer->editState().forceClientComposition = true;
+ }
+
+ template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
template <typename Case>
@@ -1073,8 +1109,6 @@
for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
hwcDisplay->mutableLayers().clear();
}
-
- test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
}
};
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 5f58e7d..fcce57b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -95,11 +95,10 @@
DisplayTransactionTest();
~DisplayTransactionTest() override;
- void setupScheduler();
-
// --------------------------------------------------------------------
// Mock/Fake injection
+ void injectMockScheduler();
void injectMockComposer(int virtualDisplayCount);
void injectFakeBufferQueueFactory();
void injectFakeNativeWindowSurfaceFactory();
@@ -119,11 +118,7 @@
// --------------------------------------------------------------------
// Test instances
- TestableScheduler* mScheduler;
TestableSurfaceFlinger mFlinger;
- mock::EventThread* mEventThread = new mock::EventThread();
- mock::EventThread* mSFEventThread = new mock::EventThread();
- mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
sp<mock::NativeWindow> mNativeWindow = new mock::NativeWindow();
sp<GraphicBuffer> mBuffer = new GraphicBuffer();
@@ -134,7 +129,11 @@
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
- mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+
+ mock::DispSync* mPrimaryDispSync = new mock::DispSync;
+ mock::EventControlThread* mEventControlThread = new mock::EventControlThread;
+ mock::EventThread* mEventThread = new mock::EventThread;
+ mock::EventThread* mSFEventThread = new mock::EventThread;
// These mocks are created only when expected to be created via a factory.
sp<mock::GraphicBufferConsumer> mConsumer;
@@ -150,7 +149,7 @@
// Default to no wide color display support configured
mFlinger.mutableHasWideColorDisplay() = false;
mFlinger.mutableUseColorManagement() = false;
- mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
// Default to using HWC virtual displays
mFlinger.mutableUseHwcVirtualDisplays() = true;
@@ -164,7 +163,7 @@
return nullptr;
});
- setupScheduler();
+ injectMockScheduler();
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
@@ -178,20 +177,21 @@
ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
}
-void DisplayTransactionTest::setupScheduler() {
- mScheduler = new TestableScheduler(mFlinger.mutableRefreshRateConfigs());
- mScheduler->mutableEventControlThread().reset(mEventControlThread);
- mScheduler->mutablePrimaryDispSync().reset(mPrimaryDispSync);
+void DisplayTransactionTest::injectMockScheduler() {
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_));
- EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*mEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(mEventThread, ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
- sp<Scheduler::ConnectionHandle> sfConnectionHandle =
- mScheduler->addConnection(std::unique_ptr<EventThread>(mSFEventThread));
- mFlinger.mutableSfConnectionHandle() = std::move(sfConnectionHandle);
- sp<Scheduler::ConnectionHandle> appConnectionHandle =
- mScheduler->addConnection(std::unique_ptr<EventThread>(mEventThread));
- mFlinger.mutableAppConnectionHandle() = std::move(appConnectionHandle);
- mFlinger.mutableScheduler().reset(mScheduler);
+ EXPECT_CALL(*mSFEventThread, registerDisplayEventConnection(_));
+ EXPECT_CALL(*mSFEventThread, createEventConnection(_, _))
+ .WillOnce(Return(new EventThreadConnection(mSFEventThread, ResyncCallback(),
+ ISurfaceComposer::eConfigChangedSuppress)));
+
+ mFlinger.setupScheduler(std::unique_ptr<DispSync>(mPrimaryDispSync),
+ std::unique_ptr<EventControlThread>(mEventControlThread),
+ std::unique_ptr<EventThread>(mEventThread),
+ std::unique_ptr<EventThread>(mSFEventThread));
}
void DisplayTransactionTest::injectMockComposer(int virtualDisplayCount) {
@@ -598,7 +598,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableHasWideColorDisplay() = false;
test->mFlinger.mutableUseColorManagement() = false;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -618,7 +618,7 @@
static void injectConfigChange(DisplayTransactionTest* test) {
test->mFlinger.mutableUseColorManagement() = true;
test->mFlinger.mutableHasWideColorDisplay() = true;
- test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::UNMANAGED;
+ test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
}
static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -1131,8 +1131,8 @@
// Preconditions
// vsync is enabled and available
- mScheduler->mutablePrimaryHWVsyncEnabled() = true;
- mScheduler->mutableHWVsyncAvailable() = true;
+ mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = true;
+ mFlinger.scheduler()->mutableHWVsyncAvailable() = true;
// A display exists
auto existing = Case::Display::makeFakeExistingDisplayInjector(this);
@@ -1156,8 +1156,8 @@
// Postconditions
// vsyncs should be off and not available.
- EXPECT_FALSE(mScheduler->mutablePrimaryHWVsyncEnabled());
- EXPECT_FALSE(mScheduler->mutableHWVsyncAvailable());
+ EXPECT_FALSE(mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled());
+ EXPECT_FALSE(mFlinger.scheduler()->mutableHWVsyncAvailable());
// The display should have been removed from the display map.
EXPECT_FALSE(hasDisplayDevice(existing.token()));
@@ -3008,7 +3008,7 @@
}
static void setInitialPrimaryHWVsyncEnabled(DisplayTransactionTest* test, bool enabled) {
- test->mScheduler->mutablePrimaryHWVsyncEnabled() = enabled;
+ test->mFlinger.scheduler()->mutablePrimaryHWVsyncEnabled() = enabled;
}
static void setupRepaintEverythingCallExpectations(DisplayTransactionTest* test) {
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index dbd9b84..2662f52 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -42,6 +42,8 @@
class MockVSyncSource : public VSyncSource {
public:
+ const char* getName() const override { return "test"; }
+
MOCK_METHOD1(setVSyncEnabled, void(bool));
MOCK_METHOD1(setCallback, void(VSyncSource::Callback*));
MOCK_METHOD1(setPhaseOffset, void(nsecs_t));
@@ -54,8 +56,7 @@
protected:
class MockEventThreadConnection : public EventThreadConnection {
public:
- MockEventThreadConnection(android::impl::EventThread* eventThread,
- ResyncCallback&& resyncCallback,
+ MockEventThreadConnection(impl::EventThread* eventThread, ResyncCallback&& resyncCallback,
ISurfaceComposer::ConfigChanged configChanged)
: EventThreadConnection(eventThread, std::move(resyncCallback), configChanged) {}
MOCK_METHOD1(postEvent, status_t(const DisplayEventReceiver::Event& event));
@@ -67,7 +68,7 @@
EventThreadTest();
~EventThreadTest() override;
- void createThread();
+ void createThread(std::unique_ptr<VSyncSource>);
sp<MockEventThreadConnection> createConnection(ConnectionEventRecorder& recorder,
ISurfaceComposer::ConfigChanged configChanged);
@@ -91,9 +92,9 @@
AsyncCallRecorder<void (*)(nsecs_t)> mInterceptVSyncCallRecorder;
ConnectionEventRecorder mConnectionEventCallRecorder{0};
- MockVSyncSource mVSyncSource;
+ MockVSyncSource* mVSyncSource;
VSyncSource::Callback* mCallback = nullptr;
- std::unique_ptr<android::impl::EventThread> mThread;
+ std::unique_ptr<impl::EventThread> mThread;
sp<MockEventThreadConnection> mConnection;
};
@@ -102,16 +103,19 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- EXPECT_CALL(mVSyncSource, setVSyncEnabled(_))
+ auto vsyncSource = std::make_unique<MockVSyncSource>();
+ mVSyncSource = vsyncSource.get();
+
+ EXPECT_CALL(*mVSyncSource, setVSyncEnabled(_))
.WillRepeatedly(Invoke(mVSyncSetEnabledCallRecorder.getInvocable()));
- EXPECT_CALL(mVSyncSource, setCallback(_))
+ EXPECT_CALL(*mVSyncSource, setCallback(_))
.WillRepeatedly(Invoke(mVSyncSetCallbackCallRecorder.getInvocable()));
- EXPECT_CALL(mVSyncSource, setPhaseOffset(_))
+ EXPECT_CALL(*mVSyncSource, setPhaseOffset(_))
.WillRepeatedly(Invoke(mVSyncSetPhaseOffsetCallRecorder.getInvocable()));
- createThread();
+ createThread(std::move(vsyncSource));
mConnection = createConnection(mConnectionEventCallRecorder,
ISurfaceComposer::eConfigChangedDispatch);
@@ -129,11 +133,9 @@
EXPECT_TRUE(!mVSyncSetCallbackCallRecorder.waitForUnexpectedCall().has_value());
}
-void EventThreadTest::createThread() {
- mThread =
- std::make_unique<android::impl::EventThread>(&mVSyncSource,
- mInterceptVSyncCallRecorder.getInvocable(),
- "unit-test-event-thread");
+void EventThreadTest::createThread(std::unique_ptr<VSyncSource> source) {
+ mThread = std::make_unique<impl::EventThread>(std::move(source),
+ mInterceptVSyncCallRecorder.getInvocable());
// EventThread should register itself as VSyncSource callback.
mCallback = expectVSyncSetCallbackCallReceived();
diff --git a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
index 1d75011..66c7f6b 100644
--- a/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
+++ b/services/surfaceflinger/tests/unittests/FakePhaseOffsets.h
@@ -20,42 +20,22 @@
#include "Scheduler/PhaseOffsets.h"
-namespace android {
-namespace scheduler {
+namespace android::scheduler {
-using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+struct FakePhaseOffsets : PhaseOffsets {
+ static constexpr nsecs_t FAKE_PHASE_OFFSET_NS = 0;
-class FakePhaseOffsets : public android::scheduler::PhaseOffsets {
- nsecs_t FAKE_PHASE_OFFSET_NS = 0;
+ Offsets getOffsetsForRefreshRate(RefreshRateType) const override { return getCurrentOffsets(); }
-public:
- FakePhaseOffsets() = default;
- ~FakePhaseOffsets() = default;
-
- nsecs_t getCurrentAppOffset() override { return FAKE_PHASE_OFFSET_NS; }
- nsecs_t getCurrentSfOffset() override { return FAKE_PHASE_OFFSET_NS; }
-
- PhaseOffsets::Offsets getOffsetsForRefreshRate(
- RefreshRateType /*refreshRateType*/) const override {
- return getCurrentOffsets();
+ Offsets getCurrentOffsets() const override {
+ return {{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
+ FAKE_PHASE_OFFSET_NS};
}
- // Returns early, early GL, and late offsets for Apps and SF.
- PhaseOffsets::Offsets getCurrentOffsets() const override {
- return Offsets{{RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS},
- {RefreshRateType::DEFAULT, FAKE_PHASE_OFFSET_NS, FAKE_PHASE_OFFSET_NS}};
- }
-
- // This function should be called when the device is switching between different
- // refresh rates, to properly update the offsets.
- void setRefreshRateType(RefreshRateType /*refreshRateType*/) override {}
-
- nsecs_t getOffsetThresholdForNextVsync() const override { return FAKE_PHASE_OFFSET_NS; }
-
- // Returns current offsets in human friendly format.
- void dump(std::string& /*result*/) const override {}
+ void setRefreshRateType(RefreshRateType) override {}
+ void dump(std::string&) const override {}
};
-} // namespace scheduler
-} // namespace android
+} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
new file mode 100644
index 0000000..b5af591
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/FrameTracerTest.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include <FrameTracer/FrameTracer.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <log/log.h>
+#include <perfetto/trace/trace.pb.h>
+
+#include "libsurfaceflinger_unittest_main.h"
+
+using namespace google::protobuf;
+
+namespace android {
+namespace {
+
+class FrameTracerTest : public testing::Test {
+public:
+ FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+ // Need to initialize tracing in process for testing, and only once per test suite.
+ static bool wasInitialized = false;
+ if (!wasInitialized) {
+ perfetto::TracingInitArgs args;
+ args.backends = perfetto::kInProcessBackend;
+ perfetto::Tracing::Initialize(args);
+ wasInitialized = true;
+ }
+ }
+
+ ~FrameTracerTest() {
+ const ::testing::TestInfo* const test_info =
+ ::testing::UnitTest::GetInstance()->current_test_info();
+ ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+ }
+
+ void SetUp() override {
+ mFrameTracer = std::make_unique<FrameTracer>();
+ mFrameTracer->registerDataSource();
+ }
+
+ void TearDown() override { mFrameTracer.reset(); }
+
+ // Each tracing session can be used for a single block of Start -> Stop.
+ static std::unique_ptr<perfetto::TracingSession> getTracingSessionForTest() {
+ perfetto::TraceConfig cfg;
+ cfg.set_duration_ms(500);
+ cfg.add_buffers()->set_size_kb(1024);
+ auto* ds_cfg = cfg.add_data_sources()->mutable_config();
+ ds_cfg->set_name(FrameTracer::kFrameTracerDataSource);
+
+ auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend);
+ tracingSession->Setup(cfg);
+ return tracingSession;
+ }
+
+ std::unique_ptr<FrameTracer> mFrameTracer;
+ FenceToFenceTimeMap fenceFactory;
+};
+
+TEST_F(FrameTracerTest, traceNewLayerStartsTrackingLayerWhenTracing) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ tracingSession->StopBlocking();
+}
+
+TEST_F(FrameTracerTest, onDestroyRemovesTheTrackedLayer) {
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const int32_t secondLayerID = 6;
+
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceNewLayer(secondLayerID, layerName);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 2\n");
+ tracingSession->StopBlocking();
+
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(layerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 1\n");
+ mFrameTracer->onDestroy(secondLayerID);
+ EXPECT_EQ(mFrameTracer->miniDump(),
+ "FrameTracer miniDump:\nNumber of layers currently being traced is 0\n");
+}
+
+TEST_F(FrameTracerTest, canTraceAfterAddingLayer) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 1;
+ const uint32_t bufferID = 2;
+ const uint64_t frameNumber = 3;
+ const nsecs_t timestamp = 4;
+ const nsecs_t duration = 5;
+ const auto type = FrameTracer::FrameEvent::POST;
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceTimestamp(layerID, bufferID, frameNumber, timestamp, type, duration);
+ // Create second trace packet to finalize the previous one.
+ mFrameTracer->traceTimestamp(layerID, 0, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 1);
+
+ const auto& packet = trace.packet().Get(0);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ ASSERT_TRUE(buffer_event.has_duration_ns());
+ EXPECT_EQ(buffer_event.duration_ns(), duration);
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceTriggersOnNextTraceAfterFenceFired) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, Fence::SIGNAL_TIME_PENDING);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ // Trace.
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ // Create extra trace packet to (hopefully not) trigger and finalize the fence packet.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+ }
+
+ {
+ auto fenceTime = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto tracingSession = getTracingSessionForTest();
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fenceTime, type);
+ const nsecs_t timestamp = systemTime();
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, timestamp);
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2); // Two packets because of the extra trace made above.
+
+ const auto& packet = trace.packet().Get(1);
+ ASSERT_TRUE(packet.has_timestamp());
+ EXPECT_EQ(packet.timestamp(), timestamp);
+ ASSERT_TRUE(packet.has_graphics_frame_event());
+ const auto& frame_event = packet.graphics_frame_event();
+ ASSERT_TRUE(frame_event.has_buffer_event());
+ const auto& buffer_event = frame_event.buffer_event();
+ ASSERT_TRUE(buffer_event.has_buffer_id());
+ EXPECT_EQ(buffer_event.buffer_id(), bufferID);
+ ASSERT_TRUE(buffer_event.has_frame_number());
+ EXPECT_EQ(buffer_event.frame_number(), frameNumber);
+ ASSERT_TRUE(buffer_event.has_type());
+ EXPECT_EQ(buffer_event.type(), perfetto::protos::GraphicsFrameEvent_BufferEventType(type));
+ EXPECT_FALSE(buffer_event.has_duration_ns());
+ }
+}
+
+TEST_F(FrameTracerTest, traceFenceWithStartTimeAfterSignalTime_ShouldHaveNoDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 + 100000;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 + 100000;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), signalTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), signalTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_FALSE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+}
+
+TEST_F(FrameTracerTest, traceFenceOlderThanDeadline_ShouldBeIgnored) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t signalTime = systemTime() - FrameTracer::kFenceSignallingDeadline;
+
+ auto tracingSession = getTracingSessionForTest();
+ auto fence = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence, type);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime);
+ // Create extra trace packet to trigger and finalize any previous fence packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ EXPECT_EQ(raw_trace.size(), 0);
+}
+
+TEST_F(FrameTracerTest, traceFenceWithValidStartTime_ShouldHaveCorrectDuration) {
+ const std::string layerName = "co.layername#0";
+ const int32_t layerID = 5;
+ const uint32_t bufferID = 4;
+ const uint64_t frameNumber = 3;
+ const auto type = FrameTracer::FrameEvent::ACQUIRE_FENCE;
+ const nsecs_t duration = 1234;
+
+ auto tracingSession = getTracingSessionForTest();
+
+ tracingSession->StartBlocking();
+ // Clean up irrelevant traces.
+ tracingSession->ReadTraceBlocking();
+ mFrameTracer->traceNewLayer(layerID, layerName);
+
+ // traceFence called after fence signalled.
+ const nsecs_t signalTime1 = systemTime();
+ const nsecs_t startTime1 = signalTime1 - duration;
+ auto fence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime1);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence1, type, startTime1);
+
+ // traceFence called before fence signalled.
+ const nsecs_t signalTime2 = systemTime();
+ const nsecs_t startTime2 = signalTime2 - duration;
+ auto fence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ mFrameTracer->traceFence(layerID, bufferID, frameNumber, fence2, type, startTime2);
+ fenceFactory.signalAllForTest(Fence::NO_FENCE, signalTime2);
+
+ // Create extra trace packet to trigger and finalize fence trace packets.
+ mFrameTracer->traceTimestamp(layerID, bufferID, 0, 0, FrameTracer::FrameEvent::UNSPECIFIED);
+ tracingSession->StopBlocking();
+
+ std::vector<char> raw_trace = tracingSession->ReadTraceBlocking();
+ ASSERT_GT(raw_trace.size(), 0);
+
+ perfetto::protos::Trace trace;
+ ASSERT_TRUE(trace.ParseFromArray(raw_trace.data(), int(raw_trace.size())));
+ ASSERT_FALSE(trace.packet().empty());
+ EXPECT_EQ(trace.packet().size(), 2);
+
+ const auto& packet1 = trace.packet().Get(0);
+ ASSERT_TRUE(packet1.has_timestamp());
+ EXPECT_EQ(packet1.timestamp(), startTime1);
+ ASSERT_TRUE(packet1.has_graphics_frame_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet1.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event1 = packet1.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event1.duration_ns(), duration);
+
+ const auto& packet2 = trace.packet().Get(1);
+ ASSERT_TRUE(packet2.has_timestamp());
+ EXPECT_EQ(packet2.timestamp(), startTime2);
+ ASSERT_TRUE(packet2.has_graphics_frame_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().has_buffer_event());
+ ASSERT_TRUE(packet2.graphics_frame_event().buffer_event().has_duration_ns());
+ const auto& buffer_event2 = packet2.graphics_frame_event().buffer_event();
+ EXPECT_EQ(buffer_event2.duration_ns(), duration);
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
similarity index 75%
rename from services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
rename to services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
index eff22b6..0208728 100644
--- a/services/surfaceflinger/tests/unittests/IdleTimerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/OneShotTimerTest.cpp
@@ -21,17 +21,17 @@
#include <utils/Log.h>
#include "AsyncCallRecorder.h"
-#include "Scheduler/IdleTimer.h"
+#include "Scheduler/OneShotTimer.h"
using namespace std::chrono_literals;
namespace android {
namespace scheduler {
-class IdleTimerTest : public testing::Test {
+class OneShotTimerTest : public testing::Test {
protected:
- IdleTimerTest() = default;
- ~IdleTimerTest() override = default;
+ OneShotTimerTest() = default;
+ ~OneShotTimerTest() override = default;
// This timeout should be used when a 3ms callback is expected.
// While the tests typically request a callback after 3ms, the scheduler
@@ -46,7 +46,7 @@
AsyncCallRecorder<void (*)()> mResetTimerCallback;
AsyncCallRecorder<void (*)()> mExpiredTimerCallback;
- std::unique_ptr<IdleTimer> mIdleTimer;
+ std::unique_ptr<OneShotTimer> mIdleTimer;
void clearPendingCallbacks() {
while (mExpiredTimerCallback.waitForCall(0us).has_value()) {
@@ -55,13 +55,14 @@
};
namespace {
-TEST_F(IdleTimerTest, createAndDestroyTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, [] {}, [] {});
+TEST_F(OneShotTimerTest, createAndDestroyTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(
+ 3ms, [] {}, [] {});
}
-TEST_F(IdleTimerTest, startStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(30ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startStopTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(30ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
auto startTime = std::chrono::steady_clock::now();
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -70,7 +71,7 @@
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
+ // a callback is observed. We check the elapsed time since before the OneShotTimer
// thread was started as a sanity check to not have a flakey test.
EXPECT_FALSE(callbackCalled && std::chrono::steady_clock::now() - startTime < 30ms);
@@ -79,9 +80,9 @@
mIdleTimer->stop();
}
-TEST_F(IdleTimerTest, resetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
// Observe any event that happens in about 25ms. We don't care if one was
@@ -104,9 +105,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, resetBackToBackTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(20ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, resetBackToBackTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(20ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -135,9 +136,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, startNotCalledTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, startNotCalledTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
// The start hasn't happened, so the callback does not happen.
EXPECT_FALSE(mExpiredTimerCallback.waitForCall(waitTimeForUnexpected3msCallback).has_value());
EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
@@ -147,9 +148,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, idleTimerIdlesTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, idleTimerIdlesTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
@@ -167,18 +168,18 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall(0ms).has_value());
}
-TEST_F(IdleTimerTest, timeoutCallbackExecutionTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, timeoutCallbackExecutionTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
mIdleTimer->stop();
}
-TEST_F(IdleTimerTest, noCallbacksAfterStopAndResetTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopAndResetTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
EXPECT_TRUE(mExpiredTimerCallback.waitForCall(waitTimeForExpected3msCallback).has_value());
@@ -190,9 +191,9 @@
EXPECT_FALSE(mResetTimerCallback.waitForCall().has_value());
}
-TEST_F(IdleTimerTest, noCallbacksAfterStopTest) {
- mIdleTimer = std::make_unique<scheduler::IdleTimer>(3ms, mResetTimerCallback.getInvocable(),
- mExpiredTimerCallback.getInvocable());
+TEST_F(OneShotTimerTest, noCallbacksAfterStopTest) {
+ mIdleTimer = std::make_unique<scheduler::OneShotTimer>(3ms, mResetTimerCallback.getInvocable(),
+ mExpiredTimerCallback.getInvocable());
mIdleTimer->start();
EXPECT_TRUE(mResetTimerCallback.waitForCall().has_value());
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 5067fe8..f315a8a 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -23,7 +23,6 @@
#include "DisplayHardware/HWC2.h"
#include "Scheduler/RefreshRateConfigs.h"
-#include "mock/DisplayHardware/MockDisplay.h"
using namespace std::chrono_literals;
using testing::_;
@@ -50,9 +49,8 @@
ASSERT_EQ(left.configId, right.configId);
ASSERT_EQ(left.name, right.name);
ASSERT_EQ(left.fps, right.fps);
+ ASSERT_EQ(left.vsyncPeriod, right.vsyncPeriod);
}
-
- RefreshRateConfigs mConfigs;
};
RefreshRateConfigsTest::RefreshRateConfigsTest() {
@@ -71,101 +69,39 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) {
- std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
- mConfigs.populate(displayConfigs);
-
- // We always store a configuration for screen off.
- const auto& rates = mConfigs.getRefreshRates();
- ASSERT_EQ(1, rates.size());
- const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
- ASSERT_NE(rates.end(), powerSavingRate);
- ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
- ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT));
-
- RefreshRate expectedConfig =
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
- assertRatesEqual(expectedConfig, *powerSavingRate->second);
-
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- assertRatesEqual(expectedConfig, *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
- ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
-
- // Sanity check that getRefreshRate() does not modify the underlying configs.
- ASSERT_EQ(1, mConfigs.getRefreshRates().size());
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_isRejected) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfig=*/0);
+ ASSERT_FALSE(refreshRateConfigs->refreshRateSwitchingSupported());
}
-TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) {
- auto display = new Hwc2::mock::Display();
- std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
- auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
- config60.setVsyncPeriod(VSYNC_60);
- displayConfigs.push_back(config60.build());
- mConfigs.populate(displayConfigs);
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesFullRefreshRateMap) {
+ std::vector<RefreshRateConfigs::InputConfig> configs{{HWC2_CONFIG_ID_60, VSYNC_60},
+ {HWC2_CONFIG_ID_90, VSYNC_90}};
+ auto refreshRateConfigs =
+ std::make_unique<RefreshRateConfigs>(/*refreshRateSwitching=*/true, configs,
+ /*currentConfig=*/0);
- const auto& rates = mConfigs.getRefreshRates();
+ ASSERT_TRUE(refreshRateConfigs->refreshRateSwitchingSupported());
+ const auto& rates = refreshRateConfigs->getRefreshRateMap();
ASSERT_EQ(2, rates.size());
- const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
- const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
- ASSERT_NE(rates.end(), powerSavingRate);
- ASSERT_NE(rates.end(), defaultRate);
- ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
-
- RefreshRate expectedPowerSavingConfig =
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
- assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
- RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60};
- assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
-
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- assertRatesEqual(expectedPowerSavingConfig,
- *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- ASSERT_FALSE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
-
- // Sanity check that getRefreshRate() does not modify the underlying configs.
- ASSERT_EQ(2, mConfigs.getRefreshRates().size());
-}
-
-TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) {
- auto display = new Hwc2::mock::Display();
- std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
- auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
- config60.setVsyncPeriod(VSYNC_60);
- displayConfigs.push_back(config60.build());
- auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
- config90.setVsyncPeriod(VSYNC_90);
- displayConfigs.push_back(config90.build());
- mConfigs.populate(displayConfigs);
-
- const auto& rates = mConfigs.getRefreshRates();
- ASSERT_EQ(3, rates.size());
- const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
- ASSERT_NE(rates.end(), powerSavingRate);
ASSERT_NE(rates.end(), defaultRate);
ASSERT_NE(rates.end(), performanceRate);
- RefreshRate expectedPowerSavingConfig =
- RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0, HWC2_SCREEN_OFF_CONFIG_ID};
- assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
- RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60, HWC2_CONFIG_ID_60};
- assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
- RefreshRate expectedPerformanceConfig =
- RefreshRate{CONFIG_ID_90, "90fps", 90, HWC2_CONFIG_ID_90};
- assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
+ RefreshRate expectedDefaultConfig = {CONFIG_ID_60, "60fps", 60, VSYNC_60, HWC2_CONFIG_ID_60};
+ assertRatesEqual(expectedDefaultConfig, defaultRate->second);
+ RefreshRate expectedPerformanceConfig = {CONFIG_ID_90, "90fps", 90, VSYNC_90,
+ HWC2_CONFIG_ID_90};
+ assertRatesEqual(expectedPerformanceConfig, performanceRate->second);
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- assertRatesEqual(expectedPowerSavingConfig,
- *mConfigs.getRefreshRate(RefreshRateType::POWER_SAVING));
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- assertRatesEqual(expectedDefaultConfig, *mConfigs.getRefreshRate(RefreshRateType::DEFAULT));
- ASSERT_TRUE(mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
+ assertRatesEqual(expectedDefaultConfig,
+ refreshRateConfigs->getRefreshRateFromType(RefreshRateType::DEFAULT));
assertRatesEqual(expectedPerformanceConfig,
- *mConfigs.getRefreshRate(RefreshRateType::PERFORMANCE));
+ refreshRateConfigs->getRefreshRateFromType(RefreshRateType::PERFORMANCE));
}
} // namespace
} // namespace scheduler
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
index 411ec61..cec0b32 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateStatsTest.cpp
@@ -22,7 +22,6 @@
#include <thread>
#include "Scheduler/RefreshRateStats.h"
-#include "mock/DisplayHardware/MockDisplay.h"
#include "mock/MockTimeStats.h"
using namespace std::chrono_literals;
@@ -42,9 +41,18 @@
RefreshRateStatsTest();
~RefreshRateStatsTest();
+ void init(const std::vector<RefreshRateConfigs::InputConfig>& configs) {
+ mRefreshRateConfigs = std::make_unique<RefreshRateConfigs>(
+ /*refreshRateSwitching=*/true, configs, /*currentConfig=*/0);
+ mRefreshRateStats =
+ std::make_unique<RefreshRateStats>(*mRefreshRateConfigs, mTimeStats,
+ /*currentConfig=*/0,
+ /*currentPowerMode=*/HWC_POWER_MODE_OFF);
+ }
+
mock::TimeStats mTimeStats;
- RefreshRateConfigs mRefreshRateConfigs;
- RefreshRateStats mRefreshRateStats{mRefreshRateConfigs, mTimeStats};
+ std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<RefreshRateStats> mRefreshRateStats;
};
RefreshRateStatsTest::RefreshRateStatsTest() {
@@ -63,63 +71,46 @@
/* ------------------------------------------------------------------------
* Test cases
*/
-TEST_F(RefreshRateStatsTest, canCreateAndDestroyTest) {
- std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
- mRefreshRateConfigs.populate(configs);
-
- // There is one default config, so the refresh rates should have one item.
- EXPECT_EQ(1, mRefreshRateStats.getTotalTimes().size());
-}
-
TEST_F(RefreshRateStatsTest, oneConfigTest) {
- auto display = new Hwc2::mock::Display();
-
- auto config = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
- config.setVsyncPeriod(VSYNC_90);
- std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
- configs.push_back(config.build());
-
- mRefreshRateConfigs.populate(configs);
+ init({{CONFIG_ID_90, VSYNC_90}});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
- std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes();
- EXPECT_EQ(2, times.size());
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(1, times.size());
EXPECT_NE(0u, times.count("ScreenOff"));
- EXPECT_EQ(1u, times.count("90fps"));
- EXPECT_EQ(0, times["90fps"]);
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
int screenOff = times["ScreenOff"];
- int ninety = times["90fps"];
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(0, times["90fps"]);
+ EXPECT_EQ(0u, times.count("90fps"));
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_LT(ninety, times["90fps"]);
+ ASSERT_EQ(1u, times.count("90fps"));
+ EXPECT_LT(0, times["90fps"]);
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE);
- ninety = mRefreshRateStats.getTotalTimes()["90fps"];
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
// Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
// does not update refresh rates that come from the config.
EXPECT_LT(screenOff, times["ScreenOff"]);
@@ -127,93 +118,75 @@
}
TEST_F(RefreshRateStatsTest, twoConfigsTest) {
- auto display = new Hwc2::mock::Display();
-
- auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
- config90.setVsyncPeriod(VSYNC_90);
- std::vector<std::shared_ptr<const HWC2::Display::Config>> configs;
- configs.push_back(config90.build());
-
- auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
- config60.setVsyncPeriod(VSYNC_60);
- configs.push_back(config60.build());
-
- mRefreshRateConfigs.populate(configs);
+ init({{CONFIG_ID_90, VSYNC_90}, {CONFIG_ID_60, VSYNC_60}});
EXPECT_CALL(mTimeStats, recordRefreshRate(0, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(60, _)).Times(AtLeast(1));
EXPECT_CALL(mTimeStats, recordRefreshRate(90, _)).Times(AtLeast(1));
- std::unordered_map<std::string, int64_t> times = mRefreshRateStats.getTotalTimes();
- EXPECT_EQ(3, times.size());
+ std::unordered_map<std::string, int64_t> times = mRefreshRateStats->getTotalTimes();
+ ASSERT_EQ(1, times.size());
EXPECT_NE(0u, times.count("ScreenOff"));
- EXPECT_EQ(1u, times.count("60fps"));
- EXPECT_EQ(0, times["60fps"]);
- EXPECT_EQ(1u, times.count("90fps"));
- EXPECT_EQ(0, times["90fps"]);
// Setting up tests on mobile harness can be flaky with time passing, so testing for
// exact time changes can result in flaxy numbers. To avoid that remember old
// numbers to make sure the correct values are increasing in the next test.
int screenOff = times["ScreenOff"];
- int sixty = times["60fps"];
- int ninety = times["90fps"];
// Screen is off by default.
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
- EXPECT_EQ(sixty, times["60fps"]);
- EXPECT_EQ(ninety, times["90fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_NORMAL);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_NORMAL);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
- EXPECT_EQ(sixty, times["60fps"]);
- EXPECT_LT(ninety, times["90fps"]);
+ ASSERT_EQ(1u, times.count("90fps"));
+ EXPECT_LT(0, times["90fps"]);
// When power mode is normal, time for configs updates.
- mRefreshRateStats.setConfigMode(CONFIG_ID_60);
- ninety = mRefreshRateStats.getTotalTimes()["90fps"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ int ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
- EXPECT_LT(sixty, times["60fps"]);
+ ASSERT_EQ(1u, times.count("60fps"));
+ EXPECT_LT(0, times["60fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- sixty = mRefreshRateStats.getTotalTimes()["60fps"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ int sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_LT(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_60);
- ninety = mRefreshRateStats.getTotalTimes()["90fps"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ ninety = mRefreshRateStats->getTotalTimes()["90fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_EQ(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_LT(sixty, times["60fps"]);
// Because the power mode is not HWC_POWER_MODE_NORMAL, switching the config
// does not update refresh rates that come from the config.
- mRefreshRateStats.setPowerMode(HWC_POWER_MODE_DOZE);
- mRefreshRateStats.setConfigMode(CONFIG_ID_90);
- sixty = mRefreshRateStats.getTotalTimes()["60fps"];
+ mRefreshRateStats->setPowerMode(HWC_POWER_MODE_DOZE);
+ mRefreshRateStats->setConfigMode(CONFIG_ID_90);
+ sixty = mRefreshRateStats->getTotalTimes()["60fps"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
- mRefreshRateStats.setConfigMode(CONFIG_ID_60);
- screenOff = mRefreshRateStats.getTotalTimes()["ScreenOff"];
+ mRefreshRateStats->setConfigMode(CONFIG_ID_60);
+ screenOff = mRefreshRateStats->getTotalTimes()["ScreenOff"];
std::this_thread::sleep_for(std::chrono::milliseconds(2));
- times = mRefreshRateStats.getTotalTimes();
+ times = mRefreshRateStats->getTotalTimes();
EXPECT_LT(screenOff, times["ScreenOff"]);
EXPECT_EQ(ninety, times["90fps"]);
EXPECT_EQ(sixty, times["60fps"]);
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 740115e..b4cc1e1 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -3,14 +3,14 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-
#include <log/log.h>
#include <mutex>
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
-#include "Scheduler/Scheduler.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "TestableScheduler.h"
#include "mock/MockEventThread.h"
using testing::_;
@@ -34,37 +34,14 @@
MOCK_METHOD0(requestNextVsync, void());
};
- scheduler::RefreshRateConfigs mRefreshRateConfigs;
-
- /**
- * This mock Scheduler class uses implementation of mock::EventThread but keeps everything else
- * the same.
- */
- class MockScheduler : public android::Scheduler {
- public:
- MockScheduler(const scheduler::RefreshRateConfigs& refreshRateConfigs,
- std::unique_ptr<EventThread> eventThread)
- : Scheduler([](bool) {}, refreshRateConfigs), mEventThread(std::move(eventThread)) {}
-
- std::unique_ptr<EventThread> makeEventThread(
- const char* /* connectionName */, DispSync* /* dispSync */,
- nsecs_t /* phaseOffsetNs */, nsecs_t /* offsetThresholdForNextVsync */,
- impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
- return std::move(mEventThread);
- }
-
- MockScheduler() = default;
- ~MockScheduler() override = default;
-
- std::unique_ptr<EventThread> mEventThread;
- };
-
SchedulerTest();
~SchedulerTest() override;
- sp<Scheduler::ConnectionHandle> mConnectionHandle;
+ std::unique_ptr<scheduler::RefreshRateConfigs> mRefreshRateConfigs;
+ std::unique_ptr<TestableScheduler> mScheduler;
+
+ Scheduler::ConnectionHandle mConnectionHandle;
mock::EventThread* mEventThread;
- std::unique_ptr<MockScheduler> mScheduler;
sp<MockEventThreadConnection> mEventThreadConnection;
};
@@ -73,9 +50,15 @@
::testing::UnitTest::GetInstance()->current_test_info();
ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
- std::unique_ptr<mock::EventThread> eventThread = std::make_unique<mock::EventThread>();
+ std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
+ mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false, configs,
+ /*currentConfig=*/0);
+
+ mScheduler = std::make_unique<TestableScheduler>(*mRefreshRateConfigs);
+
+ auto eventThread = std::make_unique<mock::EventThread>();
mEventThread = eventThread.get();
- mScheduler = std::make_unique<MockScheduler>(mRefreshRateConfigs, std::move(eventThread));
EXPECT_CALL(*mEventThread, registerDisplayEventConnection(_)).WillOnce(Return(0));
mEventThreadConnection = new MockEventThreadConnection(mEventThread);
@@ -85,9 +68,8 @@
EXPECT_CALL(*mEventThread, createEventConnection(_, _))
.WillRepeatedly(Return(mEventThreadConnection));
- mConnectionHandle = mScheduler->createConnection("appConnection", 16, 16, ResyncCallback(),
- impl::EventThread::InterceptVSyncsCallback());
- EXPECT_TRUE(mConnectionHandle != nullptr);
+ mConnectionHandle = mScheduler->createConnection(std::move(eventThread));
+ EXPECT_TRUE(mConnectionHandle);
}
SchedulerTest::~SchedulerTest() {
@@ -101,78 +83,48 @@
* Test cases
*/
-TEST_F(SchedulerTest, testNullPtr) {
- // Passing a null pointer for ConnectionHandle is a valid argument. The code doesn't throw any
- // exceptions, just gracefully continues.
- sp<IDisplayEventConnection> returnedValue;
- ASSERT_NO_FATAL_FAILURE(
- returnedValue =
- mScheduler->createDisplayEventConnection(nullptr, ResyncCallback(),
- ISurfaceComposer::
- eConfigChangedSuppress));
- EXPECT_TRUE(returnedValue == nullptr);
- EXPECT_TRUE(mScheduler->getEventThread(nullptr) == nullptr);
- EXPECT_TRUE(mScheduler->getEventConnection(nullptr) == nullptr);
- 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;
- ASSERT_NO_FATAL_FAILURE(mScheduler->dump(nullptr, testString));
- EXPECT_TRUE(testString == "");
- ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(nullptr, 10));
-}
-
TEST_F(SchedulerTest, invalidConnectionHandle) {
- // Passing an invalid ConnectionHandle is a valid argument. The code doesn't throw any
- // exceptions, just gracefully continues.
- sp<Scheduler::ConnectionHandle> connectionHandle = new Scheduler::ConnectionHandle(20);
+ Scheduler::ConnectionHandle handle;
- sp<IDisplayEventConnection> returnedValue;
+ sp<IDisplayEventConnection> connection;
ASSERT_NO_FATAL_FAILURE(
- returnedValue =
- mScheduler->createDisplayEventConnection(connectionHandle, ResyncCallback(),
- ISurfaceComposer::
- eConfigChangedSuppress));
- EXPECT_TRUE(returnedValue == nullptr);
- EXPECT_TRUE(mScheduler->getEventThread(connectionHandle) == nullptr);
- EXPECT_TRUE(mScheduler->getEventConnection(connectionHandle) == nullptr);
+ connection = mScheduler->createDisplayEventConnection(handle,
+ ISurfaceComposer::
+ eConfigChangedSuppress));
+ EXPECT_FALSE(connection);
+ EXPECT_FALSE(mScheduler->getEventConnection(handle));
// 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, PHYSICAL_DISPLAY_ID, false));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onHotplugReceived(handle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(connectionHandle));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(handle));
EXPECT_CALL(*mEventThread, onScreenReleased()).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(connectionHandle));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(handle));
- std::string testString;
+ std::string output;
EXPECT_CALL(*mEventThread, dump(_)).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->dump(connectionHandle, testString));
- EXPECT_TRUE(testString == "");
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(handle, output));
+ EXPECT_TRUE(output.empty());
EXPECT_CALL(*mEventThread, setPhaseOffset(_)).Times(0);
- ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(connectionHandle, 10));
+ ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(handle, 10));
}
TEST_F(SchedulerTest, validConnectionHandle) {
- sp<IDisplayEventConnection> returnedValue;
+ sp<IDisplayEventConnection> connection;
ASSERT_NO_FATAL_FAILURE(
- returnedValue =
- mScheduler->createDisplayEventConnection(mConnectionHandle, ResyncCallback(),
- ISurfaceComposer::
- eConfigChangedSuppress));
- EXPECT_TRUE(returnedValue != nullptr);
- ASSERT_EQ(returnedValue, mEventThreadConnection);
-
- EXPECT_TRUE(mScheduler->getEventThread(mConnectionHandle) != nullptr);
- EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle) != nullptr);
+ connection = mScheduler->createDisplayEventConnection(mConnectionHandle,
+ ISurfaceComposer::
+ eConfigChangedSuppress));
+ ASSERT_EQ(mEventThreadConnection, connection);
+ EXPECT_TRUE(mScheduler->getEventConnection(mConnectionHandle));
EXPECT_CALL(*mEventThread, onHotplugReceived(PHYSICAL_DISPLAY_ID, false)).Times(1);
ASSERT_NO_FATAL_FAILURE(
- mScheduler->hotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
+ mScheduler->onHotplugReceived(mConnectionHandle, PHYSICAL_DISPLAY_ID, false));
EXPECT_CALL(*mEventThread, onScreenAcquired()).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenAcquired(mConnectionHandle));
@@ -180,13 +132,14 @@
EXPECT_CALL(*mEventThread, onScreenReleased()).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->onScreenReleased(mConnectionHandle));
- std::string testString("dump");
- EXPECT_CALL(*mEventThread, dump(testString)).Times(1);
- ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, testString));
- EXPECT_TRUE(testString != "");
+ std::string output("dump");
+ EXPECT_CALL(*mEventThread, dump(output)).Times(1);
+ ASSERT_NO_FATAL_FAILURE(mScheduler->dump(mConnectionHandle, output));
+ EXPECT_FALSE(output.empty());
EXPECT_CALL(*mEventThread, setPhaseOffset(10)).Times(1);
ASSERT_NO_FATAL_FAILURE(mScheduler->setPhaseOffset(mConnectionHandle, 10));
}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index cb6980e..ae72467 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -19,30 +19,25 @@
#include <gmock/gmock.h>
#include <gui/ISurfaceComposer.h>
+#include "Scheduler/DispSync.h"
#include "Scheduler/EventThread.h"
-#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/Scheduler.h"
namespace android {
class TestableScheduler : public Scheduler {
public:
- TestableScheduler(const scheduler::RefreshRateConfigs& refreshRateConfig)
- : Scheduler([](bool) {}, refreshRateConfig) {}
+ explicit TestableScheduler(const scheduler::RefreshRateConfigs& configs)
+ : Scheduler([](bool) {}, configs) {}
- // Creates EventThreadConnection with the given eventThread. Creates Scheduler::Connection
- // and adds it to the list of connectins. Returns the ConnectionHandle for the
- // Scheduler::Connection. This allows plugging in mock::EventThread.
- sp<Scheduler::ConnectionHandle> addConnection(std::unique_ptr<EventThread> eventThread) {
- sp<EventThreadConnection> eventThreadConnection =
- new EventThreadConnection(eventThread.get(), ResyncCallback(),
- ISurfaceComposer::eConfigChangedSuppress);
- const int64_t id = sNextId++;
- mConnections.emplace(id,
- std::make_unique<Scheduler::Connection>(new ConnectionHandle(id),
- eventThreadConnection,
- std::move(eventThread)));
- return mConnections[id]->handle;
+ TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ const scheduler::RefreshRateConfigs& configs)
+ : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs) {}
+
+ // Used to inject mock event thread.
+ ConnectionHandle createConnection(std::unique_ptr<EventThread> eventThread) {
+ return Scheduler::createConnection(std::move(eventThread));
}
/* ------------------------------------------------------------------------
@@ -62,7 +57,7 @@
mutableEventControlThread().reset();
mutablePrimaryDispSync().reset();
mConnections.clear();
- };
+ }
};
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 64d34ee..b77f82a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -18,9 +18,9 @@
#include <compositionengine/Display.h>
#include <compositionengine/Layer.h>
+#include <compositionengine/LayerFECompositionState.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/CompositionEngine.h>
-#include <compositionengine/impl/LayerCompositionState.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include "BufferQueueLayer.h"
@@ -32,12 +32,12 @@
#include "Layer.h"
#include "NativeWindowSurface.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/RefreshRateConfigs.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
#include "SurfaceInterceptor.h"
-
-#include "TimeStats/TimeStats.h"
+#include "TestableScheduler.h"
namespace android {
@@ -61,7 +61,7 @@
public:
~Factory() = default;
- std::unique_ptr<DispSync> createDispSync(const char*, bool, int64_t) override {
+ std::unique_ptr<DispSync> createDispSync(const char*, bool) override {
// TODO: Use test-fixture controlled factory
return nullptr;
}
@@ -151,11 +151,6 @@
return nullptr;
}
- std::shared_ptr<TimeStats> createTimeStats() override {
- // TODO: Use test-fixture controlled factory
- return std::make_shared<android::impl::TimeStats>();
- }
-
using CreateBufferQueueFunction =
std::function<void(sp<IGraphicBufferProducer>* /* outProducer */,
sp<IGraphicBufferConsumer>* /* outConsumer */,
@@ -176,6 +171,8 @@
class TestableSurfaceFlinger {
public:
+ TestableScheduler* scheduler() { return mScheduler; }
+
// Extend this as needed for accessing SurfaceFlinger private (and public)
// functions.
@@ -188,6 +185,33 @@
std::make_unique<impl::HWComposer>(std::move(composer)));
}
+ void setupScheduler(std::unique_ptr<DispSync> primaryDispSync,
+ std::unique_ptr<EventControlThread> eventControlThread,
+ std::unique_ptr<EventThread> appEventThread,
+ std::unique_ptr<EventThread> sfEventThread) {
+ std::vector<scheduler::RefreshRateConfigs::InputConfig> configs{{/*hwcId=*/0, 16666667}};
+ mFlinger->mRefreshRateConfigs =
+ std::make_unique<scheduler::RefreshRateConfigs>(/*refreshRateSwitching=*/false,
+ configs, /*currentConfig=*/0);
+ mFlinger->mRefreshRateStats =
+ std::make_unique<scheduler::RefreshRateStats>(*mFlinger->mRefreshRateConfigs,
+ *mFlinger->mTimeStats,
+ /*currentConfig=*/0,
+ /*powerMode=*/HWC_POWER_MODE_OFF);
+
+ mScheduler =
+ new TestableScheduler(std::move(primaryDispSync), std::move(eventControlThread),
+ *mFlinger->mRefreshRateConfigs);
+
+ mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
+ mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
+
+ mFlinger->mScheduler.reset(mScheduler);
+ mFlinger->mVSyncModulator.emplace(*mScheduler, mFlinger->mAppConnectionHandle,
+ mFlinger->mSfConnectionHandle,
+ mFlinger->mPhaseOffsets->getCurrentOffsets());
+ }
+
using CreateBufferQueueFunction = surfaceflinger::test::Factory::CreateBufferQueueFunction;
void setCreateBufferQueueFunction(CreateBufferQueueFunction f) {
mFactory.mCreateBufferQueue = f;
@@ -211,7 +235,7 @@
void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
layer->mDrawingState.sidebandStream = sidebandStream;
layer->mSidebandStream = sidebandStream;
- layer->getCompositionLayer()->editState().frontEnd.sidebandStream = sidebandStream;
+ layer->getCompositionLayer()->editFEState().sidebandStream = sidebandStream;
}
void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
@@ -338,10 +362,6 @@
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutableInternalHwcDisplayId() { return getHwComposer().mInternalHwcDisplayId; }
auto& mutableExternalHwcDisplayId() { return getHwComposer().mExternalHwcDisplayId; }
- auto& mutableScheduler() { return mFlinger->mScheduler; }
- auto& mutableAppConnectionHandle() { return mFlinger->mAppConnectionHandle; }
- auto& mutableSfConnectionHandle() { return mFlinger->mSfConnectionHandle; }
- auto& mutableRefreshRateConfigs() { return mFlinger->mRefreshRateConfigs; }
~TestableSurfaceFlinger() {
// All these pointer and container clears help ensure that GMock does
@@ -353,7 +373,7 @@
mutableDrawingState().displays.clear();
mutableEventQueue().reset();
mutableInterceptor().reset();
- mutableScheduler().reset();
+ mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
std::unique_ptr<renderengine::RenderEngine>());
@@ -573,6 +593,7 @@
surfaceflinger::test::Factory mFactory;
sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
+ TestableScheduler* mScheduler = nullptr;
// We need to keep a reference to these so they are properly destroyed.
std::vector<std::unique_ptr<HWC2Display>> mFakeHwcDisplays;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index f35758d..dee2cae 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -17,6 +17,7 @@
#undef LOG_TAG
#define LOG_TAG "LibSurfaceFlingerUnittests"
+#include <TimeStats/TimeStats.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -27,8 +28,6 @@
#include <random>
#include <unordered_set>
-#include "TimeStats/TimeStats.h"
-
#include "libsurfaceflinger_unittest_main.h"
using namespace android::surfaceflinger;
@@ -210,6 +209,10 @@
return distr(mRandomEngine);
}
+TEST_F(TimeStatsTest, enabledByDefault) {
+ ASSERT_TRUE(mTimeStats->isEnabled());
+}
+
TEST_F(TimeStatsTest, canEnableAndDisableTimeStats) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_TRUE(mTimeStats->isEnabled());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
similarity index 60%
copy from services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
copy to services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
index ab01c20..358dfdb 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/LayerCompositionState.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.cpp
@@ -14,28 +14,14 @@
* limitations under the License.
*/
-#pragma once
-
-#include <cstdint>
-#include <string>
-
-#include <compositionengine/LayerFECompositionState.h>
-#include <renderengine/Mesh.h>
+#include "mock/MockFrameTracer.h"
namespace android {
+namespace mock {
-namespace compositionengine::impl {
+// Explicit default instantiation is recommended.
+FrameTracer::FrameTracer() = default;
+FrameTracer::~FrameTracer() = default;
-struct LayerCompositionState {
- /*
- * State intended to be set by LayerFE::getCompositionState
- */
-
- LayerFECompositionState frontEnd;
-
- // Debugging
- void dump(std::string& result) const;
-};
-
-} // namespace compositionengine::impl
+} // namespace mock
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
new file mode 100644
index 0000000..f768b81
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTracer.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "FrameTracer/FrameTracer.h"
+
+namespace android {
+namespace mock {
+
+class FrameTracer : public android::FrameTracer {
+public:
+ FrameTracer();
+ ~FrameTracer();
+
+ MOCK_METHOD0(initialize, void());
+ MOCK_METHOD0(registerDataSource, void());
+ MOCK_METHOD2(traceNewLayer, void(int32_t, const std::string&));
+ MOCK_METHOD6(traceTimestamp,
+ void(int32_t, uint64_t, uint64_t, nsecs_t, FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD6(traceFence,
+ void(int32_t, uint64_t, uint64_t, const std::shared_ptr<FenceTime>&,
+ FrameEvent::BufferEventType, nsecs_t));
+ MOCK_METHOD0(miniDump, std::string());
+};
+
+} // namespace mock
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
index 1b1c1a7..e781c0a 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockMessageQueue.h
@@ -30,7 +30,6 @@
~MessageQueue() override;
MOCK_METHOD1(init, void(const sp<SurfaceFlinger>&));
- MOCK_METHOD2(setEventThread, void(android::EventThread*, ResyncCallback));
MOCK_METHOD1(setEventConnection, void(const sp<EventThreadConnection>& connection));
MOCK_METHOD0(waitMessage, void());
MOCK_METHOD2(postMessage, status_t(const sp<MessageBase>&, nsecs_t));
diff --git a/services/surfaceflinger/tests/utils/CallbackUtils.h b/services/surfaceflinger/tests/utils/CallbackUtils.h
new file mode 100644
index 0000000..51ae8c4
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/CallbackUtils.h
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <gtest/gtest.h>
+#include <gui/SurfaceComposerClient.h>
+#include <gui/SurfaceControl.h>
+#include <ui/Fence.h>
+#include <utils/Timers.h>
+#include <thread>
+
+namespace android {
+
+namespace {
+
+struct CallbackData {
+ CallbackData() = default;
+ CallbackData(nsecs_t time, const sp<Fence>& fence,
+ const std::vector<SurfaceControlStats>& stats)
+ : latchTime(time), presentFence(fence), surfaceControlStats(stats) {}
+
+ nsecs_t latchTime;
+ sp<Fence> presentFence;
+ std::vector<SurfaceControlStats> surfaceControlStats;
+};
+
+class ExpectedResult {
+public:
+ enum Transaction {
+ NOT_PRESENTED = 0,
+ PRESENTED,
+ };
+
+ enum Buffer {
+ NOT_ACQUIRED = 0,
+ ACQUIRED,
+ };
+
+ enum PreviousBuffer {
+ NOT_RELEASED = 0,
+ RELEASED,
+ UNKNOWN,
+ };
+
+ void reset() {
+ mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ mExpectedSurfaceResults.clear();
+ }
+
+ void addSurface(ExpectedResult::Transaction transactionResult, const sp<SurfaceControl>& layer,
+ ExpectedResult::Buffer bufferResult = ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ mTransactionResult = transactionResult;
+ mExpectedSurfaceResults.emplace(std::piecewise_construct, std::forward_as_tuple(layer),
+ std::forward_as_tuple(bufferResult, previousBufferResult));
+ }
+
+ void addSurfaces(ExpectedResult::Transaction transactionResult,
+ const std::vector<sp<SurfaceControl>>& layers,
+ ExpectedResult::Buffer bufferResult = ACQUIRED,
+ ExpectedResult::PreviousBuffer previousBufferResult = NOT_RELEASED) {
+ for (const auto& layer : layers) {
+ addSurface(transactionResult, layer, bufferResult, previousBufferResult);
+ }
+ }
+
+ void addExpectedPresentTime(nsecs_t expectedPresentTime) {
+ mExpectedPresentTime = expectedPresentTime;
+ }
+
+ void verifyCallbackData(const CallbackData& callbackData) const {
+ const auto& [latchTime, presentFence, surfaceControlStats] = callbackData;
+ if (mTransactionResult == ExpectedResult::Transaction::PRESENTED) {
+ ASSERT_GE(latchTime, 0) << "bad latch time";
+ ASSERT_NE(presentFence, nullptr);
+ if (mExpectedPresentTime >= 0) {
+ ASSERT_EQ(presentFence->wait(3000), NO_ERROR);
+ ASSERT_GE(presentFence->getSignalTime(), mExpectedPresentTime - nsecs_t(5 * 1e6));
+ // if the panel is running at 30 hz, at the worst case, our expected time just
+ // misses vsync and we have to wait another 33.3ms
+ ASSERT_LE(presentFence->getSignalTime(),
+ mExpectedPresentTime + nsecs_t(66.666666 * 1e6));
+ }
+ } else {
+ ASSERT_EQ(presentFence, nullptr) << "transaction shouldn't have been presented";
+ ASSERT_EQ(latchTime, -1) << "unpresented transactions shouldn't be latched";
+ }
+
+ ASSERT_EQ(surfaceControlStats.size(), mExpectedSurfaceResults.size())
+ << "wrong number of surfaces";
+
+ for (const auto& stats : surfaceControlStats) {
+ ASSERT_NE(stats.surfaceControl, nullptr) << "returned null surface control";
+
+ const auto& expectedSurfaceResult = mExpectedSurfaceResults.find(stats.surfaceControl);
+ ASSERT_NE(expectedSurfaceResult, mExpectedSurfaceResults.end())
+ << "unexpected surface control";
+ expectedSurfaceResult->second.verifySurfaceControlStats(stats, latchTime);
+ }
+ }
+
+private:
+ class ExpectedSurfaceResult {
+ public:
+ ExpectedSurfaceResult(ExpectedResult::Buffer bufferResult,
+ ExpectedResult::PreviousBuffer previousBufferResult)
+ : mBufferResult(bufferResult), mPreviousBufferResult(previousBufferResult) {}
+
+ void verifySurfaceControlStats(const SurfaceControlStats& surfaceControlStats,
+ nsecs_t latchTime) const {
+ const auto& [surfaceControl, acquireTime, previousReleaseFence] = surfaceControlStats;
+
+ ASSERT_EQ(acquireTime > 0, mBufferResult == ExpectedResult::Buffer::ACQUIRED)
+ << "bad acquire time";
+ ASSERT_LE(acquireTime, latchTime) << "acquire time should be <= latch time";
+
+ if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::RELEASED) {
+ ASSERT_NE(previousReleaseFence, nullptr)
+ << "failed to set release prev buffer fence";
+ } else if (mPreviousBufferResult == ExpectedResult::PreviousBuffer::NOT_RELEASED) {
+ ASSERT_EQ(previousReleaseFence, nullptr)
+ << "should not have set released prev buffer fence";
+ }
+ }
+
+ private:
+ ExpectedResult::Buffer mBufferResult;
+ ExpectedResult::PreviousBuffer mPreviousBufferResult;
+ };
+
+ struct SCHash {
+ std::size_t operator()(const sp<SurfaceControl>& sc) const {
+ return std::hash<IBinder*>{}(sc->getHandle().get());
+ }
+ };
+ ExpectedResult::Transaction mTransactionResult = ExpectedResult::Transaction::NOT_PRESENTED;
+ nsecs_t mExpectedPresentTime = -1;
+ std::unordered_map<sp<SurfaceControl>, ExpectedSurfaceResult, SCHash> mExpectedSurfaceResults;
+};
+
+class CallbackHelper {
+public:
+ static void function(void* callbackContext, nsecs_t latchTime, const sp<Fence>& presentFence,
+ const std::vector<SurfaceControlStats>& stats) {
+ if (!callbackContext) {
+ ALOGE("failed to get callback context");
+ }
+ CallbackHelper* helper = static_cast<CallbackHelper*>(callbackContext);
+ std::lock_guard lock(helper->mMutex);
+ helper->mCallbackDataQueue.emplace(latchTime, presentFence, stats);
+ helper->mConditionVariable.notify_all();
+ }
+
+ void getCallbackData(CallbackData* outData) {
+ std::unique_lock lock(mMutex);
+
+ if (mCallbackDataQueue.empty()) {
+ ASSERT_NE(mConditionVariable.wait_for(lock, std::chrono::seconds(3)),
+ std::cv_status::timeout)
+ << "did not receive callback";
+ }
+
+ *outData = std::move(mCallbackDataQueue.front());
+ mCallbackDataQueue.pop();
+ }
+
+ void verifyFinalState() {
+ // Wait to see if there are extra callbacks
+ std::this_thread::sleep_for(500ms);
+
+ std::lock_guard lock(mMutex);
+ EXPECT_EQ(mCallbackDataQueue.size(), 0) << "extra callbacks received";
+ mCallbackDataQueue = {};
+ }
+
+ void* getContext() { return static_cast<void*>(this); }
+
+ std::mutex mMutex;
+ std::condition_variable mConditionVariable;
+ std::queue<CallbackData> mCallbackDataQueue;
+};
+}
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/ColorUtils.h b/services/surfaceflinger/tests/utils/ColorUtils.h
new file mode 100644
index 0000000..07916b6
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/ColorUtils.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <ui/ColorSpace.h>
+
+namespace android {
+
+namespace {
+
+struct Color {
+ uint8_t r;
+ uint8_t g;
+ uint8_t b;
+ uint8_t a;
+
+ static const Color RED;
+ static const Color GREEN;
+ static const Color BLUE;
+ static const Color WHITE;
+ static const Color BLACK;
+ static const Color TRANSPARENT;
+};
+
+const Color Color::RED{255, 0, 0, 255};
+const Color Color::GREEN{0, 255, 0, 255};
+const Color Color::BLUE{0, 0, 255, 255};
+const Color Color::WHITE{255, 255, 255, 255};
+const Color Color::BLACK{0, 0, 0, 255};
+const Color Color::TRANSPARENT{0, 0, 0, 0};
+
+class ColorTransformHelper {
+public:
+ static void DegammaColorSingle(half& s) {
+ if (s <= 0.03928f)
+ s = s / 12.92f;
+ else
+ s = pow((s + 0.055f) / 1.055f, 2.4f);
+ }
+
+ static void DegammaColor(half3& color) {
+ DegammaColorSingle(color.r);
+ DegammaColorSingle(color.g);
+ DegammaColorSingle(color.b);
+ }
+
+ static void GammaColorSingle(half& s) {
+ if (s <= 0.0031308f) {
+ s = s * 12.92f;
+ } else {
+ s = 1.055f * pow(s, (1.0f / 2.4f)) - 0.055f;
+ }
+ }
+
+ static void GammaColor(half3& color) {
+ GammaColorSingle(color.r);
+ GammaColorSingle(color.g);
+ GammaColorSingle(color.b);
+ }
+
+ static void applyMatrix(half3& color, const mat3& mat) {
+ half3 ret = half3(0);
+
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ ret[i] = ret[i] + color[j] * mat[j][i];
+ }
+ }
+ color = ret;
+ }
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/ScreenshotUtils.h b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
new file mode 100644
index 0000000..5480b00
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/ScreenshotUtils.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include <ui/Rect.h>
+#include <utils/String8.h>
+#include "TransactionUtils.h"
+
+namespace android {
+
+namespace {
+
+// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
+// individual pixel values for testing purposes.
+class ScreenCapture : public RefBase {
+public:
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc) {
+ captureScreen(sc, SurfaceComposerClient::getInternalDisplayToken());
+ }
+
+ static void captureScreen(std::unique_ptr<ScreenCapture>* sc, sp<IBinder> displayToken) {
+ const auto sf = ComposerService::getComposerService();
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureScreen(displayToken, &outBuffer, Rect(), 0, 0, false));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ static void captureLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ static void captureChildLayers(std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ Rect crop = Rect::EMPTY_RECT, float frameScale = 1.0) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR, sf->captureLayers(parentHandle, &outBuffer, crop, frameScale, true));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ static void captureChildLayersExcluding(
+ std::unique_ptr<ScreenCapture>* sc, sp<IBinder>& parentHandle,
+ std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>> excludeLayers) {
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ SurfaceComposerClient::Transaction().apply(true);
+
+ sp<GraphicBuffer> outBuffer;
+ ASSERT_EQ(NO_ERROR,
+ sf->captureLayers(parentHandle, &outBuffer, ui::Dataspace::V0_SRGB,
+ ui::PixelFormat::RGBA_8888, Rect::EMPTY_RECT, excludeLayers,
+ 1.0f, true));
+ *sc = std::make_unique<ScreenCapture>(outBuffer);
+ }
+
+ void expectColor(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+ TransactionUtils::expectBufferColor(mOutBuffer, mPixels, rect, color, tolerance);
+ }
+
+ void expectBorder(const Rect& rect, const Color& color, uint8_t tolerance = 0) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+ const bool leftBorder = rect.left > 0;
+ const bool topBorder = rect.top > 0;
+ const bool rightBorder = rect.right < int32_t(mOutBuffer->getWidth());
+ const bool bottomBorder = rect.bottom < int32_t(mOutBuffer->getHeight());
+
+ if (topBorder) {
+ Rect top(rect.left, rect.top - 1, rect.right, rect.top);
+ if (leftBorder) {
+ top.left -= 1;
+ }
+ if (rightBorder) {
+ top.right += 1;
+ }
+ expectColor(top, color, tolerance);
+ }
+ if (leftBorder) {
+ Rect left(rect.left - 1, rect.top, rect.left, rect.bottom);
+ expectColor(left, color, tolerance);
+ }
+ if (rightBorder) {
+ Rect right(rect.right, rect.top, rect.right + 1, rect.bottom);
+ expectColor(right, color, tolerance);
+ }
+ if (bottomBorder) {
+ Rect bottom(rect.left, rect.bottom, rect.right, rect.bottom + 1);
+ if (leftBorder) {
+ bottom.left -= 1;
+ }
+ if (rightBorder) {
+ bottom.right += 1;
+ }
+ expectColor(bottom, color, tolerance);
+ }
+ }
+
+ void expectQuadrant(const Rect& rect, const Color& topLeft, const Color& topRight,
+ const Color& bottomLeft, const Color& bottomRight, bool filtered = false,
+ uint8_t tolerance = 0) {
+ ASSERT_TRUE((rect.right - rect.left) % 2 == 0 && (rect.bottom - rect.top) % 2 == 0);
+
+ const int32_t centerX = rect.left + (rect.right - rect.left) / 2;
+ const int32_t centerY = rect.top + (rect.bottom - rect.top) / 2;
+ // avoid checking borders due to unspecified filtering behavior
+ const int32_t offsetX = filtered ? 2 : 0;
+ const int32_t offsetY = filtered ? 2 : 0;
+ expectColor(Rect(rect.left, rect.top, centerX - offsetX, centerY - offsetY), topLeft,
+ tolerance);
+ expectColor(Rect(centerX + offsetX, rect.top, rect.right, centerY - offsetY), topRight,
+ tolerance);
+ expectColor(Rect(rect.left, centerY + offsetY, centerX - offsetX, rect.bottom), bottomLeft,
+ tolerance);
+ expectColor(Rect(centerX + offsetX, centerY + offsetY, rect.right, rect.bottom),
+ bottomRight, tolerance);
+ }
+
+ void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+ ASSERT_EQ(HAL_PIXEL_FORMAT_RGBA_8888, mOutBuffer->getPixelFormat());
+ const uint8_t* pixel = mPixels + (4 * (y * mOutBuffer->getStride() + x));
+ if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+ String8 err(String8::format("pixel @ (%3d, %3d): "
+ "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+ x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+ EXPECT_EQ(String8(), err) << err.string();
+ }
+ }
+
+ void expectFGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 195, 63, 63); }
+
+ void expectBGColor(uint32_t x, uint32_t y) { checkPixel(x, y, 63, 63, 195); }
+
+ void expectChildColor(uint32_t x, uint32_t y) { checkPixel(x, y, 200, 200, 200); }
+
+ explicit ScreenCapture(const sp<GraphicBuffer>& outBuffer) : mOutBuffer(outBuffer) {
+ mOutBuffer->lock(GRALLOC_USAGE_SW_READ_OFTEN, reinterpret_cast<void**>(&mPixels));
+ }
+
+ ~ScreenCapture() { mOutBuffer->unlock(); }
+
+private:
+ sp<GraphicBuffer> mOutBuffer;
+ uint8_t* mPixels = nullptr;
+};
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/utils/TransactionUtils.h b/services/surfaceflinger/tests/utils/TransactionUtils.h
new file mode 100644
index 0000000..22df255
--- /dev/null
+++ b/services/surfaceflinger/tests/utils/TransactionUtils.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <gtest/gtest.h>
+
+#include <android/native_window.h>
+#include <hardware/hwcomposer_defs.h>
+
+#include <binder/IPCThreadState.h>
+
+#include <gui/Surface.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/gui/ComposerService.h>
+
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+
+#include "ColorUtils.h"
+
+namespace android {
+
+namespace {
+
+using namespace std::chrono_literals;
+using Transaction = SurfaceComposerClient::Transaction;
+
+std::ostream& operator<<(std::ostream& os, const Color& color) {
+ os << int(color.r) << ", " << int(color.g) << ", " << int(color.b) << ", " << int(color.a);
+ return os;
+}
+
+class TransactionUtils {
+public:
+ // Fill a region with the specified color.
+ static void fillANativeWindowBufferColor(const ANativeWindow_Buffer& buffer, const Rect& rect,
+ const Color& color) {
+ Rect r(0, 0, buffer.width, buffer.height);
+ if (!r.intersect(rect, &r)) {
+ return;
+ }
+
+ int32_t width = r.right - r.left;
+ int32_t height = r.bottom - r.top;
+
+ for (int32_t row = 0; row < height; row++) {
+ uint8_t* dst = static_cast<uint8_t*>(buffer.bits) +
+ (buffer.stride * (r.top + row) + r.left) * 4;
+ for (int32_t column = 0; column < width; column++) {
+ dst[0] = color.r;
+ dst[1] = color.g;
+ dst[2] = color.b;
+ dst[3] = color.a;
+ dst += 4;
+ }
+ }
+ }
+
+ // Fill a region with the specified color.
+ static void fillGraphicBufferColor(const sp<GraphicBuffer>& buffer, const Rect& rect,
+ const Color& color) {
+ Rect r(0, 0, buffer->width, buffer->height);
+ if (!r.intersect(rect, &r)) {
+ return;
+ }
+
+ int32_t width = r.right - r.left;
+ int32_t height = r.bottom - r.top;
+
+ uint8_t* pixels;
+ buffer->lock(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
+ reinterpret_cast<void**>(&pixels));
+
+ for (int32_t row = 0; row < height; row++) {
+ uint8_t* dst = pixels + (buffer->getStride() * (r.top + row) + r.left) * 4;
+ for (int32_t column = 0; column < width; column++) {
+ dst[0] = color.r;
+ dst[1] = color.g;
+ dst[2] = color.b;
+ dst[3] = color.a;
+ dst += 4;
+ }
+ }
+ buffer->unlock();
+ }
+
+ // Check if a region has the specified color.
+ static void expectBufferColor(const sp<GraphicBuffer>& outBuffer, uint8_t* pixels,
+ const Rect& rect, const Color& color, uint8_t tolerance) {
+ int32_t x = rect.left;
+ int32_t y = rect.top;
+ int32_t width = rect.right - rect.left;
+ int32_t height = rect.bottom - rect.top;
+
+ int32_t bufferWidth = int32_t(outBuffer->getWidth());
+ int32_t bufferHeight = int32_t(outBuffer->getHeight());
+ if (x + width > bufferWidth) {
+ x = std::min(x, bufferWidth);
+ width = bufferWidth - x;
+ }
+ if (y + height > bufferHeight) {
+ y = std::min(y, bufferHeight);
+ height = bufferHeight - y;
+ }
+
+ auto colorCompare = [tolerance](uint8_t a, uint8_t b) {
+ uint8_t tmp = a >= b ? a - b : b - a;
+ return tmp <= tolerance;
+ };
+ for (int32_t j = 0; j < height; j++) {
+ const uint8_t* src = pixels + (outBuffer->getStride() * (y + j) + x) * 4;
+ for (int32_t i = 0; i < width; i++) {
+ const uint8_t expected[4] = {color.r, color.g, color.b, color.a};
+ EXPECT_TRUE(std::equal(src, src + 4, expected, colorCompare))
+ << "pixel @ (" << x + i << ", " << y + j << "): "
+ << "expected (" << color << "), "
+ << "got (" << Color{src[0], src[1], src[2], src[3]} << ")";
+ src += 4;
+ }
+ }
+ }
+
+ // Fill an RGBA_8888 formatted surface with a single color.
+ static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc, uint8_t r, uint8_t g, uint8_t b,
+ bool unlock = true) {
+ ANativeWindow_Buffer outBuffer;
+ sp<Surface> s = sc->getSurface();
+ ASSERT_TRUE(s != nullptr);
+ ASSERT_EQ(NO_ERROR, s->lock(&outBuffer, nullptr));
+ uint8_t* img = reinterpret_cast<uint8_t*>(outBuffer.bits);
+ for (int y = 0; y < outBuffer.height; y++) {
+ for (int x = 0; x < outBuffer.width; x++) {
+ uint8_t* pixel = img + (4 * (y * outBuffer.stride + x));
+ pixel[0] = r;
+ pixel[1] = g;
+ pixel[2] = b;
+ pixel[3] = 255;
+ }
+ }
+ if (unlock) {
+ ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+ }
+ }
+};
+
+enum class RenderPath { SCREENSHOT, VIRTUAL_DISPLAY };
+
+// Environment for starting up binder threads. This is required for testing
+// virtual displays, as BufferQueue parameters may be queried over binder.
+class BinderEnvironment : public ::testing::Environment {
+public:
+ void SetUp() override { ProcessState::self()->startThreadPool(); }
+};
+
+/** RAII Wrapper around get/seteuid */
+class UIDFaker {
+ uid_t oldId;
+
+public:
+ UIDFaker(uid_t uid) {
+ oldId = geteuid();
+ seteuid(uid);
+ }
+ ~UIDFaker() { seteuid(oldId); }
+};
+} // namespace
+} // namespace android
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index a7fd912..b71964b 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -350,7 +350,7 @@
while (!buffer_state_->compare_exchange_weak(
current_buffer_state, updated_buffer_state, std::memory_order_acq_rel,
std::memory_order_acquire)) {
- ALOGI(
+ ALOGV(
"%s: Failed to post to the new consumer. "
"Current buffer state was changed to %" PRIx32
" when trying to acquire the buffer and modify the buffer state to "
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index c202b5c..4df7b7c 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -12,10 +12,14 @@
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
+ "android.hardware.graphics.composer@2.1-resources",
"android.hardware.graphics.mapper@2.0",
"android.hardware.graphics.mapper@3.0",
+ "android.hardware.graphics.mapper@4.0",
"libbase",
"libbufferhubqueue",
"libbinder",
@@ -32,11 +36,11 @@
header_libs: [
"android.hardware.graphics.composer@2.1-command-buffer",
- "android.hardware.graphics.composer@2.1-hal",
+ "android.hardware.graphics.composer@2.3-hal",
],
export_header_lib_headers: [
- "android.hardware.graphics.composer@2.1-hal",
+ "android.hardware.graphics.composer@2.3-hal",
],
export_static_lib_headers: [
@@ -44,8 +48,10 @@
],
export_shared_lib_headers: [
- "android.frameworks.vr.composer@1.0",
+ "android.frameworks.vr.composer@2.0",
"android.hardware.graphics.composer@2.1",
+ "android.hardware.graphics.composer@2.2",
+ "android.hardware.graphics.composer@2.3",
],
export_include_dirs: ["."],
@@ -102,8 +108,8 @@
"libvr_hwc-binder",
],
shared_libs: [
- "android.frameworks.vr.composer@1.0",
- "android.hardware.graphics.composer@2.1",
+ "android.frameworks.vr.composer@2.0",
+ "android.hardware.graphics.composer@2.3",
"libbase",
"libbinder",
"liblog",
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 786d5fa..36f6b32 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
#include <hardware/gralloc.h>
#include <hardware/gralloc1.h>
#include <log/log.h>
@@ -27,8 +27,7 @@
namespace android {
namespace dvr {
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::frameworks::vr::composer::V1_0::IVrComposerClient;
+using android::frameworks::vr::composer::V2_0::IVrComposerClient;
VrComposerClient::VrComposerClient(dvr::VrHwc& hal)
: ComposerClient(&hal), mVrHal(hal) {
@@ -51,7 +50,8 @@
VrComposerClient::VrCommandEngine::~VrCommandEngine() {}
bool VrComposerClient::VrCommandEngine::executeCommand(
- IComposerClient::Command command, uint16_t length) {
+ hardware::graphics::composer::V2_1::IComposerClient::Command command,
+ uint16_t length) {
IVrComposerClient::VrCommand vrCommand =
static_cast<IVrComposerClient::VrCommand>(command);
switch (vrCommand) {
@@ -107,12 +107,14 @@
IVrComposerClient::BufferMetadata
VrComposerClient::VrCommandEngine::readBufferMetadata() {
IVrComposerClient::BufferMetadata metadata = {
- .width = read(),
- .height = read(),
- .stride = read(),
- .layerCount = read(),
- .format = static_cast<PixelFormat>(readSigned()),
- .usage = read64(),
+ .width = read(),
+ .height = read(),
+ .stride = read(),
+ .layerCount = read(),
+ .format =
+ static_cast<android::hardware::graphics::common::V1_2::PixelFormat>(
+ readSigned()),
+ .usage = read64(),
};
return metadata;
}
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.h b/services/vr/hardware_composer/impl/vr_composer_client.h
index 0b7ce5e..1b2b5f4 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.h
+++ b/services/vr/hardware_composer/impl/vr_composer_client.h
@@ -17,10 +17,12 @@
#ifndef ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_COMPOSER_CLIENT_H
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <composer-command-buffer/2.1/ComposerCommandBuffer.h>
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
+#include <composer-command-buffer/2.3/ComposerCommandBuffer.h>
#include <composer-hal/2.1/ComposerClient.h>
#include <composer-hal/2.1/ComposerCommandEngine.h>
+#include <composer-hal/2.2/ComposerClient.h>
+#include <composer-hal/2.3/ComposerClient.h>
namespace android {
namespace dvr {
@@ -28,8 +30,8 @@
class VrHwc;
using hardware::graphics::composer::V2_1::hal::ComposerCommandEngine;
-using hardware::graphics::composer::V2_1::hal::ComposerHal;
-using hardware::graphics::composer::V2_1::hal::detail::ComposerClientImpl;
+using hardware::graphics::composer::V2_3::hal::ComposerHal;
+using hardware::graphics::composer::V2_3::hal::detail::ComposerClientImpl;
using ComposerClient = ComposerClientImpl<IVrComposerClient, ComposerHal>;
@@ -44,8 +46,9 @@
explicit VrCommandEngine(VrComposerClient& client);
~VrCommandEngine() override;
- bool executeCommand(IComposerClient::Command command,
- uint16_t length) override;
+ bool executeCommand(
+ hardware::graphics::composer::V2_1::IComposerClient::Command command,
+ uint16_t length) override;
private:
bool executeSetLayerInfo(uint16_t length);
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index fb7932d..e530b16 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -27,7 +27,7 @@
#include "vr_composer_client.h"
using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_3;
using android::base::StringPrintf;
using android::hardware::hidl_handle;
@@ -36,12 +36,12 @@
using android::hardware::Return;
using android::hardware::Void;
+namespace types = android::hardware::graphics::common;
+
namespace android {
namespace dvr {
namespace {
-using android::hardware::graphics::common::V1_0::PixelFormat;
-
const Display kDefaultDisplayId = 1;
const Config kDefaultConfigId = 1;
@@ -269,7 +269,8 @@
// onHotplug() call, so it's important to release mutex_ here.
lock.unlock();
event_callback_->onHotplug(kDefaultDisplayId,
- IComposerCallback::Connection::CONNECTED);
+ hardware::graphics::composer::V2_1::
+ IComposerCallback::Connection::CONNECTED);
lock.lock();
UpdateVsyncCallbackEnabledLocked();
}
@@ -282,15 +283,6 @@
uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
-Error VrHwc::createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay) {
- *format = PixelFormat::RGBA_8888;
- *outDisplay = display_count_;
- displays_[display_count_].reset(new HwcDisplay(width, height));
- display_count_++;
- return Error::NONE;
-}
-
Error VrHwc::destroyVirtualDisplay(Display display) {
std::lock_guard<std::mutex> guard(mutex_);
if (display == kDefaultDisplayId || displays_.erase(display) == 0)
@@ -332,24 +324,6 @@
return Error::NONE;
}
-Error VrHwc::getClientTargetSupport(Display display, uint32_t /* width */,
- uint32_t /* height */,
- PixelFormat /* format */,
- Dataspace /* dataspace */) {
- std::lock_guard<std::mutex> guard(mutex_);
- if (!FindDisplay(display))
- return Error::BAD_DISPLAY;
-
- return Error::NONE;
-}
-
-Error VrHwc::getColorModes(Display /* display */,
- hidl_vec<ColorMode>* outModes) {
- std::vector<ColorMode> color_modes(1, ColorMode::NATIVE);
- *outModes = hidl_vec<ColorMode>(color_modes);
- return Error::NONE;
-}
-
Error VrHwc::getDisplayAttribute(Display display, Config config,
IComposerClient::Attribute attribute,
int32_t* outValue) {
@@ -441,17 +415,6 @@
return Error::NONE;
}
-Error VrHwc::getHdrCapabilities(Display /* display */,
- hidl_vec<Hdr>* /* outTypes */,
- float* outMaxLuminance,
- float* outMaxAverageLuminance,
- float* outMinLuminance) {
- *outMaxLuminance = 0;
- *outMaxAverageLuminance = 0;
- *outMinLuminance = 0;
- return Error::NONE;
-}
-
Error VrHwc::setActiveConfig(Display display, Config config) {
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
@@ -464,47 +427,6 @@
return Error::NONE;
}
-Error VrHwc::setColorMode(Display display, ColorMode mode) {
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
- return Error::BAD_PARAMETER;
-
- display_ptr->set_color_mode(mode);
- return Error::NONE;
-}
-
-Error VrHwc::setPowerMode(Display display, IComposerClient::PowerMode mode) {
- bool dozeSupported = false;
-
- Error dozeSupportError = getDozeSupport(display, &dozeSupported);
-
- if (dozeSupportError != Error::NONE)
- return dozeSupportError;
-
- std::lock_guard<std::mutex> guard(mutex_);
- auto display_ptr = FindDisplay(display);
- if (!display_ptr)
- return Error::BAD_DISPLAY;
-
- if (mode < IComposerClient::PowerMode::OFF ||
- mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
- return Error::BAD_PARAMETER;
- }
-
- if (!dozeSupported &&
- (mode == IComposerClient::PowerMode::DOZE ||
- mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
- return Error::UNSUPPORTED;
- }
-
- display_ptr->set_power_mode(mode);
- return Error::NONE;
-}
-
Error VrHwc::setVsyncEnabled(Display display, IComposerClient::Vsync enabled) {
std::lock_guard<std::mutex> guard(mutex_);
auto display_ptr = FindDisplay(display);
@@ -956,6 +878,23 @@
return Void();
}
+Return<void> VrHwc::createClient_2_3(IComposer::createClient_2_3_cb hidl_cb) {
+ std::lock_guard<std::mutex> guard(mutex_);
+
+ Error status = Error::NONE;
+ sp<VrComposerClient> client;
+ if (!client_.promote().get()) {
+ client = new VrComposerClient(*this);
+ } else {
+ ALOGE("Already have a client");
+ status = Error::NO_RESOURCES;
+ }
+
+ client_ = client;
+ hidl_cb(status, client);
+ return Void();
+}
+
void VrHwc::ForceDisplaysRefresh() {
std::lock_guard<std::mutex> guard(mutex_);
if (event_callback_ != nullptr) {
@@ -994,6 +933,26 @@
vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr);
}
+Return<void> VrHwc::debug(const hidl_handle& fd,
+ const hidl_vec<hidl_string>& args) {
+ std::string result;
+
+ {
+ std::lock_guard<std::mutex> guard(mutex_);
+ for (const auto& pair : displays_) {
+ result += StringPrintf("Display id: %d\n", static_cast<int>(pair.first));
+ pair.second->dumpDebugInfo(&result);
+ }
+ result += "\n";
+ }
+
+ FILE* out = fdopen(dup(fd->data[0]), "w");
+ fprintf(out, "%s", result.c_str());
+ fclose(out);
+
+ return Void();
+}
+
void HwcLayer::dumpDebugInfo(std::string* result) const {
if (!result) {
return;
@@ -1024,5 +983,196 @@
callback_ = callback;
}
+// composer::V2_2::ComposerHal
+Error VrHwc::setReadbackBuffer(Display display,
+ const native_handle_t* bufferHandle,
+ android::base::unique_fd fenceFd) {
+ return Error::NONE;
+}
+
+Error VrHwc::getReadbackBufferFence(Display display,
+ android::base::unique_fd* outFenceFd) {
+ return Error::NONE;
+}
+
+Error VrHwc::createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+ types::V1_1::PixelFormat* format,
+ Display* outDisplay) {
+ *format = types::V1_1::PixelFormat::RGBA_8888;
+ *outDisplay = display_count_;
+ displays_[display_count_].reset(new HwcDisplay(width, height));
+ display_count_++;
+ return Error::NONE;
+}
+
+Error VrHwc::setPowerMode_2_2(Display display,
+ IComposerClient::PowerMode mode) {
+ bool dozeSupported = false;
+
+ Error dozeSupportError = getDozeSupport(display, &dozeSupported);
+
+ if (dozeSupportError != Error::NONE)
+ return dozeSupportError;
+
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
+
+ if (mode < IComposerClient::PowerMode::OFF ||
+ mode > IComposerClient::PowerMode::DOZE_SUSPEND) {
+ return Error::BAD_PARAMETER;
+ }
+
+ if (!dozeSupported && (mode == IComposerClient::PowerMode::DOZE ||
+ mode == IComposerClient::PowerMode::DOZE_SUSPEND)) {
+ return Error::UNSUPPORTED;
+ }
+
+ display_ptr->set_power_mode(mode);
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerFloatColor(Display display, Layer layer,
+ IComposerClient::FloatColor color) {
+ return Error::NONE;
+}
+
+Error VrHwc::getRenderIntents(Display display, types::V1_1::ColorMode mode,
+ std::vector<RenderIntent>* outIntents) {
+ return Error::NONE;
+}
+
+std::array<float, 16> VrHwc::getDataspaceSaturationMatrix(
+ types::V1_1::Dataspace dataspace) {
+ return {};
+}
+
+// composer::V2_3::ComposerHal
+Error VrHwc::getHdrCapabilities_2_3(Display /*display*/,
+ hidl_vec<Hdr>* /*outTypes*/,
+ float* outMaxLuminance,
+ float* outMaxAverageLuminance,
+ float* outMinLuminance) {
+ *outMaxLuminance = 0;
+ *outMaxAverageLuminance = 0;
+ *outMinLuminance = 0;
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerPerFrameMetadata_2_3(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& metadata) {
+ return Error::NONE;
+}
+
+Error VrHwc::getPerFrameMetadataKeys_2_3(
+ Display display,
+ std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
+ return Error::NONE;
+}
+
+Error VrHwc::setColorMode_2_3(Display display, ColorMode mode,
+ RenderIntent intent) {
+ std::lock_guard<std::mutex> guard(mutex_);
+ auto display_ptr = FindDisplay(display);
+ if (!display_ptr)
+ return Error::BAD_DISPLAY;
+
+ if (mode < ColorMode::NATIVE || mode > ColorMode::DISPLAY_P3)
+ return Error::BAD_PARAMETER;
+
+ display_ptr->set_color_mode(mode);
+ return Error::NONE;
+}
+
+Error VrHwc::getRenderIntents_2_3(Display display, ColorMode mode,
+ std::vector<RenderIntent>* outIntents) {
+ return Error::NONE;
+}
+
+Error VrHwc::getColorModes_2_3(Display display, hidl_vec<ColorMode>* outModes) {
+ return Error::NONE;
+}
+
+Error VrHwc::getClientTargetSupport_2_3(Display display, uint32_t width,
+ uint32_t height, PixelFormat format,
+ Dataspace dataspace) {
+ return Error::NONE;
+}
+
+Error VrHwc::getReadbackBufferAttributes_2_3(Display display,
+ PixelFormat* outFormat,
+ Dataspace* outDataspace) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) {
+ int error = 0;
+ auto display_client = display::DisplayClient::Create(&error);
+ if (!display_client) {
+ ALOGE("Could not connect to display service : %s(%d)", strerror(error),
+ error);
+ return Error::BAD_CONFIG;
+ }
+ auto edid_data = display_client->GetConfigurationData(
+ display::ConfigFileType::kDeviceEdid);
+ auto display_identification_port =
+ display_client->GetDisplayIdentificationPort();
+ *outPort = display_identification_port.get();
+
+ std::copy(edid_data.get().begin(), edid_data.get().end(),
+ std::back_inserter(*outData));
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerColorTransform(Display display, Layer layer,
+ const float* matrix) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayedContentSamplingAttributes(
+ Display display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask) {
+ return Error::NONE;
+}
+
+Error VrHwc::setDisplayedContentSamplingEnabled(
+ Display display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayedContentSample(Display display, uint64_t maxFrames,
+ uint64_t timestamp, uint64_t& frameCount,
+ hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayCapabilities(
+ Display display,
+ std::vector<IComposerClient::DisplayCapability>* outCapabilities) {
+ return Error::NONE;
+}
+
+Error VrHwc::setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) {
+ return Error::NONE;
+}
+
+Error VrHwc::getDisplayBrightnessSupport(Display display, bool* outSupport) {
+ return Error::NONE;
+}
+
+Error VrHwc::setDisplayBrightness(Display display, float brightness) {
+ return Error::NONE;
+}
+
} // namespace dvr
} // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index e8c0212..3e3a630 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -17,9 +17,9 @@
#define ANDROID_DVR_HARDWARE_COMPOSER_IMPL_VR_HWC_H
#include <android-base/unique_fd.h>
-#include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
-#include <android/hardware/graphics/composer/2.1/IComposer.h>
-#include <composer-hal/2.1/ComposerHal.h>
+#include <android/frameworks/vr/composer/2.0/IVrComposerClient.h>
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <composer-hal/2.3/ComposerHal.h>
#include <private/dvr/vsync_service.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
@@ -28,15 +28,21 @@
#include <mutex>
#include <unordered_map>
-using namespace android::frameworks::vr::composer::V1_0;
+using namespace android::frameworks::vr::composer::V2_0;
using namespace android::hardware::graphics::common::V1_0;
-using namespace android::hardware::graphics::composer::V2_1;
+using namespace android::hardware::graphics::composer::V2_3;
+using android::hardware::hidl_bitfield;
using android::hardware::hidl_handle;
using android::hardware::hidl_string;
using android::hardware::hidl_vec;
using android::hardware::Return;
using android::hardware::Void;
+using android::hardware::graphics::composer::V2_1::Config;
+using android::hardware::graphics::composer::V2_1::Display;
+using android::hardware::graphics::composer::V2_1::Error;
+using android::hardware::graphics::composer::V2_1::Layer;
+using android::hardware::graphics::composer::V2_3::IComposerClient;
namespace android {
@@ -46,16 +52,23 @@
class VrComposerClient;
-using android::hardware::graphics::common::V1_0::PixelFormat;
-using android::hardware::graphics::composer::V2_1::hal::ComposerHal;
+using android::hardware::graphics::composer::V2_3::hal::ComposerHal;
+
+namespace types = android::hardware::graphics::common;
+
+using types::V1_1::RenderIntent;
+using types::V1_2::ColorMode;
+using types::V1_2::Dataspace;
+using types::V1_2::Hdr;
+using types::V1_2::PixelFormat;
class ComposerView {
public:
struct ComposerLayer {
- using Recti = hardware::graphics::composer::V2_1::IComposerClient::Rect;
- using Rectf = hardware::graphics::composer::V2_1::IComposerClient::FRect;
+ using Recti = hardware::graphics::composer::V2_3::IComposerClient::Rect;
+ using Rectf = hardware::graphics::composer::V2_3::IComposerClient::FRect;
using BlendMode =
- hardware::graphics::composer::V2_1::IComposerClient::BlendMode;
+ hardware::graphics::composer::V2_3::IComposerClient::BlendMode;
Layer id;
sp<GraphicBuffer> buffer;
@@ -111,7 +124,7 @@
struct HwcLayer {
using Composition =
- hardware::graphics::composer::V2_1::IComposerClient::Composition;
+ hardware::graphics::composer::V2_3::IComposerClient::Composition;
explicit HwcLayer(Layer new_id) { info.id = new_id; }
@@ -205,96 +218,157 @@
Display display, Layer layer,
const IVrComposerClient::BufferMetadata& metadata);
- // ComposerHal
+ // composer::V2_1::ComposerHal
bool hasCapability(hwc2_capability_t capability) override;
std::string dumpDebugInfo() override { return {}; }
- void registerEventCallback(EventCallback* callback) override;
+
+ void registerEventCallback(ComposerHal::EventCallback* callback) override;
void unregisterEventCallback() override;
uint32_t getMaxVirtualDisplayCount() override;
- Error createVirtualDisplay(uint32_t width, uint32_t height,
- PixelFormat* format, Display* outDisplay) override;
Error destroyVirtualDisplay(Display display) override;
Error createLayer(Display display, Layer* outLayer) override;
Error destroyLayer(Display display, Layer layer) override;
Error getActiveConfig(Display display, Config* outConfig) override;
- Error getClientTargetSupport(Display display,
- uint32_t width, uint32_t height,
- PixelFormat format, Dataspace dataspace) override;
- Error getColorModes(Display display, hidl_vec<ColorMode>* outModes) override;
Error getDisplayAttribute(Display display, Config config,
- IComposerClient::Attribute attribute, int32_t* outValue) override;
+ IComposerClient::Attribute attribute,
+ int32_t* outValue) override;
Error getDisplayConfigs(Display display, hidl_vec<Config>* outConfigs) override;
Error getDisplayName(Display display, hidl_string* outName) override;
Error getDisplayType(Display display,
- IComposerClient::DisplayType* outType) override;
+ IComposerClient::DisplayType* outType) override;
Error getDozeSupport(Display display, bool* outSupport) override;
- Error getHdrCapabilities(Display display, hidl_vec<Hdr>* outTypes,
- float* outMaxLuminance, float* outMaxAverageLuminance,
- float* outMinLuminance) override;
Error setActiveConfig(Display display, Config config) override;
- Error setColorMode(Display display, ColorMode mode) override;
- Error setPowerMode(Display display, IComposerClient::PowerMode mode) override;
Error setVsyncEnabled(Display display, IComposerClient::Vsync enabled) override;
Error setColorTransform(Display display, const float* matrix,
- int32_t hint) override;
+ int32_t hint) override;
Error setClientTarget(Display display, buffer_handle_t target,
- int32_t acquireFence, int32_t dataspace,
- const std::vector<hwc_rect_t>& damage) override;
+ int32_t acquireFence, int32_t dataspace,
+ const std::vector<hwc_rect_t>& damage) override;
Error setOutputBuffer(Display display, buffer_handle_t buffer,
- int32_t releaseFence) override;
- Error validateDisplay(Display display,
- std::vector<Layer>* outChangedLayers,
- std::vector<IComposerClient::Composition>* outCompositionTypes,
- uint32_t* outDisplayRequestMask,
- std::vector<Layer>* outRequestedLayers,
- std::vector<uint32_t>* outRequestMasks) override;
+ int32_t releaseFence) override;
+ Error validateDisplay(
+ Display display, std::vector<Layer>* outChangedLayers,
+ std::vector<IComposerClient::Composition>* outCompositionTypes,
+ uint32_t* outDisplayRequestMask, std::vector<Layer>* outRequestedLayers,
+ std::vector<uint32_t>* outRequestMasks) override;
Error acceptDisplayChanges(Display display) override;
Error presentDisplay(Display display, int32_t* outPresentFence,
- std::vector<Layer>* outLayers,
- std::vector<int32_t>* outReleaseFences) override;
+ std::vector<Layer>* outLayers,
+ std::vector<int32_t>* outReleaseFences) override;
- Error setLayerCursorPosition(Display display, Layer layer,
- int32_t x, int32_t y) override;
- Error setLayerBuffer(Display display, Layer layer,
- buffer_handle_t buffer, int32_t acquireFence) override;
+ Error setLayerCursorPosition(Display display, Layer layer, int32_t x,
+ int32_t y) override;
+ Error setLayerBuffer(Display display, Layer layer, buffer_handle_t buffer,
+ int32_t acquireFence) override;
Error setLayerSurfaceDamage(Display display, Layer layer,
- const std::vector<hwc_rect_t>& damage) override;
+ const std::vector<hwc_rect_t>& damage) override;
Error setLayerBlendMode(Display display, Layer layer, int32_t mode) override;
Error setLayerColor(Display display, Layer layer,
- IComposerClient::Color color) override;
+ IComposerClient::Color color) override;
Error setLayerCompositionType(Display display, Layer layer,
- int32_t type) override;
+ int32_t type) override;
Error setLayerDataspace(Display display, Layer layer,
- int32_t dataspace) override;
+ int32_t dataspace) override;
Error setLayerDisplayFrame(Display display, Layer layer,
- const hwc_rect_t& frame) override;
+ const hwc_rect_t& frame) override;
Error setLayerPlaneAlpha(Display display, Layer layer, float alpha) override;
Error setLayerSidebandStream(Display display, Layer layer,
- buffer_handle_t stream) override;
+ buffer_handle_t stream) override;
Error setLayerSourceCrop(Display display, Layer layer,
- const hwc_frect_t& crop) override;
+ const hwc_frect_t& crop) override;
Error setLayerTransform(Display display, Layer layer,
- int32_t transform) override;
+ int32_t transform) override;
Error setLayerVisibleRegion(Display display, Layer layer,
- const std::vector<hwc_rect_t>& visible) override;
+ const std::vector<hwc_rect_t>& visible) override;
Error setLayerZOrder(Display display, Layer layer, uint32_t z) override;
+ // composer::V2_2::ComposerHal
+ Error setReadbackBuffer(Display display, const native_handle_t* bufferHandle,
+ android::base::unique_fd fenceFd) override;
+ Error getReadbackBufferFence(Display display,
+ android::base::unique_fd* outFenceFd) override;
+ Error createVirtualDisplay_2_2(uint32_t width, uint32_t height,
+ types::V1_1::PixelFormat* format,
+ Display* outDisplay) override;
+ Error setPowerMode_2_2(Display display,
+ IComposerClient::PowerMode mode) override;
+ Error setLayerFloatColor(Display display, Layer layer,
+ IComposerClient::FloatColor color) override;
+ Error getRenderIntents(Display display, types::V1_1::ColorMode mode,
+ std::vector<RenderIntent>* outIntents) override;
+ std::array<float, 16> getDataspaceSaturationMatrix(
+ types::V1_1::Dataspace dataspace) override;
+
+ // composer::V2_3::ComposerHal
+ Error getHdrCapabilities_2_3(Display display, hidl_vec<Hdr>* outTypes,
+ float* outMaxLuminance,
+ float* outMaxAverageLuminance,
+ float* outMinLuminance) override;
+ Error setLayerPerFrameMetadata_2_3(
+ Display display, Layer layer,
+ const std::vector<IComposerClient::PerFrameMetadata>& metadata) override;
+ Error getPerFrameMetadataKeys_2_3(
+ Display display,
+ std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
+ Error setColorMode_2_3(Display display, ColorMode mode,
+ RenderIntent intent) override;
+ Error getRenderIntents_2_3(Display display, ColorMode mode,
+ std::vector<RenderIntent>* outIntents) override;
+ Error getColorModes_2_3(Display display,
+ hidl_vec<ColorMode>* outModes) override;
+ Error getClientTargetSupport_2_3(Display display, uint32_t width,
+ uint32_t height, PixelFormat format,
+ Dataspace dataspace) override;
+ Error getReadbackBufferAttributes_2_3(Display display, PixelFormat* outFormat,
+ Dataspace* outDataspace) override;
+ Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+ std::vector<uint8_t>* outData) override;
+ Error setLayerColorTransform(Display display, Layer layer,
+ const float* matrix) override;
+ Error getDisplayedContentSamplingAttributes(
+ Display display, PixelFormat& format, Dataspace& dataspace,
+ hidl_bitfield<IComposerClient::FormatColorComponent>& componentMask)
+ override;
+ Error setDisplayedContentSamplingEnabled(
+ Display display, IComposerClient::DisplayedContentSampling enable,
+ hidl_bitfield<IComposerClient::FormatColorComponent> componentMask,
+ uint64_t maxFrames) override;
+ Error getDisplayedContentSample(
+ Display display, uint64_t maxFrames, uint64_t timestamp,
+ uint64_t& frameCount, hidl_vec<uint64_t>& sampleComponent0,
+ hidl_vec<uint64_t>& sampleComponent1,
+ hidl_vec<uint64_t>& sampleComponent2,
+ hidl_vec<uint64_t>& sampleComponent3) override;
+ Error getDisplayCapabilities(Display display,
+ std::vector<IComposerClient::DisplayCapability>*
+ outCapabilities) override;
+ Error setLayerPerFrameMetadataBlobs(
+ Display display, Layer layer,
+ std::vector<IComposerClient::PerFrameMetadataBlob>& blobs) override;
+ Error getDisplayBrightnessSupport(Display display, bool* outSupport) override;
+ Error setDisplayBrightness(Display display, float brightness) override;
+
// IComposer:
Return<void> getCapabilities(getCapabilities_cb hidl_cb) override;
Return<void> dumpDebugInfo(dumpDebugInfo_cb hidl_cb) override;
Return<void> createClient(createClient_cb hidl_cb) override;
+ Return<void> createClient_2_3(
+ IComposer::createClient_2_3_cb hidl_cb) override;
// ComposerView:
void ForceDisplaysRefresh() override;
void RegisterObserver(Observer* observer) override;
void UnregisterObserver(Observer* observer) override;
+ Return<void> debug(const hidl_handle& fd,
+ const hidl_vec<hidl_string>& args) override;
+
private:
class VsyncCallback : public BnVsyncCallback {
public:
diff --git a/services/vr/virtual_touchpad/virtual_touchpad.rc b/services/vr/virtual_touchpad/virtual_touchpad.rc
index 99315ef..0de0f9e 100644
--- a/services/vr/virtual_touchpad/virtual_touchpad.rc
+++ b/services/vr/virtual_touchpad/virtual_touchpad.rc
@@ -1,5 +1,5 @@
service virtual_touchpad /system/bin/virtual_touchpad
class core
user system
- group system input
+ group system input uhid
writepid /dev/cpuset/system/tasks
diff --git a/vulkan/Android.bp b/vulkan/Android.bp
index 7747734..4934970 100644
--- a/vulkan/Android.bp
+++ b/vulkan/Android.bp
@@ -31,6 +31,5 @@
subdirs = [
"nulldrv",
"libvulkan",
- "tools",
"vkjson",
]
diff --git a/vulkan/README.md b/vulkan/README.md
index 9fba728..185aa39 100644
--- a/vulkan/README.md
+++ b/vulkan/README.md
@@ -2,6 +2,10 @@
This subdirectory contains Android's Vulkan loader, as well as some Vulkan-related tools useful to platform developers.
+## Documentation
+
+The former contents of doc/implementors_guide/ are now at https://source.android.com/devices/graphics/implement-vulkan.
+
## Coding Style
We follow the [Chromium coding style](https://www.chromium.org/developers/coding-style) for naming and formatting, except with four-space indentation instead of two spaces. In general, any C++ features supported by the prebuilt platform toolchain are allowed.
@@ -10,19 +14,9 @@
## Code Generation
-We generate several parts of the loader and tools from a Vulkan API description file, stored in `api/vulkan.api`. Code generation must be done manually because the generator tools aren't part of the platform toolchain (yet?). Files named `foo_gen.*` are generated from the API file and a template file named `foo.tmpl`.
+We generate several parts of the loader and tools driectly from the Vulkan Registry (external/vulkan-headers/registry/vk.xml). Code generation must be done manually because the generator is not part of the platform toolchain (yet?). Files named `foo_gen.*` are generated by the code generator.
- To run the generator:
+### Run The Code Generator
-### One-time setup
-- Install [golang](https://golang.org/), if you don't have it already.
-- Create a directory (e.g. `$HOME/lib/go`) for local go sources and binaries and add it to `$GOPATH`.
-- `$ git clone https://android.googlesource.com/platform/tools/gpu $GOPATH/src/android.googlesource.com/platform/tools/gpu`
-- `$ go get android.googlesource.com/platform/tools/gpu/api/...`
-- You should now have `$GOPATH/bin/apic`. You might want to add `$GOPATH/bin` to your `$PATH`.
-
-### Generating code
-To generate `libvulkan/*_gen.*`,
-- `$ cd libvulkan`
-- `$ apic template ../api/vulkan.api code-generator.tmpl`
-Similar for `nulldrv/null_driver_gen.*`.
+Install Python3 (if not already installed) and execute below:
+`$ ./scripts/code_generator.py`
diff --git a/vulkan/api/platform.api b/vulkan/api/platform.api
deleted file mode 100644
index a7c4c30..0000000
--- a/vulkan/api/platform.api
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2015 The Khronos Group Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and/or associated documentation files (the
-// "Materials"), to deal in the Materials without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Materials, and to
-// permit persons to whom the Materials are furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Materials.
-//
-// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-
-// Platform types, as defined or included in vk_platform.h
-
-type u64 size_t
-
-// VK_USE_PLATFORM_XLIB_KHR
-@internal class Display {}
-@internal class Window {}
-@internal type u64 VisualID
-
-// VK_USE_PLATFORM_XCB_KHR
-@internal class xcb_connection_t {}
-@internal type u32 xcb_window_t
-@internal type u32 xcb_visualid_t
-
-// VK_USE_PLATFORM_WAYLAND_KHR
-@internal class wl_display {}
-@internal class wl_surface {}
-
-// VK_USE_PLATFORM_MIR_KHR
-@internal class MirConnection {}
-@internal class MirSurface {}
-
-// VK_USE_PLATFORM_ANDROID_KHR
-@internal class ANativeWindow {}
-@internal class AHardwareBuffer {}
-@internal type void* buffer_handle_t
-
-// VK_USE_PLATFORM_WIN32_KHR
-@internal type void* HINSTANCE
-@internal type void* HWND
-@internal type void* HANDLE
-@internal type u32 DWORD
-@internal type u16* LPCWSTR
-@internal class SECURITY_ATTRIBUTES {}
-
-// VK_USE_PLATFORM_XLIB_XRANDR_EXT
-@internal type u64 RROutput
-
-// VK_USE_PLATFORM_FUCHSIA
-@internal type u32 zx_handle_t
\ No newline at end of file
diff --git a/vulkan/api/templates/asciidoc.tmpl b/vulkan/api/templates/asciidoc.tmpl
deleted file mode 100644
index 3009e19..0000000
--- a/vulkan/api/templates/asciidoc.tmpl
+++ /dev/null
@@ -1,151 +0,0 @@
-{{Include "vulkan_common.tmpl"}}
-{{if not (Global "AsciiDocPath")}}{{Global "AsciiDocPath" "../../doc/specs/vulkan/"}}{{end}}
-{{$ | Macro "AsciiDoc.Main"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- AsciiDoc generation main entry point.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Main"}}
- {{$docPath := Global "AsciiDocPath"}}
-
- {{/* Generate AsciiDoc files for API enums and bitfields (flags). */}}
- {{range $e := $.Enums}}
- {{if not $e.IsBitfield}}
- {{$filename := print $docPath "enums/" (Macro "EnumName" $e) ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Enum" $e) "File" $filename}}
- {{else}}
- {{$filename := print $docPath "flags/" (Macro "EnumName" $e) ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Flag" $e) "File" $filename}}
- {{end}}
- {{end}}
-
- {{/* Generate AsciiDoc files for API commands (protos). */}}
- {{range $f := (AllCommands $)}}
- {{if not (GetAnnotation $f "pfn")}}
- {{$filename := print $docPath "protos/" $f.Name ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Proto" $f) "File" $filename}}
- {{end}}
- {{end}}
-
- {{/* Generate AsciiDoc files for API structs. */}}
- {{range $c := $.Classes}}
- {{if not (GetAnnotation $c "internal")}}
- {{$filename := print $docPath "structs/" $c.Name ".txt"}}
- {{Macro "AsciiDoc.Write" "Code" (Macro "AsciiDoc.Struct" $c) "File" $filename}}
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Enum"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef enum {
- {{range $i, $e := $.Entries}}
- {{Macro "EnumEntry" $e}} = {{AsSigned $e.Value}}, {{Macro "Docs" $e.Docs}}
- {{end}}
- ¶
- {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}}
- {{$first := Macro "EnumFirstEntry" $}}
- {{$last := Macro "EnumLastEntry" $}}
- {{$name}}_BEGIN_RANGE = {{$first}},
- {{$name}}_END_RANGE = {{$last}},
- {{$name}}_NUM = ({{$last}} - {{$first}} + 1),
- {{$name}}_MAX_ENUM = 0x7FFFFFFF
- } {{Macro "EnumName" $}};
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API bitfield.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Flag"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef VkFlags {{Macro "EnumName" $}};
- {{if $.Entries}}
- typedef enum {
- {{range $e := $.Entries}}
- {{Macro "BitfieldEntryName" $e}} = {{printf "%#.8x" $e.Value}}, {{Macro "Docs" $e.Docs}}
- {{end}}
- } {{Macro "EnumName" $ | TrimRight "s"}}Bits;
- {{end}}
-{{end}}
-
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API class.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Struct"}}
- {{AssertType $ "Class"}}
-
- {{Macro "Docs" $.Docs}}
- typedef {{if GetAnnotation $ "union"}}union{{else}}struct{{end}} {
- {{range $f := $.Fields}}
- {{Node "Type" $f}} {{$f.Name}}{{Macro "ArrayPostfix" (TypeOf $f)}}; {{Macro "Docs" $f.Docs}}
- {{end}}
- } {{Macro "StructName" $}};
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the AsciiDoc contents for the specified API function.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Proto"}}
- {{AssertType $ "Function"}}
-
- {{Macro "Docs" $.Docs}}
- {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}});
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Wraps the specified Code in AsciiDoc source tags then writes to the specified File.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Write"}}
- {{AssertType $.Code "string"}}
- {{AssertType $.File "string"}}
-
- {{$code := $.Code | Format (Global "clang-format")}}
- {{JoinWith "\n" (Macro "AsciiDoc.Header") $code (Macro "AsciiDoc.Footer") ""| Write $.File}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits an AsciiDoc source header.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Header"}}
-[source,{basebackend@docbook:c++:cpp}]
-------------------------------------------------------------------------------
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits an AsciiDoc source footer.
--------------------------------------------------------------------------------
-*/}}
-{{define "AsciiDoc.Footer"}}
-------------------------------------------------------------------------------
-{{end}}
diff --git a/vulkan/api/templates/vk_xml.tmpl b/vulkan/api/templates/vk_xml.tmpl
deleted file mode 100644
index 893bde7..0000000
--- a/vulkan/api/templates/vk_xml.tmpl
+++ /dev/null
@@ -1,435 +0,0 @@
-{{Include "vulkan_common.tmpl"}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "vk.xml" | Reflow 4 | Write "vk.xml"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Entry point
--------------------------------------------------------------------------------
-*/}}
-{{define "vk.xml"}}
-<?xml version="1.0" encoding="UTF-8"?>
-<registry>
- »<comment>«
-Copyright (c) 2015 The Khronos Group Inc.
-¶
-Permission is hereby granted, free of charge, to any person obtaining a
-copy of this software and/or associated documentation files (the
-"Materials"), to deal in the Materials without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Materials, and to
-permit persons to whom the Materials are furnished to do so, subject to
-the following conditions:
-¶
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Materials.
-¶
-THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-¶
-------------------------------------------------------------------------
-¶
-This file, vk.xml, is the Vulkan API Registry.»
- </comment>
-¶
- <!-- SECTION: Vulkan type definitions -->
- <types>»
- <type name="vk_platform" category="include">#include "vk_platform.h"</type>
-¶
- <type category="define">#define <name>VK_MAKE_VERSION</name>(major, minor, patch) \
- «((major << 22) | (minor << 12) | patch)</type>»
-¶
- <type category="define">// Vulkan API version supported by this file««
-#define <name>VK_API_VERSION</name> <type>VK_MAKE_VERSION</type>({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})</type>
-¶
- »»<type category="define">««
-#if (_MSC_VER >= 1800 || __cplusplus >= 201103L)
-#define <name>VK_NONDISP_HANDLE_OPERATOR_BOOL</name>() explicit operator bool() const { return handle != 0; }
-#else
-#define VK_NONDISP_HANDLE_OPERATOR_BOOL()
-«#endif
- »»»</type>
-¶
- <type category="define">«««
-#define <name>VK_DEFINE_HANDLE</name>(obj) typedef struct obj##_T* obj;</type>
- »»»<type category="define">«««
-#if defined(__cplusplus)
- »»#if (_MSC_VER >= 1800 || __cplusplus >= 201103L)
- »// The bool operator only works if there are no implicit conversions from an obj to
- // a bool-compatible type, which can then be used to unintentionally violate type safety.
- // C++11 and above supports the "explicit" keyword on conversion operators to stop this
- // from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating
- // the object handle as a bool in expressions like:
- // if (obj) vkDestroy(obj);
- #define VK_NONDISP_HANDLE_OPERATOR_BOOL() explicit operator bool() const { return handle != 0; }
- #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- explicit obj(uint64_t x) : handle(x) { } \
- obj(decltype(nullptr)) : handle(0) { }
- «#else»
- #define VK_NONDISP_HANDLE_OPERATOR_BOOL()
- #define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj(uint64_t x) : handle(x) { }
- «#endif
- #define <name>VK_DEFINE_NONDISP_HANDLE</name>(obj) \»
- struct obj { \
- obj() { } \
- VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj& operator =(uint64_t x) { handle = x; return *this; } \
- bool operator==(const obj& other) const { return handle == other.handle; } \
- bool operator!=(const obj& other) const { return handle != other.handle; } \
- bool operator!() const { return !handle; } \
- VK_NONDISP_HANDLE_OPERATOR_BOOL() \
- uint64_t handle; \
- };
-««#else
- »#define VK_DEFINE_NONDISP_HANDLE(obj) typedef struct obj##_T { uint64_t handle; } obj;«
-#endif
- »»</type>
-¶
- <type category="define">
-#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800) || __cplusplus >= 201103L)
- »#define <name>VK_NULL_HANDLE</name> nullptr
-«#else
- »#define VK_NULL_HANDLE 0
-«#endif
- »»</type>
-¶
- <type requires="vk_platform" name="VkDeviceSize"/>
- <type requires="vk_platform" name="VkSampleMask"/>
- <type requires="vk_platform" name="VkFlags"/>
- <!-- Basic C types, pulled in via vk_platform.h -->
- <type requires="vk_platform" name="char"/>
- <type requires="vk_platform" name="float"/>
- <type requires="vk_platform" name="VkBool32"/>
- <type requires="vk_platform" name="uint8_t"/>
- <type requires="vk_platform" name="uint32_t"/>
- <type requires="vk_platform" name="uint64_t"/>
- <type requires="vk_platform" name="int32_t"/>
- <type requires="vk_platform" name="size_t"/>
- <!-- Bitfield types -->
- {{range $e := $.Enums}}
- {{if $e.IsBitfield}}
- {{$bits := print (Macro "EnumName" $e | TrimRight "s") "Bits"}}
- <type{{if $e.Entries}} requires="{{$bits}}"{{end}} category="bitmask">typedef <type>VkFlags</type> <name>{{$e.Name}}</name>;</type>§
- {{if $e.Entries}}{{Macro "XML.Docs" $e.Docs}}
- {{else}}{{Macro "XML.Docs" (Strings $e.Docs "(no bits yet)")}}
- {{end}}
- {{end}}
- {{end}}
-¶
- <!-- Types which can be void pointers or class pointers, selected at compile time -->
- {{range $i, $p := $.Pseudonyms}}
- {{ if (GetAnnotation $p "dispatchHandle")}}
- {{if Global "VK_DEFINE_HANDLE_TYPE_DEFINED"}}
- <type category="handle">VK_DEFINE_HANDLE(<name>{{$p.Name}}</name>)</type>
- {{else}}
- {{Global "VK_DEFINE_HANDLE_TYPE_DEFINED" "YES"}}
- <type category="handle"><type>VK_DEFINE_HANDLE</type>(<name>{{$p.Name}}</name>)</type>
- {{end}}
- {{else if (GetAnnotation $p "nonDispatchHandle")}}
- {{if Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED"}}
- <type category="handle">VK_DEFINE_NONDISP_HANDLE(<name>{{$p.Name}}</name>)</type>
- {{else}}
- {{Global "VK_DEFINE_NONDISP_HANDLE_TYPE_DEFINED" "YES"}}
- <type category="handle"><type>VK_DEFINE_NONDISP_HANDLE</type>(<name>{{$p.Name}}</name>)</type>
- {{end}}
- {{end}}
- {{end}}
-¶
- <!-- Types generated from corresponding <enums> tags below -->
- {{range $e := SortBy $.Enums "EnumName"}}
- {{if and $e.Entries (not (GetAnnotation $e "internal"))}}
- {{if $e.IsBitfield}}
- <type name="{{Macro "EnumName" $e | TrimRight "s"}}Bits" category="enum"/>
- {{else}}
- <type name="{{$e.Name}}" category="enum"/>
- {{end}}
- {{end}}
- {{end}}
-¶
- <!-- The PFN_vk*Function types are used by VkAllocCallbacks below -->
- <type>typedef void* (VKAPI *<name>PFN_vkAllocFunction</name>)(«
- void* pUserData,
- size_t size,
- size_t alignment,
- <type>VkSystemAllocType</type> allocType);</type>»
- <type>typedef void (VKAPI *<name>PFN_vkFreeFunction</name>)(«
- void* pUserData,
- void* pMem);</type>»
-¶
- <!-- The PFN_vkVoidFunction type are used by VkGet*ProcAddr below -->
- <type>typedef void (VKAPI *<name>PFN_vkVoidFunction</name>)(void);</type>
-¶
- <!-- Struct types -->
- {{range $c := $.Classes}}
- {{if not (GetAnnotation $c "internal")}}
- {{Macro "Struct" $c}}
- {{end}}
- {{end}}
- «</types>
-¶
- <!-- SECTION: Vulkan enumerant (token) definitions. -->
-¶
- <enums namespace="VK" comment="Misc. hardcoded constants - not an enumerated type">»
- <!-- This is part of the header boilerplate -->
- {{range $d := $.Definitions}}
- {{if HasPrefix $d.Name "VK_"}}
- <enum value="{{$d.Expression}}" name="{{$d.Name}}"/>{{Macro "XML.Docs" $d.Docs}}
- {{end}}
- {{end}}
- <enum value="1000.0f" name="VK_LOD_CLAMP_NONE"/>
- <enum value="(-0U)" name="VK_REMAINING_MIP_LEVELS"/>
- <enum value="(~0U)" name="VK_REMAINING_ARRAY_LAYERS"/>
- <enum value="(_0ULL)" name="VK_WHOLE_SIZE"/>
- <enum value="(~0U)" name="VK_ATTACHMENT_UNUSED"/>
- <enum value="(~0U)" name="VK_QUEUE_FAMILY_IGNORED"/>
- <enum value="(~0U)" name="VK_SUBPASS_EXTERNAL"/>
- «</enums>
-¶
- <!-- Unlike OpenGL, most tokens in Vulkan are actual typed enumerants in»
- their own numeric namespaces. The "name" attribute is the C enum
- type name, and is pulled in from a <type> definition above
- (slightly clunky, but retains the type / enum distinction). "type"
- attributes of "enum" or "bitmask" indicate that these values should
- be generated inside an appropriate definition. -->«
-¶
- {{range $e := $.Enums}}
- {{if not (or $e.IsBitfield (GetAnnotation $e "internal"))}}
- {{Macro "XML.Enum" $e}}
- {{end}}
- {{end}}
-¶
- <!-- Flags -->
- {{range $e := $.Enums}}
- {{if $e.IsBitfield}}
- {{Macro "XML.Bitfield" $e}}
- {{end}}
- {{end}}
-¶
- <!-- SECTION: Vulkan command definitions -->
- <commands namespace="vk">»
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- {{Macro "XML.Function" $f}}
- {{end}}
- {{end}}
- «</commands>
-¶
- <!-- SECTION: Vulkan API interface definitions -->
- <feature api="vulkan" name="VK_VERSION_1_0" number="1.0">»
- <require comment="Header boilerplate">»
- <type name="vk_platform"/>
- «</require>
- <require comment="API version">»
- <type name="VK_API_VERSION"/>
- «</require>
- <require comment="API constants">»
- <enum name="VK_LOD_CLAMP_NONE"/>
- <enum name="VK_REMAINING_MIP_LEVELS"/>
- <enum name="VK_REMAINING_ARRAY_LAYERS"/>
- <enum name="VK_WHOLE_SIZE"/>
- <enum name="VK_ATTACHMENT_UNUSED"/>
- <enum name="VK_TRUE"/>
- <enum name="VK_FALSE"/>
- «</require>
- <require comment="All functions (TODO: split by type)">»
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- <command name="{{$f.Name}}"/>
- {{end}}
- {{end}}
- </require>
- «<require comment="Types not directly used by the API">»
- <!-- Include <type name="typename"/> here for e.g. structs that»
- are not parameter types of commands, but still need to be
- defined in the API.
- «-->
- <type name="VkBufferMemoryBarrier"/>
- <type name="VkDispatchIndirectCmd"/>
- <type name="VkDrawIndexedIndirectCmd"/>
- <type name="VkDrawIndirectCmd"/>
- <type name="VkImageMemoryBarrier"/>
- <type name="VkMemoryBarrier"/>
- «</require>
- «</feature>
-¶
- <!-- SECTION: Vulkan extension interface definitions (none yet) -->
-«</registry>
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified bitfield.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Bitfield"}}
- {{AssertType $ "Enum"}}
-
- {{if $.Entries}}
- <enums namespace="VK" name="{{Macro "EnumName" $ | TrimRight "s"}}Bits" type="bitmask">»
- {{range $e := $.Entries}}
- {{$pos := Bitpos $e.Value}}
- <enum §
- {{if gt $pos -1}} bitpos="{{$pos}}" §
- {{else}}value="{{if $e.Value}}{{printf "0x%.8X" $e.Value}}{{else}}0{{end}}" §
- {{end}}name="{{Macro "BitfieldEntryName" $e}}" §
- {{if $d := $e.Docs}} comment="{{$d | JoinWith " "}}"{{end}}/>
- {{end}}
- «</enums>
- {{end}}
-
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Enum"}}
- {{AssertType $ "Enum"}}
-
- <enums namespace="VK" name="{{Macro "EnumName" $}}" type="enum" §
- expand="{{Macro "EnumName" $ | SplitPascalCase | Upper | JoinWith "_"}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>»
- {{range $i, $e := $.Entries}}
- <enum value="{{AsSigned $e.Value}}" name="{{Macro "BitfieldEntryName" $e}}"{{if $e.Docs}} comment="{{$e.Docs | JoinWith " "}}"{{end}}/>
- {{end}}
- {{if $lu := GetAnnotation $ "lastUnused"}}
- <unused start="{{index $lu.Arguments 0}}"/>
- {{end}}
- «</enums>
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "Struct"}}
- {{AssertType $ "Class"}}
-
- <type category="{{Macro "StructType" $}}" name="{{Macro "StructName" $}}"{{if $.Docs}} comment="{{$.Docs | JoinWith " "}}"{{end}}>»
- {{range $f := $.Fields}}
- <member>{{Node "XML.Type" $f}} <name>{{$f.Name}}</name>{{Macro "XML.ArrayPostfix" $f}}</member>{{Macro "XML.Docs" $f.Docs}}
- {{end}}
- «</type>
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits either 'struct' or 'union' for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "StructType"}}
- {{AssertType $ "Class"}}
-
- {{if GetAnnotation $ "union"}}union{{else}}struct{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function pointer typedef declaration for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Function"}}
- {{AssertType $ "Function"}}
-
- {{$ts := GetAnnotation $ "threadSafety"}}
- <command{{if $ts}} threadsafe="{{index $ts.Arguments 0}}"{{end}}>»
- <proto>{{Node "XML.Type" $.Return}} <name>{{$.Name}}</name></proto>
- {{range $p := $.CallParameters}}
- <param>{{Node "XML.Type" $p}} <name>{{$p.Name}}{{Macro "ArrayPostfix" $p}}</name></param>
- {{end}}
- «</command>
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the XML translation for the specified documentation block (string array).
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Docs"}}
- {{if $}} <!-- {{JoinWith " " $ | Replace "<" "" | Replace ">" ""}} -->{{end}}
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C translation for the specified type.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Type.Class" }}<type>{{Macro "StructName" $.Type}}</type>{{end}}
-{{define "XML.Type.Pseudonym" }}<type>{{$.Type.Name}}</type>{{end}}
-{{define "XML.Type.Enum" }}<type>{{$.Type.Name}}</type>{{end}}
-{{define "XML.Type.StaticArray"}}{{Node "XML.Type" $.Type.ValueType}}{{end}}
-{{define "XML.Type.Pointer" }}{{if $.Type.Const}}{{Node "XML.ConstType" $.Type.To}}{{else}}{{Node "XML.Type" $.Type.To}}{{end}}*{{end}}
-{{define "XML.Type.Slice" }}<type>{{Node "XML.Type" $.Type.To}}</type>*{{end}}
-{{define "XML.Type#s8" }}<type>int8_t</type>{{end}}
-{{define "XML.Type#u8" }}<type>uint8_t</type>{{end}}
-{{define "XML.Type#s16" }}<type>int16_t</type>{{end}}
-{{define "XML.Type#u16" }}<type>uint16_t</type>{{end}}
-{{define "XML.Type#s32" }}<type>int32_t</type>{{end}}
-{{define "XML.Type#u32" }}<type>uint32_t</type>{{end}}
-{{define "XML.Type#f32" }}<type>float</type>{{end}}
-{{define "XML.Type#s64" }}<type>int64_t</type>{{end}}
-{{define "XML.Type#u64" }}<type>uint64_t</type>{{end}}
-{{define "XML.Type#f64" }}<type>double</type>{{end}}
-{{define "XML.Type#char" }}<type>char</type>{{end}}
-{{define "XML.Type#void" }}void{{end}}
-
-{{define "XML.ConstType_Default"}}const {{Node "XML.Type" $.Type}}{{end}}
-{{define "XML.ConstType.Pointer"}}{{Node "XML.Type" $.Type}} const{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a C type and name for the given parameter
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Parameter"}}
- {{AssertType $ "Parameter"}}
-
- <type>{{Macro "ParameterType" $}}</type> <name>{{$.Name}}{{Macro "ArrayPostfix" $}}</name>
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits a comma-separated list of C type-name paired parameters for the given
- command.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.Parameters"}}
- {{AssertType $ "Function"}}
-
- {{ForEach $.CallParameters "XML.Parameter" | JoinWith ", "}}
- {{if not $.CallParameters}}<type>void</type>{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the fixed-size-array postfix for pseudonym types annotated with @array
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.ArrayPostfix"}}{{Node "XML.ArrayPostfix" $}}{{end}}
-{{define "XML.ArrayPostfix.StaticArray"}}[{{Node "XML.NamedValue" $.Type.SizeExpr}}]{{end}}
-{{define "XML.ArrayPostfix_Default"}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the value of the given constant, or the <enum> tagged name if existant.
--------------------------------------------------------------------------------
-*/}}
-{{define "XML.NamedValue.Definition"}}<enum>{{$.Node.Name}}</enum>{{end}}
-{{define "XML.NamedValue.EnumEntry"}}<enum>{{$.Node.Name}}</enum>{{end}}
-{{define "XML.NamedValue_Default"}}{{$.Node}}{{end}}
diff --git a/vulkan/api/templates/vulkan_common.tmpl b/vulkan/api/templates/vulkan_common.tmpl
deleted file mode 100644
index f694c56..0000000
--- a/vulkan/api/templates/vulkan_common.tmpl
+++ /dev/null
@@ -1,223 +0,0 @@
-{{$clang_style := "{BasedOnStyle: Google, AccessModifierOffset: -4, ColumnLimit: 200, ContinuationIndentWidth: 8, IndentWidth: 4, AlignOperands: true, CommentPragmas: '.*'}"}}
-{{Global "clang-format" (Strings "clang-format" "-style" $clang_style)}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C translation for the specified type.
--------------------------------------------------------------------------------
-*/}}
-{{define "Type.Class" }}{{if GetAnnotation $.Type "internal"}}struct {{end}}{{Macro "StructName" $.Type}}{{end}}
-{{define "Type.Pseudonym" }}{{$.Type.Name}}{{end}}
-{{define "Type.Enum" }}{{$.Type.Name}}{{end}}
-{{define "Type.StaticArray"}}{{Node "Type" $.Type.ValueType}}{{end}}
-{{define "Type.Pointer" }}{{if $.Type.Const}}{{Node "ConstType" $.Type.To}}{{else}}{{Node "Type" $.Type.To}}{{end}}*{{end}}
-{{define "Type.Slice" }}{{Log "%T %+v" $.Node $.Node}}{{Node "Type" $.Type.To}}*{{end}}
-{{define "Type#bool" }}bool{{end}}
-{{define "Type#int" }}int{{end}}
-{{define "Type#uint" }}unsigned int{{end}}
-{{define "Type#s8" }}int8_t{{end}}
-{{define "Type#u8" }}uint8_t{{end}}
-{{define "Type#s16" }}int16_t{{end}}
-{{define "Type#u16" }}uint16_t{{end}}
-{{define "Type#s32" }}int32_t{{end}}
-{{define "Type#u32" }}uint32_t{{end}}
-{{define "Type#f32" }}float{{end}}
-{{define "Type#s64" }}int64_t{{end}}
-{{define "Type#u64" }}uint64_t{{end}}
-{{define "Type#f64" }}double{{end}}
-{{define "Type#void" }}void{{end}}
-{{define "Type#char" }}char{{end}}
-
-{{define "ConstType_Default"}}const {{Node "Type" $.Type}}{{end}}
-{{define "ConstType.Pointer"}}{{Node "Type" $.Type}} const{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C translation for the specified documentation block (string array).
--------------------------------------------------------------------------------
-*/}}
-{{define "Docs"}}
- {{if $}}// {{$ | JoinWith "\n// "}}{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of a bitfield entry.
--------------------------------------------------------------------------------
-*/}}
-{{define "BitfieldEntryName"}}
- {{AssertType $ "EnumEntry"}}
-
- {{Macro "EnumEntry" $}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of an enum type.
--------------------------------------------------------------------------------
-*/}}
-{{define "EnumName"}}{{AssertType $ "Enum"}}{{$.Name}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of an enum entry.
--------------------------------------------------------------------------------
-*/}}
-{{define "EnumEntry"}}
- {{AssertType $.Owner "Enum"}}
- {{AssertType $.Name "string"}}
-
- {{$.Name}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of the first entry of an enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "EnumFirstEntry"}}
- {{AssertType $ "Enum"}}
-
- {{range $i, $e := $.Entries}}
- {{if not $i}}{{$e.Name}}{{end}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of the last entry of an enum.
--------------------------------------------------------------------------------
-*/}}{{define "EnumLastEntry"}}
- {{AssertType $ "Enum"}}
-
- {{range $i, $e := $.Entries}}
- {{if not (HasMore $i $.Entries)}}{{$e.Name}}{{end}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of a struct (class) type.
--------------------------------------------------------------------------------
-*/}}
-{{define "StructName"}}{{AssertType $ "Class"}}{{$.Name}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the name of a function.
--------------------------------------------------------------------------------
-*/}}
-{{define "FunctionName"}}{{AssertType $ "Function"}}{{$.Name}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the fixed-size-array postfix for pseudonym types annotated with @array
--------------------------------------------------------------------------------
-*/}}
-{{define "ArrayPostfix"}}{{Node "ArrayPostfix" $}}{{end}}
-{{define "ArrayPostfix.StaticArray"}}[{{$.Type.Size}}]{{end}}
-{{define "ArrayPostfix_Default"}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a C type and name for the given parameter
--------------------------------------------------------------------------------
-*/}}
-{{define "Parameter"}}
- {{AssertType $ "Parameter"}}
-
- {{if GetAnnotation $ "readonly"}}const {{end}}{{Macro "ParameterType" $}} {{$.Name}}{{Macro "ArrayPostfix" $}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a C name for the given parameter
--------------------------------------------------------------------------------
-*/}}
-{{define "ParameterName"}}
- {{AssertType $ "Parameter"}}
-
- {{$.Name}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a C type for the given parameter
--------------------------------------------------------------------------------
-*/}}
-{{define "ParameterType"}}{{AssertType $ "Parameter"}}{{Node "Type" $}}{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a comma-separated list of C type-name paired parameters for the given
- command.
--------------------------------------------------------------------------------
-*/}}
-{{define "Parameters"}}
- {{AssertType $ "Function"}}
-
- {{ForEach $.CallParameters "Parameter" | JoinWith ", "}}
- {{if not $.CallParameters}}void{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function pointer name for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "FunctionPtrName"}}
- {{AssertType $ "Function"}}
-
- PFN_{{$.Name}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Parses const variables as text Globals.
--------------------------------------------------------------------------------
-*/}}
-{{define "DefineGlobals"}}
- {{AssertType $ "API"}}
-
- {{range $d := $.Definitions}}
- {{Global $d.Name $d.Expression}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Given a function, return "Global", "Instance", or "Device" depending on which
- dispatch table the function belongs to.
--------------------------------------------------------------------------------
-*/}}
-{{define "Vtbl#VkInstance" }}Instance{{end}}
-{{define "Vtbl#VkPhysicalDevice"}}Instance{{end}}
-{{define "Vtbl#VkDevice" }}Device{{end}}
-{{define "Vtbl#VkQueue" }}Device{{end}}
-{{define "Vtbl#VkCommandBuffer" }}Device{{end}}
-{{define "Vtbl_Default" }}Global{{end}}
-{{define "Vtbl"}}
- {{AssertType $ "Function"}}
-
- {{if gt (len $.CallParameters) 0}}
- {{Node "Vtbl" (index $.CallParameters 0)}}
- {{else}}Global
- {{end}}
-{{end}}
diff --git a/vulkan/api/templates/vulkan_h.tmpl b/vulkan/api/templates/vulkan_h.tmpl
deleted file mode 100644
index 83a5e40..0000000
--- a/vulkan/api/templates/vulkan_h.tmpl
+++ /dev/null
@@ -1,295 +0,0 @@
-{{Include "vulkan_common.tmpl"}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "vulkan.h" | Format (Global "clang-format") | Write "../include/vulkan.h"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Entry point
--------------------------------------------------------------------------------
-*/}}
-{{define "vulkan.h"}}
-#ifndef __vulkan_h_
-#define __vulkan_h_ 1
-¶
-#ifdef __cplusplus
-extern "C" {
-#endif
-¶
-/*
-** Copyright (c) 2015-2016 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-¶
-/*
-** This header is generated from the Khronos Vulkan API Registry.
-**
-*/
-¶
-#define VK_VERSION_1_0 1
-#include "vk_platform.h"
-¶
-#define VK_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
-¶
-// Vulkan API version supported by this file
-#define VK_API_VERSION \
- VK_MAKE_VERSION({{Global "VERSION_MAJOR"}}, {{Global "VERSION_MINOR"}}, {{Global "VERSION_PATCH"}})
-¶
-#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
-#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
-#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
-¶
-#if defined(__cplusplus) && ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L)
- #define VK_NULL_HANDLE nullptr
-#else
- #define VK_NULL_HANDLE 0
-#endif
-¶
-#define VK_DEFINE_HANDLE(obj) typedef struct obj##_T* obj;
-¶
-#if defined(__cplusplus)
-#if ((defined(_MSC_VER) && _MSC_VER >= 1800 || __cplusplus >= 201103L)
-// The bool operator only works if there are no implicit conversions from an obj to
-// a bool-compatible type, which can then be used to unintentionally violate type safety.
-// C++11 and above supports the "explicit" keyword on conversion operators to stop this
-// from happening. Otherwise users of C++ below C++11 won't get direct access to evaluating
-// the object handle as a bool in expressions like:
-// if (obj) vkDestroy(obj);
-#define VK_NONDISP_HANDLE_OPERATOR_BOOL() \
- explicit operator bool() const { return handle != 0; }
-#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- explicit obj(uint64_t x) : handle(x) { } \
- obj(decltype(nullptr)) : handle(0) { }
-#else
-#define VK_NONDISP_HANDLE_OPERATOR_BOOL()
-#define VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj(uint64_t x) : handle(x) { }
-#endif
-#define VK_DEFINE_NONDISP_HANDLE(obj) \
- struct obj { \
- obj() : handle(0) { } \
- VK_NONDISP_HANDLE_CONSTRUCTOR_FROM_UINT64(obj) \
- obj& operator=(uint64_t x) { \
- handle = x; \
- return *this; \
- } \
- bool operator==(const obj& other) const { return handle == other.handle; } \
- bool operator!=(const obj& other) const { return handle != other.handle; } \
- bool operator!() const { return !handle; } \
- VK_NONDISP_HANDLE_OPERATOR_BOOL() \
- uint64_t handle; \
- };
-#else
-#define VK_DEFINE_NONDISP_HANDLE(obj) \
- typedef struct obj##_T { uint64_t handle; } obj;
-#endif
-¶
-#define VK_LOD_CLAMP_NONE 1000.0f
-#define VK_REMAINING_MIP_LEVELS (~0U)
-#define VK_REMAINING_ARRAY_LAYERS (~0U)
-#define VK_WHOLE_SIZE (~0ULL)
-#define VK_ATTACHMENT_UNUSED (~0U)
-define VK_QUEUE_FAMILY_IGNORED (~0U)
-define VK_SUBPASS_EXTERNAL (~0U)
-{{range $d := $.Definitions}}
- {{if HasPrefix $d.Name "VK_"}}#define {{$d.Name}} {{$d.Expression}}{{end}}
-{{end}}
-¶
-{{range $i, $p := $.Pseudonyms}}
- {{if GetAnnotation $p "dispatchHandle"}}VK_DEFINE_HANDLE({{$p.Name}})
- {{else if GetAnnotation $p "nonDispatchHandle"}}VK_DEFINE_NONDISP_HANDLE({{$p.Name}})
- {{end}}
-{{end}}
-¶
-// ------------------------------------------------------------------------------------------------
-// Enumerations
-¶
- {{range $e := $.Enums}}
- {{if not $e.IsBitfield}}
- {{Macro "Enum" $e}}
- {{end}}
- {{end}}
-¶
-// ------------------------------------------------------------------------------------------------
-// Flags
-¶
- {{range $e := $.Enums}}
- {{if $e.IsBitfield}}
- {{Macro "Bitfield" $e}}
- {{end}}
- {{end}}
-¶
-// ------------------------------------------------------------------------------------------------
-// Vulkan structures
-¶
- {{/* Function pointers */}}
- {{range $f := AllCommands $}}
- {{if GetAnnotation $f "pfn"}}
- {{Macro "FunctionTypedef" $f}}
- {{end}}
- {{end}}
-¶
- {{range $c := $.Classes}}
- {{if not (GetAnnotation $c "internal")}}
- {{Macro "Struct" $c}}
- {{end}}
- {{end}}
-¶
-// ------------------------------------------------------------------------------------------------
-// API functions
-¶
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- {{Macro "FunctionTypedef" $f}}
- {{end}}
- {{end}}
-¶
-#ifdef VK_NO_PROTOTYPES
-¶
- {{range $f := AllCommands $}}
- {{if not (GetAnnotation $f "pfn")}}
- {{Macro "FunctionDecl" $f}}
- {{end}}
- {{end}}
-¶
-#endif
-¶
-#ifdef __cplusplus
-}
-#endif
-¶
-#endif
-{{end}}
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified bitfield.
--------------------------------------------------------------------------------
-*/}}
-{{define "Bitfield"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef VkFlags {{Macro "EnumName" $}};
- {{if $.Entries}}
- typedef enum {
- {{range $b := $.Entries}}
- {{Macro "BitfieldEntryName" $b}} = {{printf "0x%.8X" $b.Value}}, {{Macro "Docs" $b.Docs}}
- {{end}}
- } {{Macro "EnumName" $ | TrimRight "s"}}Bits;
- {{end}}
- ¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified enum.
--------------------------------------------------------------------------------
-*/}}
-{{define "Enum"}}
- {{AssertType $ "Enum"}}
-
- {{Macro "Docs" $.Docs}}
- typedef enum {
- {{range $i, $e := $.Entries}}
- {{Macro "EnumEntry" $e}} = {{printf "0x%.8X" $e.Value}}, {{Macro "Docs" $e.Docs}}
- {{end}}
- ¶
- {{$name := Macro "EnumName" $ | TrimRight "ABCDEFGHIJKLMNOQRSTUVWXYZ" | SplitPascalCase | Upper | JoinWith "_"}}
- {{if GetAnnotation $ "enumMaxOnly"}}
- VK_MAX_ENUM({{$name | SplitOn "VK_"}})
- {{else}}
- {{$first := Macro "EnumFirstEntry" $ | SplitOn $name | TrimLeft "_"}}
- {{$last := Macro "EnumLastEntry" $ | SplitOn $name | TrimLeft "_"}}
- VK_ENUM_RANGE({{$name | SplitOn "VK_"}}, {{$first}}, {{$last}})
- {{end}}
- } {{Macro "EnumName" $}};
- ¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "Struct"}}
- {{AssertType $ "Class"}}
-
- {{Macro "Docs" $.Docs}}
- typedef {{Macro "StructType" $}} {
- {{ForEach $.Fields "Field" | JoinWith "\n"}}
- } {{Macro "StructName" $}};
- ¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C declaration for the specified class field.
--------------------------------------------------------------------------------
-*/}}
-{{define "Field"}}
- {{AssertType $ "Field"}}
-
- {{Node "Type" $}} {{$.Name}}§
- {{Macro "ArrayPostfix" (TypeOf $)}}; {{Macro "Docs" $.Docs}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits either 'struct' or 'union' for the specified class.
--------------------------------------------------------------------------------
-*/}}
-{{define "StructType"}}
- {{AssertType $ "Class"}}
-
- {{if GetAnnotation $ "union"}}union{{else}}struct{{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function pointer typedef declaration for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "FunctionTypedef"}}
- {{AssertType $ "Function"}}
-
- typedef {{Node "Type" $.Return}} (VKAPI* {{Macro "FunctionPtrName" $}})({{Macro "Parameters" $}});
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits the C function declaration for the specified command.
--------------------------------------------------------------------------------
-*/}}
-{{define "FunctionDecl"}}
- {{AssertType $ "Function"}}
-
- {{if not (GetAnnotation $ "fptr")}}
- {{Macro "Docs" $.Docs}}
- {{Node "Type" $.Return}} VKAPI {{Macro "FunctionName" $}}({{Macro "Parameters" $}});
- {{end}}
-{{end}}
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
deleted file mode 100644
index 76503c8..0000000
--- a/vulkan/api/vulkan.api
+++ /dev/null
@@ -1,12163 +0,0 @@
-// Copyright (c) 2015 The Khronos Group Inc.
-//
-// Permission is hereby granted, free of charge, to any person obtaining a
-// copy of this software and/or associated documentation files (the
-// "Materials"), to deal in the Materials without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Materials, and to
-// permit persons to whom the Materials are furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be included
-// in all copies or substantial portions of the Materials.
-//
-// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-
-import platform "platform.api"
-
-///////////////
-// Constants //
-///////////////
-
-// API version (major.minor.patch)
-define VERSION_MAJOR 1
-define VERSION_MINOR 1
-define VERSION_PATCH 96
-
-// API limits
-define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
-define VK_UUID_SIZE 16
-define VK_MAX_EXTENSION_NAME_SIZE 256
-define VK_MAX_DESCRIPTION_SIZE 256
-define VK_MAX_MEMORY_TYPES 32
-define VK_MAX_MEMORY_HEAPS 16 /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types.
-@vulkan1_1
-define VK_MAX_DEVICE_GROUP_SIZE 32
-@vulkan1_1
-define VK_LUID_SIZE 8
-@vulkan1_1
-define VK_QUEUE_FAMILY_EXTERNAL -2
-@extension("VK_EXT_queue_family_foreign")
-define VK_QUEUE_FAMILY_FOREIGN_EXT -3
-@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
-define VK_MAX_DRIVER_NAME_SIZE_KHR 256
-@extension("VK_MAX_DRIVER_NAME_SIZE_KHR") // 197
-define VK_MAX_DRIVER_INFO_SIZE_KHR 256
-
-// API keywords
-define VK_TRUE 1
-define VK_FALSE 0
-
-// API keyword, but needs special handling by some templates
-define NULL_HANDLE 0
-
-// 1
-@extension("VK_KHR_surface") define VK_KHR_SURFACE_SPEC_VERSION 25
-@extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME "VK_KHR_surface"
-
-// 2
-@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION 70
-@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME "VK_KHR_swapchain"
-
-// 3
-@extension("VK_KHR_display") define VK_KHR_DISPLAY_SPEC_VERSION 21
-@extension("VK_KHR_display") define VK_KHR_DISPLAY_EXTENSION_NAME "VK_KHR_display"
-
-// 4
-@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION 9
-@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME "VK_KHR_display_swapchain"
-
-// 5
-@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_SPEC_VERSION 6
-@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_NAME "VK_KHR_xlib_surface"
-
-// 6
-@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_SPEC_VERSION 6
-@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_NAME "VK_KHR_xcb_surface"
-
-// 7
-@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 6
-@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME "VK_KHR_wayland_surface"
-
-// 8 - VK_KHR_mir_surface removed
-
-// 9
-@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
-@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME "VK_KHR_android_surface"
-
-// 10
-@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION 6
-@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME "VK_KHR_win32_surface"
-
-// 11
-@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION 8
-@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME "VK_ANDROID_native_buffer"
-
-// 12
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION 9
-@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME "VK_EXT_debug_report"
-
-// 13
-@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION 1
-@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME "VK_NV_glsl_shader"
-
-// 14
-@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_SPEC_VERSION 1
-@extension("VK_EXT_depth_range_unrestricted") define VK_EXT_DEPTH_RANGE_UNRESTRICTED_NAME "VK_EXT_depth_range_unrestricted"
-
-// 15
-@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION 1
-@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME "VK_KHR_sampler_mirror_clamp_to_edge"
-
-// 16
-@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_SPEC_VERSION 1
-@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_NAME "VK_IMG_filter_cubic"
-
-// 19
-@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION 1
-@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME "VK_AMD_rasterization_order"
-
-// 21
-@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_SPEC_VERSION 1
-@extension("VK_AMD_shader_trinary_minmax") define VK_AMD_SHADER_TRINARY_MINMAX_EXTENSION_NAME "VK_AMD_shader_trinary_minmax"
-
-// 22
-@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_SPEC_VERSION 1
-@extension("VK_AMD_shader_explicit_vertex_parameter") define VK_AMD_SHADER_EXPLICIT_VERTEX_PARAMETER_EXTENSION_NAME "VK_AMD_shader_explicit_vertex_parameter"
-
-// 23
-@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION 4
-@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME "VK_EXT_debug_marker"
-
-// 26
-@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_SPEC_VERSION 1
-@extension("VK_AMD_gcn_shader") define VK_AMD_GCN_SHADER_EXTENSION_NAME "VK_AMD_gcn_shader"
-
-// 27
-@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_SPEC_VERSION 1
-@extension("VK_NV_dedicated_allocation") define VK_NV_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_NV_dedicated_allocation"
-
-// 28
-@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_SPEC_VERSION 1
-@extension("VK_IMG_format_pvrtc") define VK_IMG_FORMAT_PVRTC_EXTENSION_NAME "VK_IMG_format_pvrtc"
-
-// 29
-@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_SPEC_VERSION 1
-@extension("VK_EXT_transform_feedback") define VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME "VK_EXT_transform_feedback"
-
-// 34
-@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
-@extension("VK_AMD_draw_indirect_count") define VK_AMD_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_AMD_draw_indirect_count"
-
-// 36
-@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_SPEC_VERSION 1
-@extension("VK_AMD_negative_viewport_height") define VK_AMD_NEGATIVE_VIEWPORT_HEIGHT_EXTENSION_NAME "VK_AMD_negative_viewport_height"
-
-// 37
-@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_SPEC_VERSION 1
-@extension("VK_AMD_gpu_shader_half_float") define VK_AMD_GPU_SHADER_HALF_FLOAT_EXTENSION_NAME "VK_AMD_gpu_shader_half_float"
-
-// 38
-@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_SPEC_VERSION 1
-@extension("VK_AMD_shader_ballot") define VK_AMD_SHADER_BALLOT_EXTENSION_NAME "VK_AMD_shader_ballot"
-
-// 42
-@extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_SPEC_VERSION 1
-@extension("VK_AMD_texture_gather_bias_lod") define VK_AMD_TEXTURE_GATHER_BIAS_LOD_EXTENSION_NAME "VK_AMD_texture_gather_bias_lod"
-
-// 43
-@extension("VK_AMD_shader_info") define VK_AMD_SHADER_INFO_SPEC_VERSION 1
-@extension("VK_AMD_shader_info") define VK_AMD_SHADER_INFO_EXTENSION_NAME "VK_AMD_shader_info"
-
-// 47
-@extension("VK_AMD_shader_image_load_store_lod") define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_SPEC_VERSION 1
-@extension("VK_AMD_shader_image_load_store_lod") define VK_AMD_SHADER_IMAGE_LOAD_STORE_LOD_EXTENSION_NAME "VK_AMD_shader_image_load_store_lod"
-
-// 51
-@extension("VK_NV_corner_sampled_image") define VK_NV_CORNER_SAMPLED_IMAGE_SPEC_VERSION 2
-@extension("VK_NV_corner_sampled_image") define VK_NV_CORNER_SAMPLED_IMAGE_EXTENSION_NAME "VK_NV_corner_sampled_image"
-
-// 54
-@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_SPEC_VERSION 1
-@extension("VK_KHR_multiview") define VK_KHR_MULTIVIEW_EXTENSION_NAME "VK_KHR_multiview"
-
-// 56
-@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
-@extension("VK_NV_external_memory_capabilities") define VK_NV_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_NV_external_memory_capabilities"
-
-// 57
-@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_SPEC_VERSION 1
-@extension("VK_NV_external_memory") define VK_NV_EXTERNAL_MEMORY_EXTENSION_NAME "VK_NV_external_memory"
-
-// 58
-@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
-@extension("VK_NV_external_memory_win32") define VK_NV_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_NV_external_memory_win32"
-
-// 59
-@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_SPEC_VERSION 1
-@extension("VK_NV_win32_keyed_mutex") define VK_NV_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_NV_win32_keyed_mutex"
-
-// 60
-@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_SPEC_VERSION 1
-@extension("VK_KHR_get_physical_device_properties2") define VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_physical_device_properties2"
-
-// 61
-@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_SPEC_VERSION 3
-@extension("VK_KHR_device_group") define VK_KHR_DEVICE_GROUP_EXTENSION_NAME "VK_KHR_device_group"
-
-// 62
-@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_SPEC_VERSION 1
-@extension("VK_EXT_validation_flags") define VK_EXT_VALIDATION_FLAGS_EXTENSION_NAME "VK_EXT_validation_flags"
-
-// 63
-@extension("VK_NN_vi_surface") define VK_NN_VI_SURFACE_SPEC_VERSION 1
-@extension("VK_NN_vi_surface") define VK_NN_VI_SURFACE_EXTENSION_NAME "VK_NN_vi_surface"
-
-// 64
-@extension("VK_KHR_shader_draw_parameters") define VK_KHR_SHADER_DRAW_PARAMETERS_SPEC_VERSION 1
-@extension("VK_KHR_shader_draw_parameters") define VK_KHR_SHADER_DRAW_PARAMETERS_EXTENSION_NAME "VK_KHR_shader_draw_parameters"
-
-// 65
-@extension("VK_EXT_shader_subgroup_ballot") define VK_EXT_SHADER_SUBGROUP_BALLOT_SPEC_VERSION 1
-@extension("VK_EXT_shader_subgroup_ballot") define VK_EXT_SHADER_SUBGROUP_BALLOT_EXTENSION_NAME "VK_EXT_shader_subgroup_ballot"
-
-// 66
-@extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
-@extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
-
-// 68
-@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1
-@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode"
-
-// 70
-@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_SPEC_VERSION 2
-@extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
-
-// 71
-@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_SPEC_VERSION 1
-@extension("VK_KHR_device_group_creation") define VK_KHR_DEVICE_GROUP_CREATION_EXTENSION_NAME "VK_KHR_device_group_creation"
-
-// 72
-@extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_SPEC_VERSION 1
-@extension("VK_KHR_external_memory_capabilities") define VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_memory_capabilities"
-
-// 73
-@extension("VK_KHR_external_memory") define VK_KHR_EXTERNAL_MEMORY_SPEC_VERSION 1
-@extension("VK_KHR_external_memory") define VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME "VK_KHR_external_memory"
-
-// 74
-@extension("VK_KHR_external_memory_win32") define VK_KHR_EXTERNAL_MEMORY_WIN32_SPEC_VERSION 1
-@extension("VK_KHR_external_memory_win32") define VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME "VK_KHR_external_memory_win32"
-
-// 75
-@extension("VK_KHR_external_memory_fd") define VK_KHR_EXTERNAL_MEMORY_FD_SPEC_VERSION 1
-@extension("VK_KHR_external_memory_fd") define VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME "VK_KHR_external_memory_fd"
-
-// 76
-@extension("VK_KHR_win32_keyed_mutex") define VK_KHR_WIN32_KEYED_MUTEX_SPEC_VERSION 1
-@extension("VK_KHR_win32_keyed_mutex") define VK_KHR_WIN32_KEYED_MUTEX_EXTENSION_NAME "VK_KHR_win32_keyed_mutex"
-
-// 77
-@extension("VK_KHR_external_semaphore_capabilities") define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_SPEC_VERSION 1
-@extension("VK_KHR_external_semaphore_capabilities") define VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_semaphore_capabilities"
-
-// 78
-@extension("VK_KHR_external_semaphore") define VK_KHR_EXTERNAL_SEMAPHORE_SPEC_VERSION 1
-@extension("VK_KHR_external_semaphore") define VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME "VK_KHR_external_semaphore"
-
-// 79
-@extension("VK_KHR_external_semaphore_win32") define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_SPEC_VERSION 1
-@extension("VK_KHR_external_semaphore_win32") define VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME "VK_KHR_external_semaphore_win32"
-
-// 80
-@extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_SPEC_VERSION 1
-@extension("VK_KHR_external_semaphore_fd") define VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME "VK_KHR_external_semaphore_fd"
-
-// 81
-@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_SPEC_VERSION 2
-@extension("VK_KHR_push_descriptor") define VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME "VK_KHR_push_descriptor"
-
-// 82
-@extension("VK_EXT_conditional_rendering") define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1
-@extension("VK_EXT_conditional_rendering") define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering"
-
-// 83
-@extension("VK_KHR_shader_float16_int8") define VK_KHR_SHADER_FLOAT16_INT8_SPEC_VERSION 1
-@extension("VK_KHR_shader_float16_int8") define VK_KHR_SHADER_FLOAT16_INT8_EXTENSION_NAME "VK_KHR_shader_float16_int8"
-
-// 84
-@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_SPEC_VERSION 1
-@extension("VK_KHR_16bit_storage") define VK_KHR_16BIT_STORAGE_EXTENSION_NAME "VK_KHR_16bit_storage"
-
-// 85
-@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION 1
-@extension("VK_KHR_incremental_present") define VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME "VK_KHR_incremental_present"
-
-// 86
-@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_SPEC_VERSION 1
-@extension("VK_KHR_descriptor_update_template") define VK_KHR_DESCRIPTOR_UPDATE_TEMPLATE_EXTENSION_NAME "VK_KHR_descriptor_update_template"
-
-// 87
-@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_SPEC_VERSION 3
-@extension("VK_NVX_device_generated_commands") define VK_NVX_DEVICE_GENERATED_COMMANDS_EXTENSION_NAME "VK_NVX_device_generated_commands"
-
-// 88
-@extension("VK_NV_clip_space_w_scaling") define VK_NV_CLIP_SPACE_W_SCALING_SPEC_VERSION 1
-@extension("VK_NV_clip_space_w_scaling") define VK_NV_CLIP_SPACE_W_SCALING_EXTENSION_NAME "VK_NV_clip_space_w_scaling"
-
-// 89
-@extension("VK_EXT_direct_mode_display") define VK_EXT_DIRECT_MODE_DISPLAY_SPEC_VERSION 1
-@extension("VK_EXT_direct_mode_display") define VK_EXT_DIRECT_MODE_DISPLAY_EXTENSION_NAME "VK_EXT_direct_mode_display"
-
-// 90
-@extension("VK_EXT_acquire_xlib_display") define VK_EXT_ACQUIRE_XLIB_DISPLAY_SPEC_VERSION 1
-@extension("VK_EXT_acquire_xlib_display") define VK_EXT_ACQUIRE_XLIB_DISPLAY_EXTENSION_NAME "VK_EXT_acquire_xlib_display"
-
-// 91
-@extension("VK_EXT_display_surface_counter") define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
-@extension("VK_EXT_display_surface_counter") define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
-
-// 92
-@extension("VK_EXT_display_control") define VK_EXT_DISPLAY_CONTROL_SPEC_VERSION 1
-@extension("VK_EXT_display_control") define VK_EXT_DISPLAY_CONTROL_COUNTER_EXTENSION_NAME "VK_EXT_display_control"
-
-// 93
-@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_SPEC_VERSION 1
-@extension("VK_GOOGLE_display_timing") define VK_GOOGLE_DISPLAY_TIMING_EXTENSION_NAME "VK_GOOGLE_display_timing"
-
-// 95
-@extension("VK_NV_sample_mask_override_coverage") define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_SPEC_VERSION 1
-@extension("VK_NV_sample_mask_override_coverage") define VK_NV_SAMPLE_MASK_OVERRIDE_COVERAGE_EXTENSION_NAME "VK_NV_sample_mask_override_coverage"
-
-// 96
-@extension("VK_NV_geometry_shader_passthrough") define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_SPEC_VERSION 1
-@extension("VK_NV_geometry_shader_passthrough") define VK_NV_GEOMETRY_SHADER_PASSTHROUGH_EXTENSION_NAME "VK_NV_geometry_shader_passthrough"
-
-// 97
-@extension("VK_NV_viewport_array2") define VK_NV_VIEWPORT_ARRAY2_SPEC_VERSION 1
-@extension("VK_NV_viewport_array2") define VK_NV_VIEWPORT_ARRAY2_EXTENSION_NAME "VK_NV_viewport_array2"
-
-// 98
-@extension("VK_NVX_multiview_per_view_attributes") define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_SPEC_VERSION 1
-@extension("VK_NVX_multiview_per_view_attributes") define VK_NVX_MULTIVIEW_PER_VIEW_ATTRIBUTES_EXTENSION_NAME "VK_NVX_multiview_per_view_attributes"
-
-// 99
-@extension("VK_NV_viewport_swizzle") define VK_NV_VIEWPORT_SWIZZLE_SPEC_VERSION 1
-@extension("VK_NV_viewport_swizzle") define VK_NV_VIEWPORT_SWIZZLE_EXTENSION_NAME "VK_NV_viewport_swizzle"
-
-// 100
-@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_SPEC_VERSION 1
-@extension("VK_EXT_discard_rectangles") define VK_EXT_DISCARD_RECTANGLES_EXTENSION_NAME "VK_EXT_discard_rectangles"
-
-// 102
-@extension("VK_EXT_conservative_rasterization") define VK_EXT_CONSERVATIVE_RASTERIZATION_SPEC_VERSION 1
-@extension("VK_EXT_conservative_rasterization") define VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME "VK_EXT_conservative_rasterization"
-
-// 105
-@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_SPEC_VERSION 3
-@extension("VK_EXT_swapchain_colorspace") define VK_EXT_SWAPCHAIN_COLORSPACE_EXTENSION_NAME "VK_EXT_swapchain_colorspace"
-
-// 106
-@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_SPEC_VERSION 1
-@extension("VK_EXT_hdr_metadata") define VK_EXT_HDR_METADATA_EXTENSION_NAME "VK_EXT_hdr_metadata"
-
-// 110
-@extension("VK_KHR_create_renderpass2") define VK_KHR_CREATE_RENDERPASS2_SPEC_VERSION 1
-@extension("VK_KHR_create_renderpass2") define VK_KHR_CREATE_RENDERPASS2_EXTENSION_NAME "VK_KHR_create_renderpass2"
-
-// 112
-@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_SPEC_VERSION 1
-@extension("VK_KHR_shared_presentable_image") define VK_KHR_SHARED_PRESENTABLE_IMAGE_EXTENSION_NAME "VK_KHR_shared_presentable_image"
-
-// 113
-@extension("VK_KHR_external_fence_capabilities") define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_SPEC_VERSION 1
-@extension("VK_KHR_external_fence_capabilities") define VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME "VK_KHR_external_fence_capabilities"
-
-// 114
-@extension("VK_KHR_external_fence") define VK_KHR_EXTERNAL_FENCE_SPEC_VERSION 1
-@extension("VK_KHR_external_fence") define VK_KHR_EXTERNAL_FENCE_EXTENSION_NAME "VK_KHR_external_fence"
-
-// 115
-@extension("VK_KHR_external_fence_win32") define VK_KHR_EXTERNAL_FENCE_WIN32_SPEC_VERSION 1
-@extension("VK_KHR_external_fence_win32") define VK_KHR_EXTERNAL_FENCE_WIN32_EXTENSION_NAME "VK_KHR_external_fence_win32"
-
-// 116
-@extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_SPEC_VERSION 1
-@extension("VK_KHR_external_fence_fd") define VK_KHR_EXTERNAL_FENCE_FD_EXTENSION_NAME "VK_KHR_external_fence_fd"
-
-// 118
-@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_SPEC_VERSION 1
-@extension("VK_KHR_maintenance2") define VK_KHR_MAINTENANCE2_EXTENSION_NAME "VK_KHR_maintenance2"
-
-// 120
-@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_SPEC_VERSION 1
-@extension("VK_KHR_get_surface_capabilities2") define VK_KHR_GET_SURFACE_CAPABILITIES_2_EXTENSION_NAME "VK_KHR_get_surface_capabilities2"
-
-// 121
-@extension("VK_KHR_variable_pointers") define VK_KHR_VARIABLE_POINTERS_SPEC_VERSION 1
-@extension("VK_KHR_variable_pointers") define VK_KHR_VARIABLE_POINTERS_EXTENSION_NAME "VK_KHR_variable_pointers"
-
-// 122
-@extension("VK_KHR_get_display_properties2") define VK_KHR_GET_DISPLAY_PROPERTIES_2_SPEC_VERSION 1
-@extension("VK_KHR_get_display_properties2") define VK_KHR_GET_DISPLAY_PROPERTIES_2_EXTENSION_NAME "VK_KHR_get_display_properties2"
-
-// 123
-@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_SPEC_VERSION 1
-@extension("VK_MVK_ios_surface") define VK_MVK_IOS_SURFACE_EXTENSION_NAME "VK_MVK_ios_surface"
-
-// 124
-@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_SPEC_VERSION 1
-@extension("VK_MVK_macos_surface") define VK_MVK_MACOS_SURFACE_EXTENSION_NAME "VK_MVK_macos_surface"
-
-// 126
-@extension("VK_EXT_external_memory_dma_buf") define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_SPEC_VERSION 1
-@extension("VK_EXT_external_memory_dma_buf") define VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME "VK_EXT_external_memory_dma_buf"
-
-// 127
-@extension("VK_EXT_queue_family_foreign") define VK_EXT_QUEUE_FAMILY_FOREIGN_SPEC_VERSION 1
-@extension("VK_EXT_queue_family_foreign") define VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME "VK_EXT_queue_family_foreign"
-
-// 128
-@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_SPEC_VERSION 3
-@extension("VK_KHR_dedicated_allocation") define VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME "VK_KHR_dedicated_allocation"
-
-// 128
-@extension("VK_EXT_debug_utils") define VK_EXT_DEBUG_UTILS_SPEC_VERSION 1
-@extension("VK_EXT_debug_utils") define VK_EXT_DEBUG_UTILS_EXTENSION_NAME "VK_EXT_debug_utils"
-
-// 130
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_SPEC_VERSION 3
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") define VK_ANDROID_EXTERNAL_MEMORY_ANDROID_HARDWARE_BUFFER_EXTENSION_NAME "VK_ANDROID_external_memory_android_hardware_buffer"
-
-// 131
-@extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_SPEC_VERSION 1
-@extension("VK_EXT_sampler_filter_minmax") define VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME "VK_EXT_sampler_filter_minmax"
-
-// 132
-@extension("VK_KHR_storage_buffer_storage_class") define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_SPEC_VERSION 1
-@extension("VK_KHR_storage_buffer_storage_class") define VK_KHR_STORAGE_BUFFER_STORAGE_CLASS_EXTENSION_NAME "VK_KHR_storage_buffer_storage_class"
-
-// 133
-@extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_SPEC_VERSION 1
-@extension("VK_AMD_gpu_shader_int16") define VK_AMD_GPU_SHADER_INT16_EXTENSION_NAME "VK_AMD_gpu_shader_int16"
-
-// 137
-@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_SPEC_VERSION 1
-@extension("VK_AMD_mixed_attachment_samples") define VK_AMD_MIXED_ATTACHMENT_SAMPLES_EXTENSION_NAME "VK_AMD_mixed_attachment_samples"
-
-// 138
-@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1
-@extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
-
-// 139
-@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1
-@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block"
-
-// 141
-@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
-@extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
-
-// 144
-@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_SPEC_VERSION 1
-@extension("VK_EXT_sample_locations") define VK_EXT_SAMPLE_LOCATIONS_EXTENSION_NAME "VK_EXT_sample_locations"
-
-// 145
-@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_SPEC_VERSION 1
-@extension("VK_KHR_relaxed_block_layout") define VK_KHR_RELAXED_BLOCK_LAYOUT_EXTENSION_NAME "VK_KHR_relaxed_block_layout"
-
-// 147
-@extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_SPEC_VERSION 1
-@extension("VK_KHR_get_memory_requirements2") define VK_KHR_GET_MEMORY_REQUIREMENTS2_EXTENSION_NAME "VK_KHR_get_memory_requirements2"
-
-// 148
-@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_SPEC_VERSION 1
-@extension("VK_KHR_image_format_list") define VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME "VK_KHR_image_format_list"
-
-// 149
-@extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_SPEC_VERSION 2
-@extension("VK_EXT_blend_operation_advanced") define VK_EXT_BLEND_OPERATION_ADVANCED_EXTENSION_NAME "VK_EXT_blend_operation_advanced"
-
-// 150
-@extension("VK_NV_fragment_coverage_to_color") define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_SPEC_VERSION 1
-@extension("VK_NV_fragment_coverage_to_color") define VK_NV_FRAGMENT_COVERAGE_TO_COLOR_EXTENSION_NAME "VK_NV_fragment_coverage_to_color"
-
-// 153
-@extension("VK_NV_framebuffer_mixed_samples") define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_SPEC_VERSION 1
-@extension("VK_NV_framebuffer_mixed_samples") define VK_NV_FRAMEBUFFER_MIXED_SAMPLES_EXTENSION_NAME "VK_NV_framebuffer_mixed_samples"
-
-// 154
-@extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_SPEC_VERSION 1
-@extension("VK_NV_fill_rectangle") define VK_NV_FILL_RECTANGLE_EXTENSION_NAME "VK_NV_fill_rectangle"
-
-// 156
-@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_SPEC_VERSION 1
-@extension("VK_EXT_post_depth_coverage") define VK_EXT_POST_DEPTH_COVERAGE_EXTENSION_NAME "VK_EXT_post_depth_coverage"
-
-// 157
-@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_SPEC_VERSION 1
-@extension("VK_KHR_sampler_ycbcr_conversion") define VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME "VK_KHR_sampler_ycbcr_conversion"
-
-// 158
-@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_SPEC_VERSION 1
-@extension("VK_KHR_bind_memory2") define VK_KHR_BIND_MEMORY2_EXTENSION_NAME "VK_KHR_bind_memory2"
-
-// 159
-@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_SPEC_VERSION 1
-@extension("VK_EXT_image_drm_format_modifier") define VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME "VK_EXT_image_drm_format_modifier"
-
-// 161
-@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
-@extension("VK_EXT_validation_cache") define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
-
-// 162
-@extension("VK_EXT_descriptor_indexing") define VK_EXT_DESCRIPTOR_INDEXING_SPEC_VERSION 2
-@extension("VK_EXT_descriptor_indexing") define VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME "VK_EXT_descriptor_indexing"
-
-// 163
-@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_SPEC_VERSION 1
-@extension("VK_EXT_shader_viewport_index_layer") define VK_EXT_SHADER_VIEWPORT_INDEX_LAYER_EXTENSION_NAME "VK_EXT_shader_viewport_index_layer"
-
-// 165
-@extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_SPEC_VERSION 3
-@extension("VK_NV_shading_rate_image") define VK_NV_SHADING_RATE_IMAGE_EXTENSION_NAME "VK_NV_shading_rate_image"
-
-// 166
-@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_SPEC_VERSION 3
-@extension("VK_NV_ray_tracing") define VK_NV_RAY_TRACING_EXTENSION_NAME "VK_NV_ray_tracing"
-
-// 167
-@extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_SPEC_VERSION 1
-@extension("VK_NV_representative_fragment_test") define VK_NV_REPRESENTATIVE_FRAGMENT_TEST_EXTENSION_NAME "VK_NV_representative_fragment_test"
-
-// 169
-@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_SPEC_VERSION 1
-@extension("VK_KHR_maintenance3") define VK_KHR_MAINTENANCE3_EXTENSION_NAME "VK_KHR_maintenance3"
-
-// 170
-@extension("VK_KHR_draw_indirect_count") define VK_KHR_DRAW_INDIRECT_COUNT_SPEC_VERSION 1
-@extension("VK_KHR_draw_indirect_count") define VK_KHR_DRAW_INDIRECT_COUNT_EXTENSION_NAME "VK_KHR_draw_indirect_count"
-
-// 175
-@extension("VK_EXT_global_priority") define VK_EXT_GLOBAL_PRIORITY_SPEC_VERSION 1
-@extension("VK_EXT_global_priority") define VK_EXT_GLOBAL_PRIORITY_EXTENSION_NAME "VK_EXT_global_priority"
-
-// 178
-@extension("VK_KHR_8bit_storage") define VK_KHR_8BIT_STORAGE_SPEC_VERSION 1
-@extension("VK_KHR_8bit_storage") define VK_KHR_8BIT_STORAGE_EXTENSION_NAME "VK_KHR_8bit_storage"
-
-// 179
-@extension("VK_EXT_external_memory_host") define VK_EXT_EXTERNAL_MEMORY_HOST_SPEC_VERSION 1
-@extension("VK_EXT_external_memory_host") define VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME "VK_EXT_external_memory_host"
-
-// 180
-@extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_SPEC_VERSION 1
-@extension("VK_AMD_buffer_marker") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_AMD_buffer_marker"
-
-// 181
-@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_SPEC_VERSION 1
-@extension("VK_KHR_shader_atomic_int64") define VK_KHR_SHADER_ATOMIC_INT64_EXTENSION_NAME "VK_KHR_shader_atomic_int64"
-
-// 186
-@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
-@extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
-
-// 190
-@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_SPEC_VERSION 1
-@extension("VK_AMD_memory_overallocation_behavior") define VK_AMD_MEMORY_OVERALLOCATION_BEHAVIOR_EXTENSION_NAME "VK_AMD_memory_overallocation_behavior"
-
-// 191
-@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
-@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
-
-// 197
-@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_SPEC_VERSION 1
-@extension("VK_KHR_driver_properties") define VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME "VK_KHR_driver_properties"
-
-// 198
-@extension("VK_KHR_shader_float_controls") define VK_KHR_SHADER_FLOAT_CONTROLS_SPEC_VERSION 1
-@extension("VK_KHR_shader_float_controls") define VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME "VK_KHR_shader_float_controls"
-
-// 199
-@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
-@extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_EXTENSION_NAME "VK_NV_shader_subgroup_partitioned"
-
-// 201
-@extension("VK_KHR_swapchain_mutable_format") define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_SPEC_VERSION 1
-@extension("VK_KHR_swapchain_mutable_format") define VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME "VK_KHR_swapchain_mutable_format"
-
-// 202
-@extension("VK_NV_compute_shader_derivatives") define VK_NV_COMPUTE_SHADER_DERIVATIVES_SPEC_VERSION 1
-@extension("VK_NV_compute_shader_derivatives") define VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME "VK_NV_compute_shader_derivatives"
-
-// 203
-@extension("VK_NV_mesh_shader") define VK_NV_MESH_SHADER_SPEC_VERSION 1
-@extension("VK_NV_mesh_shader") define VK_NV_MESH_SHADER_EXTENSION_NAME "VK_NV_mesh_shader"
-
-// 204
-@extension("VK_NV_fragment_shader_barycentric") define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_SPEC_VERSION 1
-@extension("VK_NV_fragment_shader_barycentric") define VK_NV_FRAGMENT_SHADER_BARYCENTRIC_EXTENSION_NAME "VK_NV_fragment_shader_barycentric"
-
-// 205
-@extension("VK_NV_shader_image_footprint") define VK_NV_SHADER_IMAGE_FOOTPRINT_SPEC_VERSION 1
-@extension("VK_NV_shader_image_footprint") define VK_NV_SHADER_IMAGE_FOOTPRINT_EXTENSION_NAME "VK_NV_shader_image_footprint"
-
-// 206
-@extension("VK_NV_scissor_exclusive") define VK_NV_SCISSOR_EXCLUSIVE_SPEC_VERSION 1
-@extension("VK_NV_scissor_exclusive") define VK_NV_SCISSOR_EXCLUSIVE_EXTENSION_NAME "VK_NV_scissor_exclusive"
-
-// 207
-@extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2
-@extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints"
-
-// 212
-@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
-@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
-
-// 213
-@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_SPEC_VERSION 2
-@extension("VK_EXT_pci_bus_info") define VK_EXT_PCI_BUS_INFO_EXENSION_NAME "VK_EXT_pci_bus_info"
-
-// 215
-@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_SPEC_VERSION 1
-@extension("VK_FUCHSIA_imagepipe_surface") define VK_FUCHSIA_IMAGEPIPE_SURFACE_EXTENSION_NAME "VK_FUCHSIA_imagepipe_surface"
-
-// 219
-@extension("VK_EXT_fragment_density_map") define VK_EXT_FRAGMENT_DENSITY_MAP_SPEC_VERSION 1
-@extension("VK_EXT_fragment_density_map") define VK_EXT_FRAGMENT_DENSITY_MAP_EXTENSION_NAME "VK_EXT_fragment_density_map"
-
-// 222
-@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_SPEC_VERSION 1
-@extension("VK_EXT_scalar_block_layout") define VK_EXT_SCALAR_BLOCK_LAYOUT_EXTENSION_NAME "VK_EXT_scalar_block_layout"
-
-// 224
-@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_SPEC_VERSION 1
-@extension("VK_GOOGLE_hlsl_functionality1") define VK_GOOGLE_HLSL_FUNCTIONALITY1_EXTENSION_NAME "VK_GOOGLE_hlsl_functionality1"
-
-// 225
-@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_SPEC_VERSION 1
-@extension("VK_GOOGLE_decorate_string") define VK_GOOGLE_DECORATE_STRING_EXTENSION_NAME "VK_GOOGLE_decorate_string"
-
-// 247
-@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_SPEC_VERSION 1
-@extension("VK_EXT_separate_stencil_usage") define VK_EXT_SEPARATE_STENCIL_USAGE_EXTENSION_NAME "VK_EXT_separate_stencil_usage"
-
-/////////////
-// Types //
-/////////////
-
-type u32 VkBool32
-type u32 VkFlags
-type u64 VkDeviceSize
-type u32 VkSampleMask
-
-/// Dispatchable handle types.
-@dispatchHandle type u64 VkInstance
-@dispatchHandle type u64 VkPhysicalDevice
-@dispatchHandle type u64 VkDevice
-@dispatchHandle type u64 VkQueue
-@dispatchHandle type u64 VkCommandBuffer
-
-/// Non dispatchable handle types.
-@nonDispatchHandle type u64 VkDeviceMemory
-@nonDispatchHandle type u64 VkCommandPool
-@nonDispatchHandle type u64 VkBuffer
-@nonDispatchHandle type u64 VkBufferView
-@nonDispatchHandle type u64 VkImage
-@nonDispatchHandle type u64 VkImageView
-@nonDispatchHandle type u64 VkShaderModule
-@nonDispatchHandle type u64 VkPipeline
-@nonDispatchHandle type u64 VkPipelineLayout
-@nonDispatchHandle type u64 VkSampler
-@nonDispatchHandle type u64 VkDescriptorSet
-@nonDispatchHandle type u64 VkDescriptorSetLayout
-@nonDispatchHandle type u64 VkDescriptorPool
-@nonDispatchHandle type u64 VkFence
-@nonDispatchHandle type u64 VkSemaphore
-@nonDispatchHandle type u64 VkEvent
-@nonDispatchHandle type u64 VkQueryPool
-@nonDispatchHandle type u64 VkFramebuffer
-@nonDispatchHandle type u64 VkRenderPass
-@nonDispatchHandle type u64 VkPipelineCache
-
-@vulkan1_1
-@nonDispatchHandle type u64 VkSamplerYcbcrConversion
-@nonDispatchHandle type u64 VkDescriptorUpdateTemplate
-
-// 1
-@extension("VK_KHR_surface") @nonDispatchHandle type u64 VkSurfaceKHR
-
-// 2
-@extension("VK_KHR_swapchain") @nonDispatchHandle type u64 VkSwapchainKHR
-
-// 3
-@extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayKHR
-@extension("VK_KHR_display") @nonDispatchHandle type u64 VkDisplayModeKHR
-
-// 12
-@extension("VK_EXT_debug_report") @nonDispatchHandle type u64 VkDebugReportCallbackEXT
-
-// 86
-@extension("VK_KHR_descriptor_update_template") @nonDispatchHandle type u64 VkDescriptorUpdateTemplateKHR
-
-// 87
-@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkObjectTableNVX
-@extension("VK_NVX_device_generated_commands") @nonDispatchHandle type u64 VkIndirectCommandsLayoutNVX
-
-// 129
-@extension("VK_EXT_debug_utils") @nonDispatchHandle type u64 VkDebugUtilsMessengerEXT
-
-// 157
-@extension("VK_KHR_sampler_ycbcr_conversion") @nonDispatchHandle type u64 VkSamplerYcbcrConversionKHR
-
-// 161
-@extension("VK_EXT_validation_cache") @nonDispatchHandle type u64 VkValidationCacheEXT
-
-// 166
-@extension("VK_NV_ray_tracing") @nonDispatchHandle type u64 VkAccelerationStructureNV
-
-/////////////
-// Enums //
-/////////////
-
-enum VkImageLayout {
- VK_IMAGE_LAYOUT_UNDEFINED = 0x00000000, /// Implicit layout an image is when its contents are undefined due to various reasons (e.g. right after creation)
- VK_IMAGE_LAYOUT_GENERAL = 0x00000001, /// General layout when image can be used for any kind of access
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL = 0x00000002, /// Optimal layout when image is only used for color attachment read/write
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL = 0x00000003, /// Optimal layout when image is only used for depth/stencil attachment read/write
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL = 0x00000004, /// Optimal layout when image is used for read only depth/stencil attachment and shader access
- VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL = 0x00000005, /// Optimal layout when image is used for read only shader access
- VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL = 0x00000006, /// Optimal layout when image is used only as source of transfer operations
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL = 0x00000007, /// Optimal layout when image is used only as destination of transfer operations
- VK_IMAGE_LAYOUT_PREINITIALIZED = 0x00000008, /// Initial layout used when the data is populated by the CPU
-
- //@vulkan1_1
- VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL = 1000117000,
- VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL = 1000117001,
-
- //@extension("VK_KHR_swapchain") // 2
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR = 1000001002,
-
- //@extension("VK_KHR_shared_presentable_image") // 112
- VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR = 1000111000,
-
- //@extension("VK_KHR_maintenance2") // 118
- VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR = 1000117000,
- VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR = 1000117001,
-
- //@extension("VK_NV_shading_rate_image") // 165
- VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV = 1000164003,
-
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_IMAGE_LAYOUT_FRAGMENT_DENSITY_MAP_OPTIMAL_EXT = 1000218000,
-}
-
-enum VkAttachmentLoadOp {
- VK_ATTACHMENT_LOAD_OP_LOAD = 0x00000000,
- VK_ATTACHMENT_LOAD_OP_CLEAR = 0x00000001,
- VK_ATTACHMENT_LOAD_OP_DONT_CARE = 0x00000002,
-}
-
-enum VkAttachmentStoreOp {
- VK_ATTACHMENT_STORE_OP_STORE = 0x00000000,
- VK_ATTACHMENT_STORE_OP_DONT_CARE = 0x00000001,
-}
-
-enum VkImageType {
- VK_IMAGE_TYPE_1D = 0x00000000,
- VK_IMAGE_TYPE_2D = 0x00000001,
- VK_IMAGE_TYPE_3D = 0x00000002,
-}
-
-enum VkImageTiling {
- VK_IMAGE_TILING_OPTIMAL = 0x00000000,
- VK_IMAGE_TILING_LINEAR = 0x00000001,
-
- //@extension("VK_EXT_image_drm_format_modifier") // 159
- VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT = 1000158000,
-}
-
-enum VkImageViewType {
- VK_IMAGE_VIEW_TYPE_1D = 0x00000000,
- VK_IMAGE_VIEW_TYPE_2D = 0x00000001,
- VK_IMAGE_VIEW_TYPE_3D = 0x00000002,
- VK_IMAGE_VIEW_TYPE_CUBE = 0x00000003,
- VK_IMAGE_VIEW_TYPE_1D_ARRAY = 0x00000004,
- VK_IMAGE_VIEW_TYPE_2D_ARRAY = 0x00000005,
- VK_IMAGE_VIEW_TYPE_CUBE_ARRAY = 0x00000006,
-}
-
-enum VkCommandBufferLevel {
- VK_COMMAND_BUFFER_LEVEL_PRIMARY = 0x00000000,
- VK_COMMAND_BUFFER_LEVEL_SECONDARY = 0x00000001,
-}
-
-enum VkComponentSwizzle {
- VK_COMPONENT_SWIZZLE_IDENTITY = 0x00000000,
- VK_COMPONENT_SWIZZLE_ZERO = 0x00000001,
- VK_COMPONENT_SWIZZLE_ONE = 0x00000002,
- VK_COMPONENT_SWIZZLE_R = 0x00000003,
- VK_COMPONENT_SWIZZLE_G = 0x00000004,
- VK_COMPONENT_SWIZZLE_B = 0x00000005,
- VK_COMPONENT_SWIZZLE_A = 0x00000006,
-}
-
-enum VkDescriptorType {
- VK_DESCRIPTOR_TYPE_SAMPLER = 0x00000000,
- VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER = 0x00000001,
- VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE = 0x00000002,
- VK_DESCRIPTOR_TYPE_STORAGE_IMAGE = 0x00000003,
- VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER = 0x00000004,
- VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER = 0x00000005,
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER = 0x00000006,
- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER = 0x00000007,
- VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 0x00000008,
- VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 0x00000009,
- VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 0x0000000a,
-
- //@extension("VK_EXT_inline_uniform_block") // 139
- VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
-}
-
-enum VkQueryType {
- VK_QUERY_TYPE_OCCLUSION = 0x00000000,
- VK_QUERY_TYPE_PIPELINE_STATISTICS = 0x00000001, /// Optional
- VK_QUERY_TYPE_TIMESTAMP = 0x00000002,
-
- //@extension("VK_EXT_transform_feedback") // 29
- VK_QUERY_TYPE_TRANSFORM_FEEDBACK_STREAM_EXT = 1000028004,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_QUERY_TYPE_ACCELERATION_STRUCTURE_COMPACTED_SIZE_NV = 1000165000,
-}
-
-enum VkBorderColor {
- VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK = 0x00000000,
- VK_BORDER_COLOR_INT_TRANSPARENT_BLACK = 0x00000001,
- VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK = 0x00000002,
- VK_BORDER_COLOR_INT_OPAQUE_BLACK = 0x00000003,
- VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE = 0x00000004,
- VK_BORDER_COLOR_INT_OPAQUE_WHITE = 0x00000005,
-}
-
-enum VkPipelineBindPoint {
- VK_PIPELINE_BIND_POINT_GRAPHICS = 0x00000000,
- VK_PIPELINE_BIND_POINT_COMPUTE = 0x00000001,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_PIPELINE_BIND_POINT_RAY_TRACING_NV = 1000165000,
-}
-
-enum VkPrimitiveTopology {
- VK_PRIMITIVE_TOPOLOGY_POINT_LIST = 0x00000000,
- VK_PRIMITIVE_TOPOLOGY_LINE_LIST = 0x00000001,
- VK_PRIMITIVE_TOPOLOGY_LINE_STRIP = 0x00000002,
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST = 0x00000003,
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP = 0x00000004,
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN = 0x00000005,
- VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY = 0x00000006,
- VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY = 0x00000007,
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY = 0x00000008,
- VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY = 0x00000009,
- VK_PRIMITIVE_TOPOLOGY_PATCH_LIST = 0x0000000a,
-}
-
-enum VkSharingMode {
- VK_SHARING_MODE_EXCLUSIVE = 0x00000000,
- VK_SHARING_MODE_CONCURRENT = 0x00000001,
-}
-
-enum VkIndexType {
- VK_INDEX_TYPE_UINT16 = 0x00000000,
- VK_INDEX_TYPE_UINT32 = 0x00000001,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_INDEX_TYPE_NONE_NV = 1000165000,
-}
-
-enum VkFilter {
- VK_FILTER_NEAREST = 0x00000000,
- VK_FILTER_LINEAR = 0x00000001,
-
- //@extension("VK_IMG_filter_cubic") // 16
- VK_FILTER_CUBIC_IMG = 1000015000,
-}
-
-enum VkSamplerMipmapMode {
- VK_SAMPLER_MIPMAP_MODE_NEAREST = 0x00000001, /// Choose nearest mip level
- VK_SAMPLER_MIPMAP_MODE_LINEAR = 0x00000002, /// Linear filter between mip levels
-}
-
-enum VkSamplerAddressMode {
- VK_SAMPLER_ADDRESS_MODE_REPEAT = 0x00000000,
- VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT = 0x00000001,
- VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE = 0x00000002,
- VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER = 0x00000003,
- VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE = 0x00000004,
-}
-
-enum VkCompareOp {
- VK_COMPARE_OP_NEVER = 0x00000000,
- VK_COMPARE_OP_LESS = 0x00000001,
- VK_COMPARE_OP_EQUAL = 0x00000002,
- VK_COMPARE_OP_LESS_OR_EQUAL = 0x00000003,
- VK_COMPARE_OP_GREATER = 0x00000004,
- VK_COMPARE_OP_NOT_EQUAL = 0x00000005,
- VK_COMPARE_OP_GREATER_OR_EQUAL = 0x00000006,
- VK_COMPARE_OP_ALWAYS = 0x00000007,
-}
-
-enum VkPolygonMode {
- VK_POLYGON_MODE_FILL = 0x00000000,
- VK_POLYGON_MODE_LINE = 0x00000001,
- VK_POLYGON_MODE_POINT = 0x00000002,
-
- //@extension("VK_NV_fill_rectangle") // 154
- VK_POLYGON_MODE_FILL_RECTANGLE_NV = 1000153000,
-}
-
-enum VkFrontFace {
- VK_FRONT_FACE_COUNTER_CLOCKWISE = 0x00000000,
- VK_FRONT_FACE_CLOCKWISE = 0x00000001,
-}
-
-enum VkBlendFactor {
- VK_BLEND_FACTOR_ZERO = 0x00000000,
- VK_BLEND_FACTOR_ONE = 0x00000001,
- VK_BLEND_FACTOR_SRC_COLOR = 0x00000002,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR = 0x00000003,
- VK_BLEND_FACTOR_DST_COLOR = 0x00000004,
- VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR = 0x00000005,
- VK_BLEND_FACTOR_SRC_ALPHA = 0x00000006,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA = 0x00000007,
- VK_BLEND_FACTOR_DST_ALPHA = 0x00000008,
- VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA = 0x00000009,
- VK_BLEND_FACTOR_CONSTANT_COLOR = 0x0000000a,
- VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR = 0x0000000b,
- VK_BLEND_FACTOR_CONSTANT_ALPHA = 0x0000000c,
- VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA = 0x0000000d,
- VK_BLEND_FACTOR_SRC_ALPHA_SATURATE = 0x0000000e,
- VK_BLEND_FACTOR_SRC1_COLOR = 0x0000000f,
- VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR = 0x00000010,
- VK_BLEND_FACTOR_SRC1_ALPHA = 0x00000011,
- VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA = 0x00000012,
-}
-
-enum VkBlendOp {
- VK_BLEND_OP_ADD = 0x00000000,
- VK_BLEND_OP_SUBTRACT = 0x00000001,
- VK_BLEND_OP_REVERSE_SUBTRACT = 0x00000002,
- VK_BLEND_OP_MIN = 0x00000003,
- VK_BLEND_OP_MAX = 0x00000004,
-
- //@extension("VK_EXT_blend_operation_advanced") // 149
- VK_BLEND_OP_ZERO_EXT = 1000148000,
- VK_BLEND_OP_SRC_EXT = 1000148001,
- VK_BLEND_OP_DST_EXT = 1000148002,
- VK_BLEND_OP_SRC_OVER_EXT = 1000148003,
- VK_BLEND_OP_DST_OVER_EXT = 1000148004,
- VK_BLEND_OP_SRC_IN_EXT = 1000148005,
- VK_BLEND_OP_DST_IN_EXT = 1000148006,
- VK_BLEND_OP_SRC_OUT_EXT = 1000148007,
- VK_BLEND_OP_DST_OUT_EXT = 1000148008,
- VK_BLEND_OP_SRC_ATOP_EXT = 1000148009,
- VK_BLEND_OP_DST_ATOP_EXT = 1000148010,
- VK_BLEND_OP_XOR_EXT = 1000148011,
- VK_BLEND_OP_MULTIPLY_EXT = 1000148012,
- VK_BLEND_OP_SCREEN_EXT = 1000148013,
- VK_BLEND_OP_OVERLAY_EXT = 1000148014,
- VK_BLEND_OP_DARKEN_EXT = 1000148015,
- VK_BLEND_OP_LIGHTEN_EXT = 1000148016,
- VK_BLEND_OP_COLORDODGE_EXT = 1000148017,
- VK_BLEND_OP_COLORBURN_EXT = 1000148018,
- VK_BLEND_OP_HARDLIGHT_EXT = 1000148019,
- VK_BLEND_OP_SOFTLIGHT_EXT = 1000148020,
- VK_BLEND_OP_DIFFERENCE_EXT = 1000148021,
- VK_BLEND_OP_EXCLUSION_EXT = 1000148022,
- VK_BLEND_OP_INVERT_EXT = 1000148023,
- VK_BLEND_OP_INVERT_RGB_EXT = 1000148024,
- VK_BLEND_OP_LINEARDODGE_EXT = 1000148025,
- VK_BLEND_OP_LINEARBURN_EXT = 1000148026,
- VK_BLEND_OP_VIVIDLIGHT_EXT = 1000148027,
- VK_BLEND_OP_LINEARLIGHT_EXT = 1000148028,
- VK_BLEND_OP_PINLIGHT_EXT = 1000148029,
- VK_BLEND_OP_HARDMIX_EXT = 1000148030,
- VK_BLEND_OP_HSL_HUE_EXT = 1000148031,
- VK_BLEND_OP_HSL_SATURATION_EXT = 1000148032,
- VK_BLEND_OP_HSL_COLOR_EXT = 1000148033,
- VK_BLEND_OP_HSL_LUMINOSITY_EXT = 1000148034,
- VK_BLEND_OP_PLUS_EXT = 1000148035,
- VK_BLEND_OP_PLUS_CLAMPED_EXT = 1000148036,
- VK_BLEND_OP_PLUS_CLAMPED_ALPHA_EXT = 1000148037,
- VK_BLEND_OP_PLUS_DARKER_EXT = 1000148038,
- VK_BLEND_OP_MINUS_EXT = 1000148039,
- VK_BLEND_OP_MINUS_CLAMPED_EXT = 1000148040,
- VK_BLEND_OP_CONTRAST_EXT = 1000148041,
- VK_BLEND_OP_INVERT_OVG_EXT = 1000148042,
- VK_BLEND_OP_RED_EXT = 1000148043,
- VK_BLEND_OP_GREEN_EXT = 1000148044,
- VK_BLEND_OP_BLUE_EXT = 1000148045,
-}
-
-enum VkStencilOp {
- VK_STENCIL_OP_KEEP = 0x00000000,
- VK_STENCIL_OP_ZERO = 0x00000001,
- VK_STENCIL_OP_REPLACE = 0x00000002,
- VK_STENCIL_OP_INCREMENT_AND_CLAMP = 0x00000003,
- VK_STENCIL_OP_DECREMENT_AND_CLAMP = 0x00000004,
- VK_STENCIL_OP_INVERT = 0x00000005,
- VK_STENCIL_OP_INCREMENT_AND_WRAP = 0x00000006,
- VK_STENCIL_OP_DECREMENT_AND_WRAP = 0x00000007,
-}
-
-enum VkLogicOp {
- VK_LOGIC_OP_CLEAR = 0x00000000,
- VK_LOGIC_OP_AND = 0x00000001,
- VK_LOGIC_OP_AND_REVERSE = 0x00000002,
- VK_LOGIC_OP_COPY = 0x00000003,
- VK_LOGIC_OP_AND_INVERTED = 0x00000004,
- VK_LOGIC_OP_NO_OP = 0x00000005,
- VK_LOGIC_OP_XOR = 0x00000006,
- VK_LOGIC_OP_OR = 0x00000007,
- VK_LOGIC_OP_NOR = 0x00000008,
- VK_LOGIC_OP_EQUIVALENT = 0x00000009,
- VK_LOGIC_OP_INVERT = 0x0000000a,
- VK_LOGIC_OP_OR_REVERSE = 0x0000000b,
- VK_LOGIC_OP_COPY_INVERTED = 0x0000000c,
- VK_LOGIC_OP_OR_INVERTED = 0x0000000d,
- VK_LOGIC_OP_NAND = 0x0000000e,
- VK_LOGIC_OP_SET = 0x0000000f,
-}
-
-enum VkSystemAllocationScope {
- VK_SYSTEM_ALLOCATION_SCOPE_COMMAND = 0x00000000,
- VK_SYSTEM_ALLOCATION_SCOPE_OBJECT = 0x00000001,
- VK_SYSTEM_ALLOCATION_SCOPE_CACHE = 0x00000002,
- VK_SYSTEM_ALLOCATION_SCOPE_DEVICE = 0x00000003,
- VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE = 0x00000004,
-}
-
-enum VkInternalAllocationType {
- VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE = 0x00000000,
-}
-
-enum VkPhysicalDeviceType {
- VK_PHYSICAL_DEVICE_TYPE_OTHER = 0x00000000,
- VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 0x00000001,
- VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 0x00000002,
- VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 0x00000003,
- VK_PHYSICAL_DEVICE_TYPE_CPU = 0x00000004,
-}
-
-enum VkVertexInputRate {
- VK_VERTEX_INPUT_RATE_VERTEX = 0x00000000,
- VK_VERTEX_INPUT_RATE_INSTANCE = 0x00000001,
-}
-
-/// Vulkan format definitions
-enum VkFormat {
- VK_FORMAT_UNDEFINED = 0,
- VK_FORMAT_R4G4_UNORM_PACK8 = 1,
- VK_FORMAT_R4G4B4A4_UNORM_PACK16 = 2,
- VK_FORMAT_B4G4R4A4_UNORM_PACK16 = 3,
- VK_FORMAT_R5G6B5_UNORM_PACK16 = 4,
- VK_FORMAT_B5G6R5_UNORM_PACK16 = 5,
- VK_FORMAT_R5G5B5A1_UNORM_PACK16 = 6,
- VK_FORMAT_B5G5R5A1_UNORM_PACK16 = 7,
- VK_FORMAT_A1R5G5B5_UNORM_PACK16 = 8,
- VK_FORMAT_R8_UNORM = 9,
- VK_FORMAT_R8_SNORM = 10,
- VK_FORMAT_R8_USCALED = 11,
- VK_FORMAT_R8_SSCALED = 12,
- VK_FORMAT_R8_UINT = 13,
- VK_FORMAT_R8_SINT = 14,
- VK_FORMAT_R8_SRGB = 15,
- VK_FORMAT_R8G8_UNORM = 16,
- VK_FORMAT_R8G8_SNORM = 17,
- VK_FORMAT_R8G8_USCALED = 18,
- VK_FORMAT_R8G8_SSCALED = 19,
- VK_FORMAT_R8G8_UINT = 20,
- VK_FORMAT_R8G8_SINT = 21,
- VK_FORMAT_R8G8_SRGB = 22,
- VK_FORMAT_R8G8B8_UNORM = 23,
- VK_FORMAT_R8G8B8_SNORM = 24,
- VK_FORMAT_R8G8B8_USCALED = 25,
- VK_FORMAT_R8G8B8_SSCALED = 26,
- VK_FORMAT_R8G8B8_UINT = 27,
- VK_FORMAT_R8G8B8_SINT = 28,
- VK_FORMAT_R8G8B8_SRGB = 29,
- VK_FORMAT_B8G8R8_UNORM = 30,
- VK_FORMAT_B8G8R8_SNORM = 31,
- VK_FORMAT_B8G8R8_USCALED = 32,
- VK_FORMAT_B8G8R8_SSCALED = 33,
- VK_FORMAT_B8G8R8_UINT = 34,
- VK_FORMAT_B8G8R8_SINT = 35,
- VK_FORMAT_B8G8R8_SRGB = 36,
- VK_FORMAT_R8G8B8A8_UNORM = 37,
- VK_FORMAT_R8G8B8A8_SNORM = 38,
- VK_FORMAT_R8G8B8A8_USCALED = 39,
- VK_FORMAT_R8G8B8A8_SSCALED = 40,
- VK_FORMAT_R8G8B8A8_UINT = 41,
- VK_FORMAT_R8G8B8A8_SINT = 42,
- VK_FORMAT_R8G8B8A8_SRGB = 43,
- VK_FORMAT_B8G8R8A8_UNORM = 44,
- VK_FORMAT_B8G8R8A8_SNORM = 45,
- VK_FORMAT_B8G8R8A8_USCALED = 46,
- VK_FORMAT_B8G8R8A8_SSCALED = 47,
- VK_FORMAT_B8G8R8A8_UINT = 48,
- VK_FORMAT_B8G8R8A8_SINT = 49,
- VK_FORMAT_B8G8R8A8_SRGB = 50,
- VK_FORMAT_A8B8G8R8_UNORM_PACK32 = 51,
- VK_FORMAT_A8B8G8R8_SNORM_PACK32 = 52,
- VK_FORMAT_A8B8G8R8_USCALED_PACK32 = 53,
- VK_FORMAT_A8B8G8R8_SSCALED_PACK32 = 54,
- VK_FORMAT_A8B8G8R8_UINT_PACK32 = 55,
- VK_FORMAT_A8B8G8R8_SINT_PACK32 = 56,
- VK_FORMAT_A8B8G8R8_SRGB_PACK32 = 57,
- VK_FORMAT_A2R10G10B10_UNORM_PACK32 = 58,
- VK_FORMAT_A2R10G10B10_SNORM_PACK32 = 59,
- VK_FORMAT_A2R10G10B10_USCALED_PACK32 = 60,
- VK_FORMAT_A2R10G10B10_SSCALED_PACK32 = 61,
- VK_FORMAT_A2R10G10B10_UINT_PACK32 = 62,
- VK_FORMAT_A2R10G10B10_SINT_PACK32 = 63,
- VK_FORMAT_A2B10G10R10_UNORM_PACK32 = 64,
- VK_FORMAT_A2B10G10R10_SNORM_PACK32 = 65,
- VK_FORMAT_A2B10G10R10_USCALED_PACK32 = 66,
- VK_FORMAT_A2B10G10R10_SSCALED_PACK32 = 67,
- VK_FORMAT_A2B10G10R10_UINT_PACK32 = 68,
- VK_FORMAT_A2B10G10R10_SINT_PACK32 = 69,
- VK_FORMAT_R16_UNORM = 70,
- VK_FORMAT_R16_SNORM = 71,
- VK_FORMAT_R16_USCALED = 72,
- VK_FORMAT_R16_SSCALED = 73,
- VK_FORMAT_R16_UINT = 74,
- VK_FORMAT_R16_SINT = 75,
- VK_FORMAT_R16_SFLOAT = 76,
- VK_FORMAT_R16G16_UNORM = 77,
- VK_FORMAT_R16G16_SNORM = 78,
- VK_FORMAT_R16G16_USCALED = 79,
- VK_FORMAT_R16G16_SSCALED = 80,
- VK_FORMAT_R16G16_UINT = 81,
- VK_FORMAT_R16G16_SINT = 82,
- VK_FORMAT_R16G16_SFLOAT = 83,
- VK_FORMAT_R16G16B16_UNORM = 84,
- VK_FORMAT_R16G16B16_SNORM = 85,
- VK_FORMAT_R16G16B16_USCALED = 86,
- VK_FORMAT_R16G16B16_SSCALED = 87,
- VK_FORMAT_R16G16B16_UINT = 88,
- VK_FORMAT_R16G16B16_SINT = 89,
- VK_FORMAT_R16G16B16_SFLOAT = 90,
- VK_FORMAT_R16G16B16A16_UNORM = 91,
- VK_FORMAT_R16G16B16A16_SNORM = 92,
- VK_FORMAT_R16G16B16A16_USCALED = 93,
- VK_FORMAT_R16G16B16A16_SSCALED = 94,
- VK_FORMAT_R16G16B16A16_UINT = 95,
- VK_FORMAT_R16G16B16A16_SINT = 96,
- VK_FORMAT_R16G16B16A16_SFLOAT = 97,
- VK_FORMAT_R32_UINT = 98,
- VK_FORMAT_R32_SINT = 99,
- VK_FORMAT_R32_SFLOAT = 100,
- VK_FORMAT_R32G32_UINT = 101,
- VK_FORMAT_R32G32_SINT = 102,
- VK_FORMAT_R32G32_SFLOAT = 103,
- VK_FORMAT_R32G32B32_UINT = 104,
- VK_FORMAT_R32G32B32_SINT = 105,
- VK_FORMAT_R32G32B32_SFLOAT = 106,
- VK_FORMAT_R32G32B32A32_UINT = 107,
- VK_FORMAT_R32G32B32A32_SINT = 108,
- VK_FORMAT_R32G32B32A32_SFLOAT = 109,
- VK_FORMAT_R64_UINT = 110,
- VK_FORMAT_R64_SINT = 111,
- VK_FORMAT_R64_SFLOAT = 112,
- VK_FORMAT_R64G64_UINT = 113,
- VK_FORMAT_R64G64_SINT = 114,
- VK_FORMAT_R64G64_SFLOAT = 115,
- VK_FORMAT_R64G64B64_UINT = 116,
- VK_FORMAT_R64G64B64_SINT = 117,
- VK_FORMAT_R64G64B64_SFLOAT = 118,
- VK_FORMAT_R64G64B64A64_UINT = 119,
- VK_FORMAT_R64G64B64A64_SINT = 120,
- VK_FORMAT_R64G64B64A64_SFLOAT = 121,
- VK_FORMAT_B10G11R11_UFLOAT_PACK32 = 122,
- VK_FORMAT_E5B9G9R9_UFLOAT_PACK32 = 123,
- VK_FORMAT_D16_UNORM = 124,
- VK_FORMAT_X8_D24_UNORM_PACK32 = 125,
- VK_FORMAT_D32_SFLOAT = 126,
- VK_FORMAT_S8_UINT = 127,
- VK_FORMAT_D16_UNORM_S8_UINT = 128,
- VK_FORMAT_D24_UNORM_S8_UINT = 129,
- VK_FORMAT_D32_SFLOAT_S8_UINT = 130,
- VK_FORMAT_BC1_RGB_UNORM_BLOCK = 131,
- VK_FORMAT_BC1_RGB_SRGB_BLOCK = 132,
- VK_FORMAT_BC1_RGBA_UNORM_BLOCK = 133,
- VK_FORMAT_BC1_RGBA_SRGB_BLOCK = 134,
- VK_FORMAT_BC2_UNORM_BLOCK = 135,
- VK_FORMAT_BC2_SRGB_BLOCK = 136,
- VK_FORMAT_BC3_UNORM_BLOCK = 137,
- VK_FORMAT_BC3_SRGB_BLOCK = 138,
- VK_FORMAT_BC4_UNORM_BLOCK = 139,
- VK_FORMAT_BC4_SNORM_BLOCK = 140,
- VK_FORMAT_BC5_UNORM_BLOCK = 141,
- VK_FORMAT_BC5_SNORM_BLOCK = 142,
- VK_FORMAT_BC6H_UFLOAT_BLOCK = 143,
- VK_FORMAT_BC6H_SFLOAT_BLOCK = 144,
- VK_FORMAT_BC7_UNORM_BLOCK = 145,
- VK_FORMAT_BC7_SRGB_BLOCK = 146,
- VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK = 147,
- VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK = 148,
- VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK = 149,
- VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK = 150,
- VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK = 151,
- VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK = 152,
- VK_FORMAT_EAC_R11_UNORM_BLOCK = 153,
- VK_FORMAT_EAC_R11_SNORM_BLOCK = 154,
- VK_FORMAT_EAC_R11G11_UNORM_BLOCK = 155,
- VK_FORMAT_EAC_R11G11_SNORM_BLOCK = 156,
- VK_FORMAT_ASTC_4x4_UNORM_BLOCK = 157,
- VK_FORMAT_ASTC_4x4_SRGB_BLOCK = 158,
- VK_FORMAT_ASTC_5x4_UNORM_BLOCK = 159,
- VK_FORMAT_ASTC_5x4_SRGB_BLOCK = 160,
- VK_FORMAT_ASTC_5x5_UNORM_BLOCK = 161,
- VK_FORMAT_ASTC_5x5_SRGB_BLOCK = 162,
- VK_FORMAT_ASTC_6x5_UNORM_BLOCK = 163,
- VK_FORMAT_ASTC_6x5_SRGB_BLOCK = 164,
- VK_FORMAT_ASTC_6x6_UNORM_BLOCK = 165,
- VK_FORMAT_ASTC_6x6_SRGB_BLOCK = 166,
- VK_FORMAT_ASTC_8x5_UNORM_BLOCK = 167,
- VK_FORMAT_ASTC_8x5_SRGB_BLOCK = 168,
- VK_FORMAT_ASTC_8x6_UNORM_BLOCK = 169,
- VK_FORMAT_ASTC_8x6_SRGB_BLOCK = 170,
- VK_FORMAT_ASTC_8x8_UNORM_BLOCK = 171,
- VK_FORMAT_ASTC_8x8_SRGB_BLOCK = 172,
- VK_FORMAT_ASTC_10x5_UNORM_BLOCK = 173,
- VK_FORMAT_ASTC_10x5_SRGB_BLOCK = 174,
- VK_FORMAT_ASTC_10x6_UNORM_BLOCK = 175,
- VK_FORMAT_ASTC_10x6_SRGB_BLOCK = 176,
- VK_FORMAT_ASTC_10x8_UNORM_BLOCK = 177,
- VK_FORMAT_ASTC_10x8_SRGB_BLOCK = 178,
- VK_FORMAT_ASTC_10x10_UNORM_BLOCK = 179,
- VK_FORMAT_ASTC_10x10_SRGB_BLOCK = 180,
- VK_FORMAT_ASTC_12x10_UNORM_BLOCK = 181,
- VK_FORMAT_ASTC_12x10_SRGB_BLOCK = 182,
- VK_FORMAT_ASTC_12x12_UNORM_BLOCK = 183,
- VK_FORMAT_ASTC_12x12_SRGB_BLOCK = 184,
-
- //@vulkan1_1
- VK_FORMAT_G8B8G8R8_422_UNORM = 1000156000,
- VK_FORMAT_B8G8R8G8_422_UNORM = 1000156001,
- VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM = 1000156002,
- VK_FORMAT_G8_B8R8_2PLANE_420_UNORM = 1000156003,
- VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM = 1000156004,
- VK_FORMAT_G8_B8R8_2PLANE_422_UNORM = 1000156005,
- VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM = 1000156006,
- VK_FORMAT_R10X6_UNORM_PACK16 = 1000156007,
- VK_FORMAT_R10X6G10X6_UNORM_2PACK16 = 1000156008,
- VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 = 1000156009,
- VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 = 1000156010,
- VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 = 1000156011,
- VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 = 1000156012,
- VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 = 1000156013,
- VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 = 1000156014,
- VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 = 1000156015,
- VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 = 1000156016,
- VK_FORMAT_R12X4_UNORM_PACK16 = 1000156017,
- VK_FORMAT_R12X4G12X4_UNORM_2PACK16 = 1000156018,
- VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 = 1000156019,
- VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 = 1000156020,
- VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 = 1000156021,
- VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 = 1000156022,
- VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 = 1000156023,
- VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 = 1000156024,
- VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 = 1000156025,
- VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 = 1000156026,
- VK_FORMAT_G16B16G16R16_422_UNORM = 1000156027,
- VK_FORMAT_B16G16R16G16_422_UNORM = 1000156028,
- VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM = 1000156029,
- VK_FORMAT_G16_B16R16_2PLANE_420_UNORM = 1000156030,
- VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM = 1000156031,
- VK_FORMAT_G16_B16R16_2PLANE_422_UNORM = 1000156032,
- VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM = 1000156033,
-
- //@extension("VK_IMG_format_pvrtc") // 28
- VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG = 1000054000,
- VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG = 1000054001,
- VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG = 1000054002,
- VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG = 1000054003,
- VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG = 1000054004,
- VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG = 1000054005,
- VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG = 1000054006,
- VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG = 1000054007,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_FORMAT_G8B8G8R8_422_UNORM_KHR = 1000156000,
- VK_FORMAT_B8G8R8G8_422_UNORM_KHR = 1000156001,
- VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR = 1000156002,
- VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR = 1000156003,
- VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR = 1000156004,
- VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR = 1000156005,
- VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR = 1000156006,
- VK_FORMAT_R10X6_UNORM_PACK16_KHR = 1000156007,
- VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR = 1000156008,
- VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR = 1000156009,
- VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR = 1000156010,
- VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR = 1000156011,
- VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR = 1000156012,
- VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR = 1000156013,
- VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR = 1000156014,
- VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR = 1000156015,
- VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR = 1000156016,
- VK_FORMAT_R12X4_UNORM_PACK16_KHR = 1000156017,
- VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR = 1000156018,
- VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR = 1000156019,
- VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR = 1000156020,
- VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR = 1000156021,
- VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR = 1000156022,
- VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR = 1000156023,
- VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR = 1000156024,
- VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR = 1000156025,
- VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR = 1000156026,
- VK_FORMAT_G16B16G16R16_422_UNORM_KHR = 1000156027,
- VK_FORMAT_B16G16R16G16_422_UNORM_KHR = 1000156028,
- VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR = 1000156029,
- VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR = 1000156030,
- VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR = 1000156031,
- VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR = 1000156032,
- VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR = 1000156033,
-}
-
-/// Structure type enumerant
-enum VkStructureType {
- VK_STRUCTURE_TYPE_APPLICATION_INFO = 0,
- VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO = 1,
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO = 2,
- VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO = 3,
- VK_STRUCTURE_TYPE_SUBMIT_INFO = 4,
- VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO = 5,
- VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE = 6,
- VK_STRUCTURE_TYPE_BIND_SPARSE_INFO = 7,
- VK_STRUCTURE_TYPE_FENCE_CREATE_INFO = 8,
- VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO = 9,
- VK_STRUCTURE_TYPE_EVENT_CREATE_INFO = 10,
- VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO = 11,
- VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO = 12,
- VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO = 13,
- VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO = 14,
- VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO = 15,
- VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO = 16,
- VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO = 17,
- VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO = 18,
- VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO = 19,
- VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20,
- VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO = 21,
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO = 22,
- VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO = 23,
- VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO = 24,
- VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO = 25,
- VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO = 26,
- VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO = 27,
- VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO = 28,
- VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO = 29,
- VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO = 30,
- VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO = 31,
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO = 32,
- VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO = 33,
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO = 34,
- VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET = 35,
- VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET = 36,
- VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO = 37,
- VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO = 38,
- VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO = 39,
- VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO = 40,
- VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO = 41,
- VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO = 42,
- VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO = 43,
- VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER = 44,
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER = 45,
- VK_STRUCTURE_TYPE_MEMORY_BARRIER = 46,
- VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO = 47,
- VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO = 48,
-
- //@vulkan1_1
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES = 1000094000,
- VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO = 1000157000,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO = 1000157001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES = 1000083000,
- VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS = 1000127000,
- VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO = 1000127001,
- VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO = 1000060000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO = 1000060003,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO = 1000060004,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO = 1000060005,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO = 1000060006,
- VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO = 1000060013,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO = 1000060014,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES = 1000070000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO = 1000070001,
- VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2 = 1000146000,
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2 = 1000146001,
- VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2 = 1000146002,
- VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2 = 1000146003,
- VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2 = 1000146004,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 = 1000059000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2 = 1000059001,
- VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2 = 1000059002,
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2 = 1000059003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2 = 1000059004,
- VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2 = 1000059005,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2 = 1000059006,
- VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2 = 1000059007,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2 = 1000059008,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES = 1000117000,
- VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO = 1000117001,
- VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO = 1000117002,
- VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO = 1000117003,
- VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO = 1000053000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES = 1000053001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES = 1000053002,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES = 1000120000,
- VK_STRUCTURE_TYPE_PROTECTED_SUBMIT_INFO = 1000145000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES = 1000145001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_PROPERTIES = 1000145002,
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2 = 1000145003,
- VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO = 1000156000,
- VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO = 1000156001,
- VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO = 1000156002,
- VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO = 1000156003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES = 1000156004,
- VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES = 1000156005,
- VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO = 1000085000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO = 1000071000,
- VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES = 1000071001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO = 1000071002,
- VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES = 1000071003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES = 1000071004,
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO = 1000072000,
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO = 1000072001,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO = 1000072002,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO = 1000112000,
- VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES = 1000112001,
- VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO = 1000113000,
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO = 1000077000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO = 1000076000,
- VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES = 1000076001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES = 1000168000,
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT = 1000168001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES = 1000063000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
-
- //@extension("VK_KHR_swapchain") // 2
- VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR = 1000001000,
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR = 1000001001,
- // added as interaction from VK_KHR_device_group / VK 1.1
- VK_STRUCTURE_TYPE_IMAGE_SWAPCHAIN_CREATE_INFO_KHR = 1000060008,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_SWAPCHAIN_INFO_KHR = 1000060009,
- VK_STRUCTURE_TYPE_ACQUIRE_NEXT_IMAGE_INFO_KHR = 1000060010,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_INFO_KHR = 1000060011,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SWAPCHAIN_CREATE_INFO_KHR = 1000060012,
-
- //@extension("VK_KHR_display") // 3
- VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR = 1000002000,
- VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR = 1000002001,
-
- //@extension("VK_KHR_display_swapchain") // 4
- VK_STRUCTURE_TYPE_DISPLAY_DISPLAY_PRESENT_INFO_KHR = 1000003000,
-
- //@extension("VK_KHR_xlib_surface") // 5
- VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR = 1000004000,
-
- //@extension("VK_KHR_xcb_surface") // 6
- VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR = 1000005000,
-
- //@extension("VK_KHR_wayland_surface") // 7
- VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR = 1000006000,
-
- //@extension("VK_KHR_android_surface") // 9
- VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR = 1000008000,
-
- //@extension("VK_KHR_win32_surface") // 10
- VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR = 1000009000,
-
- //@extension("VK_ANDROID_native_buffer") // 11
- VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID = 1000010000,
- VK_STRUCTURE_TYPE_SWAPCHAIN_IMAGE_CREATE_INFO_ANDROID = 1000010001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENTATION_PROPERTIES_ANDROID = 1000010002,
-
- //@extension("VK_EXT_debug_report") // 12
- VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT = 1000011000,
-
- //@extension("VK_AMD_rasterization_order") // 19
- VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,
-
- //@extension("VK_EXT_debug_marker") // 23
- VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT = 1000022000,
- VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT = 1000022001,
- VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT = 1000022002,
-
- //@extension("VK_NV_dedicated_allocation") // 27
- VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_IMAGE_CREATE_INFO_NV = 1000026000,
- VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_BUFFER_CREATE_INFO_NV = 1000026001,
- VK_STRUCTURE_TYPE_DEDICATED_ALLOCATION_MEMORY_ALLOCATE_INFO_NV = 1000026002,
-
- //@extension("VK_EXT_transform_feedback") // 29
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_FEATURES_EXT = 1000028000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT = 1000028001,
- VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_STREAM_CREATE_INFO_EXT = 1000028002,
-
- //@extension("VK_AMD_texture_gather_bias_lod") // 42
- VK_STRUCTURE_TYPE_TEXTURE_LOD_GATHER_FORMAT_PROPERTIES_AMD = 1000041000,
-
- //@extension("VK_NV_corner_sampled_image") // 51
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CORNER_SAMPLED_IMAGE_FEATURES_NV = 1000050000,
-
- //@extension("VK_KHR_multiview") // 54
- VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = 1000053000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = 1000053001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = 1000053002,
-
- //@extension("VK_NV_external_memory") // 57
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_NV = 1000056000,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_NV = 1000056001,
-
- //@extension("VK_NV_external_memory_win32") // 58
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057000,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_NV = 1000057001,
-
- //@extension("VK_NV_win32_keyed_mutex") // 59
- VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
-
- //@extension("VK_KHR_get_physical_device_properties2") // 60
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR = 1000059000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR = 1000059001,
- VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2_KHR = 1000059002,
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2_KHR = 1000059004,
- VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2_KHR = 1000059005,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_PROPERTIES_2_KHR = 1000059006,
- VK_STRUCTURE_TYPE_SPARSE_IMAGE_FORMAT_PROPERTIES_2_KHR = 1000059007,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SPARSE_IMAGE_FORMAT_INFO_2_KHR = 1000059008,
-
- //@extension("VK_KHR_device_group") // 61
- VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_FLAGS_INFO_KHR = 1000060000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_RENDER_PASS_BEGIN_INFO_KHR = 1000060003,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_COMMAND_BUFFER_BEGIN_INFO_KHR = 1000060004,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_SUBMIT_INFO_KHR = 1000060005,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_BIND_SPARSE_INFO_KHR = 1000060006,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_PRESENT_CAPABILITIES_KHR = 1000060007,
- // tokens 08-12 are listed with VK_KHR_swapchain
- VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060013,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_DEVICE_GROUP_INFO_KHR = 1000060014,
-
- //@extension("VK_EXT_validation_flags") // 62
- VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
-
- //@extension("VK_NN_vi_surface") // 63
- VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
-
- //@extension("VK_EXT_astc_decode_mode") // 68
- VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001,
-
- //@extension("VK_KHR_device_group_creation") // 71
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR = 1000070000,
- VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR = 1000070001,
-
- //@extension("VK_KHR_external_memory_capabilities") // 72
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO_KHR = 1000071000,
- VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES_KHR = 1000071001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_BUFFER_INFO_KHR = 1000071002,
- VK_STRUCTURE_TYPE_EXTERNAL_BUFFER_PROPERTIES_KHR = 1000071003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR = 1000071004,
-
- //@extension("VK_KHR_external_memory") // 73
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO_KHR = 1000072000,
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR = 1000072001,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO_KHR = 1000072002,
-
- //@extension("VK_KHR_external_memory_win32") // 74
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
- VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
- VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
-
- //@extension("VK_KHR_external_memory_fd") // 75
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR = 1000074000,
- VK_STRUCTURE_TYPE_MEMORY_FD_PROPERTIES_KHR = 1000074001,
-
- //@extension("VK_KHR_win32_keyed_mutex") // 76
- VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_KHR = 1000075000,
-
- //@extension("VK_KHR_external_semaphore_capabilities") // 77
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO_KHR = 1000076000,
- VK_STRUCTURE_TYPE_EXTERNAL_SEMAPHORE_PROPERTIES_KHR = 1000076001,
-
- //@extension("VK_KHR_external_semaphore") // 78
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = 1000077000,
-
- //@extension("VK_KHR_external_semaphore_win32") // 79
- VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078000,
- VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_WIN32_HANDLE_INFO_KHR = 1000078001,
- VK_STRUCTURE_TYPE_D3D12_FENCE_SUBMIT_INFO_KHR = 1000078002,
-
- //@extension("VK_KHR_external_semaphore_fd") // 80
- VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR = 1000079000,
- VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR = 1000079001,
-
- //@extension("VK_KHR_push_descriptor") // 81
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PUSH_DESCRIPTOR_PROPERTIES_KHR = 1000080000,
-
- //@extension("VK_KHR_16bit_storage") // 84
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = 1000083000,
-
- //@extension("VK_KHR_incremental_present") // 85
- VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR = 1000084000,
-
- //@extension("VK_EXT_conditional_rendering") // 82
- VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_CONDITIONAL_RENDERING_INFO_EXT = 1000081000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONDITIONAL_RENDERING_FEATURES_EXT = 1000081001,
- VK_STRUCTURE_TYPE_CONDITIONAL_RENDERING_BEGIN_INFO_EXT = 1000081002,
-
- //@extension("VK_KHR_shader_float16_int8") // 83
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT16_INT8_FEATURES_KHR = 1000082000,
-
- //@extension("VK_KHR_descriptor_update_template") // 86
- VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = 1000085000,
-
- //@extension("VK_NVX_device_generated_commands") // 87
- VK_STRUCTURE_TYPE_OBJECT_TABLE_CREATE_INFO_NVX = 1000086000,
- VK_STRUCTURE_TYPE_INDIRECT_COMMANDS_LAYOUT_CREATE_INFO_NVX = 1000086001,
- VK_STRUCTURE_TYPE_CMD_PROCESS_COMMANDS_INFO_NVX = 1000086002,
- VK_STRUCTURE_TYPE_CMD_RESERVE_SPACE_FOR_COMMANDS_INFO_NVX = 1000086003,
- VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_LIMITS_NVX = 1000086004,
- VK_STRUCTURE_TYPE_DEVICE_GENERATED_COMMANDS_FEATURES_NVX = 1000086005,
-
- //@extension("VK_NV_clip_space_w_scaling") // 88
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_W_SCALING_STATE_CREATE_INFO_NV = 1000087000,
-
- //@extension("VK_EXT_display_surface_counter") // 91
- VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT = 1000090000,
-
- //@extension("VK_EXT_display_control") // 92
- VK_STRUCTURE_TYPE_DISPLAY_POWER_INFO_EXT = 1000091000,
- VK_STRUCTURE_TYPE_DEVICE_EVENT_INFO_EXT = 1000091001,
- VK_STRUCTURE_TYPE_DISPLAY_EVENT_INFO_EXT = 1000091002,
- VK_STRUCTURE_TYPE_SWAPCHAIN_COUNTER_CREATE_INFO_EXT = 1000091003,
-
- //@extension("VK_GOOGLE_display_timing") // 93
- VK_STRUCTURE_TYPE_PRESENT_TIMES_INFO_GOOGLE = 1000092000,
-
- //@extension("VK_NVX_multiview_per_view_attributes") // 98
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PER_VIEW_ATTRIBUTES_PROPERTIES_NVX = 1000097000,
-
- //@extension("VK_NV_viewport_swizzle") // 99
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV = 1000098000,
-
- //@extension("VK_EXT_discard_rectangles") // 100
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DISCARD_RECTANGLE_PROPERTIES_EXT = 1000099000,
- VK_STRUCTURE_TYPE_PIPELINE_DISCARD_RECTANGLE_STATE_CREATE_INFO_EXT = 1000099001,
-
- //@extension("VK_EXT_conservative_rasterization") // 102
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_CONSERVATIVE_RASTERIZATION_PROPERTIES_EXT = 1000101000,
- VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_CONSERVATIVE_STATE_CREATE_INFO_EXT = 1000101001,
-
- //@extension("VK_KHR_create_renderpass2") // 110
- VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2_KHR = 1000109000,
- VK_STRUCTURE_TYPE_ATTACHMENT_REFERENCE_2_KHR = 1000109001,
- VK_STRUCTURE_TYPE_SUBPASS_DESCRIPTION_2_KHR = 1000109002,
- VK_STRUCTURE_TYPE_SUBPASS_DEPENDENCY_2_KHR = 1000109003,
- VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO_2_KHR = 1000109004,
- VK_STRUCTURE_TYPE_SUBPASS_BEGIN_INFO_KHR = 1000109005,
- VK_STRUCTURE_TYPE_SUBPASS_END_INFO_KHR = 1000109006,
-
- //@extension("VK_EXT_hdr_metadata") // 106
- VK_STRUCTURE_TYPE_HDR_METADATA_EXT = 1000105000,
-
- //@extension("VK_KHR_shared_presentable_image") // 112
- VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR = 1000111000,
-
- //@extension("VK_KHR_external_fence_capabilities") // 113
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = 1000112000,
- VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = 1000112001,
-
- //@extension("VK_KHR_external_fence") // 114
- VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = 1000113000,
-
- //@extension("VK_KHR_external_fence_win32") // 115
- VK_STRUCTURE_TYPE_IMPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114000,
- VK_STRUCTURE_TYPE_EXPORT_FENCE_WIN32_HANDLE_INFO_KHR = 1000114001,
- VK_STRUCTURE_TYPE_FENCE_GET_WIN32_HANDLE_INFO_KHR = 1000114002,
-
- //@extension("VK_KHR_external_fence_fd") // 117
- VK_STRUCTURE_TYPE_IMPORT_FENCE_FD_INFO_KHR = 1000115000,
- VK_STRUCTURE_TYPE_FENCE_GET_FD_INFO_KHR = 1000115001,
-
- //@extension("VK_KHR_maintenance2") // 118
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES_KHR = 1000117000,
- VK_STRUCTURE_TYPE_RENDER_PASS_INPUT_ATTACHMENT_ASPECT_CREATE_INFO_KHR = 1000117001,
- VK_STRUCTURE_TYPE_IMAGE_VIEW_USAGE_CREATE_INFO_KHR = 1000117002,
- VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_DOMAIN_ORIGIN_STATE_CREATE_INFO_KHR = 1000117003,
-
- //@extension("VK_KHR_get_surface_capabilities2") // 120
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR = 1000119000,
- VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR = 1000119001,
- VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR = 1000119002,
-
- //@extension("VK_KHR_variable_pointers") // 121
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR = 1000120000,
-
- //@extension("VK_KHR_display_properties2") // 122
- VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR = 1000121000,
- VK_STRUCTURE_TYPE_DISPLAY_PLANE_PROPERTIES_2_KHR = 1000121001,
- VK_STRUCTURE_TYPE_DISPLAY_MODE_PROPERTIES_2_KHR = 1000121002,
- VK_STRUCTURE_TYPE_DISPLAY_PLANE_INFO_2_KHR = 1000121003,
- VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR = 1000121004,
-
- //@extension("VK_MVK_ios_surface") // 123
- VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK = 1000122000,
-
- //@extension("VK_MVK_macos_surface") // 124
- VK_STRUCTURE_TYPE_MACOS_SURFACE_CREATE_INFO_MVK = 1000123000,
-
- //@extension("VK_KHR_dedicated_allocation") // 128
- VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS_KHR = 1000127000,
- VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR = 1000127001,
-
- //@extension("VK_EXT_debug_utils") // 129
- VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT = 1000128000,
- VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_TAG_INFO_EXT = 1000128001,
- VK_STRUCTURE_TYPE_DEBUG_UTILS_LABEL_EXT = 1000128002,
- VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CALLBACK_DATA_EXT = 1000128003,
- VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT = 1000128004,
-
- //@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
- VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_USAGE_ANDROID = 1000129000,
- VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_PROPERTIES_ANDROID = 1000129001,
- VK_STRUCTURE_TYPE_ANDROID_HARDWARE_BUFFER_FORMAT_PROPERTIES_ANDROID = 1000129002,
- VK_STRUCTURE_TYPE_IMPORT_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129003,
- VK_STRUCTURE_TYPE_MEMORY_GET_ANDROID_HARDWARE_BUFFER_INFO_ANDROID = 1000129004,
- VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005,
-
- //@extension("VK_EXT_sampler_filter_minmax") // 131
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
- VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
-
- //@extension("VK_EXT_inline_uniform_block") // 139
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001,
- VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002,
- VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003,
-
- //@extension("VK_EXT_sample_locations") // 144
- VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000,
- VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001,
- VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLE_LOCATIONS_PROPERTIES_EXT = 1000143003,
- VK_STRUCTURE_TYPE_MULTISAMPLE_PROPERTIES_EXT = 1000143004,
-
- //@extension("VK_KHR_get_memory_requirements2") // 147
- VK_STRUCTURE_TYPE_BUFFER_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146000,
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146001,
- VK_STRUCTURE_TYPE_IMAGE_SPARSE_MEMORY_REQUIREMENTS_INFO_2_KHR = 1000146002,
- VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2_KHR = 1000146003,
- VK_STRUCTURE_TYPE_SPARSE_IMAGE_MEMORY_REQUIREMENTS_2_KHR = 1000146004,
-
- //@extension("VK_KHR_image_format_list") // 148
- VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR = 1000147000,
-
- //@extension("VK_EXT_blend_operation_advanced") // 149
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_FEATURES_EXT = 1000148000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_BLEND_OPERATION_ADVANCED_PROPERTIES_EXT = 1000148001,
- VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_ADVANCED_STATE_CREATE_INFO_EXT = 1000148002,
-
- //@extension("VK_NV_fragment_coverage_to_color") // 150
- VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_TO_COLOR_STATE_CREATE_INFO_NV = 1000149000,
-
- //@extension("VK_NV_framebuffer_mixed_samples") // 153
- VK_STRUCTURE_TYPE_PIPELINE_COVERAGE_MODULATION_STATE_CREATE_INFO_NV = 1000152000,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO_KHR = 1000156000,
- VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO_KHR = 1000156001,
- VK_STRUCTURE_TYPE_BIND_IMAGE_PLANE_MEMORY_INFO_KHR = 1000156002,
- VK_STRUCTURE_TYPE_IMAGE_PLANE_MEMORY_REQUIREMENTS_INFO_KHR = 1000156003,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES_KHR = 1000156004,
- VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_IMAGE_FORMAT_PROPERTIES_KHR = 1000156005,
-
- //@extension("VK_EXT_image_drm_format_modifier") // 159
- VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_LIST_EXT = 1000158000,
- VK_STRUCTURE_TYPE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_DRM_FORMAT_MODIFIER_INFO_EXT = 1000158002,
- VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_LIST_CREATE_INFO_EXT = 1000158003,
- VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT = 1000158004,
- VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_PROPERTIES_EXT = 1000158005,
-
- //@extension("VK_KHR_bind_memory2") // 158
- VK_STRUCTURE_TYPE_BIND_BUFFER_MEMORY_INFO_KHR = 1000157000,
- VK_STRUCTURE_TYPE_BIND_IMAGE_MEMORY_INFO_KHR = 1000157001,
-
- //@extension("VK_EXT_validation_cache") // 161
- VK_STRUCTURE_TYPE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160000,
- VK_STRUCTURE_TYPE_SHADER_MODULE_VALIDATION_CACHE_CREATE_INFO_EXT = 1000160001,
-
- //@extension("VK_EXT_descriptor_indexing") // 162
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT = 1000161000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT = 1000161001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_PROPERTIES_EXT = 1000161002,
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO_EXT = 1000161003,
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_LAYOUT_SUPPORT_EXT = 1000161004,
-
- //@extension("VK_NV_shading_rate_image") // 165
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SHADING_RATE_IMAGE_STATE_CREATE_INFO_NV = 1000164000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_FEATURES_NV = 1000164001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADING_RATE_IMAGE_PROPERTIES_NV = 1000164002,
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_COARSE_SAMPLE_ORDER_STATE_CREATE_INFO_NV = 1000164005,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_STRUCTURE_TYPE_RAY_TRACING_PIPELINE_CREATE_INFO_NV = 1000165000,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_CREATE_INFO_NV = 1000165001,
- VK_STRUCTURE_TYPE_GEOMETRY_NV = 1000165003,
- VK_STRUCTURE_TYPE_GEOMETRY_TRIANGLES_NV = 1000165004,
- VK_STRUCTURE_TYPE_GEOMETRY_AABB_NV = 1000165005,
- VK_STRUCTURE_TYPE_BIND_ACCELERATION_STRUCTURE_MEMORY_INFO_NV = 1000165006,
- VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_ACCELERATION_STRUCTURE_NV = 1000165007,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_INFO_NV = 1000165008,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_RAY_TRACING_PROPERTIES_NV = 1000165009,
- VK_STRUCTURE_TYPE_RAY_TRACING_SHADER_GROUP_CREATE_INFO_NV = 1000165011,
- VK_STRUCTURE_TYPE_ACCELERATION_STRUCTURE_INFO_NV = 1000165012,
-
- //@extension("VK_NV_representative_fragment_test") // 167
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_REPRESENTATIVE_FRAGMENT_TEST_FEATURES_NV = 1000166000,
- VK_STRUCTURE_TYPE_PIPELINE_REPRESENTATIVE_FRAGMENT_TEST_STATE_CREATE_INFO_NV = 1000166001,
-
- //@extension("VK_KHR_maintenance3") // 169
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES_KHR = 1000168000,
- VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_SUPPORT_KHR = 1000168001,
-
- //@extension("VK_EXT_global_priority") // 175
- VK_STRUCTURE_TYPE_DEVICE_QUEUE_GLOBAL_PRIORITY_CREATE_INFO_EXT = 1000174000,
-
- //@extension("VK_KHR_8bit_storage") // 178
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_8BIT_STORAGE_FEATURES_KHR = 1000177000,
-
- //@extension("VK_EXT_external_memory_host") // 179
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT = 1000178000,
- VK_STRUCTURE_TYPE_MEMORY_HOST_POINTER_PROPERTIES_EXT = 1000178001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT = 1000178002,
-
- //@extension("VK_KHR_shader_atomic_int64") // 181
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_ATOMIC_INT64_FEATURES_KHR = 1000180000,
-
- //@extension("VK_EXT_calibrated_timestamps") // 185
- VK_STRUCTURE_TYPE_CALIBRATED_TIMESTAMP_INFO_EXT = 1000184000,
-
- //@extension("VK_KHR_driver_properties") // 197
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR = 1000196000,
-
- //@extension("VK_KHR_shader_float_controls") // 198
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FLOAT_CONTROLS_PROPERTIES_KHR = 1000197000,
-
- //@extension("VK_AMD_shader_core_properties") // 186
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
-
- //@extension("VK_AMD_memory_overallocation_behavior") // 190
- VK_STRUCTURE_TYPE_DEVICE_MEMORY_OVERALLOCATION_CREATE_INFO_AMD = 1000189000,
-
- //@extension("VK_EXT_vertex_attribute_divisor") // 191
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
- VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
-
- //@extension("VK_NV_device_diagnostic_checkpoints") // 207
- VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
- VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
-
- //@extension("VK_KHR_vulkan_memory_model") // 212
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
-
- //@extension("VK_EXT_pci_bus_info") // 213
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT = 1000212000,
-
- //@extension("VK_FUCHSIA_imagepipe_surface") // 215
- VK_STRUCTURE_TYPE_IMAGEPIPE_SURFACE_CREATE_INFO_FUCHSIA = 1000214000,
-
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_FEATURES_EXT = 1000218000,
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FRAGMENT_DENSITY_MAP_PROPERTIES_EXT = 1000218001,
- VK_STRUCTURE_TYPE_RENDER_PASS_FRAGMENT_DENSITY_MAP_CREATE_INFO_EXT = 1000218002,
-
- //@extension("VK_EXT_scalar_block_layout")
- VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SCALAR_BLOCK_LAYOUT_FEATURES_EXT = 1000221000,
-
- //@extension("VK_EXT_separate_stencil_usage") // 247
- VK_STRUCTURE_TYPE_IMAGE_STENCIL_USAGE_CREATE_INFO_EXT = 1000246000,
-}
-
-enum VkSubpassContents {
- VK_SUBPASS_CONTENTS_INLINE = 0x00000000,
- VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS = 0x00000001,
-}
-
-enum VkPipelineCacheHeaderVersion {
- VK_PIPELINE_CACHE_HEADER_VERSION_ONE = 1,
-}
-
-@lastUnused(-11)
-/// Error and return codes
-enum VkResult {
- // Return codes for successful operation execution (positive values)
- VK_SUCCESS = 0,
- VK_NOT_READY = 1,
- VK_TIMEOUT = 2,
- VK_EVENT_SET = 3,
- VK_EVENT_RESET = 4,
- VK_INCOMPLETE = 5,
-
- //@extension("VK_KHR_swapchain") // 2
- VK_SUBOPTIMAL_KHR = 1000001003,
-
- // Error codes (negative values)
- VK_ERROR_OUT_OF_HOST_MEMORY = 0xFFFFFFFF, // -1
- VK_ERROR_OUT_OF_DEVICE_MEMORY = 0xFFFFFFFE, // -2
- VK_ERROR_INITIALIZATION_FAILED = 0xFFFFFFFD, // -3
- VK_ERROR_DEVICE_LOST = 0xFFFFFFFC, // -4
- VK_ERROR_MEMORY_MAP_FAILED = 0xFFFFFFFB, // -5
- VK_ERROR_LAYER_NOT_PRESENT = 0xFFFFFFFA, // -6
- VK_ERROR_EXTENSION_NOT_PRESENT = 0xFFFFFFF9, // -7
- VK_ERROR_FEATURE_NOT_PRESENT = 0xFFFFFFF8, // -8
- VK_ERROR_INCOMPATIBLE_DRIVER = 0xFFFFFFF7, // -9
- VK_ERROR_TOO_MANY_OBJECTS = 0xFFFFFFF6, // -10
- VK_ERROR_FORMAT_NOT_SUPPORTED = 0xFFFFFFF5, // -11
- VK_ERROR_FRAGMENTED_POOL = 0xFFFFFFF4, // -12
-
- //@vulkan1_1
- VK_ERROR_OUT_OF_POOL_MEMORY = 0xC4642878, // -1000069000
- VK_ERROR_INVALID_EXTERNAL_HANDLE = 0xC4641CBD, // -1000072003
-
- //@extension("VK_KHR_surface") // 1
- VK_ERROR_SURFACE_LOST_KHR = 0xC4653600, // -1000000000
- VK_ERROR_NATIVE_WINDOW_IN_USE_KHR = 0xC46535FF, // -1000000001
-
- //@extension("VK_KHR_swapchain") // 2
- VK_ERROR_OUT_OF_DATE_KHR = 0xC4653214, // -1000001004
-
- //@extension("VK_KHR_display_swapchain") // 4
- VK_ERROR_INCOMPATIBLE_DISPLAY_KHR = 0xC4652A47, // -1000003001
-
- //@extension("VK_EXT_debug_report") // 12
- VK_ERROR_VALIDATION_FAILED_EXT = 0xC4650B07, // -1000011001
-
- //@extension("VK_NV_glsl_shader") // 13
- VK_ERROR_INVALID_SHADER_NV = 0xC4650720, // -1000012000
-
- //@extension("VK_KHR_maintenance1") // 70
- VK_ERROR_OUT_OF_POOL_MEMORY_KHR = 0xC4642878, // -1000069000
-
- //@extension("VK_KHR_external_memory") // 73
- VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR = 0xC4641CBD, // -1000072003
-
- //@extension("VK_EXT_image_drm_format_modifier") // 159
- VK_ERROR_INVALID_DRM_FORMAT_MODIFIER_PLANE_LAYOUT_EXT = 0xC462CCD0, // -1000158000
-
- //@extension("VK_EXT_descriptor_indexing") // 162
- VK_ERROR_FRAGMENTATION_EXT = 0xc462c118, // -1000161000
-
- //@extension("VK_EXT_global_priority") // 175
- VK_ERROR_NOT_PERMITTED_EXT = 0xC4628E4F, // -1000174001
-}
-
-enum VkDynamicState {
- VK_DYNAMIC_STATE_VIEWPORT = 0x00000000,
- VK_DYNAMIC_STATE_SCISSOR = 0x00000001,
- VK_DYNAMIC_STATE_LINE_WIDTH = 0x00000002,
- VK_DYNAMIC_STATE_DEPTH_BIAS = 0x00000003,
- VK_DYNAMIC_STATE_BLEND_CONSTANTS = 0x00000004,
- VK_DYNAMIC_STATE_DEPTH_BOUNDS = 0x00000005,
- VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK = 0x00000006,
- VK_DYNAMIC_STATE_STENCIL_WRITE_MASK = 0x00000007,
- VK_DYNAMIC_STATE_STENCIL_REFERENCE = 0x00000008,
-
- //@extension("VK_NV_clip_space_w_scaling") // 88
- VK_DYNAMIC_STATE_VIEWPORT_W_SCALING_NV = 1000087000,
-
- //@extension("VK_EXT_discard_rectangles") // 100
- VK_DYNAMIC_STATE_DISCARD_RECTANGLE_EXT = 1000099000,
-
- //@extension("VK_EXT_sample_locations") // 144
- VK_DYNAMIC_STATE_SAMPLE_LOCATIONS_EXT = 1000143000,
-
- //@extension("VK_NV_shading_rate_image") // 165
- VK_DYNAMIC_STATE_VIEWPORT_SHADING_RATE_PALETTE_NV = 1000164004,
- VK_DYNAMIC_STATE_VIEWPORT_COARSE_SAMPLE_ORDER_NV = 1000164006,
-
- //@extension("VK_NV_scissor_exclusive") // 206
- VK_DYNAMIC_STATE_EXCLUSIVE_SCISSOR_NV = 1000205001,
-}
-
-enum VkObjectType {
- VK_OBJECT_TYPE_UNKNOWN = 0,
- VK_OBJECT_TYPE_INSTANCE = 1,
- VK_OBJECT_TYPE_PHYSICAL_DEVICE = 2,
- VK_OBJECT_TYPE_DEVICE = 3,
- VK_OBJECT_TYPE_QUEUE = 4,
- VK_OBJECT_TYPE_SEMAPHORE = 5,
- VK_OBJECT_TYPE_COMMAND_BUFFER = 6,
- VK_OBJECT_TYPE_FENCE = 7,
- VK_OBJECT_TYPE_DEVICE_MEMORY = 8,
- VK_OBJECT_TYPE_BUFFER = 9,
- VK_OBJECT_TYPE_IMAGE = 10,
- VK_OBJECT_TYPE_EVENT = 11,
- VK_OBJECT_TYPE_QUERY_POOL = 12,
- VK_OBJECT_TYPE_BUFFER_VIEW = 13,
- VK_OBJECT_TYPE_IMAGE_VIEW = 14,
- VK_OBJECT_TYPE_SHADER_MODULE = 15,
- VK_OBJECT_TYPE_PIPELINE_CACHE = 16,
- VK_OBJECT_TYPE_PIPELINE_LAYOUT = 17,
- VK_OBJECT_TYPE_RENDER_PASS = 18,
- VK_OBJECT_TYPE_PIPELINE = 19,
- VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT = 20,
- VK_OBJECT_TYPE_SAMPLER = 21,
- VK_OBJECT_TYPE_DESCRIPTOR_POOL = 22,
- VK_OBJECT_TYPE_DESCRIPTOR_SET = 23,
- VK_OBJECT_TYPE_FRAMEBUFFER = 24,
- VK_OBJECT_TYPE_COMMAND_POOL = 25,
-
- //@vulkan1_1
- VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION = 1000156000,
- VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE = 1000085000,
-
- //@extension("VK_KHR_surface") // 1
- VK_OBJECT_TYPE_SURFACE_KHR = 1000000000,
-
- //@extension("VK_KHR_swapchain") // 2
- VK_OBJECT_TYPE_SWAPCHAIN_KHR = 1000001000,
-
- //@extension("VK_KHR_display") // 3
- VK_OBJECT_TYPE_DISPLAY_KHR = 1000002000,
- VK_OBJECT_TYPE_DISPLAY_MODE_KHR = 1000002001,
-
- //@extension("VK_KHR_debug_report") // 12
- VK_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT = 1000011000,
-
- //@extension("VK_KHR_descriptor_update_template") // 86
- VK_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR = 1000085000,
-
- //@extension("VK_NVX_device_generated_commands") // 87
- VK_OBJECT_TYPE_OBJECT_TABLE_NVX = 1000086000,
- VK_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX = 1000086001,
-
- //@extension("VK_EXT_debug_utils") // 129
- VK_OBJECT_TYPE_DEBUG_UTILS_MESSENGER_EXT = 1000128000,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR = 1000156000,
-
- //@extension("VK_EXT_validation_cache") // 161
- VK_OBJECT_TYPE_VALIDATION_CACHE_EXT = 1000160000,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV = 1000165000,
-}
-
-
-//@vulkan1_1 enums
-
-enum VkPointClippingBehavior {
- VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES = 0,
- VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY = 1,
-}
-
-enum VkTessellationDomainOrigin {
- VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT = 0,
- VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT = 1,
-}
-
-enum VkSamplerYcbcrModelConversion {
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY = 1,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709 = 2,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601 = 3,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020 = 4,
-}
-
-enum VkSamplerYcbcrRange {
- VK_SAMPLER_YCBCR_RANGE_ITU_FULL = 0,
- VK_SAMPLER_YCBCR_RANGE_ITU_NARROW = 1,
-}
-
-enum VkChromaLocation {
- VK_CHROMA_LOCATION_COSITED_EVEN = 0,
- VK_CHROMA_LOCATION_MIDPOINT = 1,
-}
-
-enum VkDescriptorUpdateTemplateType {
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET = 0,
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
-}
-
-enum VkVendorId {
- VK_VENDOR_ID_VIV = 0x10001,
- VK_VENDOR_ID_VSI = 0x10002,
- VK_VENDOR_ID_KAZAN = 0x10003,
-}
-
-@extension("VK_KHR_surface") // 1
-enum VkPresentModeKHR {
- VK_PRESENT_MODE_IMMEDIATE_KHR = 0x00000000,
- VK_PRESENT_MODE_MAILBOX_KHR = 0x00000001,
- VK_PRESENT_MODE_FIFO_KHR = 0x00000002,
- VK_PRESENT_MODE_FIFO_RELAXED_KHR = 0x00000003,
-
- //@extension("VK_KHR_shared_presentable_image") // 112
- VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR = 1000111000,
- VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR = 1000111001,
-}
-
-@extension("VK_KHR_surface") // 1
-enum VkColorSpaceKHR {
- VK_COLOR_SPACE_SRGB_NONLINEAR_KHR = 0x00000000,
-
- //@extension("VK_EXT_swapchain_colorspace") // 105
- VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT = 1000104001,
- VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT = 1000104002,
- VK_COLOR_SPACE_DCI_P3_LINEAR_EXT = 1000104003,
- VK_COLOR_SPACE_DCI_P3_NONLINEAR_EXT = 1000104004,
- VK_COLOR_SPACE_BT709_LINEAR_EXT = 1000104005,
- VK_COLOR_SPACE_BT709_NONLINEAR_EXT = 1000104006,
- VK_COLOR_SPACE_BT2020_LINEAR_EXT = 1000104007,
- VK_COLOR_SPACE_HDR10_ST2084_EXT = 1000104008,
- VK_COLOR_SPACE_DOLBYVISION_EXT = 1000104009,
- VK_COLOR_SPACE_HDR10_HLG_EXT = 1000104010,
- VK_COLOR_SPACE_ADOBERGB_LINEAR_EXT = 1000104011,
- VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
- VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
- VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
-}
-
-@extension("VK_EXT_debug_report") // 12
-enum VkDebugReportObjectTypeEXT {
- VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT = 0,
- VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT = 1,
- VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT = 2,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT = 3,
- VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT = 4,
- VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT = 5,
- VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT = 6,
- VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT = 7,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT = 8,
- VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT = 9,
- VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT = 10,
- VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT = 11,
- VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT = 12,
- VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT = 13,
- VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT = 14,
- VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT = 15,
- VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT = 16,
- VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT = 17,
- VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT = 18,
- VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT = 19,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT = 20,
- VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT = 21,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT = 22,
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT = 23,
- VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT = 24,
- VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT = 25,
- VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT = 26,
- VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT = 27,
- VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT = 28,
- VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_KHR_EXT = 29,
- VK_DEBUG_REPORT_OBJECT_TYPE_DISPLAY_MODE_KHR_EXT = 30,
- VK_DEBUG_REPORT_OBJECT_TYPE_OBJECT_TABLE_NVX_EXT = 31,
- VK_DEBUG_REPORT_OBJECT_TYPE_INDIRECT_COMMANDS_LAYOUT_NVX_EXT = 32,
-
- //extension("VK_EXT_validation_cache") // 161
- VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
-
- //extension("VK_KHR_descriptor_update_template") // 86
- VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = 1000085000,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = 1000156000,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_DEBUG_REPORT_OBJECT_TYPE_ACCELERATION_STRUCTURE_NV_EXT = 1000165000,
-}
-
-@extension("VK_AMD_rasterization_order") // 19
-enum VkRasterizationOrderAMD {
- VK_RASTERIZATION_ORDER_STRICT_AMD = 0,
- VK_RASTERIZATION_ORDER_RELAXED_AMD = 1,
-}
-
-@extension("VK_AMD_shader_info") // 43
-enum VkShaderInfoTypeAMD {
- VK_SHADER_INFO_TYPE_STATISTICS_AMD = 0,
- VK_SHADER_INFO_TYPE_BINARY_AMD = 1,
- VK_SHADER_INFO_TYPE_DISASSEMBLY_AMD = 2,
-}
-
-@extension("VK_EXT_validation_flags") // 62
-enum VkValidationCheckEXT {
- VK_VALIDATION_CHECK_ALL_EXT = 0,
- VK_VALIDATION_CHECK_SHADERS_EXT = 1,
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-enum VkDescriptorUpdateTemplateTypeKHR {
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET_KHR = 0,
- VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_PUSH_DESCRIPTORS_KHR = 1,
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-enum VkIndirectCommandsTokenTypeNVX {
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_PIPELINE_NVX = 0,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_DESCRIPTOR_SET_NVX = 1,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_INDEX_BUFFER_NVX = 2,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_VERTEX_BUFFER_NVX = 3,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_PUSH_CONSTANT_NVX = 4,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_INDEXED_NVX = 5,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_DRAW_NVX = 6,
- VK_INDIRECT_COMMANDS_TOKEN_TYPE_DISPATCH_NVX = 7,
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-enum VkObjectEntryTypeNVX {
- VK_OBJECT_ENTRY_TYPE_DESCRIPTOR_SET_NVX = 0,
- VK_OBJECT_ENTRY_TYPE_PIPELINE_NVX = 1,
- VK_OBJECT_ENTRY_TYPE_INDEX_BUFFER_NVX = 2,
- VK_OBJECT_ENTRY_TYPE_VERTEX_BUFFER_NVX = 3,
- VK_OBJECT_ENTRY_TYPE_PUSH_CONSTANT_NVX = 4,
-}
-
-@extension("VK_EXT_display_control") // 92
-enum VkDisplayPowerStateEXT {
- VK_DISPLAY_POWER_STATE_OFF_EXT = 0,
- VK_DISPLAY_POWER_STATE_SUSPEND_EXT = 1,
- VK_DISPLAY_POWER_STATE_ON_EXT = 2,
-}
-
-@extension("VK_EXT_display_control") // 92
-enum VkDeviceEventTypeEXT {
- VK_DEVICE_EVENT_TYPE_DISPLAY_HOTPLUG_EXT = 0,
-}
-
-@extension("VK_EXT_display_control") // 92
-enum VkDisplayEventTypeEXT {
- VK_DISPLAY_EVENT_TYPE_FIRST_PIXEL_OUT_EXT = 0,
-}
-
-@extension("VK_NV_viewport_swizzle") // 99
-enum VkViewportCoordinateSwizzleNV {
- VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_X_NV = 0,
- VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_X_NV = 1,
- VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Y_NV = 2,
- VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Y_NV = 3,
- VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_Z_NV = 4,
- VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_Z_NV = 5,
- VK_VIEWPORT_COORDINATE_SWIZZLE_POSITIVE_W_NV = 6,
- VK_VIEWPORT_COORDINATE_SWIZZLE_NEGATIVE_W_NV = 7,
-}
-
-@extension("VK_EXT_discard_rectangles") // 100
-enum VkDiscardRectangleModeEXT {
- VK_DISCARD_RECTANGLE_MODE_INCLUSIVE_EXT = 0,
- VK_DISCARD_RECTANGLE_MODE_EXCLUSIVE_EXT = 1,
-}
-
-@extension("VK_EXT_conservative_rasterization") // 102
-enum VkConservativeRasterizationModeEXT {
- VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT = 0,
- VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT = 1,
- VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT = 2,
-}
-
-@extension("VK_KHR_maintenance2") // 118
-enum VkPointClippingBehaviorKHR {
- VK_POINT_CLIPPING_BEHAVIOR_ALL_CLIP_PLANES_KHR = 0,
- VK_POINT_CLIPPING_BEHAVIOR_USER_CLIP_PLANES_ONLY_KHR = 1,
-}
-
-@extension("VK_KHR_maintenance2") // 118
-enum VkTessellationDomainOriginKHR {
- VK_TESSELLATION_DOMAIN_ORIGIN_UPPER_LEFT_KHR = 0,
- VK_TESSELLATION_DOMAIN_ORIGIN_LOWER_LEFT_KHR = 1,
-}
-
-@extension("VK_EXT_sampler_filter_minmax") // 131
-enum VkSamplerReductionModeEXT {
- VK_SAMPLER_REDUCTION_MODE_WEIGHTED_AVERAGE_EXT = 0,
- VK_SAMPLER_REDUCTION_MODE_MIN_EXT = 1,
- VK_SAMPLER_REDUCTION_MODE_MAX_EXT = 2,
-}
-
-@extension("VK_EXT_blend_operation_advanced") // 149
-enum VkBlendOverlapEXT {
- VK_BLEND_OVERLAP_UNCORRELATED_EXT = 0,
- VK_BLEND_OVERLAP_DISJOINT_EXT = 1,
- VK_BLEND_OVERLAP_CONJOINT_EXT = 2,
-}
-
-@extension("VK_NV_framebuffer_mixed_samples") // 153
-enum VkCoverageModulationModeNV {
- VK_COVERAGE_MODULATION_MODE_NONE_NV = 0,
- VK_COVERAGE_MODULATION_MODE_RGB_NV = 1,
- VK_COVERAGE_MODULATION_MODE_ALPHA_NV = 2,
- VK_COVERAGE_MODULATION_MODE_RGBA_NV = 3,
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-enum VkSamplerYcbcrModelConversionKHR {
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY_KHR = 0,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY_KHR = 1,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709_KHR = 2,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_601_KHR = 3,
- VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_2020_KHR = 4,
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-enum VkSamplerYcbcrRangeKHR {
- VK_SAMPLER_YCBCR_RANGE_ITU_FULL_KHR = 0,
- VK_SAMPLER_YCBCR_RANGE_ITU_NARROW_KHR = 1,
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-enum VkChromaLocationKHR {
- VK_CHROMA_LOCATION_COSITED_EVEN_KHR = 0,
- VK_CHROMA_LOCATION_MIDPOINT_KHR = 1,
-}
-
-@extension("VK_EXT_validation_cache") // 161
-enum VkValidationCacheHeaderVersionEXT {
- VK_VALIDATION_CACHE_HEADER_VERSION_ONE_EXT = 1,
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-enum VkShadingRatePaletteEntryNV {
- VK_SHADING_RATE_PALETTE_ENTRY_NO_INVOCATIONS_NV = 0,
- VK_SHADING_RATE_PALETTE_ENTRY_16_INVOCATIONS_PER_PIXEL_NV = 1,
- VK_SHADING_RATE_PALETTE_ENTRY_8_INVOCATIONS_PER_PIXEL_NV = 2,
- VK_SHADING_RATE_PALETTE_ENTRY_4_INVOCATIONS_PER_PIXEL_NV = 3,
- VK_SHADING_RATE_PALETTE_ENTRY_2_INVOCATIONS_PER_PIXEL_NV = 4,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_PIXEL_NV = 5,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X1_PIXELS_NV = 6,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_1X2_PIXELS_NV = 7,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X2_PIXELS_NV = 8,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X2_PIXELS_NV = 9,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_2X4_PIXELS_NV = 10,
- VK_SHADING_RATE_PALETTE_ENTRY_1_INVOCATION_PER_4X4_PIXELS_NV = 11,
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-enum VkCoarseSampleOrderTypeNV {
- VK_COARSE_SAMPLE_ORDER_TYPE_DEFAULT_NV = 0,
- VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV = 1,
- VK_COARSE_SAMPLE_ORDER_TYPE_PIXEL_MAJOR_NV = 2,
- VK_COARSE_SAMPLE_ORDER_TYPE_SAMPLE_MAJOR_NV = 3,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-enum VkRayTracingShaderGroupTypeNV {
- VK_RAY_TRACING_SHADER_GROUP_TYPE_GENERAL_NV = 0,
- VK_RAY_TRACING_SHADER_GROUP_TYPE_TRIANGLES_HIT_GROUP_NV = 1,
- VK_RAY_TRACING_SHADER_GROUP_TYPE_PROCEDURAL_HIT_GROUP_NV = 2,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-enum VkGeometryTypeNV {
- VK_GEOMETRY_TYPE_TRIANGLES_NV = 0,
- VK_GEOMETRY_TYPE_AABBS_NV = 1,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-enum VkAccelerationStructureTypeNV {
- VK_ACCELERATION_STRUCTURE_TYPE_TOP_LEVEL_NV = 0,
- VK_ACCELERATION_STRUCTURE_TYPE_BOTTOM_LEVEL_NV = 1,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-enum VkCopyAccelerationStructureModeNV {
- VK_COPY_ACCELERATION_STRUCTURE_MODE_CLONE_NV = 0,
- VK_COPY_ACCELERATION_STRUCTURE_MODE_COMPACT_NV = 1,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-enum VkAccelerationStructureMemoryRequirementsTypeNV {
- VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_OBJECT_NV = 0,
- VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_BUILD_SCRATCH_NV = 1,
- VK_ACCELERATION_STRUCTURE_MEMORY_REQUIREMENTS_TYPE_UPDATE_SCRATCH_NV = 2,
-}
-
-@extension("VK_EXT_global_priority") // 175
-enum VkQueueGlobalPriorityEXT {
- VK_QUEUE_GLOBAL_PRIORITY_LOW_EXT = 128,
- VK_QUEUE_GLOBAL_PRIORITY_MEDIUM_EXT = 256,
- VK_QUEUE_GLOBAL_PRIORITY_HIGH_EXT = 512,
- VK_QUEUE_GLOBAL_PRIORITY_REALTIME_EXT = 1024,
-}
-
-@extension("VK_EXT_calibrated_timestamps") // 185
-enum VkTimeDomainEXT {
- VK_TIME_DOMAIN_DEVICE_EXT = 0,
- VK_TIME_DOMAIN_CLOCK_MONOTONIC_EXT = 1,
- VK_TIME_DOMAIN_CLOCK_MONOTONIC_RAW_EXT = 2,
- VK_TIME_DOMAIN_QUERY_PERFORMANCE_COUNTER_EXT = 3,
-}
-
-@extension("VK_AMD_memory_overallocation_behavior") // 190
-enum VkMemoryOverallocationBehaviorAMD {
- VK_MEMORY_OVERALLOCATION_BEHAVIOR_DEFAULT_AMD = 0,
- VK_MEMORY_OVERALLOCATION_BEHAVIOR_ALLOWED_AMD = 1,
- VK_MEMORY_OVERALLOCATION_BEHAVIOR_DISALLOWED_AMD = 2,
-}
-
-@extension("VK_KHR_driver_properties") // 197
-enum VkDriverIdKHR {
- VK_DRIVER_ID_AMD_PROPRIETARY_KHR = 1,
- VK_DRIVER_ID_AMD_OPEN_SOURCE_KHR = 2,
- VK_DRIVER_ID_MESA_RADV_KHR = 3,
- VK_DRIVER_ID_NVIDIA_PROPRIETARY_KHR = 4,
- VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS_KHR = 5,
- VK_DRIVER_ID_INTEL_OPEN_SOURCE_MESA_KHR = 6,
- VK_DRIVER_ID_IMAGINATION_PROPRIETARY_KHR = 7,
- VK_DRIVER_ID_QUALCOMM_PROPRIETARY_KHR = 8,
- VK_DRIVER_ID_ARM_PROPRIETARY_KHR = 9,
- VK_DRIVER_ID_GOOGLE_PASTEL_KHR = 10,
-}
-
-/////////////////
-// Bitfields //
-/////////////////
-
-/// Queue capabilities
-type VkFlags VkQueueFlags
-bitfield VkQueueFlagBits {
- VK_QUEUE_GRAPHICS_BIT = 0x00000001, /// Queue supports graphics operations
- VK_QUEUE_COMPUTE_BIT = 0x00000002, /// Queue supports compute operations
- VK_QUEUE_TRANSFER_BIT = 0x00000004, /// Queue supports transfer operations
- VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, /// Queue supports sparse resource memory management operations
-
- //@vulkan1_1
- VK_QUEUE_PROTECTED_BIT = 0x00000010,
-}
-
-/// Memory properties passed into vkAllocMemory().
-type VkFlags VkMemoryPropertyFlags
-bitfield VkMemoryPropertyFlagBits {
- VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT = 0x00000001,
- VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT = 0x00000002,
- VK_MEMORY_PROPERTY_HOST_COHERENT_BIT = 0x00000004,
- VK_MEMORY_PROPERTY_HOST_CACHED_BIT = 0x00000008,
- VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT = 0x00000010,
-
- //@vulkan1_1
- VK_MEMORY_PROPERTY_PROTECTED_BIT = 0x00000020,
-}
-
-/// Memory heap flags
-type VkFlags VkMemoryHeapFlags
-bitfield VkMemoryHeapFlagBits {
- VK_MEMORY_HEAP_DEVICE_LOCAL_BIT = 0x00000001,
-
- //@vulkan1_1
- VK_MEMORY_HEAP_MULTI_INSTANCE_BIT = 0x00000002,
-
- //@extension("VK_KHR_device_group_creation") // 71
- VK_MEMORY_HEAP_MULTI_INSTANCE_BIT_KHR = 0x00000002,
-}
-
-/// Access flags
-type VkFlags VkAccessFlags
-bitfield VkAccessFlagBits {
- VK_ACCESS_INDIRECT_COMMAND_READ_BIT = 0x00000001,
- VK_ACCESS_INDEX_READ_BIT = 0x00000002,
- VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT = 0x00000004,
- VK_ACCESS_UNIFORM_READ_BIT = 0x00000008,
- VK_ACCESS_INPUT_ATTACHMENT_READ_BIT = 0x00000010,
- VK_ACCESS_SHADER_READ_BIT = 0x00000020,
- VK_ACCESS_SHADER_WRITE_BIT = 0x00000040,
- VK_ACCESS_COLOR_ATTACHMENT_READ_BIT = 0x00000080,
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT = 0x00000100,
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT = 0x00000200,
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT = 0x00000400,
- VK_ACCESS_TRANSFER_READ_BIT = 0x00000800,
- VK_ACCESS_TRANSFER_WRITE_BIT = 0x00001000,
- VK_ACCESS_HOST_READ_BIT = 0x00002000,
- VK_ACCESS_HOST_WRITE_BIT = 0x00004000,
- VK_ACCESS_MEMORY_READ_BIT = 0x00008000,
- VK_ACCESS_MEMORY_WRITE_BIT = 0x00010000,
-
- //@extension("VK_NVX_device_generated_commands") // 87
- VK_ACCESS_COMMAND_PROCESS_READ_BIT_NVX = 0x00020000,
- VK_ACCESS_COMMAND_PROCESS_WRITE_BIT_NVX = 0x00040000,
-
- //@extension("VK_EXT_blend_operation_advanced") // 149
- VK_ACCESS_COLOR_ATTACHMENT_READ_NONCOHERENT_BIT_EXT = 0x00080000,
-
- //@extension("VK_EXT_conditional_rendering") // 82
- VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT = 0x00100000,
-
- //@extension("VK_NV_shading_rate_image") // 165
- VK_ACCESS_SHADING_RATE_IMAGE_READ_BIT_NV = 0x00800000,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_ACCESS_ACCELERATION_STRUCTURE_READ_BIT_NV = 0x00200000,
- VK_ACCESS_ACCELERATION_STRUCTURE_WRITE_BIT_NV = 0x00400000,
-
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_ACCESS_FRAGMENT_DENSITY_MAP_READ_BIT_EXT = 0x01000000,
-
- //@extension("VK_EXT_transform_feedback") // 29
- VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT = 0x02000000,
- VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_READ_BIT_EXT = 0x04000000,
- VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT = 0x08000000,
-}
-
-/// Buffer usage flags
-type VkFlags VkBufferUsageFlags
-bitfield VkBufferUsageFlagBits {
- VK_BUFFER_USAGE_TRANSFER_SRC_BIT = 0x00000001, /// Can be used as a source of transfer operations
- VK_BUFFER_USAGE_TRANSFER_DST_BIT = 0x00000002, /// Can be used as a destination of transfer operations
- VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000004, /// Can be used as TBO
- VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT = 0x00000008, /// Can be used as IBO
- VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT = 0x00000010, /// Can be used as UBO
- VK_BUFFER_USAGE_STORAGE_BUFFER_BIT = 0x00000020, /// Can be used as SSBO
- VK_BUFFER_USAGE_INDEX_BUFFER_BIT = 0x00000040, /// Can be used as source of fixed function index fetch (index buffer)
- VK_BUFFER_USAGE_VERTEX_BUFFER_BIT = 0x00000080, /// Can be used as source of fixed function vertex fetch (VBO)
- VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT = 0x00000100, /// Can be the source of indirect parameters (e.g. indirect buffer, parameter buffer)
-
- //@extension("VK_EXT_conditional_rendering") // 82
- VK_BUFFER_USAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00000200,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_BUFFER_USAGE_RAY_TRACING_BIT_NV = 0x00000400,
-
- //@extension("VK_EXT_transform_feedback") // 29
- VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT = 0x00000800,
- VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_COUNTER_BUFFER_BIT_EXT = 0x00001000,
-}
-
-/// Buffer creation flags
-type VkFlags VkBufferCreateFlags
-bitfield VkBufferCreateFlagBits {
- VK_BUFFER_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Buffer should support sparse backing
- VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Buffer should support sparse backing with partial residency
- VK_BUFFER_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers
-
- //@vulkan1_1
- VK_BUFFER_CREATE_PROTECTED_BIT = 0x00000008,
-}
-
-/// Shader stage flags
-type VkFlags VkShaderStageFlags
-bitfield VkShaderStageFlagBits {
- VK_SHADER_STAGE_VERTEX_BIT = 0x00000001,
- VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT = 0x00000002,
- VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT = 0x00000004,
- VK_SHADER_STAGE_GEOMETRY_BIT = 0x00000008,
- VK_SHADER_STAGE_FRAGMENT_BIT = 0x00000010,
- VK_SHADER_STAGE_COMPUTE_BIT = 0x00000020,
- VK_SHADER_STAGE_ALL_GRAPHICS = 0x0000001F,
-
- VK_SHADER_STAGE_ALL = 0x7FFFFFFF,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_SHADER_STAGE_RAYGEN_BIT_NV = 0x00000100,
- VK_SHADER_STAGE_ANY_HIT_BIT_NV = 0x00000200,
- VK_SHADER_STAGE_CLOSEST_HIT_BIT_NV = 0x00000400,
- VK_SHADER_STAGE_MISS_BIT_NV = 0x00000800,
- VK_SHADER_STAGE_INTERSECTION_BIT_NV = 0x00001000,
- VK_SHADER_STAGE_CALLABLE_BIT_NV = 0x00002000,
-
- //@extension("VK_NV_mesh_shader") // 203
- VK_SHADER_STAGE_TASK_BIT_NV = 0x00000040,
- VK_SHADER_STAGE_MESH_BIT_NV = 0x00000080,
-}
-
-/// Descriptor pool create flags
-type VkFlags VkDescriptorPoolCreateFlags
-bitfield VkDescriptorPoolCreateFlagBits {
- VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT = 0x00000001,
-
- //@extension("VK_EXT_descriptor_indexing") // 162
- VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT = 0x00000002,
-}
-
-/// Descriptor pool reset flags
-type VkFlags VkDescriptorPoolResetFlags
-//bitfield VkDescriptorPoolResetFlagBits {
-//}
-
-/// Image usage flags
-type VkFlags VkImageUsageFlags
-bitfield VkImageUsageFlagBits {
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT = 0x00000001, /// Can be used as a source of transfer operations
- VK_IMAGE_USAGE_TRANSFER_DST_BIT = 0x00000002, /// Can be used as a destination of transfer operations
- VK_IMAGE_USAGE_SAMPLED_BIT = 0x00000004, /// Can be sampled from (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types)
- VK_IMAGE_USAGE_STORAGE_BIT = 0x00000008, /// Can be used as storage image (STORAGE_IMAGE descriptor type)
- VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT = 0x00000010, /// Can be used as framebuffer color attachment
- VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000020, /// Can be used as framebuffer depth/stencil attachment
- VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT = 0x00000040, /// Image data not needed outside of rendering
- VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT = 0x00000080, /// Can be used as framebuffer input attachment
-
- //@extension("VK_NV_shading_rate_image") // 165
- VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00000100,
-
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT = 0x00000200,
-}
-
-/// Image creation flags
-type VkFlags VkImageCreateFlags
-bitfield VkImageCreateFlagBits {
- VK_IMAGE_CREATE_SPARSE_BINDING_BIT = 0x00000001, /// Image should support sparse backing
- VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT = 0x00000002, /// Image should support sparse backing with partial residency
- VK_IMAGE_CREATE_SPARSE_ALIASED_BIT = 0x00000004, /// Image should support constent data access to physical memory blocks mapped into multiple locations of sparse images
- VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT = 0x00000008, /// Allows image views to have different format than the base image
- VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT = 0x00000010, /// Allows creating image views with cube type from the created image
-
- //@vulkan1_1
- VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT = 0x00000020,
- VK_IMAGE_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT = 0x00000040,
- VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT = 0x00000080,
- VK_IMAGE_CREATE_EXTENDED_USAGE_BIT = 0x00000100,
- VK_IMAGE_CREATE_DISJOINT_BIT = 0x00000200,
- VK_IMAGE_CREATE_ALIAS_BIT = 0x00000400,
- VK_IMAGE_CREATE_PROTECTED_BIT = 0x00000800,
-
- //@extension("VK_KHR_maintenance1") // 70
- VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR = 0x00000020,
-
- //@extension("VK_KHR_device_group") // 61
- VK_IMAGE_CREATE_BIND_SFR_BIT_KHR = 0x00000040,
-
- //@extension("VK_KHR_maintenance2") // 118
- VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR = 0x00000080,
- VK_IMAGE_CREATE_EXTENDED_USAGE_BIT_KHR = 0x00000100,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_IMAGE_CREATE_DISJOINT_BIT_KHR = 0x00000200,
-
- //@extension("VK_KHR_bind_memory2") // 158
- VK_IMAGE_CREATE_ALIAS_BIT_KHR = 0x00000400,
-
- //@extension("VK_EXT_sample_locations") // 144
- VK_IMAGE_CREATE_SAMPLE_LOCATIONS_COMPATIBLE_DEPTH_BIT_EXT = 0x00001000,
-
- //@extension("VK_NV_corner_sampled_image") // 51
- VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV = 0x00002000,
-
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_IMAGE_CREATE_SUBSAMPLED_BIT_EXT = 0x00004000,
-}
-
-/// Image view creation flags
-type VkFlags VkImageViewCreateFlags
-bitfield VkImageViewCreateFlagBits {
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_IMAGE_VIEW_CREATE_FRAGMENT_DENSITY_MAP_DYNAMIC_BIT_EXT = 0x00000001,
-}
-
-/// Pipeline creation flags
-type VkFlags VkPipelineCreateFlags
-bitfield VkPipelineCreateFlagBits {
- VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT = 0x00000001,
- VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT = 0x00000002,
- VK_PIPELINE_CREATE_DERIVATIVE_BIT = 0x00000004,
-
- //@vulkan1_1
- VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT = 0x00000008,
- VK_PIPELINE_CREATE_DISPATCH_BASE = 0x00000010,
-
- //@extension("VK_KHR_device_group") // 61
- VK_PIPELINE_CREATE_VIEW_INDEX_FROM_DEVICE_INDEX_BIT_KHR = 0x00000008,
- VK_PIPELINE_CREATE_DISPATCH_BASE_KHR = 0x00000010,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_PIPELINE_CREATE_DEFER_COMPILE_BIT_NV = 0x00000020,
-}
-
-/// Color component flags
-type VkFlags VkColorComponentFlags
-bitfield VkColorComponentFlagBits {
- VK_COLOR_COMPONENT_R_BIT = 0x00000001,
- VK_COLOR_COMPONENT_G_BIT = 0x00000002,
- VK_COLOR_COMPONENT_B_BIT = 0x00000004,
- VK_COLOR_COMPONENT_A_BIT = 0x00000008,
-}
-
-/// Fence creation flags
-type VkFlags VkFenceCreateFlags
-bitfield VkFenceCreateFlagBits {
- VK_FENCE_CREATE_SIGNALED_BIT = 0x00000001,
-}
-
-/// Semaphore creation flags
-type VkFlags VkSemaphoreCreateFlags
-//bitfield VkSemaphoreCreateFlagBits {
-//}
-
-/// Format capability flags
-type VkFlags VkFormatFeatureFlags
-bitfield VkFormatFeatureFlagBits {
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT = 0x00000001, /// Format can be used for sampled images (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types)
- VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT = 0x00000002, /// Format can be used for storage images (STORAGE_IMAGE descriptor type)
- VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT = 0x00000004, /// Format supports atomic operations in case it's used for storage images
- VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT = 0x00000008, /// Format can be used for uniform texel buffers (TBOs)
- VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT = 0x00000010, /// Format can be used for storage texel buffers (IBOs)
- VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT = 0x00000020, /// Format supports atomic operations in case it's used for storage texel buffers
- VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT = 0x00000040, /// Format can be used for vertex buffers (VBOs)
- VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT = 0x00000080, /// Format can be used for color attachment images
- VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT = 0x00000100, /// Format supports blending in case it's used for color attachment images
- VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT = 0x00000200, /// Format can be used for depth/stencil attachment images
- VK_FORMAT_FEATURE_BLIT_SRC_BIT = 0x00000400, /// Format can be used as the source image of blits with vkCommandBlitImage
- VK_FORMAT_FEATURE_BLIT_DST_BIT = 0x00000800, /// Format can be used as the destination image of blits with vkCommandBlitImage
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT = 0x00001000,
-
- //@vulkan1_1
- VK_FORMAT_FEATURE_TRANSFER_SRC_BIT = 0x00004000,
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT = 0x00008000,
- VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT = 0x00020000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT = 0x00040000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT = 0x00080000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT = 0x00100000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT = 0x00200000,
- VK_FORMAT_FEATURE_DISJOINT_BIT = 0x00400000,
- VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT = 0x00800000,
-
- //@extension("VK_IMG_filter_cubic") // 16
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG = 0x00002000,
-
- //@extension("VK_KHR_maintenance1") // 70
- VK_FORMAT_FEATURE_TRANSFER_SRC_BIT_KHR = 0x00004000,
- VK_FORMAT_FEATURE_TRANSFER_DST_BIT_KHR = 0x00008000,
-
- //@extension("VK_EXT_sampler_filter_minmax") // 131
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_MINMAX_BIT_EXT = 0x00010000,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT_KHR = 0x00020000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT_KHR = 0x00040000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_SEPARATE_RECONSTRUCTION_FILTER_BIT_KHR = 0x00080000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_BIT_KHR = 0x00100000,
- VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_CHROMA_RECONSTRUCTION_EXPLICIT_FORCEABLE_BIT_KHR = 0x00200000,
- VK_FORMAT_FEATURE_DISJOINT_BIT_KHR = 0x00400000,
- VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT_KHR = 0x00800000,
-}
-
-/// Query control flags
-type VkFlags VkQueryControlFlags
-bitfield VkQueryControlFlagBits {
- VK_QUERY_CONTROL_PRECISE_BIT = 0x00000001,
-}
-
-/// Query result flags
-type VkFlags VkQueryResultFlags
-bitfield VkQueryResultFlagBits {
- VK_QUERY_RESULT_64_BIT = 0x00000001, /// Results of the queries are written to the destination buffer as 64-bit values
- VK_QUERY_RESULT_WAIT_BIT = 0x00000002, /// Results of the queries are waited on before proceeding with the result copy
- VK_QUERY_RESULT_WITH_AVAILABILITY_BIT = 0x00000004, /// Besides the results of the query, the availability of the results is also written
- VK_QUERY_RESULT_PARTIAL_BIT = 0x00000008, /// Copy the partial results of the query even if the final results aren't available
-}
-
-/// Shader module creation flags
-type VkFlags VkShaderModuleCreateFlags
-//bitfield VkShaderModuleCreateFlagBits {
-//}
-
-/// Event creation flags
-type VkFlags VkEventCreateFlags
-//bitfield VkEventCreateFlagBits {
-//}
-
-/// Command buffer usage flags
-type VkFlags VkCommandBufferUsageFlags
-bitfield VkCommandBufferUsageFlagBits {
- VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT = 0x00000001,
- VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT = 0x00000002,
- VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT = 0x00000004,
-}
-
-/// Pipeline statistics flags
-type VkFlags VkQueryPipelineStatisticFlags
-bitfield VkQueryPipelineStatisticFlagBits {
- VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT = 0x00000001, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT = 0x00000002, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT = 0x00000004, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT = 0x00000008, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT = 0x00000010, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT = 0x00000020, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT = 0x00000040, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT = 0x00000080, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT = 0x00000100, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT = 0x00000200, /// Optional
- VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT = 0x00000400, /// Optional
-}
-
-/// Memory mapping flags
-type VkFlags VkMemoryMapFlags
-//bitfield VkMemoryMapFlagBits {
-//}
-
-/// Bitfield of image aspects
-type VkFlags VkImageAspectFlags
-bitfield VkImageAspectFlagBits {
- VK_IMAGE_ASPECT_COLOR_BIT = 0x00000001,
- VK_IMAGE_ASPECT_DEPTH_BIT = 0x00000002,
- VK_IMAGE_ASPECT_STENCIL_BIT = 0x00000004,
- VK_IMAGE_ASPECT_METADATA_BIT = 0x00000008,
-
- //@vulkan1_1
- VK_IMAGE_ASPECT_PLANE_0_BIT = 0x00000010,
- VK_IMAGE_ASPECT_PLANE_1_BIT = 0x00000020,
- VK_IMAGE_ASPECT_PLANE_2_BIT = 0x00000040,
-
- //@extension("VK_KHR_sampler_ycbcr_conversion") // 157
- VK_IMAGE_ASPECT_PLANE_0_BIT_KHR = 0x00000010,
- VK_IMAGE_ASPECT_PLANE_1_BIT_KHR = 0x00000020,
- VK_IMAGE_ASPECT_PLANE_2_BIT_KHR = 0x00000040,
-
- //@extension("VK_EXT_transform_feedback") // 29
- VK_IMAGE_ASPECT_MEMORY_PLANE_0_BIT_EXT = 0x00000080,
- VK_IMAGE_ASPECT_MEMORY_PLANE_1_BIT_EXT = 0x00000100,
- VK_IMAGE_ASPECT_MEMORY_PLANE_2_BIT_EXT = 0x00000200,
- VK_IMAGE_ASPECT_MEMORY_PLANE_3_BIT_EXT = 0x00000400,
-}
-
-/// Sparse memory bind flags
-type VkFlags VkSparseMemoryBindFlags
-bitfield VkSparseMemoryBindFlagBits {
- VK_SPARSE_MEMORY_BIND_METADATA_BIT = 0x00000001,
-}
-
-/// Sparse image memory requirements flags
-type VkFlags VkSparseImageFormatFlags
-bitfield VkSparseImageFormatFlagBits {
- VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT = 0x00000001, /// Image uses a single miptail region for all array slices
- VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT = 0x00000002, /// Image requires mip levels to be an exact multiple of the sparse iamge block size for non-mip-tail levels.
- VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT = 0x00000004, /// Image uses a non-standard sparse block size
-}
-
-/// Pipeline stages
-type VkFlags VkPipelineStageFlags
-bitfield VkPipelineStageFlagBits {
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT = 0x00000001, /// Before subsequent commands are processed
- VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT = 0x00000002, /// Draw/DispatchIndirect command fetch
- VK_PIPELINE_STAGE_VERTEX_INPUT_BIT = 0x00000004, /// Vertex/index fetch
- VK_PIPELINE_STAGE_VERTEX_SHADER_BIT = 0x00000008, /// Vertex shading
- VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT = 0x00000010, /// Tessellation control shading
- VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT = 0x00000020, /// Tessellation evaluation shading
- VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT = 0x00000040, /// Geometry shading
- VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT = 0x00000080, /// Fragment shading
- VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT = 0x00000100, /// Early fragment (depth/stencil) tests
- VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT = 0x00000200, /// Late fragment (depth/stencil) tests
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT = 0x00000400, /// Color attachment writes
- VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT = 0x00000800, /// Compute shading
- VK_PIPELINE_STAGE_TRANSFER_BIT = 0x00001000, /// Transfer/copy operations
- VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT = 0x00002000,
- VK_PIPELINE_STAGE_HOST_BIT = 0x00004000, /// Indicates host (CPU) is a source/sink of the dependency
-
- VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT = 0x00008000, /// All stages of the graphics pipeline
- VK_PIPELINE_STAGE_ALL_COMMANDS_BIT = 0x00010000, /// All graphics, compute, copy, and transition commands
-
- //@extension("VK_NVX_device_generated_commands") // 87
- VK_PIPELINE_STAGE_COMMAND_PROCESS_BIT_NVX = 0x00020000,
-
- //@extension("VK_EXT_conditional_rendering") // 82
- VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT = 0x00040000,
-
- //@extension("VK_NV_mesh_shader") // 203
- VK_PIPELINE_STAGE_TASK_SHADER_BIT_NV = 0x00080000,
- VK_PIPELINE_STAGE_MESH_SHADER_BIT_NV = 0x00100000,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_PIPELINE_STAGE_RAY_TRACING_BIT_NV = 0x00200000,
-
- //@extension("VK_NV_shading_rate_image") // 165
- VK_PIPELINE_STAGE_SHADING_RATE_IMAGE_BIT_NV = 0x00400000,
-
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_PIPELINE_STAGE_FRAGMENT_DENSITY_PROCESS_BIT_EXT = 0x00800000,
-
- //@extension("VK_EXT_transform_feedback") // 29
- VK_PIPELINE_STAGE_TRANSFORM_FEEDBACK_BIT_EXT = 0x01000000,
-
- //@extension("VK_NV_ray_tracing") // 166
- VK_PIPELINE_STAGE_ACCELERATION_STRUCTURE_BUILD_BIT_NV = 0x02000000,
-}
-
-/// Render pass attachment description flags
-type VkFlags VkAttachmentDescriptionFlags
-bitfield VkAttachmentDescriptionFlagBits {
- VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT = 0x00000001, /// The attachment may alias physical memory of another attachment in the same renderpass
-}
-
-/// Subpass description flags
-type VkFlags VkSubpassDescriptionFlags
-bitfield VkSubpassDescriptionFlagBits {
- //@extension("VK_NVX_multiview_per_view_attributes") // 98
- VK_SUBPASS_DESCRIPTION_PER_VIEW_ATTRIBUTES_BIT_NVX = 0x00000001,
- VK_SUBPASS_DESCRIPTION_PER_VIEW_POSITION_X_ONLY_BIT_NVX = 0x00000002,
-}
-
-/// Command pool creation flags
-type VkFlags VkCommandPoolCreateFlags
-bitfield VkCommandPoolCreateFlagBits {
- VK_COMMAND_POOL_CREATE_TRANSIENT_BIT = 0x00000001, /// Command buffers have a short lifetime
- VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT = 0x00000002, /// Command buffers may release their memory individually
-
- //@vulkan1_1
- VK_COMMAND_POOL_CREATE_PROTECTED_BIT = 0x00000004,
-}
-
-/// Command pool reset flags
-type VkFlags VkCommandPoolResetFlags
-bitfield VkCommandPoolResetFlagBits {
- VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT = 0x00000001, /// Release resources owned by the pool
-}
-
-type VkFlags VkCommandBufferResetFlags
-bitfield VkCommandBufferResetFlagBits {
- VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT = 0x00000001, /// Release resources owned by the buffer
-}
-
-type VkFlags VkSampleCountFlags
-bitfield VkSampleCountFlagBits {
- VK_SAMPLE_COUNT_1_BIT = 0x00000001,
- VK_SAMPLE_COUNT_2_BIT = 0x00000002,
- VK_SAMPLE_COUNT_4_BIT = 0x00000004,
- VK_SAMPLE_COUNT_8_BIT = 0x00000008,
- VK_SAMPLE_COUNT_16_BIT = 0x00000010,
- VK_SAMPLE_COUNT_32_BIT = 0x00000020,
- VK_SAMPLE_COUNT_64_BIT = 0x00000040,
-}
-
-type VkFlags VkStencilFaceFlags
-bitfield VkStencilFaceFlagBits {
- VK_STENCIL_FACE_FRONT_BIT = 0x00000001, /// Front face
- VK_STENCIL_FACE_BACK_BIT = 0x00000002, /// Back face
- VK_STENCIL_FRONT_AND_BACK = 0x00000003,
-}
-
-/// Instance creation flags
-type VkFlags VkInstanceCreateFlags
-//bitfield VkInstanceCreateFlagBits {
-//}
-
-/// Device creation flags
-type VkFlags VkDeviceCreateFlags
-//bitfield VkDeviceCreateFlagBits {
-//}
-
-/// Device queue creation flags
-type VkFlags VkDeviceQueueCreateFlags
-@vulkan1_1
-bitfield VkDeviceQueueCreateFlagBits {
- VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001,
-}
-
-/// Query pool creation flags
-type VkFlags VkQueryPoolCreateFlags
-//bitfield VkQueryPoolCreateFlagBits {
-//}
-
-/// Buffer view creation flags
-type VkFlags VkBufferViewCreateFlags
-//bitfield VkBufferViewCreateFlagBits {
-//}
-
-/// Pipeline cache creation flags
-type VkFlags VkPipelineCacheCreateFlags
-//bitfield VkPipelineCacheCreateFlagBits {
-//}
-
-/// Pipeline shader stage creation flags
-type VkFlags VkPipelineShaderStageCreateFlags
-//bitfield VkPipelineShaderStageCreateFlagBits {
-//}
-
-/// Descriptor set layout creation flags
-type VkFlags VkDescriptorSetLayoutCreateFlags
-bitfield VkDescriptorSetLayoutCreateFlagBits {
- //@extension("VK_KHR_push_descriptor") // 81
- VK_DESCRIPTOR_SET_LAYOUT_CREATE_PUSH_DESCRIPTOR_BIT_KHR = 0x00000001,
-
- //@extension("VK_EXT_descriptor_indexing") // 162
- VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT = 0x00000002,
-}
-
-/// Pipeline vertex input state creation flags
-type VkFlags VkPipelineVertexInputStateCreateFlags
-//bitfield VkPipelineVertexInputStateCreateFlagBits {
-//}
-
-/// Pipeline input assembly state creation flags
-type VkFlags VkPipelineInputAssemblyStateCreateFlags
-//bitfield VkPipelineInputAssemblyStateCreateFlagBits {
-//}
-
-/// Tessellation state creation flags
-type VkFlags VkPipelineTessellationStateCreateFlags
-//bitfield VkPipelineTessellationStateCreateFlagBits {
-//}
-
-/// Viewport state creation flags
-type VkFlags VkPipelineViewportStateCreateFlags
-//bitfield VkPipelineViewportStateCreateFlagBits {
-//}
-
-/// Rasterization state creation flags
-type VkFlags VkPipelineRasterizationStateCreateFlags
-//bitfield VkPipelineRasterizationStateCreateFlagBits {
-//}
-
-/// Multisample state creation flags
-type VkFlags VkPipelineMultisampleStateCreateFlags
-//bitfield VkPipelineMultisampleStateCreateFlagBits {
-//}
-
-/// Color blend state creation flags
-type VkFlags VkPipelineColorBlendStateCreateFlags
-//bitfield VkPipelineColorBlendStateCreateFlagBits {
-//}
-
-/// Depth/stencil state creation flags
-type VkFlags VkPipelineDepthStencilStateCreateFlags
-//bitfield VkPipelineDepthStencilStateCreateFlagBits {
-//}
-
-/// Dynamic state creation flags
-type VkFlags VkPipelineDynamicStateCreateFlags
-//bitfield VkPipelineDynamicStateCreateFlagBits {
-//}
-
-/// Pipeline layout creation flags
-type VkFlags VkPipelineLayoutCreateFlags
-//bitfield VkPipelineLayoutCreateFlagBits {
-//}
-
-/// Sampler creation flags
-type VkFlags VkSamplerCreateFlags
-bitfield VkSamplerCreateFlagBits {
- //@extension("VK_EXT_fragment_density_map") // 219
- VK_SAMPLER_CREATE_SUBSAMPLED_BIT_EXT = 0x00000001,
- VK_SAMPLER_CREATE_SUBSAMPLED_COARSE_RECONSTRUCTION_BIT_EXT = 0x00000002,
-}
-
-/// Render pass creation flags
-type VkFlags VkRenderPassCreateFlags
-//bitfield VkRenderPassCreateFlagBits {
-//}
-
-/// Framebuffer creation flags
-type VkFlags VkFramebufferCreateFlags
-//bitfield VkFramebufferCreateFlagBits {
-//}
-
-/// Dependency flags
-type VkFlags VkDependencyFlags
-bitfield VkDependencyFlagBits {
- VK_DEPENDENCY_BY_REGION_BIT = 0x00000001,
-
- //@vulkan1_1
- VK_DEPENDENCY_DEVICE_GROUP_BIT = 0x00000004,
- VK_DEPENDENCY_VIEW_LOCAL_BIT = 0x00000002,
-
- //@extension("VK_KHR_multiview") // 54
- VK_DEPENDENCY_VIEW_LOCAL_BIT_KHR = 0x00000002,
-
- //@extension("VK_KHR_device_group") // 61
- VK_DEPENDENCY_DEVICE_GROUP_BIT_KHR = 0x00000004,
-}
-
-/// Cull mode flags
-type VkFlags VkCullModeFlags
-bitfield VkCullModeFlagBits {
- VK_CULL_MODE_NONE = 0x00000000,
- VK_CULL_MODE_FRONT_BIT = 0x00000001,
- VK_CULL_MODE_BACK_BIT = 0x00000002,
- VK_CULL_MODE_FRONT_AND_BACK = 0x00000003,
-}
-
-//@vulkan1_1 flags
-
-/// Subgroup feature flags
-type VkFlags VkSubgroupFeatureFlags
-bitfield VkSubgroupFeatureFlagBits {
- VK_SUBGROUP_FEATURE_BASIC_BIT = 0x00000001,
- VK_SUBGROUP_FEATURE_VOTE_BIT = 0x00000002,
- VK_SUBGROUP_FEATURE_ARITHMETIC_BIT = 0x00000004,
- VK_SUBGROUP_FEATURE_BALLOT_BIT = 0x00000008,
- VK_SUBGROUP_FEATURE_SHUFFLE_BIT = 0x00000010,
- VK_SUBGROUP_FEATURE_SHUFFLE_RELATIVE_BIT = 0x00000020,
- VK_SUBGROUP_FEATURE_CLUSTERED_BIT = 0x00000040,
- VK_SUBGROUP_FEATURE_QUAD_BIT = 0x00000080,
-
- //@extension("VK_NV_shader_subgroup_partitioned") // 199
- VK_SUBGROUP_FEATURE_PARTITIONED_BIT_NV = 0x00000100,
-}
-
-/// Peer memory feature flags
-type VkFlags VkPeerMemoryFeatureFlags
-bitfield VkPeerMemoryFeatureFlagBits {
- VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT = 0x00000001,
- VK_PEER_MEMORY_FEATURE_COPY_DST_BIT = 0x00000002,
- VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT = 0x00000004,
- VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT = 0x00000008,
-}
-
-/// Memory allocation flags
-type VkFlags VkMemoryAllocateFlags
-bitfield VkMemoryAllocateFlagBits {
- VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT = 0x00000001,
-}
-
-type VkFlags VkCommandPoolTrimFlags
-//bitfield VkCommandPoolTrimFlagBits {
-//}
-
-type VkFlags VkDescriptorUpdateTemplateCreateFlags
-//bitfield VkDescriptorUpdateTemplateCreateFlagBits {
-//}
-
-/// External memory handle type flags
-type VkFlags VkExternalMemoryHandleTypeFlags
-bitfield VkExternalMemoryHandleTypeFlagBits {
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT = 0x00000008,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT = 0x00000010,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT = 0x00000020,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT = 0x00000040,
-
- //@extension("VK_EXT_external_memory_host") // 179
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_ALLOCATION_BIT_EXT = 0x00000080,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT = 0x00000100,
-
- //@extension("VK_EXT_external_memory_dma_buf") // 126
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT = 0x00000200,
-
- //@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID = 0x00000400,
-}
-
-/// External memory feature flags
-type VkFlags VkExternalMemoryFeatureFlags
-bitfield VkExternalMemoryFeatureFlagBits {
- VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT = 0x00000001,
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT = 0x00000002,
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT = 0x00000004,
-}
-
-/// External fence handle type flags
-type VkFlags VkExternalFenceHandleTypeFlags
-bitfield VkExternalFenceHandleTypeFlagBits {
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000008,
-}
-
-/// External fence feature flags
-type VkFlags VkExternalFenceFeatureFlags
-bitfield VkExternalFenceFeatureFlagBits {
- VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT = 0x00000001,
- VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT = 0x00000002,
-}
-
-/// Fence import flags
-type VkFlags VkFenceImportFlags
-bitfield VkFenceImportFlagBits {
- VK_FENCE_IMPORT_TEMPORARY_BIT = 0x00000001,
-}
-
-/// Semaphore import flags
-type VkFlags VkSemaphoreImportFlags
-bitfield VkSemaphoreImportFlagBits {
- VK_SEMAPHORE_IMPORT_TEMPORARY_BIT = 0x00000001,
-}
-
-/// External semaphore handle type flags
-type VkFlags VkExternalSemaphoreHandleTypeFlags
-bitfield VkExternalSemaphoreHandleTypeFlagBits {
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT = 0x00000001,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT = 0x00000002,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT = 0x00000004,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT = 0x00000008,
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT = 0x00000010,
-}
-
-/// External semaphore feature flags
-type VkFlags VkExternalSemaphoreFeatureFlags
-bitfield VkExternalSemaphoreFeatureFlagBits {
- VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT = 0x00000001,
- VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT = 0x00000002,
-}
-
-@extension("VK_KHR_surface") // 1
-type VkFlags VkSurfaceTransformFlagsKHR
-@extension("VK_KHR_surface") // 1
-bitfield VkSurfaceTransformFlagBitsKHR {
- VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR = 0x00000001,
- VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR = 0x00000002,
- VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR = 0x00000004,
- VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR = 0x00000008,
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR = 0x00000010,
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR = 0x00000020,
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR = 0x00000040,
- VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR = 0x00000080,
- VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR = 0x00000100,
-}
-
-@extension("VK_KHR_surface") // 1
-type VkFlags VkCompositeAlphaFlagsKHR
-@extension("VK_KHR_surface") // 1
-bitfield VkCompositeAlphaFlagBitsKHR {
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
- VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR = 0x00000002,
- VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR = 0x00000004,
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR = 0x00000008,
-}
-
-@extension("VK_KHR_swapchain") // 2
-type VkFlags VkSwapchainCreateFlagsKHR
-@extension("VK_KHR_swapchain") // 2
-bitfield VkSwapchainCreateFlagBitsKHR {
- //@vulkan1_1
- VK_SWAPCHAIN_CREATE_SPLIT_INSTANCE_BIND_REGIONS_BIT_KHR = 0x00000001,
- VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR = 0x00000002,
-
- //@extension("VK_KHR_swapchain_mutable_format") // 201
- VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR = 0x00000004,
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-type VkFlags VkDeviceGroupPresentModeFlagsKHR
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-bitfield VkDeviceGroupPresentModeFlagBitsKHR {
- VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_BIT_KHR = 0x00000001,
- VK_DEVICE_GROUP_PRESENT_MODE_REMOTE_BIT_KHR = 0x00000002,
- VK_DEVICE_GROUP_PRESENT_MODE_SUM_BIT_KHR = 0x00000004,
- VK_DEVICE_GROUP_PRESENT_MODE_LOCAL_MULTI_DEVICE_BIT_KHR = 0x00000008,
-}
-
-@extension("VK_KHR_display") // 3
-type VkFlags VkDisplayPlaneAlphaFlagsKHR
-@extension("VK_KHR_display") // 3
-bitfield VkDisplayPlaneAlphaFlagBitsKHR {
- VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR = 0x00000001,
- VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR = 0x00000002,
- VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR = 0x00000004,
- VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR = 0x00000008,
-}
-
-@extension("VK_KHR_display") // 3
-type VkFlags VkDisplaySurfaceCreateFlagsKHR
-//@extension("VK_KHR_display") // 3
-//bitfield VkDisplaySurfaceCreateFlagBitsKHR {
-//}
-
-@extension("VK_KHR_display") // 3
-type VkFlags VkDisplayModeCreateFlagsKHR
-//@extension("VK_KHR_display") // 3
-//bitfield VkDisplayModeCreateFlagBitsKHR {
-//}
-
-@extension("VK_KHR_xlib_surface") // 5
-type VkFlags VkXlibSurfaceCreateFlagsKHR
-//@extension("VK_KHR_xlib_surface") // 5
-//bitfield VkXlibSurfaceCreateFlagBitsKHR {
-//}
-
-@extension("VK_KHR_xcb_surface") // 6
-type VkFlags VkXcbSurfaceCreateFlagsKHR
-//@extension("VK_KHR_xcb_surface") // 6
-//bitfield VkXcbSurfaceCreateFlagBitsKHR {
-//}
-
-@extension("VK_KHR_wayland_surface") // 7
-type VkFlags VkWaylandSurfaceCreateFlagsKHR
-//@extension("VK_KHR_wayland_surface") // 7
-//bitfield VkWaylandSurfaceCreateFlagBitsKHR {
-//}
-
-@extension("VK_KHR_android_surface") // 9
-type VkFlags VkAndroidSurfaceCreateFlagsKHR
-//@extension("VK_KHR_android_surface") // 9
-//bitfield VkAndroidSurfaceCreateFlagBitsKHR {
-//}
-
-@extension("VK_KHR_win32_surface") // 10
-type VkFlags VkWin32SurfaceCreateFlagsKHR
-//@extension("VK_KHR_win32_surface") // 10
-//bitfield VkWin32SurfaceCreateFlagBitsKHR {
-//}
-
-@extension("VK_ANDROID_native_buffer") // 11
-type VkFlags VkSwapchainImageUsageFlagsANDROID
-@extension("VK_ANDROID_native_buffer") // 11
-bitfield VkSwapchainImageUsageFlagBitsANDROID {
- VK_SWAPCHAIN_IMAGE_USAGE_FLAGS_SHARED_BIT_ANDROID = 0x00000001,
-}
-
-@extension("VK_EXT_debug_report") // 12
-type VkFlags VkDebugReportFlagsEXT
-@extension("VK_EXT_debug_report") // 12
-bitfield VkDebugReportFlagBitsEXT {
- VK_DEBUG_REPORT_INFORMATION_BIT_EXT = 0x00000001,
- VK_DEBUG_REPORT_WARNING_BIT_EXT = 0x00000002,
- VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT = 0x00000004,
- VK_DEBUG_REPORT_ERROR_BIT_EXT = 0x00000008,
- VK_DEBUG_REPORT_DEBUG_BIT_EXT = 0x00000010,
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-type VkFlags VkPipelineRasterizationStateStreamCreateFlagsEXT
-//@extension("VK_EXT_transform_feedback") // 29
-//bitfield VkPipelineRasterizationStateStreamCreateFlagBitsEXT {
-//}
-
-@extension("VK_NV_external_memory_capabilities") // 56
-type VkFlags VkExternalMemoryHandleTypeFlagsNV
-@extension("VK_NV_external_memory_capabilities") // 56
-bitfield VkExternalMemoryHandleTypeFlagBitsNV {
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_NV = 0x00000001,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_NV = 0x00000002,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_BIT_NV = 0x00000004,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_IMAGE_KMT_BIT_NV = 0x00000008,
-}
-
-@extension("VK_NV_external_memory_capabilities") // 56
-type VkFlags VkExternalMemoryFeatureFlagsNV
-@extension("VK_NV_external_memory_capabilities") // 56
-bitfield VkExternalMemoryFeatureFlagBitsNV {
- VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_NV = 0x00000001,
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_NV = 0x00000002,
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_NV = 0x00000004,
-}
-
-@extension("VK_KHR_device_group") // 61
-type VkFlags VkPeerMemoryFeatureFlagsKHR
-@extension("VK_KHR_device_group") // 61
-bitfield VkPeerMemoryFeatureFlagBitsKHR {
- VK_PEER_MEMORY_FEATURE_COPY_SRC_BIT_KHR = 0x00000001,
- VK_PEER_MEMORY_FEATURE_COPY_DST_BIT_KHR = 0x00000002,
- VK_PEER_MEMORY_FEATURE_GENERIC_SRC_BIT_KHR = 0x00000004,
- VK_PEER_MEMORY_FEATURE_GENERIC_DST_BIT_KHR = 0x00000008,
-}
-
-@extension("VK_KHR_device_group") // 61
-type VkFlags VkMemoryAllocateFlagsKHR
-@extension("VK_KHR_device_group") // 61
-bitfield VkMemoryAllocateFlagBitsKHR {
- VK_MEMORY_ALLOCATE_DEVICE_MASK_BIT_KHR = 0x00000001,
-}
-
-@extension("VK_NN_vi_surface") // 63
-type VkFlags VkViSurfaceCreateFlagsNN
-//@extension("VK_NN_vi_surface") // 63
-//bitfield VkViSurfaceCreateFlagBitsNN {
-//}
-
-@extension("VK_KHR_maintenance1") // 70
-type VkFlags VkCommandPoolTrimFlagsKHR
-//@extension("VK_KHR_maintenance1") // 70
-//bitfield VkCommandPoolTrimFlagBitsKHR {
-//}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-type VkFlags VkExternalMemoryHandleTypeFlagsKHR
-@extension("VK_KHR_external_memory_capabilities") // 72
-bitfield VkExternalMemoryHandleTypeFlagBitsKHR {
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT_KHR = 0x00000008,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_KMT_BIT_KHR = 0x00000010,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_HEAP_BIT_KHR = 0x00000020,
- VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D12_RESOURCE_BIT_KHR = 0x00000040,
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-type VkFlags VkExternalMemoryFeatureFlagsKHR
-@extension("VK_KHR_external_memory_capabilities") // 72
-bitfield VkExternalMemoryFeatureFlagBitsKHR {
- VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT_KHR = 0x00000001,
- VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT_KHR = 0x00000002,
- VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT_KHR = 0x00000004,
-}
-
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-type VkFlags VkExternalSemaphoreHandleTypeFlagsKHR
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-bitfield VkExternalSemaphoreHandleTypeFlagBitsKHR {
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_D3D12_FENCE_BIT_KHR = 0x00000008
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FENCE_FD_BIT_KHR = 0x00000010
-}
-
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-type VkFlags VkExternalSemaphoreFeatureFlagsKHR
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-bitfield VkExternalSemaphoreFeatureFlagBitsKHR {
- VK_EXTERNAL_SEMAPHORE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001,
- VK_EXTERNAL_SEMAPHORE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002,
-}
-
-@extension("VK_KHR_external_semaphore") // 78
-type VkFlags VkSemaphoreImportFlagsKHR
-@extension("VK_KHR_external_semaphore") // 78
-bitfield VkSemaphoreImportFlagBitsKHR {
- VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001,
-}
-
-@extension("VK_EXT_conditional_rendering") // 82
-type VkFlags VkConditionalRenderingFlagsEXT
-@extension("VK_EXT_conditional_rendering") // 82
-bitfield VkConditionalRenderingFlagBitsEXT {
- VK_CONDITIONAL_RENDERING_INVERTED_BIT_EXT = 0x00000001,
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-type VkFlags VkDescriptorUpdateTemplateCreateFlagsKHR
-//@extension("VK_KHR_descriptor_update_template") // 86
-//bitfield VkDescriptorUpdateTemplateCreateFlagBitsKHR {
-//}
-
-@extension("VK_NVX_device_generated_commands") // 87
-type VkFlags VkIndirectCommandsLayoutUsageFlagsNVX
-@extension("VK_NVX_device_generated_commands") // 87
-bitfield VkIndirectCommandsLayoutUsageFlagBitsNVX {
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_UNORDERED_SEQUENCES_BIT_NVX = 0x00000001,
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_SPARSE_SEQUENCES_BIT_NVX = 0x00000002,
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_EMPTY_EXECUTIONS_BIT_NVX = 0x00000004,
- VK_INDIRECT_COMMANDS_LAYOUT_USAGE_INDEXED_SEQUENCES_BIT_NVX = 0x00000008,
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-type VkFlags VkObjectEntryUsageFlagsNVX
-@extension("VK_NVX_device_generated_commands") // 87
-bitfield VkObjectEntryUsageFlagBitsNVX {
- VK_OBJECT_ENTRY_USAGE_GRAPHICS_BIT_NVX = 0x00000001,
- VK_OBJECT_ENTRY_USAGE_COMPUTE_BIT_NVX = 0x00000002,
-}
-
-@extension("VK_EXT_display_surface_counter") // 91
-type VkFlags VkSurfaceCounterFlagsEXT
-@extension("VK_EXT_display_surface_counter") // 91
-bitfield VkSurfaceCounterFlagBitsEXT {
- VK_SURFACE_COUNTER_VBLANK_EXT = 0x00000001,
-}
-
-@extension("VK_NV_viewport_swizzle") // 99
-type VkFlags VkPipelineViewportSwizzleStateCreateFlagsNV
-//@extension("VK_NV_viewport_swizzle") // 99
-//bitfield VkPipelineViewportSwizzleStateCreateFlagBitsNV {
-//}
-
-@extension("VK_EXT_discard_rectangles") // 100
-type VkFlags VkPipelineDiscardRectangleStateCreateFlagsEXT
-//@extension("VK_EXT_discard_rectangles") // 100
-//bitfield VkPipelineDiscardRectangleStateCreateFlagBitsEXT {
-//}
-
-@extension("VK_EXT_conservative_rasterization") // 102
-type VkFlags VkPipelineRasterizationConservativeStateCreateFlagsEXT
-//@extension("VK_EXT_conservative_rasterization") // 102
-//bitfield VkPipelineRasterizationConservativeStateCreateFlagBitsEXT {
-//}
-
-@extension("VK_KHR_external_fence_capabilities") // 113
-type VkFlags VkExternalFenceHandleTypeFlagsKHR
-@extension("VK_KHR_external_fence_capabilities") // 113
-bitfield VkExternalFenceHandleTypeFlagBitsKHR {
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT_KHR = 0x00000001,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR = 0x00000002,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT_KHR = 0x00000004,
- VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT_KHR = 0x00000008,
-}
-
-@extension("VK_KHR_external_fence_capabilities") // 113
-type VkFlags VkExternalFenceFeatureFlagsKHR
-@extension("VK_KHR_external_fence_capabilities") // 113
-bitfield VkExternalFenceFeatureFlagBitsKHR {
- VK_EXTERNAL_FENCE_FEATURE_EXPORTABLE_BIT_KHR = 0x00000001,
- VK_EXTERNAL_FENCE_FEATURE_IMPORTABLE_BIT_KHR = 0x00000002,
-}
-
-@extension("VK_KHR_external_fence") // 114
-type VkFlags VkFenceImportFlagsKHR
-@extension("VK_KHR_external_fence") // 114
-bitfield VkFenceImportFlagBitsKHR {
- VK_FENCE_IMPORT_TEMPORARY_BIT_KHR = 0x00000001,
-}
-
-@extension("VK_MVK_ios_surface") // 123
-type VkFlags VkIOSSurfaceCreateFlagsMVK
-//@extension("VK_MVK_ios_surface") // 123
-//bitfield VkIOSSurfaceCreateFlagBitsMVK {
-//}
-
-@extension("VK_MVK_macos_surface") // 124
-type VkFlags VkMacOSSurfaceCreateFlagsMVK
-//@extension("VK_MVK_macos_surface") // 124
-//bitfield VkMacOSSurfaceCreateFlagBitsMVK {
-//}
-
-@extension("VK_EXT_debug_utils") // 129
-type VkFlags VkDebugUtilsMessengerCallbackDataFlagsEXT
-//@extension("VK_EXT_debug_utils") // 129
-//bitfield VkDebugUtilsMessengerCallbackDataFlagBitsEXT {
-//}
-
-@extension("VK_EXT_debug_utils") // 129
-type VkFlags VkDebugUtilsMessengerCreateFlagsEXT
-//@extension("VK_EXT_debug_utils") // 129
-//bitfield VkDebugUtilsMessengerCreateFlagBitsEXT {
-//}
-
-@extension("VK_EXT_debug_utils") // 129
-type VkFlags VkDebugUtilsMessageSeverityFlagsEXT
-@extension("VK_EXT_debug_utils") // 129
-bitfield VkDebugUtilsMessageSeverityFlagBitsEXT {
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT = 0x00000001,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT = 0x00000010,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT = 0x00000100,
- VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT = 0x00001000,
-}
-
-@extension("VK_EXT_debug_utils") // 129
-type VkFlags VkDebugUtilsMessageTypeFlagsEXT
-@extension("VK_EXT_debug_utils") // 129
-bitfield VkDebugUtilsMessageTypeFlagBitsEXT {
- VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT = 0x00000001,
- VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT = 0x00000002,
- VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT = 0x00000004,
-}
-
-@extension("VK_NV_fragment_coverage_to_color") // 150
-type VkFlags VkPipelineCoverageToColorStateCreateFlagsNV
-@extension("VK_NV_fragment_coverage_to_color") // 150
-//bitfield VkPipelineCoverageToColorStateCreateFlagBitsNV {
-//}
-
-@extension("VK_NV_framebuffer_mixed_samples") // 153
-type VkFlags VkPipelineCoverageModulationStateCreateFlagsNV
-@extension("VK_NV_framebuffer_mixed_samples") // 153
-//bitfield VkPipelineCoverageModulationStateCreateFlagBitsNV {
-//}
-
-@extension("VK_EXT_validation_cache") // 161
-type VkFlags VkValidationCacheCreateFlagsEXT
-@extension("VK_EXT_validation_cache") // 161
-//bitfield VkValidationCacheCreateFlagBitsEXT {
-//}
-
-@extension("VK_EXT_descriptor_indexing") // 162
-type VkFlags VkDescriptorBindingFlagsEXT
-@extension("VK_EXT_descriptor_indexing") // 162
-bitfield VkDescriptorBindingFlagBitsEXT {
- VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT = 0x00000001,
- VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT = 0x00000002,
- VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT = 0x00000004,
- VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT = 0x00000008,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-type VkFlags VkGeometryFlagsNV
-@extension("VK_NV_ray_tracing") // 166
-bitfield VkGeometryFlagBitsNV {
- VK_GEOMETRY_OPAQUE_BIT_NV = 0x00000001,
- VK_GEOMETRY_NO_DUPLICATE_ANY_HIT_INVOCATION_BIT_NV = 0x00000002,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-type VkFlags VkGeometryInstanceFlagsNV
-@extension("VK_NV_ray_tracing") // 166
-bitfield VkGeometryInstanceFlagBitsNV {
- VK_GEOMETRY_INSTANCE_TRIANGLE_CULL_DISABLE_BIT_NV = 0x00000001,
- VK_GEOMETRY_INSTANCE_TRIANGLE_FRONT_COUNTERCLOCKWISE_BIT_NV = 0x00000002,
- VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_NV = 0x00000004,
- VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_NV = 0x00000008,
-}
-
-@extension("VK_NV_ray_tracing") // 166
-type VkFlags VkBuildAccelerationStructureFlagsNV
-@extension("VK_NV_ray_tracing") // 166
-bitfield VkBuildAccelerationStructureFlagBitsNV {
- VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_UPDATE_BIT_NV = 0x00000001,
- VK_BUILD_ACCELERATION_STRUCTURE_ALLOW_COMPACTION_BIT_NV = 0x00000002,
- VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_TRACE_BIT_NV = 0x00000004,
- VK_BUILD_ACCELERATION_STRUCTURE_PREFER_FAST_BUILD_BIT_NV = 0x00000008,
- VK_BUILD_ACCELERATION_STRUCTURE_LOW_MEMORY_BIT_NV = 0x00000010,
-}
-
-@extension("VK_FUCHSIA_imagepipe_surface") // 215
-type VkFlags VkImagePipeSurfaceCreateFlagsFUCHSIA
-//@extension("VK_FUCHSIA_imagepipe_surface") // 215
-//bitfield VkImagePipeSurfaceCreateFlagBitsFUCHSIA {
-//}
-
-//////////////////
-// Structures //
-//////////////////
-
-class VkOffset2D {
- s32 x
- s32 y
-}
-
-class VkOffset3D {
- s32 x
- s32 y
- s32 z
-}
-
-class VkExtent2D {
- u32 width
- u32 height
-}
-
-class VkExtent3D {
- u32 width
- u32 height
- u32 depth
-}
-
-class VkViewport {
- f32 x
- f32 y
- f32 width
- f32 height
- f32 minDepth
- f32 maxDepth
-}
-
-class VkRect2D {
- VkOffset2D offset
- VkExtent2D extent
-}
-
-class VkClearRect {
- VkRect2D rect
- u32 baseArrayLayer
- u32 layerCount
-}
-
-class VkComponentMapping {
- VkComponentSwizzle r
- VkComponentSwizzle g
- VkComponentSwizzle b
- VkComponentSwizzle a
-}
-
-class VkPhysicalDeviceProperties {
- u32 apiVersion
- u32 driverVersion
- u32 vendorID
- u32 deviceID
- VkPhysicalDeviceType deviceType
- char[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE] deviceName
- u8[VK_UUID_SIZE] pipelineCacheUUID
- VkPhysicalDeviceLimits limits
- VkPhysicalDeviceSparseProperties sparseProperties
-}
-
-class VkExtensionProperties {
- char[VK_MAX_EXTENSION_NAME_SIZE] extensionName /// extension name
- u32 specVersion /// version of the extension specification implemented
-}
-
-class VkLayerProperties {
- char[VK_MAX_EXTENSION_NAME_SIZE] layerName /// layer name
- u32 specVersion /// version of the layer specification implemented
- u32 implementationVersion /// build or release version of the layer's library
- char[VK_MAX_DESCRIPTION_SIZE] description /// Free-form description of the layer
-}
-
-class VkSubmitInfo {
- VkStructureType sType /// Type of structure. Should be VK_STRUCTURE_TYPE_SUBMIT_INFO
- const void* pNext /// Next structure in chain
- u32 waitSemaphoreCount
- const VkSemaphore* pWaitSemaphores
- const VkPipelineStageFlags* pWaitDstStageMask
- u32 commandBufferCount
- const VkCommandBuffer* pCommandBuffers
- u32 signalSemaphoreCount
- const VkSemaphore* pSignalSemaphores
-}
-
-class VkApplicationInfo {
- VkStructureType sType /// Type of structure. Should be VK_STRUCTURE_TYPE_APPLICATION_INFO
- const void* pNext /// Next structure in chain
- const char* pApplicationName
- u32 applicationVersion
- const char* pEngineName
- u32 engineVersion
- u32 apiVersion
-}
-
-class VkAllocationCallbacks {
- void* pUserData
- PFN_vkAllocationFunction pfnAllocation
- PFN_vkReallocationFunction pfnReallocation
- PFN_vkFreeFunction pfnFree
- PFN_vkInternalAllocationNotification pfnInternalAllocation
- PFN_vkInternalFreeNotification pfnInternalFree
-}
-
-class VkDeviceQueueCreateInfo {
- VkStructureType sStype /// Should be VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkDeviceQueueCreateFlags flags
- u32 queueFamilyIndex
- u32 queueCount
- const f32* pQueuePriorities
-}
-
-class VkDeviceCreateInfo {
- VkStructureType sType /// Should be VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkDeviceCreateFlags flags
- u32 queueCreateInfoCount
- const VkDeviceQueueCreateInfo* pQueueCreateInfos
- u32 enabledLayerCount
- const char* const* ppEnabledLayerNames /// Ordered list of layer names to be enabled
- u32 enabledExtensionCount
- const char* const* ppEnabledExtensionNames
- const VkPhysicalDeviceFeatures* pEnabledFeatures
-}
-
-class VkInstanceCreateInfo {
- VkStructureType sType /// Should be VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkInstanceCreateFlags flags
- const VkApplicationInfo* pApplicationInfo
- u32 enabledLayerCount
- const char* const* ppEnabledLayerNames /// Ordered list of layer names to be enabled
- u32 enabledExtensionCount
- const char* const* ppEnabledExtensionNames /// Extension names to be enabled
-}
-
-class VkQueueFamilyProperties {
- VkQueueFlags queueFlags /// Queue flags
- u32 queueCount
- u32 timestampValidBits
- VkExtent3D minImageTransferGranularity
-}
-
-class VkPhysicalDeviceMemoryProperties {
- u32 memoryTypeCount
- VkMemoryType[VK_MAX_MEMORY_TYPES] memoryTypes
- u32 memoryHeapCount
- VkMemoryHeap[VK_MAX_MEMORY_HEAPS] memoryHeaps
-}
-
-class VkMemoryAllocateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
- const void* pNext /// Pointer to next structure
- VkDeviceSize allocationSize /// Size of memory allocation
- u32 memoryTypeIndex /// Index of the of the memory type to allocate from
-}
-
-class VkMemoryRequirements {
- VkDeviceSize size /// Specified in bytes
- VkDeviceSize alignment /// Specified in bytes
- u32 memoryTypeBits /// Bitfield of the allowed memory type indices into memoryTypes[] for this object
-}
-
-class VkSparseImageFormatProperties {
- VkImageAspectFlagBits aspectMask
- VkExtent3D imageGranularity
- VkSparseImageFormatFlags flags
-}
-
-class VkSparseImageMemoryRequirements {
- VkSparseImageFormatProperties formatProperties
- u32 imageMipTailFirstLod
- VkDeviceSize imageMipTailSize /// Specified in bytes, must be a multiple of image block size / alignment
- VkDeviceSize imageMipTailOffset /// Specified in bytes, must be a multiple of image block size / alignment
- VkDeviceSize imageMipTailStride /// Specified in bytes, must be a multiple of image block size / alignment
-}
-
-class VkMemoryType {
- VkMemoryPropertyFlags propertyFlags /// Memory properties of this memory type
- u32 heapIndex /// Index of the memory heap allocations of this memory type are taken from
-}
-
-class VkMemoryHeap {
- VkDeviceSize size /// Available memory in the heap
- VkMemoryHeapFlags flags /// Flags for the heap
-}
-
-class VkMappedMemoryRange {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
- const void* pNext /// Pointer to next structure
- VkDeviceMemory memory /// Mapped memory object
- VkDeviceSize offset /// Offset within the mapped memory the range starts from
- VkDeviceSize size /// Size of the range within the mapped memory
-}
-
-class VkFormatProperties {
- VkFormatFeatureFlags linearTilingFeatures /// Format features in case of linear tiling
- VkFormatFeatureFlags optimalTilingFeatures /// Format features in case of optimal tiling
- VkFormatFeatureFlags bufferFeatures /// Format features supported by buffers
-}
-
-class VkImageFormatProperties {
- VkExtent3D maxExtent /// max image dimensions for this resource type
- u32 maxMipLevels /// max number of mipmap levels for this resource type
- u32 maxArrayLayers /// max array layers for this resource type
- VkSampleCountFlags sampleCounts /// supported sample counts for this resource type
- VkDeviceSize maxResourceSize /// max size (in bytes) of this resource type
-}
-
-class VkDescriptorImageInfo {
- VkSampler sampler
- VkImageView imageView
- VkImageLayout imageLayout
-}
-
-class VkDescriptorBufferInfo {
- VkBuffer buffer /// Buffer used for this descriptor when the descriptor is UNIFORM_BUFFER[_DYNAMIC]
- VkDeviceSize offset /// Base offset from buffer start in bytes to update in the descriptor set.
- VkDeviceSize range /// Size in bytes of the buffer resource for this descriptor update.
-}
-
-class VkWriteDescriptorSet {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
- const void* pNext /// Pointer to next structure
- VkDescriptorSet dstSet /// Destination descriptor set
- u32 dstBinding /// Binding within the destination descriptor set to write
- u32 dstArrayElement /// Array element within the destination binding to write
- u32 descriptorCount /// Number of descriptors to write (determines the size of the array pointed by <pDescriptors>)
- VkDescriptorType descriptorType /// Descriptor type to write (determines which fields of the array pointed by <pDescriptors> are going to be used)
- const VkDescriptorImageInfo* pImageInfo
- const VkDescriptorBufferInfo* pBufferInfo
- const VkBufferView* pTexelBufferView
-}
-
-class VkCopyDescriptorSet {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET
- const void* pNext /// Pointer to next structure
- VkDescriptorSet srcSet /// Source descriptor set
- u32 srcBinding /// Binding within the source descriptor set to copy from
- u32 srcArrayElement /// Array element within the source binding to copy from
- VkDescriptorSet dstSet /// Destination descriptor set
- u32 dstBinding /// Binding within the destination descriptor set to copy to
- u32 dstArrayElement /// Array element within the destination binding to copy to
- u32 descriptorCount /// Number of descriptors to copy
-}
-
-class VkBufferCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
- const void* pNext /// Pointer to next structure.
- VkBufferCreateFlags flags /// Buffer creation flags
- VkDeviceSize size /// Specified in bytes
- VkBufferUsageFlags usage /// Buffer usage flags
- VkSharingMode sharingMode
- u32 queueFamilyIndexCount
- const u32* pQueueFamilyIndices
-}
-
-class VkBufferViewCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO
- const void* pNext /// Pointer to next structure.
- VkBufferViewCreateFlags flags
- VkBuffer buffer
- VkFormat format /// Optionally specifies format of elements
- VkDeviceSize offset /// Specified in bytes
- VkDeviceSize range /// View size specified in bytes
-}
-
-class VkImageSubresource {
- VkImageAspectFlagBits aspectMask
- u32 mipLevel
- u32 arrayLayer
-}
-
-class VkImageSubresourceRange {
- VkImageAspectFlags aspectMask
- u32 baseMipLevel
- u32 levelCount
- u32 baseArrayLayer
- u32 layerCount
-}
-
-class VkMemoryBarrier {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_MEMORY_BARRIER
- const void* pNext /// Pointer to next structure.
- VkAccessFlags srcAccessMask
- VkAccessFlags dstAccessMask
-}
-
-class VkBufferMemoryBarrier {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER
- const void* pNext /// Pointer to next structure.
- VkAccessFlags srcAccessMask
- VkAccessFlags dstAccessMask
- u32 srcQueueFamilyIndex /// Queue family to transition ownership from
- u32 dstQueueFamilyIndex /// Queue family to transition ownership to
- VkBuffer buffer /// Buffer to sync
- VkDeviceSize offset /// Offset within the buffer to sync
- VkDeviceSize size /// Amount of bytes to sync
-}
-
-class VkImageMemoryBarrier {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
- const void* pNext /// Pointer to next structure.
- VkAccessFlags srcAccessMask
- VkAccessFlags dstAccessMask
- VkImageLayout oldLayout /// Current layout of the image
- VkImageLayout newLayout /// New layout to transition the image to
- u32 srcQueueFamilyIndex /// Queue family to transition ownership from
- u32 dstQueueFamilyIndex /// Queue family to transition ownership to
- VkImage image /// Image to sync
- VkImageSubresourceRange subresourceRange /// Subresource range to sync
-}
-
-class VkImageCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
- const void* pNext /// Pointer to next structure.
- VkImageCreateFlags flags /// Image creation flags
- VkImageType imageType
- VkFormat format
- VkExtent3D extent
- u32 mipLevels
- u32 arrayLayers
- VkSampleCountFlagBits samples
- VkImageTiling tiling
- VkImageUsageFlags usage /// Image usage flags
- VkSharingMode sharingMode /// Cross-queue-family sharing mode
- u32 queueFamilyIndexCount /// Number of queue families to share across
- const u32* pQueueFamilyIndices /// Array of queue family indices to share across
- VkImageLayout initialLayout /// Initial image layout for all subresources
-}
-
-class VkSubresourceLayout {
- VkDeviceSize offset /// Specified in bytes
- VkDeviceSize size /// Specified in bytes
- VkDeviceSize rowPitch /// Specified in bytes
- VkDeviceSize arrayPitch /// Specified in bytes
- VkDeviceSize depthPitch /// Specified in bytes
-}
-
-class VkImageViewCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkImageViewCreateFlags flags
- VkImage image
- VkImageViewType viewType
- VkFormat format
- VkComponentMapping components
- VkImageSubresourceRange subresourceRange
-}
-
-class VkBufferCopy {
- VkDeviceSize srcOffset /// Specified in bytes
- VkDeviceSize dstOffset /// Specified in bytes
- VkDeviceSize size /// Specified in bytes
-}
-
-class VkSparseMemoryBind {
- VkDeviceSize resourceOffset /// Specified in bytes
- VkDeviceSize size /// Specified in bytes
- VkDeviceMemory memory
- VkDeviceSize memoryOffset /// Specified in bytes
- VkSparseMemoryBindFlags flags
-}
-
-class VkSparseImageMemoryBind {
- VkImageSubresource subresource
- VkOffset3D offset
- VkExtent3D extent
- VkDeviceMemory memory
- VkDeviceSize memoryOffset /// Specified in bytes
- VkSparseMemoryBindFlags flags
-}
-
-class VkSparseBufferMemoryBindInfo {
- VkBuffer buffer
- u32 bindCount
- const VkSparseMemoryBind* pBinds
-}
-
-class VkSparseImageOpaqueMemoryBindInfo {
- VkImage image
- u32 bindCount
- const VkSparseMemoryBind* pBinds
-}
-
-class VkSparseImageMemoryBindInfo {
- VkImage image
- u32 bindCount
- const VkSparseMemoryBind* pBinds
-}
-
-class VkBindSparseInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_BIND_SPARSE_INFO
- const void* pNext
- u32 waitSemaphoreCount
- const VkSemaphore* pWaitSemaphores
- u32 numBufferBinds
- const VkSparseBufferMemoryBindInfo* pBufferBinds
- u32 numImageOpaqueBinds
- const VkSparseImageOpaqueMemoryBindInfo* pImageOpaqueBinds
- u32 numImageBinds
- const VkSparseImageMemoryBindInfo* pImageBinds
- u32 signalSemaphoreCount
- const VkSemaphore* pSignalSemaphores
-}
-
-class VkImageSubresourceLayers {
- VkImageAspectFlags aspectMask
- u32 mipLevel
- u32 baseArrayLayer
- u32 layerCount
-}
-
-class VkImageCopy {
- VkImageSubresourceLayers srcSubresource
- VkOffset3D srcOffset /// Specified in pixels for both compressed and uncompressed images
- VkImageSubresourceLayers dstSubresource
- VkOffset3D dstOffset /// Specified in pixels for both compressed and uncompressed images
- VkExtent3D extent /// Specified in pixels for both compressed and uncompressed images
-}
-
-class VkImageBlit {
- VkImageSubresourceLayers srcSubresource
- VkOffset3D[2] srcOffsets
- VkImageSubresourceLayers dstSubresource
- VkOffset3D[2] dstOffsets
-}
-
-class VkBufferImageCopy {
- VkDeviceSize bufferOffset /// Specified in bytes
- u32 bufferRowLength /// Specified in texels
- u32 bufferImageHeight
- VkImageSubresourceLayers imageSubresource
- VkOffset3D imageOffset /// Specified in pixels for both compressed and uncompressed images
- VkExtent3D imageExtent /// Specified in pixels for both compressed and uncompressed images
-}
-
-class VkImageResolve {
- VkImageSubresourceLayers srcSubresource
- VkOffset3D srcOffset
- VkImageSubresourceLayers dstSubresource
- VkOffset3D dstOffset
- VkExtent3D extent
-}
-
-class VkShaderModuleCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkShaderModuleCreateFlags flags /// Reserved
- platform.size_t codeSize /// Specified in bytes
- const u32* pCode /// Binary code of size codeSize
-}
-
-class VkDescriptorSetLayoutBinding {
- u32 binding
- VkDescriptorType descriptorType /// Type of the descriptors in this binding
- u32 descriptorCount /// Number of descriptors in this binding
- VkShaderStageFlags stageFlags /// Shader stages this binding is visible to
- const VkSampler* pImmutableSamplers /// Immutable samplers (used if descriptor type is SAMPLER or COMBINED_IMAGE_SAMPLER, is either NULL or contains <count> number of elements)
-}
-
-class VkDescriptorSetLayoutCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkDescriptorSetLayoutCreateFlags flags
- u32 bindingCount /// Number of bindings in the descriptor set layout
- const VkDescriptorSetLayoutBinding* pBindings /// Array of descriptor set layout bindings
-}
-
-class VkDescriptorPoolSize {
- VkDescriptorType type
- u32 descriptorCount
-}
-
-class VkDescriptorPoolCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkDescriptorPoolCreateFlags flags
- u32 maxSets
- u32 poolSizeCount
- const VkDescriptorPoolSize* pPoolSizes
-}
-
-class VkDescriptorSetAllocateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
- const void* pNext /// Pointer to next structure
- VkDescriptorPool descriptorPool
- u32 setCount
- const VkDescriptorSetLayout* pSetLayouts
-}
-
-class VkSpecializationMapEntry {
- u32 constantID /// The SpecConstant ID specified in the BIL
- u32 offset /// Offset of the value in the data block
- platform.size_t size /// Size in bytes of the SpecConstant
-}
-
-class VkSpecializationInfo {
- u32 mapEntryCount /// Number of entries in the map
- const VkSpecializationMapEntry* pMapEntries /// Array of map entries
- platform.size_t dataSize /// Size in bytes of pData
- const void* pData /// Pointer to SpecConstant data
-}
-
-class VkPipelineShaderStageCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineShaderStageCreateFlags flags
- VkShaderStageFlagBits stage
- VkShaderModule module
- const char* pName
- const VkSpecializationInfo* pSpecializationInfo
-}
-
-class VkComputePipelineCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineCreateFlags flags /// Pipeline creation flags
- VkPipelineShaderStageCreateInfo stage
- VkPipelineLayout layout /// Interface layout of the pipeline
- VkPipeline basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of
- s32 basePipelineIndex /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of
-}
-
-class VkVertexInputBindingDescription {
- u32 binding /// Vertex buffer binding id
- u32 stride /// Distance between vertices in bytes (0 = no advancement)
- VkVertexInputRate inputRate /// Rate at which binding is incremented
-}
-
-class VkVertexInputAttributeDescription {
- u32 location /// location of the shader vertex attrib
- u32 binding /// Vertex buffer binding id
- VkFormat format /// format of source data
- u32 offset /// Offset of first element in bytes from base of vertex
-}
-
-class VkPipelineVertexInputStateCreateInfo {
- VkStructureType sType /// Should be VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineVertexInputStateCreateFlags flags
- u32 vertexBindingDescriptionCount /// number of bindings
- const VkVertexInputBindingDescription* pVertexBindingDescriptions
- u32 vertexAttributeDescriptionCount /// number of attributes
- const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
-}
-
-class VkPipelineInputAssemblyStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineInputAssemblyStateCreateFlags flags
- VkPrimitiveTopology topology
- VkBool32 primitiveRestartEnable
-}
-
-class VkPipelineTessellationStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineTessellationStateCreateFlags flags
- u32 patchControlPoints
-}
-
-class VkPipelineViewportStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineViewportStateCreateFlags flags
- u32 viewportCount
- const VkViewport* pViewports
- u32 scissorCount
- const VkRect2D* pScissors
-}
-
-class VkPipelineRasterizationStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineRasterizationStateCreateFlags flags
- VkBool32 depthClampEnable
- VkBool32 rasterizerDiscardEnable
- VkPolygonMode polygonMode /// optional (GL45)
- VkCullModeFlags cullMode
- VkFrontFace frontFace
- VkBool32 depthBiasEnable
- f32 depthBiasConstantFactor
- f32 depthBiasClamp
- f32 depthBiasSlopeFactor
- f32 lineWidth
-}
-
-class VkPipelineMultisampleStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineMultisampleStateCreateFlags flags
- VkSampleCountFlagBits rasterizationSamples /// Number of samples used for rasterization
- VkBool32 sampleShadingEnable /// optional (GL45)
- f32 minSampleShading /// optional (GL45)
- const VkSampleMask* pSampleMask
- VkBool32 alphaToCoverageEnable
- VkBool32 alphaToOneEnable
-}
-
-class VkPipelineColorBlendAttachmentState {
- VkBool32 blendEnable
- VkBlendFactor srcColorBlendFactor
- VkBlendFactor dstColorBlendFactor
- VkBlendOp colorBlendOp
- VkBlendFactor srcAlphaBlendFactor
- VkBlendFactor dstAlphaBlendFactor
- VkBlendOp alphaBlendOp
- VkColorComponentFlags colorWriteMask
-}
-
-class VkPipelineColorBlendStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineColorBlendStateCreateFlags flags
- VkBool32 logicOpEnable
- VkLogicOp logicOp
- u32 attachmentCount /// # of pAttachments
- const VkPipelineColorBlendAttachmentState* pAttachments
- f32[4] blendConstants
-}
-
-class VkStencilOpState {
- VkStencilOp failOp
- VkStencilOp passOp
- VkStencilOp depthFailOp
- VkCompareOp compareOp
- u32 compareMask
- u32 writeMask
- u32 reference
-}
-
-class VkPipelineDepthStencilStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineDepthStencilStateCreateFlags flags
- VkBool32 depthTestEnable
- VkBool32 depthWriteEnable
- VkCompareOp depthCompareOp
- VkBool32 depthBoundsTestEnable /// optional (depth_bounds_test)
- VkBool32 stencilTestEnable
- VkStencilOpState front
- VkStencilOpState back
- f32 minDepthBounds
- f32 maxDepthBounds
-}
-
-class VkPipelineDynamicStateCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineDynamicStateCreateFlags flags
- u32 dynamicStateCount
- const VkDynamicState* pDynamicStates
-}
-
-class VkGraphicsPipelineCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineCreateFlags flags /// Pipeline creation flags
- u32 stageCount
- const VkPipelineShaderStageCreateInfo* pStages /// One entry for each active shader stage
- const VkPipelineVertexInputStateCreateInfo* pVertexInputState
- const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState
- const VkPipelineTessellationStateCreateInfo* pTessellationState
- const VkPipelineViewportStateCreateInfo* pViewportState
- const VkPipelineRasterizationStateCreateInfo* pRasterizationState
- const VkPipelineMultisampleStateCreateInfo* pMultisampleState
- const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState
- const VkPipelineColorBlendStateCreateInfo* pColorBlendState
- const VkPipelineDynamicStateCreateInfo* pDynamicState
- VkPipelineLayout layout /// Interface layout of the pipeline
- VkRenderPass renderPass
- u32 subpass
- VkPipeline basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of
- s32 basePipelineIndex /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of
-}
-
-class VkPipelineCacheCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineCacheCreateFlags flags
- platform.size_t initialDataSize /// Size of initial data to populate cache, in bytes
- const void* pInitialData /// Initial data to populate cache
-}
-
-class VkPushConstantRange {
- VkShaderStageFlags stageFlags /// Which stages use the range
- u32 offset /// Start of the range, in bytes
- u32 size /// Length of the range, in bytes
-}
-
-class VkPipelineLayoutCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkPipelineLayoutCreateFlags flags
- u32 descriptorSetCount /// Number of descriptor sets interfaced by the pipeline
- const VkDescriptorSetLayout* pSetLayouts /// Array of <setCount> number of descriptor set layout objects defining the layout of the
- u32 pushConstantRangeCount /// Number of push-constant ranges used by the pipeline
- const VkPushConstantRange* pPushConstantRanges /// Array of pushConstantRangeCount number of ranges used by various shader stages
-}
-
-class VkSamplerCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkSamplerCreateFlags flags
- VkFilter magFilter /// Filter mode for magnification
- VkFilter minFilter /// Filter mode for minifiation
- VkSamplerMipmapMode mipmapMode /// Mipmap selection mode
- VkSamplerAddressMode addressModeU
- VkSamplerAddressMode addressModeV
- VkSamplerAddressMode addressModeW
- f32 mipLodBias
- VkBool32 anisotropyEnable
- f32 maxAnisotropy
- VkBool32 compareEnable
- VkCompareOp compareOp
- f32 minLod
- f32 maxLod
- VkBorderColor borderColor
- VkBool32 unnormalizedCoordinates
-}
-
-class VkCommandPoolCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkCommandPoolCreateFlags flags /// Command pool creation flags
- u32 queueFamilyIndex
-}
-
-class VkCommandBufferAllocateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
- const void* pNext /// Pointer to next structure
- VkCommandPool commandPool
- VkCommandBufferLevel level
- u32 commandBufferCount
-}
-
-class VkCommandBufferInheritanceInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO
- const void* pNext /// Pointer to next structure
- VkRenderPass renderPass /// Render pass for secondary command buffers
- u32 subpass
- VkFramebuffer framebuffer /// Framebuffer for secondary command buffers
- VkBool32 occlusionQueryEnable
- VkQueryControlFlags queryFlags
- VkQueryPipelineStatisticFlags pipelineStatistics
-}
-
-class VkCommandBufferBeginInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
- const void* pNext /// Pointer to next structure
- VkCommandBufferUsageFlags flags /// Command buffer usage flags
- const VkCommandBufferInheritanceInfo* pInheritanceInfo
-}
-
-class VkRenderPassBeginInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
- const void* pNext /// Pointer to next structure
- VkRenderPass renderPass
- VkFramebuffer framebuffer
- VkRect2D renderArea
- u32 clearValueCount
- const VkClearValue* pClearValues
-}
-
-@union
-/// Union allowing specification of floating point, integer, or unsigned integer color data. Actual value selected is based on image/attachment being cleared.
-class VkClearColorValue {
- f32[4] float32
- s32[4] int32
- u32[4] uint32
-}
-
-class VkClearDepthStencilValue {
- f32 depth
- u32 stencil
-}
-
-@union
-/// Union allowing specification of color, depth, and stencil color values. Actual value selected is based on attachment being cleared.
-class VkClearValue {
- VkClearColorValue color
- VkClearDepthStencilValue depthStencil
-}
-
-class VkClearAttachment {
- VkImageAspectFlags aspectMask
- u32 colorAttachment
- VkClearValue clearValue
-}
-
-class VkAttachmentDescription {
- VkAttachmentDescriptionFlags flags
- VkFormat format
- VkSampleCountFlagBits samples
- VkAttachmentLoadOp loadOp /// Load op for color or depth data
- VkAttachmentStoreOp storeOp /// Store op for color or depth data
- VkAttachmentLoadOp stencilLoadOp /// Load op for stencil data
- VkAttachmentStoreOp stencilStoreOp /// Store op for stencil data
- VkImageLayout initialLayout
- VkImageLayout finalLayout
-}
-
-class VkAttachmentReference {
- u32 attachment
- VkImageLayout layout
-}
-
-class VkSubpassDescription {
- VkSubpassDescriptionFlags flags
- VkPipelineBindPoint pipelineBindPoint /// Must be VK_PIPELINE_BIND_POINT_GRAPHICS for now
- u32 inputAttachmentCount
- const VkAttachmentReference* pInputAttachments
- u32 colorAttachmentCount
- const VkAttachmentReference* pColorAttachments
- const VkAttachmentReference* pResolveAttachments
- const VkAttachmentReference* pDepthStencilAttachment
- u32 preserveAttachmentCount
- const u32* pPreserveAttachments
-}
-
-class VkSubpassDependency {
- u32 srcSubpass
- u32 dstSubpass
- VkPipelineStageFlags srcStageMask
- VkPipelineStageFlags dstStageMask
- VkAccessFlags srcAccessMask
- VkAccessFlags dstAccessMask
- VkDependencyFlags dependencyFlags
-}
-
-class VkRenderPassCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkRenderPassCreateFlags flags
- u32 attachmentCount
- const VkAttachmentDescription* pAttachments
- u32 subpassCount
- const VkSubpassDescription* pSubpasses
- u32 dependencyCount
- const VkSubpassDependency* pDependencies
-}
-
-class VkEventCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_EVENT_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkEventCreateFlags flags /// Event creation flags
-}
-
-class VkFenceCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkFenceCreateFlags flags /// Fence creation flags
-}
-
-class VkPhysicalDeviceFeatures {
- VkBool32 robustBufferAccess /// out of bounds buffer accesses are well defined
- VkBool32 fullDrawIndexUint32 /// full 32-bit range of indices for indexed draw calls
- VkBool32 imageCubeArray /// image views which are arrays of cube maps
- VkBool32 independentBlend /// blending operations are controlled per-attachment
- VkBool32 geometryShader /// geometry stage
- VkBool32 tessellationShader /// tessellation control and evaluation stage
- VkBool32 sampleRateShading /// per-sample shading and interpolation
- VkBool32 dualSrcBlend /// blend operations which take two sources
- VkBool32 logicOp /// logic operations
- VkBool32 multiDrawIndirect /// multi draw indirect
- VkBool32 drawIndirectFirstInstance
- VkBool32 depthClamp /// depth clamping
- VkBool32 depthBiasClamp /// depth bias clamping
- VkBool32 fillModeNonSolid /// point and wireframe fill modes
- VkBool32 depthBounds /// depth bounds test
- VkBool32 wideLines /// lines with width greater than 1
- VkBool32 largePoints /// points with size greater than 1
- VkBool32 alphaToOne /// The fragment alpha channel can be forced to maximum representable alpha value
- VkBool32 multiViewport
- VkBool32 samplerAnisotropy
- VkBool32 textureCompressionETC2 /// ETC texture compression formats
- VkBool32 textureCompressionASTC_LDR /// ASTC LDR texture compression formats
- VkBool32 textureCompressionBC /// BC1-7 texture compressed formats
- VkBool32 occlusionQueryPrecise
- VkBool32 pipelineStatisticsQuery /// pipeline statistics query
- VkBool32 vertexPipelineStoresAndAtomics
- VkBool32 fragmentStoresAndAtomics
- VkBool32 shaderTessellationAndGeometryPointSize
- VkBool32 shaderImageGatherExtended /// texture gather with run-time values and independent offsets
- VkBool32 shaderStorageImageExtendedFormats /// the extended set of formats can be used for storage images
- VkBool32 shaderStorageImageMultisample /// multisample images can be used for storage images
- VkBool32 shaderStorageImageReadWithoutFormat
- VkBool32 shaderStorageImageWriteWithoutFormat
- VkBool32 shaderUniformBufferArrayDynamicIndexing /// arrays of uniform buffers can be accessed with dynamically uniform indices
- VkBool32 shaderSampledImageArrayDynamicIndexing /// arrays of sampled images can be accessed with dynamically uniform indices
- VkBool32 shaderStorageBufferArrayDynamicIndexing /// arrays of storage buffers can be accessed with dynamically uniform indices
- VkBool32 shaderStorageImageArrayDynamicIndexing /// arrays of storage images can be accessed with dynamically uniform indices
- VkBool32 shaderClipDistance /// clip distance in shaders
- VkBool32 shaderCullDistance /// cull distance in shaders
- VkBool32 shaderFloat64 /// 64-bit floats (doubles) in shaders
- VkBool32 shaderInt64 /// 64-bit integers in shaders
- VkBool32 shaderInt16 /// 16-bit integers in shaders
- VkBool32 shaderResourceResidency /// shader can use texture operations that return resource residency information (requires sparseNonResident support)
- VkBool32 shaderResourceMinLod /// shader can use texture operations that specify minimum resource LOD
- VkBool32 sparseBinding /// Sparse resources support: Resource memory can be managed at opaque page level rather than object level
- VkBool32 sparseResidencyBuffer /// Sparse resources support: GPU can access partially resident buffers
- VkBool32 sparseResidencyImage2D /// Sparse resources support: GPU can access partially resident 2D (non-MSAA non-DepthStencil) images
- VkBool32 sparseResidencyImage3D /// Sparse resources support: GPU can access partially resident 3D images
- VkBool32 sparseResidency2Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 2 samples
- VkBool32 sparseResidency4Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 4 samples
- VkBool32 sparseResidency8Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 8 samples
- VkBool32 sparseResidency16Samples /// Sparse resources support: GPU can access partially resident MSAA 2D images with 16 samples
- VkBool32 sparseResidencyAliased /// Sparse resources support: GPU can correctly access data aliased into multiple locations (opt-in)
- VkBool32 variableMultisampleRate
- VkBool32 inheritedQueries
-}
-
-class VkPhysicalDeviceLimits {
- /// resource maximum sizes
- u32 maxImageDimension1D /// max 1D image dimension
- u32 maxImageDimension2D /// max 2D image dimension
- u32 maxImageDimension3D /// max 3D image dimension
- u32 maxImageDimensionCube /// max cubemap image dimension
- u32 maxImageArrayLayers /// max layers for image arrays
- u32 maxTexelBufferElements
- u32 maxUniformBufferRange /// max uniform buffer size (bytes)
- u32 maxStorageBufferRange /// max storage buffer size (bytes)
- u32 maxPushConstantsSize /// max size of the push constants pool (bytes)
- /// memory limits
- u32 maxMemoryAllocationCount /// max number of device memory allocations supported
- u32 maxSamplerAllocationCount
- VkDeviceSize bufferImageGranularity /// Granularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage
- VkDeviceSize sparseAddressSpaceSize /// Total address space available for sparse allocations (bytes)
- /// descriptor set limits
- u32 maxBoundDescriptorSets /// max number of descriptors sets that can be bound to a pipeline
- u32 maxPerStageDescriptorSamplers /// max num of samplers allowed per-stage in a descriptor set
- u32 maxPerStageDescriptorUniformBuffers /// max num of uniform buffers allowed per-stage in a descriptor set
- u32 maxPerStageDescriptorStorageBuffers /// max num of storage buffers allowed per-stage in a descriptor set
- u32 maxPerStageDescriptorSampledImages /// max num of sampled images allowed per-stage in a descriptor set
- u32 maxPerStageDescriptorStorageImages /// max num of storage images allowed per-stage in a descriptor set
- u32 maxPerStageDescriptorInputAttachments
- u32 maxPerStageResources
- u32 maxDescriptorSetSamplers /// max num of samplers allowed in all stages in a descriptor set
- u32 maxDescriptorSetUniformBuffers /// max num of uniform buffers allowed in all stages in a descriptor set
- u32 maxDescriptorSetUniformBuffersDynamic /// max num of dynamic uniform buffers allowed in all stages in a descriptor set
- u32 maxDescriptorSetStorageBuffers /// max num of storage buffers allowed in all stages in a descriptor set
- u32 maxDescriptorSetStorageBuffersDynamic /// max num of dynamic storage buffers allowed in all stages in a descriptor set
- u32 maxDescriptorSetSampledImages /// max num of sampled images allowed in all stages in a descriptor set
- u32 maxDescriptorSetStorageImages /// max num of storage images allowed in all stages in a descriptor set
- u32 maxDescriptorSetInputAttachments
- /// vertex stage limits
- u32 maxVertexInputAttributes /// max num of vertex input attribute slots
- u32 maxVertexInputBindings /// max num of vertex input binding slots
- u32 maxVertexInputAttributeOffset /// max vertex input attribute offset added to vertex buffer offset
- u32 maxVertexInputBindingStride /// max vertex input binding stride
- u32 maxVertexOutputComponents /// max num of output components written by vertex shader
- /// tessellation control stage limits
- u32 maxTessellationGenerationLevel /// max level supported by tess primitive generator
- u32 maxTessellationPatchSize /// max patch size (vertices)
- u32 maxTessellationControlPerVertexInputComponents /// max num of input components per-vertex in TCS
- u32 maxTessellationControlPerVertexOutputComponents /// max num of output components per-vertex in TCS
- u32 maxTessellationControlPerPatchOutputComponents /// max num of output components per-patch in TCS
- u32 maxTessellationControlTotalOutputComponents /// max total num of per-vertex and per-patch output components in TCS
- u32 maxTessellationEvaluationInputComponents /// max num of input components per vertex in TES
- u32 maxTessellationEvaluationOutputComponents /// max num of output components per vertex in TES
- /// geometry stage limits
- u32 maxGeometryShaderInvocations /// max invocation count supported in geometry shader
- u32 maxGeometryInputComponents /// max num of input components read in geometry stage
- u32 maxGeometryOutputComponents /// max num of output components written in geometry stage
- u32 maxGeometryOutputVertices /// max num of vertices that can be emitted in geometry stage
- u32 maxGeometryTotalOutputComponents /// max total num of components (all vertices) written in geometry stage
- /// fragment stage limits
- u32 maxFragmentInputComponents /// max num of input compontents read in fragment stage
- u32 maxFragmentOutputAttachments /// max num of output attachments written in fragment stage
- u32 maxFragmentDualSrcAttachments /// max num of output attachments written when using dual source blending
- u32 maxFragmentCombinedOutputResources /// max total num of storage buffers, storage images and output buffers
- /// compute stage limits
- u32 maxComputeSharedMemorySize /// max total storage size of work group local storage (bytes)
- u32[3] maxComputeWorkGroupCount /// max num of compute work groups that may be dispatched by a single command (x,y,z)
- u32 maxComputeWorkGroupInvocations /// max total compute invocations in a single local work group
- u32[3] maxComputeWorkGroupSize /// max local size of a compute work group (x,y,z)
-
- u32 subPixelPrecisionBits /// num bits of subpixel precision in screen x and y
- u32 subTexelPrecisionBits /// num bits of subtexel precision
- u32 mipmapPrecisionBits /// num bits of mipmap precision
-
- u32 maxDrawIndexedIndexValue /// max index value for indexed draw calls (for 32-bit indices)
- u32 maxDrawIndirectCount
-
- f32 maxSamplerLodBias /// max absolute sampler level of detail bias
- f32 maxSamplerAnisotropy /// max degree of sampler anisotropy
-
- u32 maxViewports /// max number of active viewports
- u32[2] maxViewportDimensions /// max viewport dimensions (x,y)
- f32[2] viewportBoundsRange /// viewport bounds range (min,max)
- u32 viewportSubPixelBits /// num bits of subpixel precision for viewport
-
- platform.size_t minMemoryMapAlignment /// min required alignment of pointers returned by MapMemory (bytes)
- VkDeviceSize minTexelBufferOffsetAlignment /// min required alignment for texel buffer offsets (bytes)
- VkDeviceSize minUniformBufferOffsetAlignment /// min required alignment for uniform buffer sizes and offsets (bytes)
- VkDeviceSize minStorageBufferOffsetAlignment /// min required alignment for storage buffer offsets (bytes)
-
- s32 minTexelOffset /// min texel offset for OpTextureSampleOffset
- u32 maxTexelOffset /// max texel offset for OpTextureSampleOffset
- s32 minTexelGatherOffset /// min texel offset for OpTextureGatherOffset
- u32 maxTexelGatherOffset /// max texel offset for OpTextureGatherOffset
- f32 minInterpolationOffset /// furthest negative offset for interpolateAtOffset
- f32 maxInterpolationOffset /// furthest positive offset for interpolateAtOffset
- u32 subPixelInterpolationOffsetBits /// num of subpixel bits for interpolateAtOffset
-
- u32 maxFramebufferWidth /// max width for a framebuffer
- u32 maxFramebufferHeight /// max height for a framebuffer
- u32 maxFramebufferLayers /// max layer count for a layered framebuffer
- VkSampleCountFlags framebufferColorSampleCounts
- VkSampleCountFlags framebufferDepthSampleCounts
- VkSampleCountFlags framebufferStencilSampleCounts
- VkSampleCountFlags framebufferNoAttachmentSampleCounts
- u32 maxColorAttachments /// max num of framebuffer color attachments
-
- VkSampleCountFlags sampledImageColorSampleCounts
- VkSampleCountFlags sampledImageIntegerSampleCounts
- VkSampleCountFlags sampledImageDepthSampleCounts
- VkSampleCountFlags sampledImageStencilSampleCounts
- VkSampleCountFlags storageImageSampleCounts
- u32 maxSampleMaskWords /// max num of sample mask words
- VkBool32 timestampComputeAndGraphics
-
- f32 timestampPeriod
-
- u32 maxClipDistances /// max number of clip distances
- u32 maxCullDistances /// max number of cull distances
- u32 maxCombinedClipAndCullDistances /// max combined number of user clipping
-
- u32 discreteQueuePriorities
-
- f32[2] pointSizeRange /// range (min,max) of supported point sizes
- f32[2] lineWidthRange /// range (min,max) of supported line widths
- f32 pointSizeGranularity /// granularity of supported point sizes
- f32 lineWidthGranularity /// granularity of supported line widths
- VkBool32 strictLines
- VkBool32 standardSampleLocations
-
- VkDeviceSize optimalBufferCopyOffsetAlignment
- VkDeviceSize optimalBufferCopyRowPitchAlignment
- VkDeviceSize nonCoherentAtomSize
-}
-
-class VkPhysicalDeviceSparseProperties {
- VkBool32 residencyStandard2DBlockShape /// Sparse resources support: GPU will access all 2D (single sample) sparse resources using the standard block shapes (based on pixel format)
- VkBool32 residencyStandard2DMultisampleBlockShape /// Sparse resources support: GPU will access all 2D (multisample) sparse resources using the standard block shapes (based on pixel format)
- VkBool32 residencyStandard3DBlockShape /// Sparse resources support: GPU will access all 3D sparse resources using the standard block shapes (based on pixel format)
- VkBool32 residencyAlignedMipSize /// Sparse resources support: Images with mip-level dimensions that are NOT a multiple of the block size will be placed in the mip tail
- VkBool32 residencyNonResidentStrict /// Sparse resources support: GPU can safely access non-resident regions of a resource, all reads return as if data is 0, writes are discarded
-}
-
-class VkSemaphoreCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkSemaphoreCreateFlags flags /// Semaphore creation flags
-}
-
-class VkQueryPoolCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkQueryPoolCreateFlags flags
- VkQueryType queryType
- u32 queryCount
- VkQueryPipelineStatisticFlags pipelineStatistics /// Optional
-}
-
-class VkFramebufferCreateInfo {
- VkStructureType sType /// Must be VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO
- const void* pNext /// Pointer to next structure
- VkFramebufferCreateFlags flags
- VkRenderPass renderPass
- u32 attachmentCount
- const VkImageView* pAttachments
- u32 width
- u32 height
- u32 layers
-}
-
-class VkDrawIndirectCommand {
- u32 vertexCount
- u32 instanceCount
- u32 firstVertex
- u32 firstInstance
-}
-
-class VkDrawIndexedIndirectCommand {
- u32 indexCount
- u32 instanceCount
- u32 firstIndex
- s32 vertexOffset
- u32 firstInstance
-}
-
-class VkDispatchIndirectCommand {
- u32 x
- u32 y
- u32 z
-}
-
-class VkBaseOutStructure {
- VkStructureType sType
- void* pNext
-}
-
-class VkBaseInStructure {
- VkStructureType sType
- const void* pNext
-}
-
-//@vulkan1_1 structures
-
-class VkPhysicalDeviceSubgroupProperties {
- VkStructureType sType
- void* pNext
- u32 subgroupSize
- VkShaderStageFlags supportedStages
- VkSubgroupFeatureFlags supportedOperations
- VkBool32 quadOperationsInAllStages
-}
-
-class VkBindBufferMemoryInfo {
- VkStructureType sType
- const void* pNext
- VkBuffer buffer
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
-}
-
-class VkBindImageMemoryInfo {
- VkStructureType sType
- const void* pNext
- VkImage image
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
-}
-
-class VkPhysicalDevice16BitStorageFeatures {
- VkStructureType sType
- void* pNext
- VkBool32 storageBuffer16BitAccess
- VkBool32 uniformAndStorageBuffer16BitAccess
- VkBool32 storagePushConstant16
- VkBool32 storageInputOutput16
-}
-
-class VkMemoryDedicatedRequirements {
- VkStructureType sType
- void* pNext
- VkBool32 prefersDedicatedAllocation
- VkBool32 requiresDedicatedAllocation
-}
-
-class VkMemoryDedicatedAllocateInfo {
- VkStructureType sType
- const void* pNext
- VkImage image
- VkBuffer buffer
-}
-
-class VkMemoryAllocateFlagsInfo {
- VkStructureType sType
- const void* pNext
- VkMemoryAllocateFlags flags
- u32 deviceMask
-}
-
-class VkDeviceGroupRenderPassBeginInfo {
- VkStructureType sType
- const void* pNext
- u32 deviceMask
- u32 deviceRenderAreaCount
- const VkRect2D* pDeviceRenderAreas
-}
-
-class VkDeviceGroupCommandBufferBeginInfo {
- VkStructureType sType
- const void* pNext
- u32 deviceMask
-}
-
-class VkDeviceGroupSubmitInfo {
- VkStructureType sType
- const void* pNext
- u32 waitSemaphoreCount
- const u32* pWaitSemaphoreDeviceIndices
- u32 commandBufferCount
- const u32* pCommandBufferDeviceMasks
- u32 signalSemaphoreCount
- const u32* pSignalSemaphoreDeviceIndices
-}
-
-class VkDeviceGroupBindSparseInfo {
- VkStructureType sType
- const void* pNext
- u32 resourceDeviceIndex
- u32 memoryDeviceIndex
-}
-
-class VkBindBufferMemoryDeviceGroupInfo {
- VkStructureType sType
- const void* pNext
- u32 deviceIndexCount
- const u32* pDeviceIndices
-}
-
-class VkBindImageMemoryDeviceGroupInfo {
- VkStructureType sType
- const void* pNext
- u32 deviceIndexCount
- const u32* pDeviceIndices
- u32 splitInstanceBindRegionCount
- const VkRect2D* pSplitInstanceBindRegions
-}
-
-class VkPhysicalDeviceGroupProperties {
- VkStructureType sType
- void* pNext
- u32 physicalDeviceCount
- VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices
- VkBool32 subsetAllocation
-}
-
-class VkDeviceGroupDeviceCreateInfo {
- VkStructureType sType
- const void* pNext
- u32 physicalDeviceCount
- const VkPhysicalDevice* pPhysicalDevices
-}
-
-class VkBufferMemoryRequirementsInfo2 {
- VkStructureType sType
- const void* pNext
- VkBuffer buffer
-}
-
-class VkImageMemoryRequirementsInfo2 {
- VkStructureType sType
- const void* pNext
- VkImage image
-}
-
-class VkImageSparseMemoryRequirementsInfo2 {
- VkStructureType sType
- const void* pNext
- VkImage image
-}
-
-class VkMemoryRequirements2 {
- VkStructureType sType
- void* pNext
- VkMemoryRequirements memoryRequirements
-}
-
-class VkSparseImageMemoryRequirements2 {
- VkStructureType sType
- void* pNext
- VkSparseImageMemoryRequirements memoryRequirements
-}
-
-class VkPhysicalDeviceFeatures2 {
- VkStructureType sType
- void* pNext
- VkPhysicalDeviceFeatures features
-}
-
-class VkPhysicalDeviceProperties2 {
- VkStructureType sType
- void* pNext
- VkPhysicalDeviceProperties properties
-}
-
-class VkFormatProperties2 {
- VkStructureType sType
- void* pNext
- VkFormatProperties formatProperties
-}
-
-class VkImageFormatProperties2 {
- VkStructureType sType
- void* pNext
- VkImageFormatProperties imageFormatProperties
-}
-
-class VkPhysicalDeviceImageFormatInfo2 {
- VkStructureType sType
- const void* pNext
- VkFormat format
- VkImageType type
- VkImageTiling tiling
- VkImageUsageFlags usage
- VkImageCreateFlags flags
-}
-
-class VkQueueFamilyProperties2 {
- VkStructureType sType
- void* pNext
- VkQueueFamilyProperties queueFamilyProperties
-}
-
-class VkPhysicalDeviceMemoryProperties2 {
- VkStructureType sType
- void* pNext
- VkPhysicalDeviceMemoryProperties memoryProperties
-}
-
-class VkSparseImageFormatProperties2 {
- VkStructureType sType
- void* pNext
- VkSparseImageFormatProperties properties
-}
-
-class VkPhysicalDeviceSparseImageFormatInfo2 {
- VkStructureType sType
- const void* pNext
- VkFormat format
- VkImageType type
- VkSampleCountFlagBits samples
- VkImageUsageFlags usage
- VkImageTiling tiling
-}
-
-class VkPhysicalDevicePointClippingProperties {
- VkStructureType sType
- void* pNext
- VkPointClippingBehavior pointClippingBehavior
-}
-
-class VkInputAttachmentAspectReference {
- u32 subpass
- u32 inputAttachmentIndex
- VkImageAspectFlags aspectMask
-}
-
-class VkRenderPassInputAttachmentAspectCreateInfo {
- VkStructureType sType
- const void* pNext
- u32 aspectReferenceCount
- const VkInputAttachmentAspectReference* pAspectReferences
-}
-
-class VkImageViewUsageCreateInfo {
- VkStructureType sType
- const void* pNext
- VkImageUsageFlags usage
-}
-
-class VkPipelineTessellationDomainOriginStateCreateInfo {
- VkStructureType sType
- const void* pNext
- VkTessellationDomainOrigin domainOrigin
-}
-
-class VkRenderPassMultiviewCreateInfo {
- VkStructureType sType
- const void* pNext
- u32 subpassCount
- const u32* pViewMasks
- u32 dependencyCount
- const s32* pViewOffsets
- u32 correlationMaskCount
- const u32* pCorrelationMasks
-}
-
-class VkPhysicalDeviceMultiviewFeatures {
- VkStructureType sType
- void* pNext
- VkBool32 multiview
- VkBool32 multiviewGeometryShader
- VkBool32 multiviewTessellationShader
-}
-
-class VkPhysicalDeviceMultiviewProperties {
- VkStructureType sType
- void* pNext
- u32 maxMultiviewViewCount
- u32 maxMultiviewInstanceIndex
-}
-
-class VkPhysicalDeviceVariablePointerFeatures {
- VkStructureType sType
- void* pNext
- VkBool32 variablePointersStorageBuffer
- VkBool32 variablePointers
-}
-
-class VkPhysicalDeviceProtectedMemoryFeatures {
- VkStructureType sType
- void* pNext
- VkBool32 protectedMemory
-}
-
-class VkPhysicalDeviceProtectedMemoryProperties {
- VkStructureType sType
- void* pNext
- VkBool32 protectedNoFault
-}
-
-class VkDeviceQueueInfo2 {
- VkStructureType sType
- const void* pNext
- VkDeviceQueueCreateFlags flags
- u32 queueFamilyIndex
- u32 queueIndex
-}
-
-class VkProtectedSubmitInfo {
- VkStructureType sType
- const void* pNext
- VkBool32 protectedSubmit
-}
-
-class VkSamplerYcbcrConversionCreateInfo {
- VkStructureType sType
- const void* pNext
- VkFormat format
- VkSamplerYcbcrModelConversion ycbcrModel
- VkSamplerYcbcrRange ycbcrRange
- VkComponentMapping components
- VkChromaLocation xChromaOffset
- VkChromaLocation yChromaOffset
- VkFilter chromaFilter
- VkBool32 forceExplicitReconstruction
-}
-
-class VkSamplerYcbcrConversionInfo {
- VkStructureType sType
- const void* pNext
- VkSamplerYcbcrConversion conversion
-}
-
-class VkBindImagePlaneMemoryInfo {
- VkStructureType sType
- const void* pNext
- VkImageAspectFlagBits planeAspect
-}
-
-class VkImagePlaneMemoryRequirementsInfo {
- VkStructureType sType
- const void* pNext
- VkImageAspectFlagBits planeAspect
-}
-
-class VkPhysicalDeviceSamplerYcbcrConversionFeatures {
- VkStructureType sType
- void* pNext
- VkBool32 samplerYcbcrConversion
-}
-
-class VkSamplerYcbcrConversionImageFormatProperties {
- VkStructureType sType
- void* pNext
- u32 combinedImageSamplerDescriptorCount
-}
-
-class VkDescriptorUpdateTemplateEntry {
- u32 dstBinding
- u32 dstArrayElement
- u32 descriptorCount
- VkDescriptorType descriptorType
- platform.size_t offset
- platform.size_t stride
-}
-
-class VkDescriptorUpdateTemplateCreateInfo {
- VkStructureType sType
- const void* pNext
- VkDescriptorUpdateTemplateCreateFlags flags
- u32 descriptorUpdateEntryCount
- const VkDescriptorUpdateTemplateEntry* pDescriptorUpdateEntries
- VkDescriptorUpdateTemplateType templateType
- VkDescriptorSetLayout descriptorSetLayout
- VkPipelineBindPoint pipelineBindPoint
- VkPipelineLayout pipelineLayout
- u32 set
-}
-
-class VkExternalMemoryProperties {
- VkExternalMemoryFeatureFlags externalMemoryFeatures
- VkExternalMemoryHandleTypeFlags exportFromImportedHandleTypes
- VkExternalMemoryHandleTypeFlags compatibleHandleTypes
-}
-
-class VkPhysicalDeviceExternalImageFormatInfo {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagBits handleType
-}
-
-class VkExternalImageFormatProperties {
- VkStructureType sType
- void* pNext
- VkExternalMemoryProperties externalMemoryProperties
-}
-
-class VkPhysicalDeviceExternalBufferInfo {
- VkStructureType sType
- const void* pNext
- VkBufferCreateFlags flags
- VkBufferUsageFlags usage
- VkExternalMemoryHandleTypeFlagBits handleType
-}
-
-class VkExternalBufferProperties {
- VkStructureType sType
- void* pNext
- VkExternalMemoryProperties externalMemoryProperties
-}
-
-class VkPhysicalDeviceIDProperties {
- VkStructureType sType
- void* pNext
- u8[VK_UUID_SIZE] deviceUUID
- u8[VK_UUID_SIZE] driverUUID
- u8[VK_LUID_SIZE] deviceLUID
- u32 deviceNodeMask
- VkBool32 deviceLUIDValid
-}
-
-class VkExternalMemoryImageCreateInfo {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlags handleTypes
-}
-
-class VkExternalMemoryBufferCreateInfo {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlags handleTypes
-}
-
-class VkExportMemoryAllocateInfo {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlags handleTypes
-}
-
-class VkPhysicalDeviceExternalFenceInfo {
- VkStructureType sType
- const void* pNext
- VkExternalFenceHandleTypeFlagBits handleType
-}
-
-class VkExternalFenceProperties {
- VkStructureType sType
- void* pNext
- VkExternalFenceHandleTypeFlags exportFromImportedHandleTypes
- VkExternalFenceHandleTypeFlags compatibleHandleTypes
- VkExternalFenceFeatureFlags externalFenceFeatures
-}
-
-class VkExportFenceCreateInfo {
- VkStructureType sType
- const void* pNext
- VkExternalFenceHandleTypeFlags handleTypes
-}
-
-class VkExportSemaphoreCreateInfo {
- VkStructureType sType
- const void* pNext
- VkExternalSemaphoreHandleTypeFlags handleTypes
-}
-
-class VkPhysicalDeviceExternalSemaphoreInfo {
- VkStructureType sType
- const void* pNext
- VkExternalSemaphoreHandleTypeFlagBits handleType
-}
-
-class VkExternalSemaphoreProperties {
- VkStructureType sType
- void* pNext
- VkExternalSemaphoreHandleTypeFlags exportFromImportedHandleTypes
- VkExternalSemaphoreHandleTypeFlags compatibleHandleTypes
- VkExternalSemaphoreFeatureFlags externalSemaphoreFeatures
-}
-
-class VkPhysicalDeviceMaintenance3Properties {
- VkStructureType sType
- void* pNext
- u32 maxPerSetDescriptors
- VkDeviceSize maxMemoryAllocationSize
-}
-
-class VkDescriptorSetLayoutSupport {
- VkStructureType sType
- void* pNext
- VkBool32 supported
-}
-
-class VkPhysicalDeviceShaderDrawParameterFeatures {
- VkStructureType sType
- void* pNext
- VkBool32 shaderDrawParameters
-}
-
-
-@extension("VK_KHR_surface") // 1
-class VkSurfaceCapabilitiesKHR {
- u32 minImageCount
- u32 maxImageCount
- VkExtent2D currentExtent
- VkExtent2D minImageExtent
- VkExtent2D maxImageExtent
- u32 maxImageArrayLayers
- VkSurfaceTransformFlagsKHR supportedTransforms
- VkSurfaceTransformFlagBitsKHR currentTransform
- VkCompositeAlphaFlagsKHR supportedCompositeAlpha
- VkImageUsageFlags supportedUsageFlags
-}
-
-@extension("VK_KHR_surface") // 1
-class VkSurfaceFormatKHR {
- VkFormat format
- VkColorSpaceKHR colorSpace
-}
-
-@extension("VK_KHR_swapchain") // 2
-class VkSwapchainCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSwapchainCreateFlagsKHR flags
- VkSurfaceKHR surface
- u32 minImageCount
- VkFormat imageFormat
- VkColorSpaceKHR imageColorSpace
- VkExtent2D imageExtent
- u32 imageArrayLayers
- VkImageUsageFlags imageUsage
- VkSharingMode sharingMode
- u32 queueFamilyIndexCount
- const u32* pQueueFamilyIndices
- VkSurfaceTransformFlagBitsKHR preTransform
- VkCompositeAlphaFlagBitsKHR compositeAlpha
- VkPresentModeKHR presentMode
- VkBool32 clipped
- VkSwapchainKHR oldSwapchain
-}
-
-@extension("VK_KHR_swapchain") // 2
-class VkPresentInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 waitSemaphoreCount
- const VkSemaphore* pWaitSemaphores
- u32 swapchainCount
- const VkSwapchainKHR* pSwapchains
- const u32* pImageIndices
- VkResult* pResults
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-class VkImageSwapchainCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSwapchainKHR swapchain
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-class VkBindImageMemorySwapchainInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSwapchainKHR swapchain
- u32 imageIndex
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-class VkAcquireNextImageInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSwapchainKHR swapchain
- u64 timeout
- VkSemaphore semaphore
- VkFence fence
- u32 deviceMask
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-class VkDeviceGroupPresentCapabilitiesKHR {
- VkStructureType sType
- const void* pNext
- u32[VK_MAX_DEVICE_GROUP_SIZE] presentMask
- VkDeviceGroupPresentModeFlagsKHR modes
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-class VkDeviceGroupPresentInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 swapchainCount
- const u32* pDeviceMasks
- VkDeviceGroupPresentModeFlagBitsKHR mode
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-class VkDeviceGroupSwapchainCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkDeviceGroupPresentModeFlagsKHR modes
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplayPropertiesKHR {
- VkDisplayKHR display
- const char* displayName
- VkExtent2D physicalDimensions
- VkExtent2D physicalResolution
- VkSurfaceTransformFlagsKHR supportedTransforms
- VkBool32 planeReorderPossible
- VkBool32 persistentContent
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplayModeParametersKHR {
- VkExtent2D visibleRegion
- u32 refreshRate
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplayModePropertiesKHR {
- VkDisplayModeKHR displayMode
- VkDisplayModeParametersKHR parameters
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplayModeCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkDisplayModeCreateFlagsKHR flags
- VkDisplayModeParametersKHR parameters
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplayPlanePropertiesKHR {
- VkDisplayKHR currentDisplay
- u32 currentStackIndex
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplayPlaneCapabilitiesKHR {
- VkDisplayPlaneAlphaFlagsKHR supportedAlpha
- VkOffset2D minSrcPosition
- VkOffset2D maxSrcPosition
- VkExtent2D minSrcExtent
- VkExtent2D maxSrcExtent
- VkOffset2D minDstPosition
- VkOffset2D maxDstPosition
- VkExtent2D minDstExtent
- VkExtent2D maxDstExtent
-}
-
-@extension("VK_KHR_display") // 3
-class VkDisplaySurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkDisplaySurfaceCreateFlagsKHR flags
- VkDisplayModeKHR displayMode
- u32 planeIndex
- u32 planeStackIndex
- VkSurfaceTransformFlagBitsKHR transform
- f32 globalAlpha
- VkDisplayPlaneAlphaFlagBitsKHR alphaMode
- VkExtent2D imageExtent
-}
-
-@extension("VK_KHR_display_swapchain") // 4
-class VkDisplayPresentInfoKHR {
- VkStructureType sType
- const void* pNext
- VkRect2D srcRect
- VkRect2D dstRect
- VkBool32 persistent
-}
-
-@extension("VK_KHR_xlib_surface") // 5
-class VkXlibSurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkXlibSurfaceCreateFlagsKHR flags
- platform.Display* dpy
- platform.Window window
-}
-
-@extension("VK_KHR_xcb_surface") // 6
-class VkXcbSurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkXcbSurfaceCreateFlagsKHR flags
- platform.xcb_connection_t* connection
- platform.xcb_window_t window
-}
-
-@extension("VK_KHR_wayland_surface") // 7
-class VkWaylandSurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkWaylandSurfaceCreateFlagsKHR flags
- platform.wl_display* display
- platform.wl_surface* surface
-}
-
-@extension("VK_KHR_android_surface") // 9
-class VkAndroidSurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkAndroidSurfaceCreateFlagsKHR flags
- platform.ANativeWindow* window
-}
-
-@extension("VK_KHR_win32_surface") // 10
-class VkWin32SurfaceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkWin32SurfaceCreateFlagsKHR flags
- platform.HINSTANCE hinstance
- platform.HWND hwnd
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-@internal class Gralloc1Usage {
- u64 consumer
- u64 producer
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-class VkNativeBufferANDROID {
- VkStructureType sType
- const void* pNext
- platform.buffer_handle_t handle
- s32 stride
- s32 format
- s32 usage
- Gralloc1Usage usage2
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-class VkSwapchainImageCreateInfoANDROID {
- VkStructureType sType
- const void* pNext
- VkSwapchainImageUsageFlagsANDROID flags
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-class VkPhysicalDevicePresentationPropertiesANDROID {
- VkStructureType sType
- void* pNext
- VkBool32 sharedImage
-}
-
-@extension("VK_EXT_debug_report") // 12
-class VkDebugReportCallbackCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDebugReportFlagsEXT flags
- PFN_vkDebugReportCallbackEXT pfnCallback
- void* pUserData
-}
-
-@extension("VK_AMD_rasterization_order") // 19
-class VkPipelineRasterizationStateRasterizationOrderAMD {
- VkStructureType sType
- const void* pNext
- VkRasterizationOrderAMD rasterizationOrder
-}
-
-@extension("VK_EXT_debug_marker") // 23
-class VkDebugMarkerObjectNameInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDebugReportObjectTypeEXT objectType
- u64 object
- const char* pObjectName
-}
-
-@extension("VK_EXT_debug_marker") // 23
-class VkDebugMarkerObjectTagInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDebugReportObjectTypeEXT objectType
- u64 object
- u64 tagName
- platform.size_t tagSize
- const void* pTag
-}
-
-@extension("VK_EXT_debug_marker") // 23
-class VkDebugMarkerMarkerInfoEXT {
- VkStructureType sType
- const void* pNext
- const char* pMarkerName
- f32[4] color
-}
-
-@extension("VK_NV_dedicated_allocation") // 27
-class VkDedicatedAllocationImageCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkBool32 dedicatedAllocation
-}
-
-@extension("VK_NV_dedicated_allocation") // 27
-class VkDedicatedAllocationBufferCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkBool32 dedicatedAllocation
-}
-
-@extension("VK_NV_dedicated_allocation") // 27
-class VkDedicatedAllocationMemoryAllocateInfoNV {
- VkStructureType sType
- const void* pNext
- VkImage image
- VkBuffer buffer
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-class VkPhysicalDeviceTransformFeedbackFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 transformFeedback
- VkBool32 geometryStreams
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-class VkPhysicalDeviceTransformFeedbackPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 maxTransformFeedbackStreams
- u32 maxTransformFeedbackBuffers
- VkDeviceSize maxTransformFeedbackBufferSize
- u32 maxTransformFeedbackStreamDataSize
- u32 maxTransformFeedbackBufferDataSize
- u32 maxTransformFeedbackBufferDataStride
- VkBool32 transformFeedbackQueries
- VkBool32 transformFeedbackStreamsLinesTriangles
- VkBool32 transformFeedbackRasterizationStreamSelect
- VkBool32 transformFeedbackDraw
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-class VkPipelineRasterizationStateStreamCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkPipelineRasterizationStateStreamCreateFlagsEXT flags
- u32 rasterizationStream
-}
-
-@extension("VK_AMD_texture_gather_bias_lod") // 42
-class VkTextureLODGatherFormatPropertiesAMD {
- VkStructureType sType
- void* pNext
- VkBool32 supportsTextureGatherLODBiasAMD
-}
-
-@extension("VK_AMD_shader_info") // 43
-class VkShaderResourceUsageAMD {
- u32 numUsedVgprs
- u32 numUsedSgprs
- u32 ldsSizePerLocalWorkGroup
- platform.size_t ldsUsageSizeInBytes
- platform.size_t scratchMemUsageInBytes
-}
-
-@extension("VK_AMD_shader_info") // 43
-class VkShaderStatisticsInfoAMD {
- VkShaderStageFlags shaderStageMask
- VkShaderResourceUsageAMD resourceUsage
- u32 numPhysicalVgprs
- u32 numPhysicalSgprs
- u32 numAvailableVgprs
- u32 numAvailableSgprs
- u32[3] computeWorkGroupSize
-}
-
-@extension("VK_NV_corner_sampled_image") // 51
-class VkPhysicalDeviceCornerSampledImageFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 cornerSampledImage
-}
-
-@extension("VK_KHR_multiview") // 54
-class VkRenderPassMultiviewCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 subpassCount
- const u32* pViewMasks
- u32 dependencyCount
- const s32* pViewOffsets
- u32 correlationMaskCount
- const u32* pCorrelationMasks
-}
-
-@extension("VK_KHR_multiview") // 54
-class VkPhysicalDeviceMultiviewFeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 multiview
- VkBool32 multiviewGeometryShader
- VkBool32 multiviewTessellationShader
-}
-
-@extension("VK_KHR_multiview") // 54
-class VkPhysicalDeviceMultiviewPropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 maxMultiviewViewCount
- u32 maxMultiviewInstanceIndex
-}
-
-@extension("VK_NV_external_memory_capabilities") // 56
-class VkExternalImageFormatPropertiesNV {
- VkImageFormatProperties imageFormatProperties
- VkExternalMemoryFeatureFlagsNV externalMemoryFeatures
- VkExternalMemoryHandleTypeFlagsNV exportFromImportedHandleTypes
- VkExternalMemoryHandleTypeFlagsNV compatibleHandleTypes
-}
-
-@extension("VK_NV_external_memory") // 57
-class VkExternalMemoryImageCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsNV handleTypes
-}
-
-@extension("VK_NV_external_memory") // 57
-class VkExportMemoryAllocateInfoNV {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsNV handleTypes
-}
-
-@extension("VK_NV_external_memory_win32") // 58
-class VkImportMemoryWin32HandleInfoNV {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsNV handleType
- platform.HANDLE handle
-}
-
-@extension("VK_NV_external_memory_win32") // 58
-class VkExportMemoryWin32HandleInfoNV {
- VkStructureType sType
- const void* pNext
- const platform.SECURITY_ATTRIBUTES* pAttributes
- platform.DWORD dwAccess
-}
-
-@extension("VK_NV_win32_keyed_mutex") // 59
-class VkWin32KeyedMutexAcquireReleaseInfoNV {
- VkStructureType sType
- const void* pNext
- u32 acquireCount
- const VkDeviceMemory* pAcquireSyncs
- const u64* pAcquireKeys
- const u32* pAcquireTimeoutMilliseconds
- u32 releaseCount
- const VkDeviceMemory* pReleaseSyncs
- const u64* pReleaseKeys
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkPhysicalDeviceFeatures2KHR {
- VkStructureType sType
- void* pNext
- VkPhysicalDeviceFeatures features
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkPhysicalDeviceProperties2KHR {
- VkStructureType sType
- void* pNext
- VkPhysicalDeviceProperties properties
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkFormatProperties2KHR {
- VkStructureType sType
- void* pNext
- VkFormatProperties formatProperties
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkImageFormatProperties2KHR {
- VkStructureType sType
- void* pNext
- VkImageFormatProperties imageFormatProperties
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkPhysicalDeviceImageFormatInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkFormat format
- VkImageType type
- VkImageTiling tiling
- VkImageUsageFlags usage
- VkImageCreateFlags flags
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkQueueFamilyProperties2KHR {
- VkStructureType sType
- void* pNext
- VkQueueFamilyProperties queueFamilyProperties
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkPhysicalDeviceMemoryProperties2KHR {
- VkStructureType sType
- void* pNext
- VkPhysicalDeviceMemoryProperties memoryProperties
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkSparseImageFormatProperties2KHR {
- VkStructureType sType
- void* pNext
- VkSparseImageFormatProperties properties
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-class VkPhysicalDeviceSparseImageFormatInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkFormat format
- VkImageType type
- VkSampleCountFlagBits samples
- VkImageUsageFlags usage
- VkImageTiling tiling
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkMemoryAllocateFlagsInfoKHR {
- VkStructureType sType
- const void* pNext
- VkMemoryAllocateFlagsKHR flags
- u32 deviceMask
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkBindBufferMemoryDeviceGroupInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 deviceIndexCount
- const u32* pDeviceIndices
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkBindImageMemoryDeviceGroupInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 deviceIndexCount
- const u32* pDeviceIndices
- u32 SFRRectCount
- const VkRect2D* pSFRRects
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkDeviceGroupRenderPassBeginInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 deviceMask
- u32 deviceRenderAreaCount
- const VkRect2D* pDeviceRenderAreas
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkDeviceGroupCommandBufferBeginInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 deviceMask
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkDeviceGroupSubmitInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 waitSemaphoreCount
- const u32* pWaitSemaphoreDeviceIndices
- u32 commandBufferCount
- const u32* pCommandBufferDeviceMasks
- u32 signalSemaphoreCount
- const u32* pSignalSemaphoreDeviceIndices
-}
-
-@extension("VK_KHR_device_group") // 61
-class VkDeviceGroupBindSparseInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 resourceDeviceIndex
- u32 memoryDeviceIndex
-}
-
-@extension("VK_EXT_validation_flags") // 62
-class VkValidationFlagsEXT {
- VkStructureType sType
- const void* pNext
- u32 disabledValidationCheckCount
- const VkValidationCheckEXT* pDisabledValidationChecks
-}
-
-@extension("VK_NN_vi_surface") // 63
-class VkViSurfaceCreateInfoNN {
- VkStructureType sType
- const void* pNext
- VkViSurfaceCreateFlagsNN flags
- void* window
-}
-
-@extension("VK_EXT_astc_decode_mode") // 68
-class VkImageViewASTCDecodeModeEXT {
- VkStructureType sType
- const void* pNext
- VkFormat decodeMode
-}
-
-@extension("VK_EXT_astc_decode_mode") // 68
-class VkPhysicalDeviceASTCDecodeFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 decodeModeSharedExponent
-}
-
-@extension("VK_KHR_device_group_creation") // 71
-class VkPhysicalDeviceGroupPropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 physicalDeviceCount
- VkPhysicalDevice[VK_MAX_DEVICE_GROUP_SIZE] physicalDevices
- VkBool32 subsetAllocation
-}
-
-@extension("VK_KHR_device_group_creation") // 71
-class VkDeviceGroupDeviceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 physicalDeviceCount
- const VkPhysicalDevice* pPhysicalDevices
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-class VkExternalMemoryPropertiesKHR {
- VkExternalMemoryFeatureFlagsKHR externalMemoryFeatures
- VkExternalMemoryHandleTypeFlagsKHR exportFromImportedHandleTypes
- VkExternalMemoryHandleTypeFlagsKHR compatibleHandleTypes
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-class VkPhysicalDeviceExternalImageFormatInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-class VkExternalImageFormatPropertiesKHR {
- VkStructureType sType
- void* pNext
- VkExternalMemoryPropertiesKHR externalMemoryProperties
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-class VkPhysicalDeviceExternalBufferInfoKHR {
- VkStructureType sType
- const void* pNext
- VkBufferCreateFlags flags
- VkBufferUsageFlags usage
- VkExternalMemoryHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-class VkExternalBufferPropertiesKHR {
- VkStructureType sType
- void* pNext
- VkExternalMemoryPropertiesKHR externalMemoryProperties
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-class VkPhysicalDeviceIDPropertiesKHR {
- VkStructureType sType
- void* pNext
- u8[VK_UUID_SIZE] deviceUUID
- u8[VK_UUID_SIZE] driverUUID
- u8[VK_LUID_SIZE] deviceLUID
- u32 deviceNodeMask
- VkBool32 deviceLUIDValid
-}
-
-@extension("VK_KHR_external_memory") // 73
-class VkExternalMemoryImageCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsKHR handleTypes
-}
-
-@extension("VK_KHR_external_memory") // 73
-class VkExternalMemoryBufferCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsKHR handleTypes
-}
-
-@extension("VK_KHR_external_memory") // 73
-class VkExportMemoryAllocateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagsKHR handleTypes
-}
-
-@extension("VK_KHR_external_memory_win32") // 74
-class VkImportMemoryWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagBitsKHR handleType
- platform.HANDLE handle
- platform.LPCWSTR name
-}
-
-@extension("VK_KHR_external_memory_win32") // 74
-class VkExportMemoryWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- const platform.SECURITY_ATTRIBUTES* pAttributes
- platform.DWORD dwAccess
- platform.LPCWSTR name
-}
-
-@extension("VK_KHR_external_memory_win32") // 74
-class VkMemoryWin32HandlePropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 memoryTypeBits
-}
-
-@extension("VK_KHR_external_memory_win32") // 74
-class VkMemoryGetWin32HandleInfoKHR {
- VkStructureType sType
- void* pNext
- VkDeviceMemory memory
- VkExternalMemoryHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_memory_fd") // 75
-class VkImportMemoryFdInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagBitsKHR handleType
- int fd
-}
-
-@extension("VK_KHR_external_memory_fd") // 75
-class VkMemoryFdPropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 memoryTypeBits
-}
-
-@extension("VK_KHR_external_memory_fd") // 75
-class VkMemoryGetFdInfoKHR {
- VkStructureType sType
- void* pNext
- VkDeviceMemory memory
- VkExternalMemoryHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_win32_keyed_mutex") // 76
-class VkWin32KeyedMutexAcquireReleaseInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 acquireCount
- const VkDeviceMemory* pAcquireSyncs
- const u64* pAcquireKeys
- const u32* pAcquireTimeouts
- u32 releaseCount
- const VkDeviceMemory* pReleaseSyncs
- const u64* pReleaseKeys
-}
-
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-class VkPhysicalDeviceExternalSemaphoreInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-class VkExternalSemaphorePropertiesKHR {
- VkStructureType sType
- void* pNext
- VkExternalSemaphoreHandleTypeFlagsKHR exportFromImportedHandleTypes
- VkExternalSemaphoreHandleTypeFlagsKHR compatibleHandleTypes
- VkExternalSemaphoreFeatureFlagsKHR externalSemaphoreFeatures
-}
-
-@extension("VK_KHR_external_semaphore") // 78
-class VkExportSemaphoreCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalSemaphoreHandleTypeFlagsKHR handleTypes
-}
-
-@extension("VK_KHR_external_semaphore_win32") // 79
-class VkImportSemaphoreWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSemaphore semaphore
- VkSemaphoreImportFlagsKHR flags
- VkExternalSemaphoreHandleTypeFlagsKHR handleType
- platform.HANDLE handle
- platform.LPCWSTR name
-}
-
-@extension("VK_KHR_external_semaphore_win32") // 79
-class VkExportSemaphoreWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- const platform.SECURITY_ATTRIBUTES* pAttributes
- platform.DWORD dwAccess
- platform.LPCWSTR name
-}
-
-@extension("VK_KHR_external_semaphore_win32") // 79
-class VkD3D12FenceSubmitInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 waitSemaphoreValuesCount
- const u64* pWaitSemaphoreValues
- u32 signalSemaphoreValuesCount
- const u64* pSignalSemaphoreValues
-}
-
-@extension("VK_KHR_external_semaphore_win32") // 79
-class VkSemaphoreGetWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSemaphore semaphore
- VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_semaphore_fd") // 80
-class VkImportSemaphoreFdInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSemaphore semaphore
- VkSemaphoreImportFlagsKHR flags
- VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
- s32 fd
-}
-
-@extension("VK_KHR_external_semaphore_fd") // 80
-class VkSemaphoreGetFdInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSemaphore semaphore
- VkExternalSemaphoreHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_push_descriptor") // 81
-class VkPhysicalDevicePushDescriptorPropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 maxPushDescriptors
-}
-
-@extension("VK_EXT_conditional_rendering") // 82
-class VkConditionalRenderingBeginInfoEXT {
- VkStructureType sType
- const void* pNext
- VkBuffer buffer
- VkDeviceSize offset
- VkConditionalRenderingFlagsEXT flags
-}
-
-@extension("VK_EXT_conditional_rendering") // 82
-class VkPhysicalDeviceConditionalRenderingFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 conditionalRendering
- VkBool32 inheritedConditionalRendering
-}
-
-@extension("VK_EXT_conditional_rendering") // 82
-class VkCommandBufferInheritanceConditionalRenderingInfoEXT {
- VkStructureType sType
- const void* pNext
- VkBool32 conditionalRenderingEnable
-}
-
-@extension("VK_KHR_shader_float16_int8") // 83
-class VkPhysicalDeviceFloat16Int8FeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 shaderFloat16
- VkBool32 shaderInt8
-}
-
-@extension("VK_KHR_16bit_storage") // 84
-class VkPhysicalDevice16BitStorageFeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 storageBuffer16BitAccess
- VkBool32 uniformAndStorageBuffer16BitAccess
- VkBool32 storagePushConstant16
- VkBool32 storageInputOutput16
-}
-
-@extension("VK_KHR_incremental_present") // 85
-class VkRectLayerKHR {
- VkOffset2D offset
- VkExtent2D extent
- u32 layer
-}
-
-@extension("VK_KHR_incremental_present") // 85
-class VkPresentRegionKHR {
- u32 rectangleCount
- const VkRectLayerKHR* pRectangles
-}
-
-@extension("VK_KHR_incremental_present") // 85
-class VkPresentRegionsKHR {
- VkStructureType sType
- const void* pNext
- u32 swapchainCount
- const VkPresentRegionKHR* pRegions
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-class VkDescriptorUpdateTemplateEntryKHR {
- u32 dstBinding
- u32 dstArrayElement
- u32 descriptorCount
- VkDescriptorType descriptorType
- platform.size_t offset
- platform.size_t stride
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-class VkDescriptorUpdateTemplateCreateInfoKHR {
- VkStructureType sType
- void* pNext
- VkDescriptorUpdateTemplateCreateFlagsKHR flags
- u32 descriptorUpdateEntryCount
- const VkDescriptorUpdateTemplateEntryKHR* pDescriptorUpdateEntries
- VkDescriptorUpdateTemplateTypeKHR templateType
- VkDescriptorSetLayout descriptorSetLayout
- VkPipelineBindPoint pipelineBindPoint
- VkPipelineLayout pipelineLayout
- u32 set
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkDeviceGeneratedCommandsFeaturesNVX {
- VkStructureType sType
- const void* pNext
- VkBool32 computeBindingPointSupport
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkDeviceGeneratedCommandsLimitsNVX {
- VkStructureType sType
- const void* pNext
- u32 maxIndirectCommandsLayoutTokenCount
- u32 maxObjectEntryCounts
- u32 minSequenceCountBufferOffsetAlignment
- u32 minSequenceIndexBufferOffsetAlignment
- u32 minCommandsTokenBufferOffsetAlignment
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkIndirectCommandsTokenNVX {
- VkIndirectCommandsTokenTypeNVX tokenType
- VkBuffer buffer
- VkDeviceSize offset
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkIndirectCommandsLayoutTokenNVX {
- VkIndirectCommandsTokenTypeNVX tokenType
- u32 bindingUnit
- u32 dynamicCount
- u32 divisor
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkIndirectCommandsLayoutCreateInfoNVX {
- VkStructureType sType
- const void* pNext
- VkPipelineBindPoint pipelineBindPoint
- VkIndirectCommandsLayoutUsageFlagsNVX flags
- u32 tokenCount
- const VkIndirectCommandsLayoutTokenNVX* pTokens
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkCmdProcessCommandsInfoNVX {
- VkStructureType sType
- const void* pNext
- VkObjectTableNVX objectTable
- VkIndirectCommandsLayoutNVX indirectCommandsLayout
- u32 indirectCommandsTokenCount
- const VkIndirectCommandsTokenNVX* pIndirectCommandsTokens
- u32 maxSequencesCount
- VkCommandBuffer targetCommandBuffer
- VkBuffer sequencesCountBuffer
- VkDeviceSize sequencesCountOffset
- VkBuffer sequencesIndexBuffer
- VkDeviceSize sequencesIndexOffset
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkCmdReserveSpaceForCommandsInfoNVX {
- VkStructureType sType
- const void* pNext
- VkObjectTableNVX objectTable
- VkIndirectCommandsLayoutNVX indirectCommandsLayout
- u32 maxSequencesCount
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTableCreateInfoNVX {
- VkStructureType sType
- const void* pNext
- u32 objectCount
- const VkObjectEntryTypeNVX* pObjectEntryTypes
- const u32* pObjectEntryCounts
- const VkObjectEntryUsageFlagsNVX* pObjectEntryUsageFlags
- u32 maxUniformBuffersPerDescriptor
- u32 maxStorageBuffersPerDescriptor
- u32 maxStorageImagesPerDescriptor
- u32 maxSampledImagesPerDescriptor
- u32 maxPipelineLayouts
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTableEntryNVX {
- VkObjectEntryTypeNVX type
- VkObjectEntryUsageFlagsNVX flags
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTablePipelineEntryNVX {
- VkObjectEntryTypeNVX type
- VkObjectEntryUsageFlagsNVX flags
- VkPipeline pipeline
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTableDescriptorSetEntryNVX {
- VkObjectEntryTypeNVX type
- VkObjectEntryUsageFlagsNVX flags
- VkPipelineLayout pipelineLayout
- VkDescriptorSet descriptorSet
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTableVertexBufferEntryNVX {
- VkObjectEntryTypeNVX type
- VkObjectEntryUsageFlagsNVX flags
- VkBuffer buffer
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTableIndexBufferEntryNVX {
- VkObjectEntryTypeNVX type
- VkObjectEntryUsageFlagsNVX flags
- VkBuffer buffer
- VkIndexType indexType
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-class VkObjectTablePushConstantEntryNVX {
- VkObjectEntryTypeNVX type
- VkObjectEntryUsageFlagsNVX flags
- VkPipelineLayout pipelineLayout
- VkShaderStageFlags stageFlags
-}
-
-@extension("VK_NV_clip_space_w_scaling") // 88
-class VkViewportWScalingNV {
- f32 xcoeff
- f32 ycoeff
-}
-
-@extension("VK_NV_clip_space_w_scaling") // 88
-class VkPipelineViewportWScalingStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkBool32 viewportWScalingEnable
- u32 viewportCount
- const VkViewportWScalingNV* pViewportWScalings
-}
-
-@extension("VK_EXT_display_surface_counter") // 91
-class VkSurfaceCapabilities2EXT {
- VkStructureType sType
- void* pNext
- u32 minImageCount
- u32 maxImageCount
- VkExtent2D currentExtent
- VkExtent2D minImageExtent
- VkExtent2D maxImageExtent
- u32 maxImageArrayLayers
- VkSurfaceTransformFlagsKHR supportedTransforms
- VkSurfaceTransformFlagBitsKHR currentTransform
- VkCompositeAlphaFlagsKHR supportedCompositeAlpha
- VkImageUsageFlags supportedUsageFlags
- VkSurfaceCounterFlagsEXT supportedSurfaceCounters
-}
-
-@extension("VK_EXT_display_control") // 92
-class VkDisplayPowerInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDisplayPowerStateEXT powerState
-}
-
-@extension("VK_EXT_display_control") // 92
-class VkDeviceEventInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDeviceEventTypeEXT deviceEvent
-}
-
-@extension("VK_EXT_display_control") // 92
-class VkDisplayEventInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDisplayEventTypeEXT displayEvent
-}
-
-@extension("VK_EXT_display_control") // 92
-class VkSwapchainCounterCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkSurfaceCounterFlagsEXT surfaceCounters
-}
-
-@extension("VK_GOOGLE_display_timing") // 93
-class VkRefreshCycleDurationGOOGLE {
- u64 refreshDuration
-}
-
-@extension("VK_GOOGLE_display_timing") // 93
-class VkPastPresentationTimingGOOGLE {
- u32 presentID
- u64 desiredPresentTime
- u64 actualPresentTime
- u64 earliestPresentTime
- u64 presentMargin
-}
-
-@extension("VK_GOOGLE_display_timing") // 93
-class VkPresentTimeGOOGLE {
- u32 presentID
- u64 desiredPresentTime
-}
-
-@extension("VK_GOOGLE_display_timing") // 93
-class VkPresentTimesInfoGOOGLE {
- VkStructureType sType
- const void* pNext
- u32 swapchainCount
- const VkPresentTimeGOOGLE* pTimes
-}
-
-@extension("VK_NVX_multiview_per_view_attributes") // 98
-class VkPhysicalDeviceMultiviewPerViewAttributesPropertiesNVX {
- VkStructureType sType
- void* pNext
- VkBool32 perViewPositionAllComponents
-}
-
-@extension("VK_NV_viewport_swizzle") // 99
-class VkViewportSwizzleNV {
- VkViewportCoordinateSwizzleNV x
- VkViewportCoordinateSwizzleNV y
- VkViewportCoordinateSwizzleNV z
- VkViewportCoordinateSwizzleNV w
-}
-
-@extension("VK_NV_viewport_swizzle") // 99
-class VkPipelineViewportSwizzleStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkPipelineViewportSwizzleStateCreateFlagsNV flags
- u32 viewportCount
- const VkViewportSwizzleNV* pViewportSwizzles
-}
-
-@extension("VK_EXT_discard_rectangles") // 100
-class VkPhysicalDeviceDiscardRectanglePropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 maxDiscardRectangles
-}
-
-@extension("VK_EXT_discard_rectangles") // 100
-class VkPipelineDiscardRectangleStateCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkPipelineDiscardRectangleStateCreateFlagsEXT flags
- VkDiscardRectangleModeEXT discardRectangleMode
- u32 discardRectangleCount
- const VkRect2D* pDiscardRectangles
-}
-
-@extension("VK_EXT_conservative_rasterization") // 102
-class VkPhysicalDeviceConservativeRasterizationPropertiesEXT {
- VkStructureType sType
- void* pNext
- f32 primitiveOverestimationSize
- f32 maxExtraPrimitiveOverestimationSize
- f32 extraPrimitiveOverestimationSizeGranularity
- VkBool32 primitiveUnderestimation
- VkBool32 conservativePointAndLineRasterization
- VkBool32 degenerateTrianglesRasterized
- VkBool32 degenerateLinesRasterized
- VkBool32 fullyCoveredFragmentShaderInputVariable
- VkBool32 conservativeRasterizationPostDepthCoverage
-}
-
-@extension("VK_EXT_conservative_rasterization") // 102
-class VkPipelineRasterizationConservativeStateCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkPipelineRasterizationConservativeStateCreateFlagsEXT flags
- VkConservativeRasterizationModeEXT conservativeRasterizationMode
- f32 extraPrimitiveOverestimationSize
-}
-
-@extension("VK_EXT_hdr_metadata") // 106
-class VkXYColorEXT {
- f32 x
- f32 y
-}
-
-@extension("VK_EXT_hdr_metadata") // 106
-class VkHdrMetadataEXT {
- VkStructureType sType
- const void* pNext
- VkXYColorEXT displayPrimaryRed
- VkXYColorEXT displayPrimaryGreen
- VkXYColorEXT displayPrimaryBlue
- VkXYColorEXT whitePoint
- f32 maxLuminance
- f32 minLuminance
- f32 maxContentLightLevel
- f32 maxFrameAverageLightLevel
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkAttachmentDescription2KHR {
- VkStructureType sType
- const void* pNext
- VkAttachmentDescriptionFlags flags
- VkFormat format
- VkSampleCountFlagBits samples
- VkAttachmentLoadOp loadOp
- VkAttachmentStoreOp storeOp
- VkAttachmentLoadOp stencilLoadOp
- VkAttachmentStoreOp stencilStoreOp
- VkImageLayout initialLayout
- VkImageLayout finalLayout
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkAttachmentReference2KHR {
- VkStructureType sType
- const void* pNext
- u32 attachment
- VkImageLayout layout
- VkImageAspectFlags aspectMask
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkSubpassDescription2KHR {
- VkStructureType sType
- const void* pNext
- VkSubpassDescriptionFlags flags
- VkPipelineBindPoint pipelineBindPoint
- u32 viewMask
- u32 inputAttachmentCount
- const VkAttachmentReference2KHR* pInputAttachments
- u32 colorAttachmentCount
- const VkAttachmentReference2KHR* pColorAttachments
- const VkAttachmentReference2KHR* pResolveAttachments
- const VkAttachmentReference2KHR* pDepthStencilAttachment
- u32 preserveAttachmentCount
- const u32* pPreserveAttachments
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkSubpassDependency2KHR {
- VkStructureType sType
- const void* pNext
- u32 srcSubpass
- u32 dstSubpass
- VkPipelineStageFlags srcStageMask
- VkPipelineStageFlags dstStageMask
- VkAccessFlags srcAccessMask
- VkAccessFlags dstAccessMask
- VkDependencyFlags dependencyFlags
- s32 viewOffset
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkRenderPassCreateInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkRenderPassCreateFlags flags
- u32 attachmentCount
- const VkAttachmentDescription2KHR* pAttachments
- u32 subpassCount
- const VkSubpassDescription2KHR* pSubpasses
- u32 dependencyCount
- const VkSubpassDependency2KHR* pDependencies
- u32 correlatedViewMaskCount
- const u32* pCorrelatedViewMasks
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkSubpassBeginInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSubpassContents contents
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-class VkSubpassEndInfoKHR {
- VkStructureType sType
- const void* pNext
-}
-
-@extension("VK_KHR_shared_presentable_image") // 112
-class VkSharedPresentSurfaceCapabilitiesKHR {
- VkStructureType sType
- const void* pNext
- VkImageUsageFlags sharedPresentSupportedUsageFlags
-}
-
-@extension("VK_KHR_external_fence_capabilities") // 113
-class VkPhysicalDeviceExternalFenceInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalFenceHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_fence_capabilities") // 113
-class VkExternalFencePropertiesKHR {
- VkStructureType sType
- void* pNext
- VkExternalFenceHandleTypeFlagsKHR exportFromImportedHandleTypes
- VkExternalFenceHandleTypeFlagsKHR compatibleHandleTypes
- VkExternalFenceFeatureFlagsKHR externalFenceFeatures
-}
-
-@extension("VK_KHR_external_fence") // 114
-class VkExportFenceCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkExternalFenceHandleTypeFlagsKHR handleTypes
-}
-
-@extension("VK_KHR_external_fence_win32") // 115
-class VkImportFenceWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- VkFence fence
- VkFenceImportFlagsKHR flags
- VkExternalFenceHandleTypeFlagBitsKHR handleType
- platform.HANDLE handle
- platform.LPCWSTR name
-}
-
-@extension("VK_KHR_external_fence_win32") // 115
-class VkExportFenceWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- const platform.SECURITY_ATTRIBUTES* pAttributes
- platform.DWORD dwAccess
- platform.LPCWSTR name
-}
-
-@extension("VK_KHR_external_fence_win32") // 115
-class VkFenceGetWin32HandleInfoKHR {
- VkStructureType sType
- const void* pNext
- VkFence fence
- VkExternalFenceHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_external_fence_fd") // 116
-class VkImportFenceFdInfoKHR {
- VkStructureType sType
- const void* pNext
- VkFence fence
- VkFenceImportFlagsKHR flags
- VkExternalFenceHandleTypeFlagBitsKHR handleType
- int fd
-}
-
-@extension("VK_KHR_external_fence_fd") // 116
-class VkFenceGetFdInfoKHR {
- VkStructureType sType
- const void* pNext
- VkFence fence
- VkExternalFenceHandleTypeFlagBitsKHR handleType
-}
-
-@extension("VK_KHR_maintenance2") // 118
-class VkPhysicalDevicePointClippingPropertiesKHR {
- VkStructureType sType
- void* pNext
- VkPointClippingBehaviorKHR pointClippingBehavior
-}
-
-@extension("VK_KHR_maintenance2") // 118
-class VkInputAttachmentAspectReferenceKHR {
- u32 subpass
- u32 inputAttachmentIndex
- VkImageAspectFlags aspectMask
-}
-
-@extension("VK_KHR_maintenance2") // 118
-class VkRenderPassInputAttachmentAspectCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 aspectReferenceCount
- const VkInputAttachmentAspectReferenceKHR* pAspectReferences
-}
-
-@extension("VK_KHR_maintenance2") // 118
-class VkImageViewUsageCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkImageUsageFlags usage
-}
-
-@extension("VK_KHR_maintenance2") // 118
-class VkPipelineTessellationDomainOriginStateCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkTessellationDomainOriginKHR domainOrigin
-}
-
-@extension("VK_KHR_get_surface_capabilities2") // 120
-class VkPhysicalDeviceSurfaceInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkSurfaceKHR surface
-}
-
-@extension("VK_KHR_get_surface_capabilities2") // 120
-class VkSurfaceCapabilities2KHR {
- VkStructureType sType
- void* pNext
- VkSurfaceCapabilitiesKHR surfaceCapabilities
-}
-
-@extension("VK_KHR_get_surface_capabilities2") // 120
-class VkSurfaceFormat2KHR {
- VkStructureType sType
- void* pNext
- VkSurfaceFormatKHR surfaceFormat
-}
-
-@extension("VK_KHR_variable_pointers") // 121
-class VkPhysicalDeviceVariablePointerFeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 variablePointersStorageBuffer
- VkBool32 variablePointers
-}
-
-@extension("VK_KHR_display_properties2") // 122
-class VkDisplayProperties2KHR {
- VkStructureType sType
- void* pNext
- VkDisplayPropertiesKHR displayProperties
-}
-
-@extension("VK_KHR_display_properties2") // 122
-class VkDisplayPlaneProperties2KHR {
- VkStructureType sType
- void* pNext
- VkDisplayPlanePropertiesKHR displayPlaneProperties
-}
-
-@extension("VK_KHR_display_properties2") // 122
-class VkDisplayModeProperties2KHR {
- VkStructureType sType
- void* pNext
- VkDisplayModePropertiesKHR displayModeProperties
-}
-
-@extension("VK_KHR_display_properties2") // 122
-class VkDisplayPlaneInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkDisplayModeKHR mode
- u32 planeIndex
-}
-
-@extension("VK_KHR_display_properties2") // 122
-class VkDisplayPlaneCapabilities2KHR {
- VkStructureType sType
- void* pNext
- VkDisplayPlaneCapabilitiesKHR capabilities
-}
-
-@extension("VK_MVK_ios_surface") // 123
-class VkIOSSurfaceCreateInfoMVK {
- VkStructureType sType
- const void* pNext
- VkIOSSurfaceCreateFlagsMVK flags
- const void* pView
-}
-
-@extension("VK_MVK_macos_surface") // 124
-class VkMacOSSurfaceCreateInfoMVK {
- VkStructureType sType
- const void* pNext
- VkMacOSSurfaceCreateFlagsMVK flags
- const void* pView
-}
-
-@extension("VK_KHR_dedicated_allocation") // 128
-class VkMemoryDedicatedRequirementsKHR {
- VkStructureType sType
- void* pNext
- VkBool32 prefersDedicatedAllocation
- VkBool32 requiresDedicatedAllocation
-}
-
-@extension("VK_KHR_dedicated_allocation") // 128
-class VkMemoryDedicatedAllocateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkImage image
- VkBuffer buffer
-}
-
-@extension("VK_EXT_debug_utils") // 129
-class VkDebugUtilsObjectNameInfoEXT {
- VkStructureType sType
- const void* pNext
- VkObjectType objectType
- u64 objectHandle
- const char* pObjectName
-}
-
-@extension("VK_EXT_debug_utils") // 129
-class VkDebugUtilsObjectTagInfoEXT {
- VkStructureType sType
- const void* pNext
- VkObjectType objectType
- u64 objectHandle
- u64 tagName
- platform.size_t tagSize
- const void* pTag
-}
-
-@extension("VK_EXT_debug_utils") // 129
-class VkDebugUtilsLabelEXT {
- VkStructureType sType
- const void* pNext
- const char* pLabelName
- f32[4] color
-}
-
-@extension("VK_EXT_debug_utils") // 129
-class VkDebugUtilsMessengerCallbackDataEXT {
- VkStructureType sType
- const void* pNext
- VkDebugUtilsMessengerCallbackDataFlagsEXT flags
- const char* pMessageIdName
- s32 messageIdNumber
- const char* pMessage
- u32 queueLabelCount
- const VkDebugUtilsLabelEXT* pQueueLabels
- u32 cmdBufLabelCount
- const VkDebugUtilsLabelEXT* pCmdBufLabels
- u32 objectCount
- const VkDebugUtilsObjectNameInfoEXT* pObjects
-}
-
-@extension("VK_EXT_debug_utils") // 129
-class VkDebugUtilsMessengerCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkDebugUtilsMessengerCreateFlagsEXT flags
- VkDebugUtilsMessageSeverityFlagsEXT messageSeverity
- VkDebugUtilsMessageTypeFlagsEXT messageTypes
- PFN_vkDebugUtilsMessengerCallbackEXT pfnUserCallback
- void* pUserData
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 131
-class VkAndroidHardwareBufferUsageANDROID {
- VkStructureType sType
- void* pNext
- u64 androidHardwareBufferUsage
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-class VkAndroidHardwareBufferPropertiesANDROID {
- VkStructureType sType
- void* pNext
- VkDeviceSize allocationSize
- u32 memoryTypeBits
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-class VkAndroidHardwareBufferFormatPropertiesANDROID {
- VkStructureType sType
- void* pNext
- VkFormat format
- u64 externalFormat
- VkFormatFeatureFlags formatFeatures
- VkComponentMapping samplerYcbcrConversionComponents
- VkSamplerYcbcrModelConversion suggestedYcbcrModel
- VkSamplerYcbcrRange suggestedYcbcrRange
- VkChromaLocation suggestedXChromaOffset
- VkChromaLocation suggestedYChromaOffset
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-class VkImportAndroidHardwareBufferInfoANDROID {
- VkStructureType sType
- const void* pNext
- platform.AHardwareBuffer* buffer
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-class VkMemoryGetAndroidHardwareBufferInfoANDROID {
- VkStructureType sType
- const void* pNext
- VkDeviceMemory memory
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-class VkExternalFormatANDROID {
- VkStructureType sType
- void* pNext
- u64 externalFormat
-}
-
-@extension("VK_EXT_sampler_filter_minmax") // 131
-class VkSamplerReductionModeCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkSamplerReductionModeEXT reductionMode
-}
-
-@extension("VK_EXT_sampler_filter_minmax") // 131
-class VkPhysicalDeviceSamplerFilterMinmaxPropertiesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 filterMinmaxSingleComponentFormats
- VkBool32 filterMinmaxImageComponentMapping
-}
-
-@extension("VK_EXT_inline_uniform_block") // 139
-class VkPhysicalDeviceInlineUniformBlockFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 inlineUniformBlock
- VkBool32 descriptorBindingInlineUniformBlockUpdateAfterBind
-}
-
-@extension("VK_EXT_inline_uniform_block") // 139
-class VkPhysicalDeviceInlineUniformBlockPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 maxInlineUniformBlockSize
- u32 maxPerStageDescriptorInlineUniformBlocks
- u32 maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks
- u32 maxDescriptorSetInlineUniformBlocks
- u32 maxDescriptorSetUpdateAfterBindInlineUniformBlocks
-}
-
-@extension("VK_EXT_inline_uniform_block") // 139
-class VkWriteDescriptorSetInlineUniformBlockEXT {
- VkStructureType sType
- const void* pNext
- u32 dataSize
- const void* pData
-}
-
-@extension("VK_EXT_inline_uniform_block") // 139
-class VkDescriptorPoolInlineUniformBlockCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- u32 maxInlineUniformBlockBindings
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkSampleLocationEXT {
- f32 x
- f32 y
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkSampleLocationsInfoEXT {
- VkStructureType sType
- const void* pNext
- VkSampleCountFlagBits sampleLocationsPerPixel
- VkExtent2D sampleLocationGridSize
- u32 sampleLocationsCount
- const VkSampleLocationEXT* pSampleLocations
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkAttachmentSampleLocationsEXT {
- u32 attachmentIndex
- VkSampleLocationsInfoEXT sampleLocationsInfo
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkSubpassSampleLocationsEXT {
- u32 subpassIndex
- VkSampleLocationsInfoEXT sampleLocationsInfo
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkRenderPassSampleLocationsBeginInfoEXT {
- VkStructureType sType
- const void* pNext
- u32 attachmentInitialSampleLocationsCount
- const VkAttachmentSampleLocationsEXT* pAttachmentInitialSampleLocations
- u32 postSubpassSampleLocationsCount
- const VkSubpassSampleLocationsEXT* pPostSubpassSampleLocations
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkPipelineSampleLocationsStateCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkBool32 sampleLocationsEnable
- VkSampleLocationsInfoEXT sampleLocationsInfo
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkPhysicalDeviceSampleLocationsPropertiesEXT {
- VkStructureType sType
- void* pNext
- VkSampleCountFlags sampleLocationSampleCounts
- VkExtent2D maxSampleLocationGridSize
- f32[2] sampleLocationCoordinateRange
- u32 sampleLocationSubPixelBits
- VkBool32 variableSampleLocations
-}
-
-@extension("VK_EXT_sample_locations") // 144
-class VkMultisamplePropertiesEXT {
- VkStructureType sType
- void* pNext
- VkExtent2D maxSampleLocationGridSize
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-class VkBufferMemoryRequirementsInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkBuffer buffer
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-class VkImageMemoryRequirementsInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkImage image
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-class VkImageSparseMemoryRequirementsInfo2KHR {
- VkStructureType sType
- const void* pNext
- VkImage image
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-class VkMemoryRequirements2KHR {
- VkStructureType sType
- void* pNext
- VkMemoryRequirements memoryRequirements
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-class VkSparseImageMemoryRequirements2KHR {
- VkStructureType sType
- void* pNext
- VkSparseImageMemoryRequirements memoryRequirements
-}
-
-@extension("VK_KHR_image_format_list") // 148
-class VkImageFormatListCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- u32 viewFormatCount
- const VkFormat* pViewFormats
-}
-
-@extension("VK_EXT_blend_operation_advanced") // 149
-class VkPhysicalDeviceBlendOperationAdvancedFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 advancedBlendCoherentOperations
-}
-
-@extension("VK_EXT_blend_operation_advanced") // 149
-class VkPhysicalDeviceBlendOperationAdvancedPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 advancedBlendMaxColorAttachments
- VkBool32 advancedBlendIndependentBlend
- VkBool32 advancedBlendNonPremultipliedSrcColor
- VkBool32 advancedBlendNonPremultipliedDstColor
- VkBool32 advancedBlendCorrelatedOverlap
- VkBool32 advancedBlendAllOperations
-}
-
-@extension("VK_EXT_blend_operation_advanced") // 149
-class VkPipelineColorBlendAdvancedStateCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkBool32 srcPremultiplied
- VkBool32 dstPremultiplied
- VkBlendOverlapEXT blendOverlap
-}
-
-@extension("VK_NV_fragment_coverage_to_color") // 150
-class VkPipelineCoverageToColorStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkPipelineCoverageToColorStateCreateFlagsNV flags
- VkBool32 coverageToColorEnable
- u32 coverageToColorLocation
-}
-
-@extension("VK_NV_framebuffer_mixed_samples") // 153
-class VkPipelineCoverageModulationStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkPipelineCoverageModulationStateCreateFlagsNV flags
- VkCoverageModulationModeNV coverageModulationMode
- VkBool32 coverageModulationTableEnable
- u32 coverageModulationTableCount
- const f32* pCoverageModulationTable
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-class VkSamplerYcbcrConversionCreateInfoKHR {
- VkStructureType sType
- const void* pNext
- VkFormat format
- VkSamplerYcbcrModelConversionKHR ycbcrModel
- VkSamplerYcbcrRangeKHR ycbcrRange
- VkComponentMapping components
- VkChromaLocationKHR xChromaOffset
- VkChromaLocationKHR yChromaOffset
- VkFilter chromaFilter
- VkBool32 forceExplicitReconstruction
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-class VkSamplerYcbcrConversionInfoKHR {
- VkStructureType sType
- const void* pNext
- VkSamplerYcbcrConversionKHR conversion
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-class VkBindImagePlaneMemoryInfoKHR {
- VkStructureType sType
- const void* pNext
- VkImageAspectFlagBits planeAspect
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-class VkImagePlaneMemoryRequirementsInfoKHR {
- VkStructureType sType
- const void* pNext
- VkImageAspectFlagBits planeAspect
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-class VkPhysicalDeviceSamplerYcbcrConversionFeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 samplerYcbcrConversion
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-class VkSamplerYcbcrConversionImageFormatPropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 combinedImageSamplerDescriptorCount
-}
-
-@extension("VK_KHR_bind_memory2") // 158
-class VkBindBufferMemoryInfoKHR {
- VkStructureType sType
- const void* pNext
- VkBuffer buffer
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
-}
-
-@extension("VK_KHR_bind_memory2") // 158
-class VkBindImageMemoryInfoKHR {
- VkStructureType sType
- const void* pNext
- VkImage image
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-class VkDrmFormatModifierPropertiesEXT {
- u64 drmFormatModifier
- u32 drmFormatModifierPlaneCount
- VkFormatFeatureFlags drmFormatModifierTilingFeatures
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-class VkDrmFormatModifierPropertiesListEXT {
- VkStructureType sType
- void* pNext
- u32 drmFormatModifierCount
- VkDrmFormatModifierPropertiesEXT* pDrmFormatModifierProperties
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-class VkPhysicalDeviceImageDrmFormatModifierInfoEXT {
- VkStructureType sType
- const void* pNext
- u64 drmFormatModifier
- VkSharingMode sharingMode
- u32 queueFamilyIndexCount
- const u32* pQueueFamilyIndices
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-class VkImageDrmFormatModifierListCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- u32 drmFormatModifierCount
- const u64* pDrmFormatModifiers
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-class VkImageDrmFormatModifierExplicitCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- u64 drmFormatModifier
- u32 drmFormatModifierPlaneCount
- const VkSubresourceLayout* pPlaneLayouts
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-class VkImageDrmFormatModifierPropertiesEXT {
- VkStructureType sType
- void* pNext
- u64 drmFormatModifier
-}
-
-@extension("VK_EXT_validation_cache") // 161
-class VkValidationCacheCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkValidationCacheCreateFlagsEXT flags
- platform.size_t initialDataSize
- const void* pInitialData
-}
-
-@extension("VK_EXT_validation_cache") // 161
-class VkShaderModuleValidationCacheCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkValidationCacheEXT validationCache
-}
-
-@extension("VK_EXT_descriptor_indexing") // 162
-class VkDescriptorSetLayoutBindingFlagsCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- u32 bindingCount
- const VkDescriptorBindingFlagsEXT* pBindingFlags
-}
-
-@extension("VK_EXT_descriptor_indexing") // 162
-class VkPhysicalDeviceDescriptorIndexingFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 shaderInputAttachmentArrayDynamicIndexing
- VkBool32 shaderUniformTexelBufferArrayDynamicIndexing
- VkBool32 shaderStorageTexelBufferArrayDynamicIndexing
- VkBool32 shaderUniformBufferArrayNonUniformIndexing
- VkBool32 shaderSampledImageArrayNonUniformIndexing
- VkBool32 shaderStorageBufferArrayNonUniformIndexing
- VkBool32 shaderStorageImageArrayNonUniformIndexing
- VkBool32 shaderInputAttachmentArrayNonUniformIndexing
- VkBool32 shaderUniformTexelBufferArrayNonUniformIndexing
- VkBool32 shaderStorageTexelBufferArrayNonUniformIndexing
- VkBool32 descriptorBindingUniformBufferUpdateAfterBind
- VkBool32 descriptorBindingSampledImageUpdateAfterBind
- VkBool32 descriptorBindingStorageImageUpdateAfterBind
- VkBool32 descriptorBindingStorageBufferUpdateAfterBind
- VkBool32 descriptorBindingUniformTexelBufferUpdateAfterBind
- VkBool32 descriptorBindingStorageTexelBufferUpdateAfterBind
- VkBool32 descriptorBindingUpdateUnusedWhilePending
- VkBool32 descriptorBindingPartiallyBound
- VkBool32 descriptorBindingVariableDescriptorCount
- VkBool32 runtimeDescriptorArray
-}
-
-@extension("VK_EXT_descriptor_indexing") // 162
-class VkPhysicalDeviceDescriptorIndexingPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 maxUpdateAfterBindDescriptorsInAllPools
- VkBool32 shaderUniformBufferArrayNonUniformIndexingNative
- VkBool32 shaderSampledImageArrayNonUniformIndexingNative
- VkBool32 shaderStorageBufferArrayNonUniformIndexingNative
- VkBool32 shaderStorageImageArrayNonUniformIndexingNative
- VkBool32 shaderInputAttachmentArrayNonUniformIndexingNative
- VkBool32 robustBufferAccessUpdateAfterBind
- VkBool32 quadDivergentImplicitLod
- u32 maxPerStageDescriptorUpdateAfterBindSamplers
- u32 maxPerStageDescriptorUpdateAfterBindUniformBuffers
- u32 maxPerStageDescriptorUpdateAfterBindStorageBuffers
- u32 maxPerStageDescriptorUpdateAfterBindSampledImages
- u32 maxPerStageDescriptorUpdateAfterBindStorageImages
- u32 maxPerStageDescriptorUpdateAfterBindInputAttachments
- u32 maxPerStageUpdateAfterBindResources
- u32 maxDescriptorSetUpdateAfterBindSamplers
- u32 maxDescriptorSetUpdateAfterBindUniformBuffers
- u32 maxDescriptorSetUpdateAfterBindUniformBuffersDynamic
- u32 maxDescriptorSetUpdateAfterBindStorageBuffers
- u32 maxDescriptorSetUpdateAfterBindStorageBuffersDynamic
- u32 maxDescriptorSetUpdateAfterBindSampledImages
- u32 maxDescriptorSetUpdateAfterBindStorageImages
- u32 maxDescriptorSetUpdateAfterBindInputAttachments
-}
-
-@extension("VK_EXT_descriptor_indexing") // 162
-class VkDescriptorSetVariableDescriptorCountAllocateInfoEXT {
- VkStructureType sType
- const void* pNext
- u32 descriptorSetCount
- const u32* pDescriptorCounts
-}
-
-@extension("VK_EXT_descriptor_indexing") // 162
-class VkDescriptorSetVariableDescriptorCountLayoutSupportEXT {
- VkStructureType sType
- void* pNext
- u32 maxVariableDescriptorCount
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkShadingRatePaletteNV {
- u32 shadingRatePaletteEntryCount
- const VkShadingRatePaletteEntryNV* pShadingRatePaletteEntries
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkPipelineViewportShadingRateImageStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkBool32 shadingRateImageEnable
- u32 viewportCount
- const VkShadingRatePaletteNV* pShadingRatePalettes
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkPhysicalDeviceShadingRateImageFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 shadingRateImage
- VkBool32 shadingRateCoarseSampleOrder
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkPhysicalDeviceShadingRateImagePropertiesNV {
- VkStructureType sType
- void* pNext
- VkExtent2D shadingRateTexelSize
- u32 shadingRatePaletteSize
- u32 shadingRateMaxCoarseSamples
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkCoarseSampleLocationNV {
- u32 pixelX
- u32 pixelY
- u32 sample
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkCoarseSampleOrderCustomNV {
- VkShadingRatePaletteEntryNV shadingRate
- u32 sampleCount
- u32 sampleLocationCount
- const VkCoarseSampleLocationNV* pSampleLocations
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-class VkPipelineViewportCoarseSampleOrderStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkCoarseSampleOrderTypeNV sampleOrderType
- u32 customSampleOrderCount
- const VkCoarseSampleOrderCustomNV* pCustomSampleOrders
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkRayTracingShaderGroupCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkRayTracingShaderGroupTypeNV type
- u32 generalShader
- u32 closestHitShader
- u32 anyHitShader
- u32 intersectionShader
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkRayTracingPipelineCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkPipelineCreateFlags flags
- u32 stageCount
- const VkPipelineShaderStageCreateInfo* pStages
- u32 groupCount
- const VkRayTracingShaderGroupCreateInfoNV* pGroups
- u32 maxRecursionDepth
- VkPipelineLayout layout
- VkPipeline basePipelineHandle
- s32 basePipelineIndex
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkGeometryTrianglesNV {
- VkStructureType sType
- const void* pNext
- VkBuffer vertexData
- VkDeviceSize vertexOffset
- u32 vertexCount
- VkDeviceSize vertexStride
- VkFormat vertexFormat
- VkBuffer indexData
- VkDeviceSize indexOffset
- u32 indexCount
- VkIndexType indexType
- VkBuffer transformData
- VkDeviceSize transformOffset
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkGeometryAABBNV {
- VkStructureType sType
- const void* pNext
- VkBuffer aabbData
- u32 numAABBs
- u32 stride
- VkDeviceSize offset
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkGeometryDataNV {
- VkGeometryTrianglesNV triangles
- VkGeometryAABBNV aabbs
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkGeometryNV {
- VkStructureType sType
- const void* pNext
- VkGeometryTypeNV geometryType
- VkGeometryDataNV geometry
- VkGeometryFlagsNV flags
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkAccelerationStructureInfoNV {
- VkStructureType sType
- const void* pNext
- VkAccelerationStructureTypeNV type
- VkBuildAccelerationStructureFlagsNV flags
- u32 instanceCount
- u32 geometryCount
- const VkGeometryNV* pGeometries
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkAccelerationStructureCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkDeviceSize compactedSize
- VkAccelerationStructureInfoNV info
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkBindAccelerationStructureMemoryInfoNV {
- VkStructureType sType
- const void* pNext
- VkAccelerationStructureNV accelerationStructure
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
- u32 deviceIndexCount
- const u32* pDeviceIndices
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkDescriptorAccelerationStructureInfoNV {
- VkStructureType sType
- const void* pNext
- u32 accelerationStructureCount
- const VkAccelerationStructureNV* pAccelerationStructures
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkAccelerationStructureMemoryRequirementsInfoNV {
- VkStructureType sType
- const void* pNext
- VkAccelerationStructureMemoryRequirementsTypeNV type
- VkAccelerationStructureNV accelerationStructure
-}
-
-@extension("VK_NV_ray_tracing") // 166
-class VkPhysicalDeviceRaytracingPropertiesNV {
- VkStructureType sType
- void* pNext
- u32 shaderGroupHandleSize
- u32 maxRecursionDepth
- u32 maxShaderGroupStride
- u32 shaderGroupBaseAlignment
- u64 maxGeometryCount
- u64 maxInstanceCount
- u64 maxTriangleCount
- u32 maxDescriptorSetAccelerationStructures
-}
-
-@extension("VK_NV_representative_fragment_test") // 167
-class VkPhysicalDeviceRepresentativeFragmentTestFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 representativeFragmentTest
-}
-
-@extension("VK_NV_representative_fragment_test") // 167
-class VkPipelineRepresentativeFragmentTestStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- VkBool32 representativeFragmentTestEnable
-}
-
-@extension("VK_KHR_maintenance3") // 169
-class VkPhysicalDeviceMaintenance3PropertiesKHR {
- VkStructureType sType
- void* pNext
- u32 maxPerSetDescriptors
- VkDeviceSize maxMemoryAllocationSize
-}
-
-@extension("VK_KHR_maintenance3") // 169
-class VkDescriptorSetLayoutSupportKHR {
- VkStructureType sType
- void* pNext
- VkBool32 supported
-}
-
-@extension("VK_EXT_global_priority") // 175
-class VkDeviceQueueGlobalPriorityCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkQueueGlobalPriorityEXT globalPriority
-}
-
-@extension("VK_KHR_8bit_storage") // 178
-class VkPhysicalDevice8BitStorageFeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 storageBuffer8BitAccess
- VkBool32 uniformAndStorageBuffer8BitAccess
- VkBool32 storagePushConstant8
-}
-
-@extension("VK_EXT_external_memory_host") // 179
-class VkImportMemoryHostPointerInfoEXT {
- VkStructureType sType
- const void* pNext
- VkExternalMemoryHandleTypeFlagBits handleType
- void* pHostPointer
-}
-
-@extension("VK_EXT_external_memory_host") // 179
-class VkMemoryHostPointerPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 memoryTypeBits
-}
-
-@extension("VK_EXT_external_memory_host") // 179
-class VkPhysicalDeviceExternalMemoryHostPropertiesEXT {
- VkStructureType sType
- void* pNext
- VkDeviceSize minImportedHostPointerAlignment
-}
-
-@extension("VK_KHR_shader_atomic_int64") // 181
-class VkPhysicalDeviceShaderAtomicInt64FeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 shaderBufferInt64Atomics
- VkBool32 shaderSharedInt64Atomics
-}
-
-@extension("VK_EXT_calibrated_timestamps") // 185
-class VkCalibratedTimestampInfoEXT {
- VkStructureType sType
- const void* pNext
- VkTimeDomainEXT timeDomain
-}
-
-@extension("VK_AMD_shader_core_properties") // 186
-class VkPhysicalDeviceShaderCorePropertiesAMD {
- VkStructureType sType
- void* pNext
- u32 shaderEngineCount
- u32 shaderArraysPerEngineCount
- u32 computeUnitsPerShaderArray
- u32 simdPerComputeUnit
- u32 wavefrontsPerSimd
- u32 wavefrontSize
- u32 sgprsPerSimd
- u32 minSgprAllocation
- u32 maxSgprAllocation
- u32 sgprAllocationGranularity
- u32 vgprsPerSimd
- u32 minVgprAllocation
- u32 maxVgprAllocation
- u32 vgprAllocationGranularity
-}
-
-@extension("VK_AMD_memory_overallocation_behavior") // 190
-class VkDeviceMemoryOverallocationCreateInfoAMD {
- VkStructureType sType
- const void* pNext
- VkMemoryOverallocationBehaviorAMD overallocationBehavior
-}
-
-@extension("VK_EXT_vertex_attribute_divisor") // 191
-class VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 maxVertexAttribDivisor
-}
-
-@extension("VK_EXT_vertex_attribute_divisor") // 191
-class VkVertexInputBindingDivisorDescriptionEXT {
- u32 binding
- u32 divisor
-}
-
-@extension("VK_EXT_vertex_attribute_divisor") // 191
-class VkPipelineVertexInputDivisorStateCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- u32 vertexBindingDivisorCount
- const VkVertexInputBindingDivisorDescriptionEXT* pVertexBindingDivisors
-}
-
-@extension("VK_EXT_vertex_attribute_divisor") // 191
-class VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 vertexAttributeInstanceRateDivisor
- VkBool32 vertexAttributeInstanceRateZeroDivisor
-}
-
-@extension("VK_KHR_driver_properties") // 197
-class VkConformanceVersionKHR {
- u8 major
- u8 minor
- u8 subminor
- u8 patch
-}
-
-@extension("VK_KHR_driver_properties") // 197
-class VkPhysicalDeviceDriverPropertiesKHR {
- VkStructureType sType
- void* pNext
- VkDriverIdKHR driverID
- char[VK_MAX_DRIVER_NAME_SIZE_KHR] driverName
- char[VK_MAX_DRIVER_INFO_SIZE_KHR] driverInfo
- VkConformanceVersionKHR conformanceVersion
-}
-
-@extension("VK_KHR_shader_float_controls") // 198
-class VkPhysicalDeviceFloatControlsPropertiesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 separateDenormSettings
- VkBool32 separateRoundingModeSettings
- VkBool32 shaderSignedZeroInfNanPreserveFloat16
- VkBool32 shaderSignedZeroInfNanPreserveFloat32
- VkBool32 shaderSignedZeroInfNanPreserveFloat64
- VkBool32 shaderDenormPreserveFloat16
- VkBool32 shaderDenormPreserveFloat32
- VkBool32 shaderDenormPreserveFloat64
- VkBool32 shaderDenormFlushToZeroFloat16
- VkBool32 shaderDenormFlushToZeroFloat32
- VkBool32 shaderDenormFlushToZeroFloat64
- VkBool32 shaderRoundingModeRTEFloat16
- VkBool32 shaderRoundingModeRTEFloat32
- VkBool32 shaderRoundingModeRTEFloat64
- VkBool32 shaderRoundingModeRTZFloat16
- VkBool32 shaderRoundingModeRTZFloat32
- VkBool32 shaderRoundingModeRTZFloat64
-}
-
-@extension("VK_NV_compute_shader_derivatives") // 202
-class VkPhysicalDeviceComputeShaderDerivativesFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 computeDerivativeGroupQuads
- VkBool32 computeDerivativeGroupLinear
-}
-
-@extension("VK_NV_mesh_shader") // 203
-class VkPhysicalDeviceMeshShaderFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 taskShader
- VkBool32 meshShader
-}
-
-@extension("VK_NV_mesh_shader") // 203
-class VkPhysicalDeviceMeshShaderPropertiesNV {
- VkStructureType sType
- void* pNext
- u32 maxDrawMeshTasksCount
- u32 maxTaskWorkGroupInvocations
- u32[3] maxTaskWorkGroupSize
- u32 maxTaskTotalMemorySize
- u32 maxTaskOutputCount
- u32 maxMeshWorkGroupInvocations
- u32[3] maxMeshWorkGroupSize
- u32 maxMeshTotalMemorySize
- u32 maxMeshOutputVertices
- u32 maxMeshOutputPrimitives
- u32 maxMeshMultiviewViewCount
- u32 meshOutputPerVertexGranularity
- u32 meshOutputPerPrimitiveGranularity
-}
-
-@extension("VK_NV_mesh_shader") // 203
-class VkDrawMeshTasksIndirectCommandNV {
- u32 taskCount
- u32 firstTask
-}
-
-@extension("VK_NV_fragment_shader_barycentric") // 204
-class VkPhysicalDeviceFragmentShaderBarycentricFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 fragmentShaderBarycentric
-}
-
-@extension("VK_NV_shader_image_footprint") // 205
-class VkPhysicalDeviceShaderImageFootprintFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 imageFootprint
-}
-
-@extension("VK_NV_scissor_exclusive") // 206
-class VkPipelineViewportExclusiveScissorStateCreateInfoNV {
- VkStructureType sType
- const void* pNext
- u32 exclusiveScissorCount
- const VkRect2D* pExclusiveScissors
-}
-
-@extension("VK_NV_scissor_exclusive") // 206
-class VkPhysicalDeviceExclusiveScissorFeaturesNV {
- VkStructureType sType
- void* pNext
- VkBool32 exclusiveScissor
-}
-
-@extension("VK_NV_device_diagnostic_checkpoints") // 207
-class VkQueueFamilyCheckpointPropertiesNV {
- VkStructureType sType
- void* pNext
- VkPipelineStageFlags checkpointExecutionStageMask
-}
-
-@extension("VK_NV_device_diagnostic_checkpoints") // 207
-class VkCheckpointDataNV {
- VkStructureType sType
- void* pNext
- VkPipelineStageFlagBits stage
- void* pCheckpointMarker
-}
-
-@extension("VK_KHR_vulkan_memory_model") // 212
-class VkPhysicalDeviceVulkanMemoryModelFeaturesKHR {
- VkStructureType sType
- void* pNext
- VkBool32 vulkanMemoryModel
- VkBool32 vulkanMemoryModelDeviceScope
-}
-
-@extension("VK_EXT_pci_bus_info") // 213
-class VkPhysicalDevicePCIBusInfoPropertiesEXT {
- VkStructureType sType
- void* pNext
- u32 pciDomain
- u32 pciBus
- u32 pciDevice
- u32 pciFunction
-}
-
-@extension("VK_FUCHSIA_imagepipe_surface") // 215
-class VkImagePipeSurfaceCreateInfoFUCHSIA {
- VkStructureType sType
- const void* pNext
- VkImagePipeSurfaceCreateFlagsFUCHSIA flags
- platform.zx_handle_t imagePipeHandle
-}
-
-@extension("VK_EXT_fragment_density_map") // 219
-class VkPhysicalDeviceFragmentDensityMapFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 fragmentDensityMap
- VkBool32 fragmentDensityMapDynamic
- VkBool32 fragmentDensityMapNonSubsampledImages
-}
-
-@extension("VK_EXT_fragment_density_map") // 219
-class VkPhysicalDeviceFragmentDensityMapPropertiesEXT {
- VkStructureType sType
- void* pNext
- VkExtent2D minFragmentDensityTexelSize
- VkExtent2D maxFragmentDensityTexelSize
- VkBool32 fragmentDensityInvocations
-}
-
-@extension("VK_EXT_fragment_density_map") // 219
-class VkRenderPassFragmentDensityMapCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkAttachmentReference fragmentDensityMapAttachment
-}
-
-@extension("VK_EXT_scalar_block_layout") // 222
-class VkPhysicalDeviceScalarBlockLayoutFeaturesEXT {
- VkStructureType sType
- void* pNext
- VkBool32 scalarBlockLayout
-}
-
-@extension("VK_EXT_separate_stencil_usage") // 247
-class VkImageStencilUsageCreateInfoEXT {
- VkStructureType sType
- const void* pNext
- VkImageUsageFlags stencilUsage
-}
-
-
-////////////////
-// Commands //
-////////////////
-
-// Function pointers. TODO: add support for function pointers.
-
-@external type void* PFN_vkVoidFunction
-@pfn cmd void vkVoidFunction() {
-}
-
-@external type void* PFN_vkAllocationFunction
-@pfn cmd void* vkAllocationFunction(
- void* pUserData,
- platform.size_t size,
- platform.size_t alignment,
- VkSystemAllocationScope allocationScope) {
- return ?
-}
-
-@external type void* PFN_vkReallocationFunction
-@pfn cmd void* vkReallocationFunction(
- void* pUserData,
- void* pOriginal,
- platform.size_t size,
- platform.size_t alignment,
- VkSystemAllocationScope allocationScope) {
- return ?
-}
-
-@external type void* PFN_vkFreeFunction
-@pfn cmd void vkFreeFunction(
- void* pUserData,
- void* pMemory) {
-}
-
-@external type void* PFN_vkInternalAllocationNotification
-@pfn cmd void vkInternalAllocationNotification(
- void* pUserData,
- platform.size_t size,
- VkInternalAllocationType allocationType,
- VkSystemAllocationScope allocationScope) {
-}
-
-@external type void* PFN_vkInternalFreeNotification
-@pfn cmd void vkInternalFreeNotification(
- void* pUserData,
- platform.size_t size,
- VkInternalAllocationType allocationType,
- VkSystemAllocationScope allocationScope) {
-}
-
-// Global functions
-
-@threadSafety("system")
-cmd VkResult vkCreateInstance(
- const VkInstanceCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkInstance* pInstance) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)
-
- instance := ?
- pInstance[0] = instance
- State.Instances[instance] = new!InstanceObject()
-
- layers := pCreateInfo.ppEnabledLayerNames[0:pCreateInfo.enabledLayerCount]
- extensions := pCreateInfo.ppEnabledExtensionNames[0:pCreateInfo.enabledExtensionCount]
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyInstance(
- VkInstance instance,
- const VkAllocationCallbacks* pAllocator) {
- instanceObject := GetInstance(instance)
-
- State.Instances[instance] = null
-}
-
-@threadSafety("system")
-cmd VkResult vkEnumeratePhysicalDevices(
- VkInstance instance,
- u32* pPhysicalDeviceCount,
- VkPhysicalDevice* pPhysicalDevices) {
- instanceObject := GetInstance(instance)
-
- physicalDeviceCount := as!u32(?)
- pPhysicalDeviceCount[0] = physicalDeviceCount
- physicalDevices := pPhysicalDevices[0:physicalDeviceCount]
-
- for i in (0 .. physicalDeviceCount) {
- physicalDevice := ?
- physicalDevices[i] = physicalDevice
- if !(physicalDevice in State.PhysicalDevices) {
- State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
- }
- }
-
- return ?
-}
-
-cmd PFN_vkVoidFunction vkGetDeviceProcAddr(
- VkDevice device,
- const char* pName) {
- if device != NULL_HANDLE {
- device := GetDevice(device)
- }
-
- return ?
-}
-
-cmd PFN_vkVoidFunction vkGetInstanceProcAddr(
- VkInstance instance,
- const char* pName) {
- if instance != NULL_HANDLE {
- instanceObject := GetInstance(instance)
- }
-
- return ?
-}
-
-cmd void vkGetPhysicalDeviceProperties(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- properties := ?
- pProperties[0] = properties
-}
-
-cmd void vkGetPhysicalDeviceQueueFamilyProperties(
- VkPhysicalDevice physicalDevice,
- u32* pQueueFamilyPropertyCount,
- VkQueueFamilyProperties* pQueueFamilyProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- // TODO: Figure out how to express fetch-count-or-properties
- // This version fails 'apic validate' with 'fence not allowed in
- // *semantic.Branch'. Other attempts have failed with the same or other
- // errors.
- // if pQueueFamilyProperties != null {
- // queuesProperties := pQueueFamilyProperties[0:pCount[0]]
- // for i in (0 .. pCount[0]) {
- // queueProperties := as!VkQueueFamilyProperties(?)
- // queuesProperties[i] = queueProperties
- // }
- // } else {
- // count := ?
- // pCount[0] = count
- // }
-}
-
-cmd void vkGetPhysicalDeviceMemoryProperties(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceMemoryProperties* pMemoryProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- memoryProperties := ?
- pMemoryProperties[0] = memoryProperties
-}
-
-cmd void vkGetPhysicalDeviceFeatures(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceFeatures* pFeatures) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- features := ?
- pFeatures[0] = features
-}
-
-cmd void vkGetPhysicalDeviceFormatProperties(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkFormatProperties* pFormatProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- formatProperties := ?
- pFormatProperties[0] = formatProperties
-}
-
-cmd VkResult vkGetPhysicalDeviceImageFormatProperties(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkImageType type,
- VkImageTiling tiling,
- VkImageUsageFlags usage,
- VkImageCreateFlags flags,
- VkImageFormatProperties* pImageFormatProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- imageFormatProperties := ?
- pImageFormatProperties[0] = imageFormatProperties
-
- return ?
-}
-
-
-// Device functions
-
-@threadSafety("system")
-cmd VkResult vkCreateDevice(
- VkPhysicalDevice physicalDevice,
- const VkDeviceCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDevice* pDevice) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO)
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- device := ?
- pDevice[0] = device
- State.Devices[device] = new!DeviceObject(physicalDevice: physicalDevice)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyDevice(
- VkDevice device,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
-
- State.Devices[device] = null
-}
-
-
-// Extension discovery functions
-
-cmd VkResult vkEnumerateInstanceLayerProperties(
- u32* pPropertyCount,
- VkLayerProperties* pProperties) {
- count := as!u32(?)
- pPropertyCount[0] = count
-
- properties := pProperties[0:count]
- for i in (0 .. count) {
- property := ?
- properties[i] = property
- }
-
- return ?
-}
-
-cmd VkResult vkEnumerateInstanceExtensionProperties(
- const char* pLayerName,
- u32* pPropertyCount,
- VkExtensionProperties* pProperties) {
- count := as!u32(?)
- pPropertyCount[0] = count
-
- properties := pProperties[0:count]
- for i in (0 .. count) {
- property := ?
- properties[i] = property
- }
-
- return ?
-}
-
-cmd VkResult vkEnumerateDeviceLayerProperties(
- VkPhysicalDevice physicalDevice,
- u32* pPropertyCount,
- VkLayerProperties* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- count := as!u32(?)
- pPropertyCount[0] = count
-
- properties := pProperties[0:count]
- for i in (0 .. count) {
- property := ?
- properties[i] = property
- }
-
- return ?
-}
-
-cmd VkResult vkEnumerateDeviceExtensionProperties(
- VkPhysicalDevice physicalDevice,
- const char* pLayerName,
- u32* pPropertyCount,
- VkExtensionProperties* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- count := as!u32(?)
- pPropertyCount[0] = count
-
- properties := pProperties[0:count]
- for i in (0 .. count) {
- property := ?
- properties[i] = property
- }
-
- return ?
-}
-
-
-// Queue functions
-
-@threadSafety("system")
-cmd void vkGetDeviceQueue(
- VkDevice device,
- u32 queueFamilyIndex,
- u32 queueIndex,
- VkQueue* pQueue) {
- deviceObject := GetDevice(device)
-
- queue := ?
- pQueue[0] = queue
-
- if !(queue in State.Queues) {
- State.Queues[queue] = new!QueueObject(device: device)
- }
-}
-
-@threadSafety("app")
-cmd VkResult vkQueueSubmit(
- VkQueue queue,
- u32 submitCount,
- const VkSubmitInfo* pSubmits,
- VkFence fence) {
- queueObject := GetQueue(queue)
-
- if fence != NULL_HANDLE {
- fenceObject := GetFence(fence)
- assert(fenceObject.device == queueObject.device)
- }
-
- // commandBuffers := pcommandBuffers[0:commandBufferCount]
- // for i in (0 .. commandBufferCount) {
- // commandBuffer := commandBuffers[i]
- // commandBufferObject := GetCommandBuffer(commandBuffer)
- // assert(commandBufferObject.device == queueObject.device)
- //
- // validate("QueueCheck", commandBufferObject.queueFlags in queueObject.flags,
- // "vkQueueSubmit: enqueued commandBuffer requires missing queue capabilities.")
- // }
-
- return ?
-}
-
-@threadSafety("system")
-cmd VkResult vkQueueWaitIdle(
- VkQueue queue) {
- queueObject := GetQueue(queue)
-
- return ?
-}
-
-@threadSafety("system")
-cmd VkResult vkDeviceWaitIdle(
- VkDevice device) {
- deviceObject := GetDevice(device)
-
- return ?
-}
-
-
-// Memory functions
-
-@threadSafety("system")
-cmd VkResult vkAllocateMemory(
- VkDevice device,
- const VkMemoryAllocateInfo* pAllocateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDeviceMemory* pMemory) {
- assert(pAllocateInfo.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO)
- deviceObject := GetDevice(device)
-
- memory := ?
- pMemory[0] = memory
- State.DeviceMemories[memory] = new!DeviceMemoryObject(
- device: device,
- allocationSize: pAllocateInfo[0].allocationSize)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkFreeMemory(
- VkDevice device,
- VkDeviceMemory memory,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- memoryObject := GetDeviceMemory(memory)
- assert(memoryObject.device == device)
-
- // Check that no objects are still bound before freeing.
- validate("MemoryCheck", len(memoryObject.boundObjects) == 0,
- "vkFreeMemory: objects still bound")
- validate("MemoryCheck", len(memoryObject.boundCommandBuffers) == 0,
- "vkFreeMemory: commandBuffers still bound")
- State.DeviceMemories[memory] = null
-}
-
-@threadSafety("app")
-cmd VkResult vkMapMemory(
- VkDevice device,
- VkDeviceMemory memory,
- VkDeviceSize offset,
- VkDeviceSize size,
- VkMemoryMapFlags flags,
- void** ppData) {
- deviceObject := GetDevice(device)
- memoryObject := GetDeviceMemory(memory)
- assert(memoryObject.device == device)
-
- assert(flags == as!VkMemoryMapFlags(0))
- assert((offset + size) <= memoryObject.allocationSize)
-
- return ?
-}
-
-@threadSafety("app")
-cmd void vkUnmapMemory(
- VkDevice device,
- VkDeviceMemory memory) {
- deviceObject := GetDevice(device)
- memoryObject := GetDeviceMemory(memory)
- assert(memoryObject.device == device)
-}
-
-cmd VkResult vkFlushMappedMemoryRanges(
- VkDevice device,
- u32 memoryRangeCount
- const VkMappedMemoryRange* pMemoryRanges) {
- deviceObject := GetDevice(device)
-
- memoryRanges := pMemoryRanges[0:memoryRangeCount]
- for i in (0 .. memoryRangeCount) {
- memoryRange := memoryRanges[i]
- memoryObject := GetDeviceMemory(memoryRange.memory)
- assert(memoryObject.device == device)
- assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize)
- }
-
- return ?
-}
-
-cmd VkResult vkInvalidateMappedMemoryRanges(
- VkDevice device,
- u32 memoryRangeCount,
- const VkMappedMemoryRange* pMemoryRanges) {
- deviceObject := GetDevice(device)
-
- memoryRanges := pMemoryRanges[0:memoryRangeCount]
- for i in (0 .. memoryRangeCount) {
- memoryRange := memoryRanges[i]
- memoryObject := GetDeviceMemory(memoryRange.memory)
- assert(memoryObject.device == device)
- assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize)
- }
-
- return ?
-}
-
-
-// Memory management API functions
-
-cmd void vkGetDeviceMemoryCommitment(
- VkDevice device,
- VkDeviceMemory memory,
- VkDeviceSize* pCommittedMemoryInBytes) {
- deviceObject := GetDevice(device)
-
- if memory != NULL_HANDLE {
- memoryObject := GetDeviceMemory(memory)
- assert(memoryObject.device == device)
- }
-
- committedMemoryInBytes := ?
- pCommittedMemoryInBytes[0] = committedMemoryInBytes
-}
-
-cmd void vkGetBufferMemoryRequirements(
- VkDevice device,
- VkBuffer buffer,
- VkMemoryRequirements* pMemoryRequirements) {
- deviceObject := GetDevice(device)
- bufferObject := GetBuffer(buffer)
- assert(bufferObject.device == device)
-}
-
-cmd VkResult vkBindBufferMemory(
- VkDevice device,
- VkBuffer buffer,
- VkDeviceMemory memory,
- VkDeviceSize memoryOffset) {
- deviceObject := GetDevice(device)
- bufferObject := GetBuffer(buffer)
- assert(bufferObject.device == device)
-
- // Unbind buffer from previous memory object, if not VK_NULL_HANDLE.
- if bufferObject.memory != NULL_HANDLE {
- memoryObject := GetDeviceMemory(bufferObject.memory)
- memoryObject.boundObjects[as!u64(buffer)] = null
- }
-
- // Bind buffer to given memory object, if not VK_NULL_HANDLE.
- if memory != NULL_HANDLE {
- memoryObject := GetDeviceMemory(memory)
- assert(memoryObject.device == device)
- memoryObject.boundObjects[as!u64(buffer)] = memoryOffset
- }
- bufferObject.memory = memory
- bufferObject.memoryOffset = memoryOffset
-
- return ?
-}
-
-cmd void vkGetImageMemoryRequirements(
- VkDevice device,
- VkImage image,
- VkMemoryRequirements* pMemoryRequirements) {
- deviceObject := GetDevice(device)
- imageObject := GetImage(image)
- assert(imageObject.device == device)
-}
-
-cmd VkResult vkBindImageMemory(
- VkDevice device,
- VkImage image,
- VkDeviceMemory memory,
- VkDeviceSize memoryOffset) {
- deviceObject := GetDevice(device)
- imageObject := GetImage(image)
- assert(imageObject.device == device)
-
- // Unbind image from previous memory object, if not VK_NULL_HANDLE.
- if imageObject.memory != NULL_HANDLE {
- memoryObject := GetDeviceMemory(imageObject.memory)
- memoryObject.boundObjects[as!u64(image)] = null
- }
-
- // Bind image to given memory object, if not VK_NULL_HANDLE.
- if memory != NULL_HANDLE {
- memoryObject := GetDeviceMemory(memory)
- assert(memoryObject.device == device)
- memoryObject.boundObjects[as!u64(image)] = memoryOffset
- }
- imageObject.memory = memory
- imageObject.memoryOffset = memoryOffset
-
- return ?
-}
-
-cmd void vkGetImageSparseMemoryRequirements(
- VkDevice device,
- VkImage image,
- u32* pSparseMemoryRequirementCount,
- VkSparseImageMemoryRequirements* pSparseMemoryRequirements) {
- deviceObject := GetDevice(device)
- imageObject := GetImage(image)
- assert(imageObject.device == device)
-}
-
-cmd void vkGetPhysicalDeviceSparseImageFormatProperties(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkImageType type,
- VkSampleCountFlagBits samples,
- VkImageUsageFlags usage,
- VkImageTiling tiling,
- u32* pPropertyCount,
- VkSparseImageFormatProperties* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-}
-
-cmd VkResult vkQueueBindSparse(
- VkQueue queue,
- u32 bindInfoCount,
- const VkBindSparseInfo* pBindInfo,
- VkFence fence) {
- queueObject := GetQueue(queue)
-
- return ?
-}
-
-
-// Fence functions
-
-@threadSafety("system")
-cmd VkResult vkCreateFence(
- VkDevice device,
- const VkFenceCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkFence* pFence) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- fence := ?
- pFence[0] = fence
- State.Fences[fence] = new!FenceObject(
- device: device, signaled: (pCreateInfo.flags == as!VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT)))
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyFence(
- VkDevice device,
- VkFence fence,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- fenceObject := GetFence(fence)
- assert(fenceObject.device == device)
-
- State.Fences[fence] = null
-}
-
-@threadSafety("system")
-cmd VkResult vkResetFences(
- VkDevice device,
- u32 fenceCount,
- const VkFence* pFences) {
- deviceObject := GetDevice(device)
-
- fences := pFences[0:fenceCount]
- for i in (0 .. fenceCount) {
- fence := fences[i]
- fenceObject := GetFence(fence)
- assert(fenceObject.device == device)
- fenceObject.signaled = false
- }
-
- return ?
-}
-
-@threadSafety("system")
-cmd VkResult vkGetFenceStatus(
- VkDevice device,
- VkFence fence) {
- deviceObject := GetDevice(device)
- fenceObject := GetFence(fence)
- assert(fenceObject.device == device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd VkResult vkWaitForFences(
- VkDevice device,
- u32 fenceCount,
- const VkFence* pFences,
- VkBool32 waitAll,
- u64 timeout) { /// timeout in nanoseconds
- deviceObject := GetDevice(device)
-
- fences := pFences[0:fenceCount]
- for i in (0 .. fenceCount) {
- fence := fences[i]
- fenceObject := GetFence(fence)
- assert(fenceObject.device == device)
- }
-
- return ?
-}
-
-
-// Queue semaphore functions
-
-@threadSafety("system")
-cmd VkResult vkCreateSemaphore(
- VkDevice device,
- const VkSemaphoreCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSemaphore* pSemaphore) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- semaphore := ?
- pSemaphore[0] = semaphore
- State.Semaphores[semaphore] = new!SemaphoreObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroySemaphore(
- VkDevice device,
- VkSemaphore semaphore,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- semaphoreObject := GetSemaphore(semaphore)
- assert(semaphoreObject.device == device)
-
- State.Semaphores[semaphore] = null
-}
-
-
-// Event functions
-
-@threadSafety("system")
-cmd VkResult vkCreateEvent(
- VkDevice device,
- const VkEventCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkEvent* pEvent) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_EVENT_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- event := ?
- pEvent[0] = event
- State.Events[event] = new!EventObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyEvent(
- VkDevice device,
- VkEvent event,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- eventObject := GetEvent(event)
- assert(eventObject.device == device)
-
- State.Events[event] = null
-}
-
-@threadSafety("system")
-cmd VkResult vkGetEventStatus(
- VkDevice device,
- VkEvent event) {
- deviceObject := GetDevice(device)
- eventObject := GetEvent(event)
- assert(eventObject.device == device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd VkResult vkSetEvent(
- VkDevice device,
- VkEvent event) {
- deviceObject := GetDevice(device)
- eventObject := GetEvent(event)
- assert(eventObject.device == device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd VkResult vkResetEvent(
- VkDevice device,
- VkEvent event) {
- deviceObject := GetDevice(device)
- eventObject := GetEvent(event)
- assert(eventObject.device == device)
-
- return ?
-}
-
-
-// Query functions
-
-@threadSafety("system")
-cmd VkResult vkCreateQueryPool(
- VkDevice device,
- const VkQueryPoolCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkQueryPool* pQueryPool) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- queryPool := ?
- pQueryPool[0] = queryPool
- State.QueryPools[queryPool] = new!QueryPoolObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyQueryPool(
- VkDevice device,
- VkQueryPool queryPool,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- queryPoolObject := GetQueryPool(queryPool)
- assert(queryPoolObject.device == device)
-
- State.QueryPools[queryPool] = null
-}
-
-@threadSafety("system")
-cmd VkResult vkGetQueryPoolResults(
- VkDevice device,
- VkQueryPool queryPool,
- u32 firstQuery,
- u32 queryCount,
- platform.size_t dataSize,
- void* pData,
- VkDeviceSize stride,
- VkQueryResultFlags flags) {
- deviceObject := GetDevice(device)
- queryPoolObject := GetQueryPool(queryPool)
- assert(queryPoolObject.device == device)
-
- data := pData[0:dataSize]
-
- return ?
-}
-
-// Buffer functions
-
-@threadSafety("system")
-cmd VkResult vkCreateBuffer(
- VkDevice device,
- const VkBufferCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkBuffer* pBuffer) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- buffer := ?
- pBuffer[0] = buffer
- State.Buffers[buffer] = new!BufferObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyBuffer(
- VkDevice device,
- VkBuffer buffer,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- bufferObject := GetBuffer(buffer)
- assert(bufferObject.device == device)
-
- assert(bufferObject.memory == 0)
- State.Buffers[buffer] = null
-}
-
-
-// Buffer view functions
-
-@threadSafety("system")
-cmd VkResult vkCreateBufferView(
- VkDevice device,
- const VkBufferViewCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkBufferView* pView) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- bufferObject := GetBuffer(pCreateInfo.buffer)
- assert(bufferObject.device == device)
-
- view := ?
- pView[0] = view
- State.BufferViews[view] = new!BufferViewObject(device: device, buffer: pCreateInfo.buffer)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyBufferView(
- VkDevice device,
- VkBufferView bufferView,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- bufferViewObject := GetBufferView(bufferView)
- assert(bufferViewObject.device == device)
-
- State.BufferViews[bufferView] = null
-}
-
-
-// Image functions
-
-@threadSafety("system")
-cmd VkResult vkCreateImage(
- VkDevice device,
- const VkImageCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkImage* pImage) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- image := ?
- pImage[0] = image
- State.Images[image] = new!ImageObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyImage(
- VkDevice device,
- VkImage image,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- imageObject := GetImage(image)
- assert(imageObject.device == device)
-
- assert(imageObject.memory == 0)
- State.Images[image] = null
-}
-
-cmd void vkGetImageSubresourceLayout(
- VkDevice device,
- VkImage image,
- const VkImageSubresource* pSubresource,
- VkSubresourceLayout* pLayout) {
- deviceObject := GetDevice(device)
- imageObject := GetImage(image)
- assert(imageObject.device == device)
-}
-
-
-// Image view functions
-
-@threadSafety("system")
-cmd VkResult vkCreateImageView(
- VkDevice device,
- const VkImageViewCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkImageView* pView) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- imageObject := GetImage(pCreateInfo.image)
- assert(imageObject.device == device)
-
- view := ?
- pView[0] = view
- State.ImageViews[view] = new!ImageViewObject(device: device, image: pCreateInfo.image)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyImageView(
- VkDevice device,
- VkImageView imageView,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- imageViewObject := GetImageView(imageView)
- assert(imageViewObject.device == device)
-
- State.ImageViews[imageView] = null
-}
-
-
-// Shader functions
-
-cmd VkResult vkCreateShaderModule(
- VkDevice device,
- const VkShaderModuleCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkShaderModule* pShaderModule) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- shaderModule := ?
- pShaderModule[0] = shaderModule
- State.ShaderModules[shaderModule] = new!ShaderModuleObject(device: device)
-
- return ?
-}
-
-cmd void vkDestroyShaderModule(
- VkDevice device,
- VkShaderModule shaderModule,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- shaderModuleObject := GetShaderModule(shaderModule)
- assert(shaderModuleObject.device == device)
-
- State.ShaderModules[shaderModule] = null
-}
-
-
-// Pipeline functions
-
-cmd VkResult vkCreatePipelineCache(
- VkDevice device,
- const VkPipelineCacheCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkPipelineCache* pPipelineCache) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- pipelineCache := ?
- pPipelineCache[0] = pipelineCache
- State.PipelineCaches[pipelineCache] = new!PipelineCacheObject(device: device)
-
- return ?
-}
-
-cmd void vkDestroyPipelineCache(
- VkDevice device,
- VkPipelineCache pipelineCache,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- pipelineCacheObject := GetPipelineCache(pipelineCache)
- assert(pipelineCacheObject.device == device)
-
- State.PipelineCaches[pipelineCache] = null
-}
-
-cmd VkResult vkGetPipelineCacheData(
- VkDevice device,
- VkPipelineCache pipelineCache,
- platform.size_t* pDataSize,
- void* pData) {
- deviceObject := GetDevice(device)
- pipelineCacheObject := GetPipelineCache(pipelineCache)
- assert(pipelineCacheObject.device == device)
-
- return ?
-}
-
-cmd VkResult vkMergePipelineCaches(
- VkDevice device,
- VkPipelineCache dstCache,
- u32 srcCacheCount,
- const VkPipelineCache* pSrcCaches) {
- deviceObject := GetDevice(device)
- dstCacheObject := GetPipelineCache(dstCache)
- assert(dstCacheObject.device == device)
-
- srcCaches := pSrcCaches[0:srcCacheCount]
- for i in (0 .. srcCacheCount) {
- srcCache := srcCaches[i]
- srcCacheObject := GetPipelineCache(srcCache)
- assert(srcCacheObject.device == device)
- }
-
- return ?
-}
-
-cmd VkResult vkCreateGraphicsPipelines(
- VkDevice device,
- VkPipelineCache pipelineCache,
- u32 createInfoCount,
- const VkGraphicsPipelineCreateInfo* pCreateInfos,
- const VkAllocationCallbacks* pAllocator,
- VkPipeline* pPipelines) {
- deviceObject := GetDevice(device)
- if pipelineCache != NULL_HANDLE {
- pipelineCacheObject := GetPipelineCache(pipelineCache)
- assert(pipelineCacheObject.device == device)
- }
-
- createInfos := pCreateInfos[0:createInfoCount]
- pipelines := pPipelines[0:createInfoCount]
- for i in (0 .. createInfoCount) {
- pipeline := ?
- pipelines[i] = pipeline
- State.Pipelines[pipeline] = new!PipelineObject(device: device)
- }
-
- return ?
-}
-
-cmd VkResult vkCreateComputePipelines(
- VkDevice device,
- VkPipelineCache pipelineCache,
- u32 createInfoCount,
- const VkComputePipelineCreateInfo* pCreateInfos,
- const VkAllocationCallbacks* pAllocator,
- VkPipeline* pPipelines) {
- deviceObject := GetDevice(device)
- if pipelineCache != NULL_HANDLE {
- pipelineCacheObject := GetPipelineCache(pipelineCache)
- assert(pipelineCacheObject.device == device)
- }
-
- createInfos := pCreateInfos[0:createInfoCount]
- pipelines := pPipelines[0:createInfoCount]
- for i in (0 .. createInfoCount) {
- pipeline := ?
- pipelines[i] = pipeline
- State.Pipelines[pipeline] = new!PipelineObject(device: device)
- }
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyPipeline(
- VkDevice device,
- VkPipeline pipeline,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- pipelineObjects := GetPipeline(pipeline)
- assert(pipelineObjects.device == device)
-
- State.Pipelines[pipeline] = null
-}
-
-
-// Pipeline layout functions
-
-@threadSafety("system")
-cmd VkResult vkCreatePipelineLayout(
- VkDevice device,
- const VkPipelineLayoutCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkPipelineLayout* pPipelineLayout) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- pipelineLayout := ?
- pPipelineLayout[0] = pipelineLayout
- State.PipelineLayouts[pipelineLayout] = new!PipelineLayoutObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyPipelineLayout(
- VkDevice device,
- VkPipelineLayout pipelineLayout,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- pipelineLayoutObjects := GetPipelineLayout(pipelineLayout)
- assert(pipelineLayoutObjects.device == device)
-
- State.PipelineLayouts[pipelineLayout] = null
-}
-
-
-// Sampler functions
-
-@threadSafety("system")
-cmd VkResult vkCreateSampler(
- VkDevice device,
- const VkSamplerCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSampler* pSampler) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- sampler := ?
- pSampler[0] = sampler
- State.Samplers[sampler] = new!SamplerObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroySampler(
- VkDevice device,
- VkSampler sampler,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- samplerObject := GetSampler(sampler)
- assert(samplerObject.device == device)
-
- State.Samplers[sampler] = null
-}
-
-
-// Descriptor set functions
-
-@threadSafety("system")
-cmd VkResult vkCreateDescriptorSetLayout(
- VkDevice device,
- const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDescriptorSetLayout* pSetLayout) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- setLayout := ?
- pSetLayout[0] = setLayout
- State.DescriptorSetLayouts[setLayout] = new!DescriptorSetLayoutObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyDescriptorSetLayout(
- VkDevice device,
- VkDescriptorSetLayout descriptorSetLayout,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- descriptorSetLayoutObject := GetDescriptorSetLayout(descriptorSetLayout)
- assert(descriptorSetLayoutObject.device == device)
-
- State.DescriptorSetLayouts[descriptorSetLayout] = null
-}
-
-@threadSafety("system")
-cmd VkResult vkCreateDescriptorPool(
- VkDevice device,
- const VkDescriptorPoolCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDescriptorPool* pDescriptorPool) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- descriptorPool := ?
- pDescriptorPool[0] = descriptorPool
- State.DescriptorPools[descriptorPool] = new!DescriptorPoolObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyDescriptorPool(
- VkDevice device,
- VkDescriptorPool descriptorPool,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- descriptorPoolObject := GetDescriptorPool(descriptorPool)
- assert(descriptorPoolObject.device == device)
-
- State.DescriptorPools[descriptorPool] = null
-}
-
-@threadSafety("app")
-cmd VkResult vkResetDescriptorPool(
- VkDevice device,
- VkDescriptorPool descriptorPool,
- VkDescriptorPoolResetFlags flags) {
- deviceObject := GetDevice(device)
- descriptorPoolObject := GetDescriptorPool(descriptorPool)
- assert(descriptorPoolObject.device == device)
-
- return ?
-}
-
-@threadSafety("app")
-cmd VkResult vkAllocateDescriptorSets(
- VkDevice device,
- const VkDescriptorSetAllocateInfo* pAllocateInfo,
- VkDescriptorSet* pDescriptorSets) {
- deviceObject := GetDevice(device)
- allocInfo := pAllocateInfo[0]
- descriptorPoolObject := GetDescriptorPool(allocInfo.descriptorPool)
-
- setLayouts := allocInfo.pSetLayouts[0:allocInfo.setCount]
- for i in (0 .. allocInfo.setCount) {
- setLayout := setLayouts[i]
- setLayoutObject := GetDescriptorSetLayout(setLayout)
- assert(setLayoutObject.device == device)
- }
-
- descriptorSets := pDescriptorSets[0:allocInfo.setCount]
- for i in (0 .. allocInfo.setCount) {
- descriptorSet := ?
- descriptorSets[i] = descriptorSet
- State.DescriptorSets[descriptorSet] = new!DescriptorSetObject(device: device)
- }
-
- return ?
-}
-
-cmd VkResult vkFreeDescriptorSets(
- VkDevice device,
- VkDescriptorPool descriptorPool,
- u32 descriptorSetCount,
- const VkDescriptorSet* pDescriptorSets) {
- deviceObject := GetDevice(device)
- descriptorPoolObject := GetDescriptorPool(descriptorPool)
-
- descriptorSets := pDescriptorSets[0:descriptorSetCount]
- for i in (0 .. descriptorSetCount) {
- descriptorSet := descriptorSets[i]
- descriptorSetObject := GetDescriptorSet(descriptorSet)
- assert(descriptorSetObject.device == device)
- State.DescriptorSets[descriptorSet] = null
- }
-
- return ?
-}
-
-cmd void vkUpdateDescriptorSets(
- VkDevice device,
- u32 descriptorWriteCount,
- const VkWriteDescriptorSet* pDescriptorWrites,
- u32 descriptorCopyCount,
- const VkCopyDescriptorSet* pDescriptorCopies) {
- deviceObject := GetDevice(device)
-
- descriptorWrites := pDescriptorWrites[0:descriptorWriteCount]
- for i in (0 .. descriptorWriteCount) {
- descriptorWrite := descriptorWrites[i]
- descriptorWriteObject := GetDescriptorSet(descriptorWrite.dstSet)
- assert(descriptorWriteObject.device == device)
- }
-
- descriptorCopies := pDescriptorCopies[0:descriptorCopyCount]
- for i in (0 .. descriptorCopyCount) {
- descriptorCopy := descriptorCopies[i]
- descriptorCopyObject := GetDescriptorSet(descriptorCopy.dstSet)
- assert(descriptorCopyObject.device == device)
- }
-}
-
-
-// Framebuffer functions
-
-@threadSafety("system")
-cmd VkResult vkCreateFramebuffer(
- VkDevice device,
- const VkFramebufferCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkFramebuffer* pFramebuffer) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- framebuffer := ?
- pFramebuffer[0] = framebuffer
- State.Framebuffers[framebuffer] = new!FramebufferObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyFramebuffer(
- VkDevice device,
- VkFramebuffer framebuffer,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- framebufferObject := GetFramebuffer(framebuffer)
- assert(framebufferObject.device == device)
-
- State.Framebuffers[framebuffer] = null
-}
-
-
-// Renderpass functions
-
-@threadSafety("system")
-cmd VkResult vkCreateRenderPass(
- VkDevice device,
- const VkRenderPassCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkRenderPass* pRenderPass) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- renderpass := ?
- pRenderPass[0] = renderpass
- State.RenderPasses[renderpass] = new!RenderPassObject(device: device)
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkDestroyRenderPass(
- VkDevice device,
- VkRenderPass renderPass,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- renderPassObject := GetRenderPass(renderPass)
- assert(renderPassObject.device == device)
-
- State.RenderPasses[renderPass] = null
-}
-
-cmd void vkGetRenderAreaGranularity(
- VkDevice device,
- VkRenderPass renderPass,
- VkExtent2D* pGranularity) {
- deviceObject := GetDevice(device)
- renderPassObject := GetRenderPass(renderPass)
-
- granularity := ?
- pGranularity[0] = granularity
-}
-
-// Command pool functions
-
-cmd VkResult vkCreateCommandPool(
- VkDevice device,
- const VkCommandPoolCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkCommandPool* pCommandPool) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO)
- deviceObject := GetDevice(device)
-
- commandPool := ?
- pCommandPool[0] = commandPool
- State.CommandPools[commandPool] = new!CommandPoolObject(device: device)
-
- return ?
-}
-
-cmd void vkDestroyCommandPool(
- VkDevice device,
- VkCommandPool commandPool,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- commandPoolObject := GetCommandPool(commandPool)
- assert(commandPoolObject.device == device)
-
- State.CommandPools[commandPool] = null
-}
-
-cmd VkResult vkResetCommandPool(
- VkDevice device,
- VkCommandPool commandPool,
- VkCommandPoolResetFlags flags) {
- deviceObject := GetDevice(device)
- commandPoolObject := GetCommandPool(commandPool)
- assert(commandPoolObject.device == device)
-
- return ?
-}
-
-// Command buffer functions
-
-macro void bindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) {
- memoryObject := GetDeviceMemory(memory)
- memoryObject.boundCommandBuffers[commandBuffer] = commandBuffer
-
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.boundObjects[as!u64(obj)] = memory
-}
-
-macro void unbindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) {
- memoryObject := GetDeviceMemory(memory)
- memoryObject.boundCommandBuffers[commandBuffer] = null
-
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.boundObjects[as!u64(obj)] = null
-}
-
-@threadSafety("system")
-cmd VkResult vkAllocateCommandBuffers(
- VkDevice device,
- const VkCommandBufferAllocateInfo* pAllocateInfo,
- VkCommandBuffer* pCommandBuffers) {
- assert(pAllocateInfo[0].sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO)
-
- count := pAllocateInfo[0].commandBufferCount
- commandBuffers := pCommandBuffers[0:count]
- for i in (0 .. count) {
- commandBuffer := ?
- commandBuffers[i] = commandBuffer
- State.CommandBuffers[commandBuffer] = new!CommandBufferObject(device: device)
- }
-
- return ?
-}
-
-@threadSafety("system")
-cmd void vkFreeCommandBuffers(
- VkDevice device,
- VkCommandPool commandPool,
- u32 commandBufferCount,
- const VkCommandBuffer* pCommandBuffers) {
- deviceObject := GetDevice(device)
-
- commandBuffers := pCommandBuffers[0:commandBufferCount]
- for i in (0 .. commandBufferCount) {
- commandBufferObject := GetCommandBuffer(commandBuffers[i])
- assert(commandBufferObject.device == device)
- // TODO: iterate over boundObjects and clear memory bindings
- State.CommandBuffers[commandBuffers[i]] = null
- }
-}
-
-@threadSafety("app")
-cmd VkResult vkBeginCommandBuffer(
- VkCommandBuffer commandBuffer,
- const VkCommandBufferBeginInfo* pBeginInfo) {
- assert(pBeginInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO)
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- // TODO: iterate over boundObjects and clear memory bindings
-
- return ?
-}
-
-@threadSafety("app")
-cmd VkResult vkEndCommandBuffer(
- VkCommandBuffer commandBuffer) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- return ?
-}
-
-@threadSafety("app")
-cmd VkResult vkResetCommandBuffer(
- VkCommandBuffer commandBuffer,
- VkCommandBufferResetFlags flags) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- // TODO: iterate over boundObjects and clear memory bindings
-
- return ?
-}
-
-
-// Command buffer building functions
-
-@threadSafety("app")
-cmd void vkCmdBindPipeline(
- VkCommandBuffer commandBuffer,
- VkPipelineBindPoint pipelineBindPoint,
- VkPipeline pipeline) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- pipelineObject := GetPipeline(pipeline)
- assert(commandBufferObject.device == pipelineObject.device)
-
- queue := switch (pipelineBindPoint) {
- case VK_PIPELINE_BIND_POINT_COMPUTE: VK_QUEUE_COMPUTE_BIT
- case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT
- }
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetViewport(
- VkCommandBuffer commandBuffer,
- u32 firstViewport,
- u32 viewportCount,
- const VkViewport* pViewports) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetScissor(
- VkCommandBuffer commandBuffer,
- u32 firstScissor,
- u32 scissorCount,
- const VkRect2D* pScissors) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetLineWidth(
- VkCommandBuffer commandBuffer,
- f32 lineWidth) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetDepthBias(
- VkCommandBuffer commandBuffer,
- f32 depthBiasConstantFactor,
- f32 depthBiasClamp,
- f32 depthBiasSlopeFactor) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetBlendConstants(
- VkCommandBuffer commandBuffer,
- // TODO(jessehall): apic only supports 'const' on pointer types. Using
- // an annotation as a quick hack to pass this to the template without
- // having to modify the AST and semantic model.
- @readonly f32[4] blendConstants) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetDepthBounds(
- VkCommandBuffer commandBuffer,
- f32 minDepthBounds,
- f32 maxDepthBounds) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetStencilCompareMask(
- VkCommandBuffer commandBuffer,
- VkStencilFaceFlags faceMask,
- u32 compareMask) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetStencilWriteMask(
- VkCommandBuffer commandBuffer,
- VkStencilFaceFlags faceMask,
- u32 writeMask) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetStencilReference(
- VkCommandBuffer commandBuffer,
- VkStencilFaceFlags faceMask,
- u32 reference) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdBindDescriptorSets(
- VkCommandBuffer commandBuffer,
- VkPipelineBindPoint pipelineBindPoint,
- VkPipelineLayout layout,
- u32 firstSet,
- u32 descriptorSetCount,
- const VkDescriptorSet* pDescriptorSets,
- u32 dynamicOffsetCount,
- const u32* pDynamicOffsets) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- descriptorSets := pDescriptorSets[0:descriptorSetCount]
- for i in (0 .. descriptorSetCount) {
- descriptorSet := descriptorSets[i]
- descriptorSetObject := GetDescriptorSet(descriptorSet)
- assert(commandBufferObject.device == descriptorSetObject.device)
- }
-
- dynamicOffsets := pDynamicOffsets[0:dynamicOffsetCount]
- for i in (0 .. dynamicOffsetCount) {
- dynamicOffset := dynamicOffsets[i]
- }
-
- queue := switch (pipelineBindPoint) {
- case VK_PIPELINE_BIND_POINT_COMPUTE: VK_QUEUE_COMPUTE_BIT
- case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT
- }
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue)
-}
-
-@threadSafety("app")
-cmd void vkCmdBindIndexBuffer(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkIndexType indexType) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- bufferObject := GetBuffer(buffer)
- assert(commandBufferObject.device == bufferObject.device)
-
- bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdBindVertexBuffers(
- VkCommandBuffer commandBuffer,
- u32 firstBinding,
- u32 bindingCount,
- const VkBuffer* pBuffers,
- const VkDeviceSize* pOffsets) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- // TODO: check if not [firstBinding:firstBinding+bindingCount]
- buffers := pBuffers[0:bindingCount]
- offsets := pOffsets[0:bindingCount]
- for i in (0 .. bindingCount) {
- buffer := buffers[i]
- offset := offsets[i]
- bufferObject := GetBuffer(buffer)
- assert(commandBufferObject.device == bufferObject.device)
-
- bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)
- }
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdDraw(
- VkCommandBuffer commandBuffer,
- u32 vertexCount,
- u32 instanceCount,
- u32 firstVertex,
- u32 firstInstance) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdDrawIndexed(
- VkCommandBuffer commandBuffer,
- u32 indexCount,
- u32 instanceCount,
- u32 firstIndex,
- s32 vertexOffset,
- u32 firstInstance) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdDrawIndirect(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- u32 drawCount,
- u32 stride) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- bufferObject := GetBuffer(buffer)
- assert(commandBufferObject.device == bufferObject.device)
-
- bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdDrawIndexedIndirect(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- u32 drawCount,
- u32 stride) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- bufferObject := GetBuffer(buffer)
- assert(commandBufferObject.device == bufferObject.device)
-
- bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdDispatch(
- VkCommandBuffer commandBuffer,
- u32 groupCountX,
- u32 groupCountY,
- u32 groupCountZ) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdDispatchIndirect(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- bufferObject := GetBuffer(buffer)
- assert(commandBufferObject.device == bufferObject.device)
-
- bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdCopyBuffer(
- VkCommandBuffer commandBuffer,
- VkBuffer srcBuffer,
- VkBuffer dstBuffer,
- u32 regionCount,
- const VkBufferCopy* pRegions) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- srcBufferObject := GetBuffer(srcBuffer)
- dstBufferObject := GetBuffer(dstBuffer)
- assert(commandBufferObject.device == srcBufferObject.device)
- assert(commandBufferObject.device == dstBufferObject.device)
-
- regions := pRegions[0:regionCount]
- for i in (0 .. regionCount) {
- region := regions[i]
- }
-
- bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory)
- bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdCopyImage(
- VkCommandBuffer commandBuffer,
- VkImage srcImage,
- VkImageLayout srcImageLayout,
- VkImage dstImage,
- VkImageLayout dstImageLayout,
- u32 regionCount,
- const VkImageCopy* pRegions) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- srcImageObject := GetImage(srcImage)
- dstImageObject := GetImage(dstImage)
- assert(commandBufferObject.device == srcImageObject.device)
- assert(commandBufferObject.device == dstImageObject.device)
-
- regions := pRegions[0:regionCount]
- for i in (0 .. regionCount) {
- region := regions[i]
- }
-
- bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
- bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdBlitImage(
- VkCommandBuffer commandBuffer,
- VkImage srcImage,
- VkImageLayout srcImageLayout,
- VkImage dstImage,
- VkImageLayout dstImageLayout,
- u32 regionCount,
- const VkImageBlit* pRegions,
- VkFilter filter) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- srcImageObject := GetImage(srcImage)
- dstImageObject := GetImage(dstImage)
- assert(commandBufferObject.device == srcImageObject.device)
- assert(commandBufferObject.device == dstImageObject.device)
-
- regions := pRegions[0:regionCount]
- for i in (0 .. regionCount) {
- region := regions[i]
- }
-
- bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
- bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdCopyBufferToImage(
- VkCommandBuffer commandBuffer,
- VkBuffer srcBuffer,
- VkImage dstImage,
- VkImageLayout dstImageLayout,
- u32 regionCount,
- const VkBufferImageCopy* pRegions) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- srcBufferObject := GetBuffer(srcBuffer)
- dstImageObject := GetImage(dstImage)
- assert(commandBufferObject.device == srcBufferObject.device)
- assert(commandBufferObject.device == dstImageObject.device)
-
- regions := pRegions[0:regionCount]
- for i in (0 .. regionCount) {
- region := regions[i]
- }
-
- bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory)
- bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdCopyImageToBuffer(
- VkCommandBuffer commandBuffer,
- VkImage srcImage,
- VkImageLayout srcImageLayout,
- VkBuffer dstBuffer,
- u32 regionCount,
- const VkBufferImageCopy* pRegions) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- srcImageObject := GetImage(srcImage)
- dstBufferObject := GetBuffer(dstBuffer)
- assert(commandBufferObject.device == srcImageObject.device)
- assert(commandBufferObject.device == dstBufferObject.device)
-
- regions := pRegions[0:regionCount]
- for i in (0 .. regionCount) {
- region := regions[i]
- }
-
- bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
- bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdUpdateBuffer(
- VkCommandBuffer commandBuffer,
- VkBuffer dstBuffer,
- VkDeviceSize dstOffset,
- VkDeviceSize dataSize,
- const void* pData) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- dstBufferObject := GetBuffer(dstBuffer)
- assert(commandBufferObject.device == dstBufferObject.device)
-
- data := pData[0:dataSize]
-
- bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdFillBuffer(
- VkCommandBuffer commandBuffer,
- VkBuffer dstBuffer,
- VkDeviceSize dstOffset,
- VkDeviceSize size,
- u32 data) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- dstBufferObject := GetBuffer(dstBuffer)
- assert(commandBufferObject.device == dstBufferObject.device)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdClearColorImage(
- VkCommandBuffer commandBuffer,
- VkImage image,
- VkImageLayout imageLayout,
- const VkClearColorValue* pColor,
- u32 rangeCount,
- const VkImageSubresourceRange* pRanges) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- imageObject := GetImage(image)
- assert(commandBufferObject.device == imageObject.device)
-
- ranges := pRanges[0:rangeCount]
- for i in (0 .. rangeCount) {
- range := ranges[i]
- }
-
- bindCommandBuffer(commandBuffer, image, imageObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdClearDepthStencilImage(
- VkCommandBuffer commandBuffer,
- VkImage image,
- VkImageLayout imageLayout,
- const VkClearDepthStencilValue* pDepthStencil,
- u32 rangeCount,
- const VkImageSubresourceRange* pRanges) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- imageObject := GetImage(image)
- assert(commandBufferObject.device == imageObject.device)
-
- ranges := pRanges[0:rangeCount]
- for i in (0 .. rangeCount) {
- range := ranges[i]
- }
-
- bindCommandBuffer(commandBuffer, image, imageObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdClearAttachments(
- VkCommandBuffer commandBuffer,
- u32 attachmentCount,
- const VkClearAttachment* pAttachments,
- u32 rectCount,
- const VkClearRect* pRects) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- rects := pRects[0:rectCount]
- for i in (0 .. rectCount) {
- rect := rects[i]
- }
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdResolveImage(
- VkCommandBuffer commandBuffer,
- VkImage srcImage,
- VkImageLayout srcImageLayout,
- VkImage dstImage,
- VkImageLayout dstImageLayout,
- u32 regionCount,
- const VkImageResolve* pRegions) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- srcImageObject := GetImage(srcImage)
- dstImageObject := GetImage(dstImage)
- assert(commandBufferObject.device == srcImageObject.device)
- assert(commandBufferObject.device == dstImageObject.device)
-
- regions := pRegions[0:regionCount]
- for i in (0 .. regionCount) {
- region := regions[i]
- }
-
- bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
- bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-@threadSafety("app")
-cmd void vkCmdSetEvent(
- VkCommandBuffer commandBuffer,
- VkEvent event,
- VkPipelineStageFlags stageMask) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- eventObject := GetEvent(event)
- assert(commandBufferObject.device == eventObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdResetEvent(
- VkCommandBuffer commandBuffer,
- VkEvent event,
- VkPipelineStageFlags stageMask) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- eventObject := GetEvent(event)
- assert(commandBufferObject.device == eventObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdWaitEvents(
- VkCommandBuffer commandBuffer,
- u32 eventCount,
- const VkEvent* pEvents,
- VkPipelineStageFlags srcStageMask,
- VkPipelineStageFlags dstStageMask,
- u32 memoryBarrierCount,
- const VkMemoryBarrier* pMemoryBarriers,
- u32 bufferMemoryBarrierCount,
- const VkBufferMemoryBarrier* pBufferMemoryBarriers,
- u32 imageMemoryBarrierCount,
- const VkImageMemoryBarrier* pImageMemoryBarriers) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- events := pEvents[0:eventCount]
- for i in (0 .. eventCount) {
- event := events[i]
- eventObject := GetEvent(event)
- assert(commandBufferObject.device == eventObject.device)
- }
-
- memoryBarriers := pMemoryBarriers[0:memoryBarrierCount]
- for i in (0 .. memoryBarrierCount) {
- memoryBarrier := memoryBarriers[i]
- }
- bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount]
- for i in (0 .. bufferMemoryBarrierCount) {
- bufferMemoryBarrier := bufferMemoryBarriers[i]
- bufferObject := GetBuffer(bufferMemoryBarrier.buffer)
- assert(bufferObject.device == commandBufferObject.device)
- }
- imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount]
- for i in (0 .. imageMemoryBarrierCount) {
- imageMemoryBarrier := imageMemoryBarriers[i]
- imageObject := GetImage(imageMemoryBarrier.image)
- assert(imageObject.device == commandBufferObject.device)
- }
-}
-
-@threadSafety("app")
-cmd void vkCmdPipelineBarrier(
- VkCommandBuffer commandBuffer,
- VkPipelineStageFlags srcStageMask,
- VkPipelineStageFlags dstStageMask,
- VkDependencyFlags dependencyFlags,
- u32 memoryBarrierCount,
- const VkMemoryBarrier* pMemoryBarriers,
- u32 bufferMemoryBarrierCount,
- const VkBufferMemoryBarrier* pBufferMemoryBarriers,
- u32 imageMemoryBarrierCount,
- const VkImageMemoryBarrier* pImageMemoryBarriers) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- memoryBarriers := pMemoryBarriers[0:memoryBarrierCount]
- for i in (0 .. memoryBarrierCount) {
- memoryBarrier := memoryBarriers[i]
- }
- bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount]
- for i in (0 .. bufferMemoryBarrierCount) {
- bufferMemoryBarrier := bufferMemoryBarriers[i]
- bufferObject := GetBuffer(bufferMemoryBarrier.buffer)
- assert(bufferObject.device == commandBufferObject.device)
- }
- imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount]
- for i in (0 .. imageMemoryBarrierCount) {
- imageMemoryBarrier := imageMemoryBarriers[i]
- imageObject := GetImage(imageMemoryBarrier.image)
- assert(imageObject.device == commandBufferObject.device)
- }
-}
-
-@threadSafety("app")
-cmd void vkCmdBeginQuery(
- VkCommandBuffer commandBuffer,
- VkQueryPool queryPool,
- u32 query,
- VkQueryControlFlags flags) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- queryPoolObject := GetQueryPool(queryPool)
- assert(commandBufferObject.device == queryPoolObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdEndQuery(
- VkCommandBuffer commandBuffer,
- VkQueryPool queryPool,
- u32 query) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- queryPoolObject := GetQueryPool(queryPool)
- assert(commandBufferObject.device == queryPoolObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdResetQueryPool(
- VkCommandBuffer commandBuffer,
- VkQueryPool queryPool,
- u32 firstQuery,
- u32 queryCount) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- queryPoolObject := GetQueryPool(queryPool)
- assert(commandBufferObject.device == queryPoolObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdWriteTimestamp(
- VkCommandBuffer commandBuffer,
- VkPipelineStageFlagBits pipelineStage,
- VkQueryPool queryPool,
- u32 query) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- queryPoolObject := GetQueryPool(queryPool)
- assert(commandBufferObject.device == queryPoolObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdCopyQueryPoolResults(
- VkCommandBuffer commandBuffer,
- VkQueryPool queryPool,
- u32 firstQuery,
- u32 queryCount,
- VkBuffer dstBuffer,
- VkDeviceSize dstOffset,
- VkDeviceSize stride,
- VkQueryResultFlags flags) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- queryPoolObject := GetQueryPool(queryPool)
- dstBufferObject := GetBuffer(dstBuffer)
- assert(commandBufferObject.device == queryPoolObject.device)
- assert(commandBufferObject.device == dstBufferObject.device)
-}
-
-cmd void vkCmdPushConstants(
- VkCommandBuffer commandBuffer,
- VkPipelineLayout layout,
- VkShaderStageFlags stageFlags,
- u32 offset,
- u32 size,
- const void* pValues) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- layoutObject := GetPipelineLayout(layout)
- assert(commandBufferObject.device == layoutObject.device)
-}
-
-@threadSafety("app")
-cmd void vkCmdBeginRenderPass(
- VkCommandBuffer commandBuffer,
- const VkRenderPassBeginInfo* pRenderPassBegin,
- VkSubpassContents contents) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
- renderPassObject := GetRenderPass(pRenderPassBegin.renderPass)
- framebufferObject := GetFramebuffer(pRenderPassBegin.framebuffer)
- assert(commandBufferObject.device == renderPassObject.device)
- assert(commandBufferObject.device == framebufferObject.device)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-cmd void vkCmdNextSubpass(
- VkCommandBuffer commandBuffer,
- VkSubpassContents contents) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-}
-
-@threadSafety("app")
-cmd void vkCmdEndRenderPass(
- VkCommandBuffer commandBuffer) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
-}
-
-cmd void vkCmdExecuteCommands(
- VkCommandBuffer commandBuffer,
- u32 commandBufferCount,
- const VkCommandBuffer* pCommandBuffers) {
- commandBufferObject := GetCommandBuffer(commandBuffer)
-
- commandBuffers := pCommandBuffers[0:commandBufferCount]
- for i in (0 .. commandBufferCount) {
- secondaryCommandBuffer := commandBuffers[i]
- secondaryCommandBufferObject := GetCommandBuffer(secondaryCommandBuffer)
- assert(commandBufferObject.device == secondaryCommandBufferObject.device)
- }
-}
-
-//@vulkan1_1 functions
-
-@vulkan1_1
-cmd VkResult vkEnumerateInstanceVersion(
- u32* pApiVersion) {
- return ?
-}
-
-@vulkan1_1
-cmd VkResult vkBindBufferMemory2(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindBufferMemoryInfo* pBindInfos) {
- return ?
-}
-
-@vulkan1_1
-cmd VkResult vkBindImageMemory2(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindImageMemoryInfo* pBindInfos) {
- return ?
-}
-
-@vulkan1_1
-cmd void vkGetDeviceGroupPeerMemoryFeatures(
- VkDevice device,
- u32 heapIndex,
- u32 localDeviceIndex,
- u32 remoteDeviceIndex,
- VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
-}
-
-@vulkan1_1
-cmd void vkCmdSetDeviceMask(
- VkCommandBuffer commandBuffer,
- u32 deviceMask) {
-}
-
-@vulkan1_1
-cmd void vkCmdDispatchBase(
- VkCommandBuffer commandBuffer,
- u32 baseGroupX,
- u32 baseGroupY,
- u32 baseGroupZ,
- u32 groupCountX,
- u32 groupCountY,
- u32 groupCountZ) {
-}
-
-@threadSafety("system")
-@vulkan1_1
-cmd VkResult vkEnumeratePhysicalDeviceGroups(
- VkInstance instance,
- u32* pPhysicalDeviceGroupCount,
- VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
- instanceObject := GetInstance(instance)
-
- physicalDeviceGroupCount := as!u32(?)
- pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount
- physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount]
-
- for i in (0 .. physicalDeviceGroupCount) {
- physicalDevice := ?
- physicalDevices[i] = physicalDevice
- if !(physicalDevice in State.PhysicalDevices) {
- State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
- }
- }
-
- return ?
-}
-
-@vulkan1_1
-cmd void vkGetImageMemoryRequirements2(
- VkDevice device,
- const VkImageMemoryRequirementsInfo2* pInfo,
- VkMemoryRequirements2* pMemoryRequirements) {
-}
-
-@vulkan1_1
-cmd void vkGetBufferMemoryRequirements2(
- VkDevice device,
- const VkBufferMemoryRequirementsInfo2* pInfo,
- VkMemoryRequirements2* pMemoryRequirements) {
-}
-
-@vulkan1_1
-cmd void vkGetImageSparseMemoryRequirements2(
- VkDevice device,
- const VkImageSparseMemoryRequirementsInfo2* pInfo,
- u32* pSparseMemoryRequirementCount,
- VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceFeatures2(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceFeatures2* pFeatures) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceProperties2(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties2* pProperties) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceFormatProperties2(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkFormatProperties2* pFormatProperties) {
-}
-
-@vulkan1_1
-cmd VkResult vkGetPhysicalDeviceImageFormatProperties2(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo,
- VkImageFormatProperties2* pImageFormatProperties) {
- return ?
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceQueueFamilyProperties2(
- VkPhysicalDevice physicalDevice,
- u32* pQueueFamilyPropertyCount,
- VkQueueFamilyProperties2* pQueueFamilyProperties) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceMemoryProperties2(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceSparseImageFormatProperties2(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo,
- u32* pPropertyCount,
- VkSparseImageFormatProperties2* pProperties) {
-}
-
-@vulkan1_1
-cmd void vkTrimCommandPool(
- VkDevice device,
- VkCommandPool commandPool,
- VkCommandPoolTrimFlags flags) {
-}
-
-
-@vulkan1_1
-cmd void vkGetDeviceQueue2(
- VkDevice device,
- const VkDeviceQueueInfo2* pQueueInfo,
- VkQueue* pQueue) {
- deviceObject := GetDevice(device)
-
- queue := ?
- pQueue[0] = queue
-
- if !(queue in State.Queues) {
- State.Queues[queue] = new!QueueObject(device: device)
- }
-}
-
-@vulkan1_1
-cmd VkResult vkCreateSamplerYcbcrConversion(
- VkDevice device,
- const VkSamplerYcbcrConversionCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSamplerYcbcrConversion* pYcbcrConversion) {
- return ?
-}
-
-@vulkan1_1
-cmd void vkDestroySamplerYcbcrConversion(
- VkDevice device,
- VkSamplerYcbcrConversion ycbcrConversion,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@vulkan1_1
-cmd VkResult vkCreateDescriptorUpdateTemplate(
- VkDevice device,
- const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
- return ?
-}
-
-@vulkan1_1
-cmd void vkDestroyDescriptorUpdateTemplate(
- VkDevice device,
- VkDescriptorUpdateTemplate descriptorUpdateTemplate,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@vulkan1_1
-cmd void vkUpdateDescriptorSetWithTemplate(
- VkDevice device,
- VkDescriptorSet descriptorSet,
- VkDescriptorUpdateTemplate descriptorUpdateTemplate,
- const void* pData) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceExternalBufferProperties(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo,
- VkExternalBufferProperties* pExternalBufferProperties) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceExternalFenceProperties(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo,
- VkExternalFenceProperties* pExternalFenceProperties) {
-}
-
-@vulkan1_1
-cmd void vkGetPhysicalDeviceExternalSemaphoreProperties(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo,
- VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
-}
-
-@vulkan1_1
-cmd void vkGetDescriptorSetLayoutSupport(
- VkDevice device,
- const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
- VkDescriptorSetLayoutSupport* pSupport) {
-}
-
-
-@extension("VK_KHR_surface") // 1
-cmd void vkDestroySurfaceKHR(
- VkInstance instance,
- VkSurfaceKHR surface,
- const VkAllocationCallbacks* pAllocator) {
- instanceObject := GetInstance(instance)
- surfaceObject := GetSurface(surface)
- assert(surfaceObject.instance == instance)
-
- State.Surfaces[surface] = null
-}
-
-@extension("VK_KHR_surface") // 1
-cmd VkResult vkGetPhysicalDeviceSurfaceSupportKHR(
- VkPhysicalDevice physicalDevice,
- u32 queueFamilyIndex,
- VkSurfaceKHR surface,
- VkBool32* pSupported) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- return ?
-}
-
-@extension("VK_KHR_surface") // 1
-cmd VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- VkSurfaceCapabilitiesKHR* pSurfaceCapabilities) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- surfaceCapabilities := ?
- pSurfaceCapabilities[0] = surfaceCapabilities
-
- return ?
-}
-
-@extension("VK_KHR_surface") // 1
-cmd VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- u32* pSurfaceFormatCount,
- VkSurfaceFormatKHR* pSurfaceFormats) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- count := as!u32(?)
- pSurfaceFormatCount[0] = count
- surfaceFormats := pSurfaceFormats[0:count]
-
- for i in (0 .. count) {
- surfaceFormat := ?
- surfaceFormats[i] = surfaceFormat
- }
-
- return ?
-}
-
-@extension("VK_KHR_surface") // 1
-cmd VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- u32* pPresentModeCount,
- VkPresentModeKHR* pPresentModes) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
-
- count := as!u32(?)
- pPresentModeCount[0] = count
- presentModes := pPresentModes[0:count]
-
- for i in (0 .. count) {
- presentMode := ?
- presentModes[i] = presentMode
- }
-
- return ?
-}
-
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkCreateSwapchainKHR(
- VkDevice device,
- const VkSwapchainCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSwapchainKHR* pSwapchain) {
- assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR)
- deviceObject := GetDevice(device)
-
- swapchain := ?
- pSwapchain[0] = swapchain
- State.Swapchains[swapchain] = new!SwapchainObject(device: device)
-
- return ?
-}
-
-@extension("VK_KHR_swapchain") // 2
-cmd void vkDestroySwapchainKHR(
- VkDevice device,
- VkSwapchainKHR swapchain,
- const VkAllocationCallbacks* pAllocator) {
- deviceObject := GetDevice(device)
- swapchainObject := GetSwapchain(swapchain)
- assert(swapchainObject.device == device)
-
- State.Swapchains[swapchain] = null
-}
-
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkGetSwapchainImagesKHR(
- VkDevice device,
- VkSwapchainKHR swapchain,
- u32* pSwapchainImageCount,
- VkImage* pSwapchainImages) {
- deviceObject := GetDevice(device)
-
- count := as!u32(?)
- pSwapchainImageCount[0] = count
- swapchainImages := pSwapchainImages[0:count]
-
- for i in (0 .. count) {
- swapchainImage := ?
- swapchainImages[i] = swapchainImage
- State.Images[swapchainImage] = new!ImageObject(device: device)
- }
-
- return ?
-}
-
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkAcquireNextImageKHR(
- VkDevice device,
- VkSwapchainKHR swapchain,
- u64 timeout,
- VkSemaphore semaphore,
- VkFence fence,
- u32* pImageIndex) {
- deviceObject := GetDevice(device)
- swapchainObject := GetSwapchain(swapchain)
-
- imageIndex := ?
- pImageIndex[0] = imageIndex
-
- return ?
-}
-
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkQueuePresentKHR(
- VkQueue queue,
- const VkPresentInfoKHR* pPresentInfo) {
- queueObject := GetQueue(queue)
-
- presentInfo := ?
- pPresentInfo[0] = presentInfo
-
- return ?
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkGetDeviceGroupPresentCapabilitiesKHR(
- VkDevice device,
- VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
- return ?
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkGetDeviceGroupSurfacePresentModesKHR(
- VkDevice device,
- VkSurfaceKHR surface,
- VkDeviceGroupPresentModeFlagsKHR* pModes) {
- return ?
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkGetPhysicalDevicePresentRectanglesKHR(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- u32* pRectCount,
- VkRect2D* pRects) {
- return ?
-}
-
-@vulkan1_1
-@extension("VK_KHR_swapchain") // 2
-cmd VkResult vkAcquireNextImage2KHR(
- VkDevice device,
- const VkAcquireNextImageInfoKHR* pAcquireInfo,
- u32* pImageIndex) {
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR(
- VkPhysicalDevice physicalDevice,
- u32* pPropertyCount,
- VkDisplayPropertiesKHR* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
- VkPhysicalDevice physicalDevice,
- u32* pPropertyCount,
- VkDisplayPlanePropertiesKHR* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkGetDisplayPlaneSupportedDisplaysKHR(
- VkPhysicalDevice physicalDevice,
- u32 planeIndex,
- u32* pDisplayCount,
- VkDisplayKHR* pDisplays) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkGetDisplayModePropertiesKHR(
- VkPhysicalDevice physicalDevice,
- VkDisplayKHR display,
- u32* pPropertyCount,
- VkDisplayModePropertiesKHR* pProperties) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkCreateDisplayModeKHR(
- VkPhysicalDevice physicalDevice,
- VkDisplayKHR display,
- const VkDisplayModeCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDisplayModeKHR* pMode) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkGetDisplayPlaneCapabilitiesKHR(
- VkPhysicalDevice physicalDevice,
- VkDisplayModeKHR mode,
- u32 planeIndex,
- VkDisplayPlaneCapabilitiesKHR* pCapabilities) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_display") // 3
-cmd VkResult vkCreateDisplayPlaneSurfaceKHR(
- VkInstance instance,
- const VkDisplaySurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- return ?
-}
-
-@extension("VK_KHR_display_swapchain") // 4
-cmd VkResult vkCreateSharedSwapchainsKHR(
- VkDevice device,
- u32 swapchainCount,
- const VkSwapchainCreateInfoKHR* pCreateInfos,
- const VkAllocationCallbacks* pAllocator,
- VkSwapchainKHR* pSwapchains) {
- return ?
-}
-
-@extension("VK_KHR_xlib_surface") // 5
-cmd VkResult vkCreateXlibSurfaceKHR(
- VkInstance instance,
- const VkXlibSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- instanceObject := GetInstance(instance)
- return ?
-}
-
-@extension("VK_KHR_xlib_surface") // 5
-cmd VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR(
- VkPhysicalDevice physicalDevice,
- u32 queueFamilyIndex,
- platform.Display* dpy,
- platform.VisualID visualID) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_xcb_surface") // 6
-cmd VkResult vkCreateXcbSurfaceKHR(
- VkInstance instance,
- const VkXcbSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- instanceObject := GetInstance(instance)
- return ?
-}
-
-@extension("VK_KHR_xcb_surface") // 6
-cmd VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR(
- VkPhysicalDevice physicalDevice,
- u32 queueFamilyIndex,
- platform.xcb_connection_t* connection,
- platform.xcb_visualid_t visual_id) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_wayland_surface") // 7
-cmd VkResult vkCreateWaylandSurfaceKHR(
- VkInstance instance,
- const VkWaylandSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- instanceObject := GetInstance(instance)
- return ?
-}
-
-@extension("VK_KHR_wayland_surface") // 7
-cmd VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR(
- VkPhysicalDevice physicalDevice,
- u32 queueFamilyIndex,
- platform.wl_display* display) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_KHR_android_surface") // 9
-cmd VkResult vkCreateAndroidSurfaceKHR(
- VkInstance instance,
- const VkAndroidSurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- instanceObject := GetInstance(instance)
- return ?
-}
-
-@extension("VK_KHR_win32_surface") // 10
-cmd VkResult vkCreateWin32SurfaceKHR(
- VkInstance instance,
- const VkWin32SurfaceCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- instanceObject := GetInstance(instance)
- return ?
-}
-
-@extension("VK_KHR_win32_surface") // 10
-cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR(
- VkPhysicalDevice physicalDevice,
- u32 queueFamilyIndex) {
- physicalDeviceObject := GetPhysicalDevice(physicalDevice)
- return ?
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-@optional
-cmd VkResult vkGetSwapchainGrallocUsageANDROID(
- VkDevice device,
- VkFormat format,
- VkImageUsageFlags imageUsage,
- s32* grallocUsage) {
- return ?
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-@optional
-cmd VkResult vkGetSwapchainGrallocUsage2ANDROID(
- VkDevice device,
- VkFormat format,
- VkImageUsageFlags imageUsage,
- VkSwapchainImageUsageFlagsANDROID swapchainImageUsage,
- u64* grallocConsumerUsage,
- u64* grallocProducerUsage) {
- return ?
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-cmd VkResult vkAcquireImageANDROID(
- VkDevice device,
- VkImage image,
- int nativeFenceFd,
- VkSemaphore semaphore,
- VkFence fence) {
- return ?
-}
-
-@extension("VK_ANDROID_native_buffer") // 11
-cmd VkResult vkQueueSignalReleaseImageANDROID(
- VkQueue queue,
- u32 waitSemaphoreCount,
- const VkSemaphore* pWaitSemaphores,
- VkImage image,
- int* pNativeFenceFd) {
- return ?
-}
-
-@extension("VK_EXT_debug_report") // 12
-@external type void* PFN_vkDebugReportCallbackEXT
-@extension("VK_EXT_debug_report") // 12
-@pfn cmd VkBool32 vkDebugReportCallbackEXT(
- VkDebugReportFlagsEXT flags,
- VkDebugReportObjectTypeEXT objectType,
- u64 object,
- platform.size_t location,
- s32 messageCode,
- const char* pLayerPrefix,
- const char* pMessage,
- void* pUserData) {
- return ?
-}
-
-@extension("VK_EXT_debug_report") // 12
-cmd VkResult vkCreateDebugReportCallbackEXT(
- VkInstance instance,
- const VkDebugReportCallbackCreateInfoEXT* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDebugReportCallbackEXT* pCallback) {
- return ?
-}
-
-@extension("VK_EXT_debug_report") // 12
-cmd void vkDestroyDebugReportCallbackEXT(
- VkInstance instance,
- VkDebugReportCallbackEXT callback,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_EXT_debug_report") // 12
-cmd void vkDebugReportMessageEXT(
- VkInstance instance,
- VkDebugReportFlagsEXT flags,
- VkDebugReportObjectTypeEXT objectType,
- u64 object,
- platform.size_t location,
- s32 messageCode,
- const char* pLayerPrefix,
- const char* pMessage) {
-}
-
-@extension("VK_EXT_debug_marker") // 23
-cmd VkResult vkDebugMarkerSetObjectTagEXT(
- VkDevice device,
- const VkDebugMarkerObjectTagInfoEXT* pTagInfo) {
- return ?
-}
-
-@extension("VK_EXT_debug_marker") // 23
-cmd VkResult vkDebugMarkerSetObjectNameEXT(
- VkDevice device,
- const VkDebugMarkerObjectNameInfoEXT* pNameInfo) {
- return ?
-}
-
-@extension("VK_EXT_debug_marker") // 23
-cmd void vkCmdDebugMarkerBeginEXT(
- VkCommandBuffer commandBuffer,
- const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
-}
-
-@extension("VK_EXT_debug_marker") // 23
-cmd void vkCmdDebugMarkerEndEXT(
- VkCommandBuffer commandBuffer) {
-}
-
-@extension("VK_EXT_debug_marker") // 23
-cmd void vkCmdDebugMarkerInsertEXT(
- VkCommandBuffer commandBuffer,
- const VkDebugMarkerMarkerInfoEXT* pMarkerInfo) {
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-cmd void vkCmdBindTransformFeedbackBuffersEXT(
- VkCommandBuffer commandBuffer,
- u32 firstBinding,
- u32 bindingCount,
- const VkBuffer* pBuffers,
- const VkDeviceSize* pOffsets,
- const VkDeviceSize* pSizes) {
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-cmd void vkCmdBeginTransformFeedbackEXT(
- VkCommandBuffer commandBuffer,
- u32 firstCounterBuffer,
- u32 counterBufferCount,
- const VkBuffer* pCounterBuffers,
- const VkDeviceSize* pCounterBufferOffsets) {
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-cmd void vkCmdEndTransformFeedbackEXT(
- VkCommandBuffer commandBuffer,
- u32 firstCounterBuffer,
- u32 counterBufferCount,
- const VkBuffer* pCounterBuffers,
- const VkDeviceSize* pCounterBufferOffsets) {
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-cmd void vkCmdBeginQueryIndexedEXT(
- VkCommandBuffer commandBuffer,
- VkQueryPool queryPool,
- u32 query,
- VkQueryControlFlags flags,
- u32 index) {
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-cmd void vkCmdEndQueryIndexedEXT(
- VkCommandBuffer commandBuffer,
- VkQueryPool queryPool,
- u32 query,
- u32 index) {
-}
-
-@extension("VK_EXT_transform_feedback") // 29
-cmd void vkCmdDrawIndirectByteCountEXT(
- VkCommandBuffer commandBuffer,
- u32 instanceCount,
- u32 firstInstance,
- VkBuffer counterBuffer,
- VkDeviceSize counterBufferOffset,
- u32 counterOffset,
- u32 vertexStride) {
-}
-
-@extension("VK_AMD_draw_indirect_count") // 34
-cmd void vkCmdDrawIndirectCountAMD(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_AMD_draw_indirect_count") // 34
-cmd void vkCmdDrawIndexedIndirectCountAMD(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_AMD_shader_info") // 43
-cmd VkResult vkGetShaderInfoAMD(
- VkDevice device,
- VkPipeline pipeline,
- VkShaderStageFlagBits shaderStage,
- VkShaderInfoTypeAMD infoType,
- platform.size_t* pInfoSize,
- void* pInfo) {
- return ?
-}
-
-@extension("VK_NV_external_memory_capabilities") // 56
-cmd VkResult vkGetPhysicalDeviceExternalImageFormatPropertiesNV(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkImageType type,
- VkImageTiling tiling,
- VkImageUsageFlags usage,
- VkImageCreateFlags flags,
- VkExternalMemoryHandleTypeFlagsNV externalHandleType,
- VkExternalImageFormatPropertiesNV* pExternalImageFormatProperties) {
- return ?
-}
-
-@extension("VK_NV_external_memory_win32") // 58
-cmd VkResult vkGetMemoryWin32HandleNV(
- VkDevice device,
- VkDeviceMemory memory,
- VkExternalMemoryHandleTypeFlagsNV handleType,
- platform.HANDLE* pHandle) {
- return ?
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd void vkGetPhysicalDeviceFeatures2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceFeatures2KHR* pFeatures) {
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd void vkGetPhysicalDeviceProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceProperties2KHR* pProperties) {
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd void vkGetPhysicalDeviceFormatProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkFormat format,
- VkFormatProperties2KHR* pFormatProperties) {
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd VkResult vkGetPhysicalDeviceImageFormatProperties2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo,
- VkImageFormatProperties2KHR* pImageFormatProperties) {
- return ?
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd void vkGetPhysicalDeviceQueueFamilyProperties2KHR(
- VkPhysicalDevice physicalDevice,
- u32* pQueueFamilyPropertyCount,
- VkQueueFamilyProperties2KHR* pQueueFamilyProperties) {
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd void vkGetPhysicalDeviceMemoryProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties) {
-}
-
-@extension("VK_KHR_get_physical_device_properties2") // 60
-cmd void vkGetPhysicalDeviceSparseImageFormatProperties2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo,
- u32* pPropertyCount,
- VkSparseImageFormatProperties2KHR* pProperties) {
-}
-
-@extension("VK_KHR_device_group") // 61
-cmd void vkGetDeviceGroupPeerMemoryFeaturesKHR(
- VkDevice device,
- u32 heapIndex,
- u32 localDeviceIndex,
- u32 remoteDeviceIndex,
- VkPeerMemoryFeatureFlagsKHR* pPeerMemoryFeatures) {
-}
-
-@extension("VK_KHR_device_group") // 61
-cmd void vkCmdSetDeviceMaskKHR(
- VkCommandBuffer commandBuffer,
- u32 deviceMask) {
-}
-
-
-@extension("VK_KHR_device_group") // 61
-cmd void vkCmdDispatchBaseKHR(
- VkCommandBuffer commandBuffer,
- u32 baseGroupX,
- u32 baseGroupY,
- u32 baseGroupZ,
- u32 groupCountX,
- u32 groupCountY,
- u32 groupCountZ) {
-}
-
-@extension("VK_NN_vi_surface") // 63
-cmd VkResult vkCreateViSurfaceNN(
- VkInstance instance,
- const VkViSurfaceCreateInfoNN* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- return ?
-}
-
-@extension("VK_KHR_maintenance1") // 70
-cmd void vkTrimCommandPoolKHR(
- VkDevice device,
- VkCommandPool commandPool,
- VkCommandPoolTrimFlagsKHR flags) {
-}
-
-@extension("VK_KHR_device_group_creation") // 71
-@threadSafety("system")
-cmd VkResult vkEnumeratePhysicalDeviceGroupsKHR(
- VkInstance instance,
- u32* pPhysicalDeviceGroupCount,
- VkPhysicalDeviceGroupPropertiesKHR* pPhysicalDeviceGroupProperties) {
- instanceObject := GetInstance(instance)
-
- physicalDeviceGroupCount := as!u32(?)
- pPhysicalDeviceGroupCount[0] = physicalDeviceGroupCount
- physicalDevices := pPhysicalDeviceGroupProperties[0:physicalDeviceGroupCount]
-
- for i in (0 .. physicalDeviceGroupCount) {
- physicalDevice := ?
- physicalDevices[i] = physicalDevice
- if !(physicalDevice in State.PhysicalDevices) {
- State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
- }
- }
-
- return ?
-}
-
-@extension("VK_KHR_external_memory_capabilities") // 72
-cmd void vkGetPhysicalDeviceExternalBufferPropertiesKHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalBufferInfoKHR* pExternalBufferInfo,
- VkExternalBufferPropertiesKHR* pExternalBufferProperties) {
-}
-
-@extension("VK_KHR_external_memory_win32") // 74
-cmd VkResult vkGetMemoryWin32HandleKHR(
- VkDevice device,
- const VkMemoryGetWin32HandleInfoKHR* pGetWin32HandleInfo,
- platform.HANDLE* pHandle) {
- return ?
-}
-
-@extension("VK_KHR_external_memory_win32") // 74
-cmd VkResult vkGetMemoryWin32HandlePropertiesKHR(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHR handleType,
- platform.HANDLE handle,
- VkMemoryWin32HandlePropertiesKHR* pMemoryWin32HandleProperties) {
- return ?
-}
-
-@extension("VK_KHR_external_memory_fd") // 75
-cmd VkResult vkGetMemoryFdKHR(
- VkDevice device,
- const VkMemoryGetFdInfoKHR* pGetFdInfo,
- s32* pFd) {
- return ?
-}
-
-@extension("VK_KHR_external_memory_fd") // 75
-cmd VkResult vkGetMemoryFdPropertiesKHR(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBitsKHR handleType,
- s32 fd,
- VkMemoryFdPropertiesKHR* pMemoryFdProperties) {
- return ?
-}
-
-@extension("VK_KHR_external_semaphore_capabilities") // 77
-cmd void vkGetPhysicalDeviceExternalSemaphorePropertiesKHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalSemaphoreInfoKHR* pExternalSemaphoreInfo,
- VkExternalSemaphorePropertiesKHR* pExternalSemaphoreProperties) {
-}
-
-@extension("VK_KHR_external_semaphore_win32") // 79
-cmd VkResult vkImportSemaphoreWin32HandleKHR(
- VkDevice device,
- const VkImportSemaphoreWin32HandleInfoKHR* pImportSemaphoreWin32HandleInfo) {
- return ?
-}
-
-@extension("VK_KHR_external_semaphore_win32") // 79
-cmd VkResult vkGetSemaphoreWin32HandleKHR(
- VkDevice device,
- const VkSemaphoreGetWin32HandleInfoKHR* pGetWin32HandleInfo,
- platform.HANDLE* pHandle) {
- return ?
-}
-
-@extension("VK_KHR_external_semaphore_fd") // 80
-cmd VkResult vkImportSemaphoreFdKHR(
- VkDevice device,
- const VkImportSemaphoreFdInfoKHR* pImportSemaphoreFdInfo) {
- return ?
-}
-
-@extension("VK_KHR_external_semaphore_fd") // 80
-cmd VkResult vkGetSemaphoreFdKHR(
- VkDevice device,
- const VkSemaphoreGetFdInfoKHR* pGetFdInfo,
- s32* pFd) {
- return ?
-}
-
-@extension("VK_KHR_push_descriptor") // 81
-cmd void vkCmdPushDescriptorSetKHR(
- VkCommandBuffer commandBuffer,
- VkPipelineBindPoint pipelineBindPoint,
- VkPipelineLayout layout,
- u32 set,
- u32 descriptorWriteCount,
- const VkWriteDescriptorSet* pDescriptorWrites) {
-}
-
-@extension("VK_EXT_conditional_rendering") // 82
-cmd void vkCmdBeginConditionalRenderingEXT(
- VkCommandBuffer commandBuffer,
- const VkConditionalRenderingBeginInfoEXT* pConditionalRenderingBegin) {
-}
-
-@extension("VK_EXT_conditional_rendering") // 82
-cmd void vkCmdEndConditionalRenderingEXT(
- VkCommandBuffer commandBuffer) {
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-cmd VkResult vkCreateDescriptorUpdateTemplateKHR(
- VkDevice device,
- const VkDescriptorUpdateTemplateCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDescriptorUpdateTemplateKHR* pDescriptorUpdateTemplate) {
- return ?
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-cmd void vkDestroyDescriptorUpdateTemplateKHR(
- VkDevice device,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-cmd void vkUpdateDescriptorSetWithTemplateKHR(
- VkDevice device,
- VkDescriptorSet descriptorSet,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
- const void* pData) {
-}
-
-@extension("VK_KHR_descriptor_update_template") // 86
-cmd void vkCmdPushDescriptorSetWithTemplateKHR(
- VkCommandBuffer commandBuffer,
- VkDescriptorUpdateTemplateKHR descriptorUpdateTemplate,
- VkPipelineLayout layout,
- u32 set,
- const void* pData) {
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd void vkCmdProcessCommandsNVX(
- VkCommandBuffer commandBuffer,
- const VkCmdProcessCommandsInfoNVX* pProcessCommandsInfo) {
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd void vkCmdReserveSpaceForCommandsNVX(
- VkCommandBuffer commandBuffer,
- const VkCmdReserveSpaceForCommandsInfoNVX* pReserveSpaceInfo) {
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd VkResult vkCreateIndirectCommandsLayoutNVX(
- VkDevice device,
- const VkIndirectCommandsLayoutCreateInfoNVX* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkIndirectCommandsLayoutNVX* pIndirectCommandsLayout) {
- return ?
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd void vkDestroyIndirectCommandsLayoutNVX(
- VkDevice device,
- VkIndirectCommandsLayoutNVX indirectCommandsLayout,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd VkResult vkCreateObjectTableNVX(
- VkDevice device,
- const VkObjectTableCreateInfoNVX* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkObjectTableNVX* pObjectTable) {
- return ?
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd void vkDestroyObjectTableNVX(
- VkDevice device,
- VkObjectTableNVX objectTable,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd VkResult vkRegisterObjectsNVX(
- VkDevice device,
- VkObjectTableNVX objectTable,
- u32 objectCount,
- const VkObjectTableEntryNVX* const* ppObjectTableEntries,
- const u32* pObjectIndices) {
- return ?
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd VkResult vkUnregisterObjectsNVX(
- VkDevice device,
- VkObjectTableNVX objectTable,
- u32 objectCount,
- const VkObjectEntryTypeNVX* pObjectEntryTypes,
- const u32* pObjectIndices) {
- return ?
-}
-
-@extension("VK_NVX_device_generated_commands") // 87
-cmd void vkGetPhysicalDeviceGeneratedCommandsPropertiesNVX(
- VkPhysicalDevice physicalDevice,
- VkDeviceGeneratedCommandsFeaturesNVX* pFeatures,
- VkDeviceGeneratedCommandsLimitsNVX* pLimits) {
-}
-
-@extension("VK_NV_clip_space_w_scaling") // 88
-cmd void vkCmdSetViewportWScalingNV(
- VkCommandBuffer commandBuffer,
- u32 firstViewport,
- u32 viewportCount,
- const VkViewportWScalingNV* pViewportWScalings) {
-}
-
-@extension("VK_EXT_direct_mode_display") // 89
-cmd VkResult vkReleaseDisplayEXT(
- VkPhysicalDevice physicalDevice,
- VkDisplayKHR display) {
- return ?
-}
-
-@extension("VK_EXT_acquire_xlib_display") // 90
-cmd VkResult vkAcquireXlibDisplayEXT(
- VkPhysicalDevice physicalDevice,
- platform.Display* dpy,
- VkDisplayKHR display) {
- return ?
-}
-
-@extension("VK_EXT_acquire_xlib_display") // 90
-cmd VkResult vkGetRandROutputDisplayEXT(
- VkPhysicalDevice physicalDevice,
- platform.Display* dpy,
- platform.RROutput rrOutput,
- VkDisplayKHR* pDisplay) {
- return ?
-}
-
-@extension("VK_EXT_display_surface_counter") // 91
-cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2EXT(
- VkPhysicalDevice physicalDevice,
- VkSurfaceKHR surface,
- VkSurfaceCapabilities2EXT* pSurfaceCapabilities) {
- return ?
-}
-
-@extension("VK_EXT_display_control") // 92
-cmd VkResult vkDisplayPowerControlEXT(
- VkDevice device,
- VkDisplayKHR display,
- const VkDisplayPowerInfoEXT* pDisplayPowerInfo) {
- return ?
-}
-
-@extension("VK_EXT_display_control") // 92
-cmd VkResult vkRegisterDeviceEventEXT(
- VkDevice device,
- const VkDeviceEventInfoEXT* pDeviceEventInfo,
- const VkAllocationCallbacks* pAllocator,
- VkFence* pFence) {
- return ?
-}
-
-@extension("VK_EXT_display_control") // 92
-cmd VkResult vkRegisterDisplayEventEXT(
- VkDevice device,
- VkDisplayKHR display,
- const VkDisplayEventInfoEXT* pDisplayEventInfo,
- const VkAllocationCallbacks* pAllocator,
- VkFence* pFence) {
- return ?
-}
-
-@extension("VK_EXT_display_control") // 92
-cmd VkResult vkGetSwapchainCounterEXT(
- VkDevice device,
- VkSwapchainKHR swapchain,
- VkSurfaceCounterFlagBitsEXT counter,
- u64* pCounterValue) {
- return ?
-}
-
-@extension("VK_GOOGLE_display_timing") // 93
-cmd VkResult vkGetRefreshCycleDurationGOOGLE(
- VkDevice device,
- VkSwapchainKHR swapchain,
- VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
- deviceObject := GetDevice(device)
- swapchainObject := GetSwapchain(swapchain)
-
- displayTimingProperties := ?
- pDisplayTimingProperties[0] = displayTimingProperties
-
- return ?
-}
-
-@extension("VK_GOOGLE_display_timing") // 93
-cmd VkResult vkGetPastPresentationTimingGOOGLE(
- VkDevice device,
- VkSwapchainKHR swapchain,
- u32* pPresentationTimingCount,
- VkPastPresentationTimingGOOGLE* pPresentationTimings) {
- return ?
-}
-
-@extension("VK_EXT_discard_rectangles") // 100
-cmd void vkCmdSetDiscardRectangleEXT(
- VkCommandBuffer commandBuffer,
- u32 firstDiscardRectangle,
- u32 discardRectangleCount,
- const VkRect2D* pDiscardRectangles) {
-}
-
-@extension("VK_EXT_hdr_metadata") // 106
-cmd void vkSetHdrMetadataEXT(
- VkDevice device,
- u32 swapchainCount,
- const VkSwapchainKHR* pSwapchains,
- const VkHdrMetadataEXT* pMetadata) {
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-cmd VkResult vkCreateRenderPass2KHR(
- VkDevice device,
- const VkRenderPassCreateInfo2KHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkRenderPass* pRenderPass) {
- return ?
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-cmd void vkCmdBeginRenderPass2KHR(
- VkCommandBuffer commandBuffer,
- const VkRenderPassBeginInfo* pRenderPassBegin,
- const VkSubpassBeginInfoKHR* pSubpassBeginInfo) {
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-cmd void vkCmdNextSubpass2KHR(
- VkCommandBuffer commandBuffer,
- const VkSubpassBeginInfoKHR* pSubpassBeginInfo,
- const VkSubpassEndInfoKHR* pSubpassEndInfo) {
-}
-
-@extension("VK_KHR_create_renderpass2") // 110
-cmd void vkCmdEndRenderPass2KHR(
- VkCommandBuffer commandBuffer,
- const VkSubpassEndInfoKHR* pSubpassEndInfo) {
-}
-
-@extension("VK_KHR_shared_presentable_image") // 112
-cmd VkResult vkGetSwapchainStatusKHR(
- VkDevice device,
- VkSwapchainKHR swapchain) {
- return ?
-}
-
-@extension("VK_KHR_external_fence_capabilities") // 113
-cmd void vkGetPhysicalDeviceExternalFencePropertiesKHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceExternalFenceInfoKHR* pExternalFenceInfo,
- VkExternalFencePropertiesKHR* pExternalFenceProperties) {
-}
-
-@extension("VK_KHR_external_fence_win32") // 115
-cmd VkResult vkImportFenceWin32HandleKHR(
- VkDevice device,
- const VkImportFenceWin32HandleInfoKHR* pImportFenceWin32HandleInfo) {
- return ?
-}
-
-@extension("VK_KHR_external_fence_win32") // 115
-cmd VkResult vkGetFenceWin32HandleKHR(
- VkDevice device,
- const VkFenceGetWin32HandleInfoKHR* pGetWin32HandleInfo,
- platform.HANDLE* pHandle) {
- return ?
-}
-
-@extension("VK_KHR_external_fence_fd") // 116
-cmd VkResult vkImportFenceFdKHR(
- VkDevice device,
- const VkImportFenceFdInfoKHR* pImportFenceFdInfo) {
- return ?
-}
-
-@extension("VK_KHR_external_fence_fd") // 116
-cmd VkResult vkGetFenceFdKHR(
- VkDevice device,
- const VkFenceGetFdInfoKHR* pGetFdInfo,
- int* pFd) {
- return ?
-}
-
-@extension("VK_KHR_get_surface_capabilities2") // 120
-cmd VkResult vkGetPhysicalDeviceSurfaceCapabilities2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
- VkSurfaceCapabilities2KHR* pSurfaceCapabilities) {
- return ?
-}
-
-@extension("VK_KHR_get_surface_capabilities2") // 120
-cmd VkResult vkGetPhysicalDeviceSurfaceFormats2KHR(
- VkPhysicalDevice physicalDevice,
- const VkPhysicalDeviceSurfaceInfo2KHR* pSurfaceInfo,
- u32* pSurfaceFormatCount,
- VkSurfaceFormat2KHR* pSurfaceFormats) {
- return ?
-}
-
-@extension("VK_KHR_display_properties2") // 122
-cmd VkResult vkGetPhysicalDeviceDisplayProperties2KHR(
- VkPhysicalDevice physicalDevice,
- u32* pPropertyCount,
- VkDisplayProperties2KHR* pProperties) {
- return ?
-}
-
-@extension("VK_KHR_display_properties2") // 122
-cmd VkResult vkGetPhysicalDeviceDisplayPlaneProperties2KHR(
- VkPhysicalDevice physicalDevice,
- u32* pPropertyCount,
- VkDisplayPlaneProperties2KHR* pProperties) {
- return ?
-}
-
-@extension("VK_KHR_display_properties2") // 122
-cmd VkResult vkGetDisplayModeProperties2KHR(
- VkPhysicalDevice physicalDevice,
- VkDisplayKHR display,
- u32* pPropertyCount,
- VkDisplayModeProperties2KHR* pProperties) {
- return ?
-}
-
-@extension("VK_KHR_display_properties2") // 122
-cmd VkResult vkGetDisplayPlaneCapabilities2KHR(
- VkPhysicalDevice physicalDevice,
- const VkDisplayPlaneInfo2KHR* pDisplayPlaneInfo,
- VkDisplayPlaneCapabilities2KHR* pCapabilities) {
- return ?
-}
-
-@extension("VK_MVK_ios_surface") // 123
-cmd VkResult vkCreateIOSSurfaceMVK(
- VkInstance instance,
- const VkIOSSurfaceCreateInfoMVK* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- return ?
-}
-
-@extension("VK_MVK_macos_surface") // 124
-cmd VkResult vkCreateMacOSSurfaceMVK(
- VkInstance instance,
- const VkMacOSSurfaceCreateInfoMVK* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- return ?
-}
-
-@extension("VK_EXT_debug_utils") // 129
-@external type void* PFN_vkDebugUtilsMessengerCallbackEXT
-@extension("VK_EXT_debug_utils") // 129
-@pfn cmd VkBool32 vkDebugUtilsMessengerCallbackEXT(
- VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
- VkDebugUtilsMessageTypeFlagsEXT messageType,
- const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
- void* pUserData) {
- return ?
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd VkResult vkSetDebugUtilsObjectNameEXT(
- VkDevice device,
- const VkDebugUtilsObjectNameInfoEXT* pNameInfo) {
- return ?
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd VkResult vkSetDebugUtilsObjectTagEXT(
- VkDevice device,
- const VkDebugUtilsObjectTagInfoEXT* pTagInfo) {
- return ?
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkQueueBeginDebugUtilsLabelEXT(
- VkQueue queue,
- const VkDebugUtilsLabelEXT* pLabelInfo) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkQueueEndDebugUtilsLabelEXT(VkQueue queue) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkQueueInsertDebugUtilsLabelEXT(
- VkQueue queue,
- const VkDebugUtilsLabelEXT* pLabelInfo) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkCmdBeginDebugUtilsLabelEXT(
- VkCommandBuffer commandBuffer,
- const VkDebugUtilsLabelEXT* pLabelInfo) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkCmdEndDebugUtilsLabelEXT(VkCommandBuffer commandBuffer) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkCmdInsertDebugUtilsLabelEXT(
- VkCommandBuffer commandBuffer,
- const VkDebugUtilsLabelEXT* pLabelInfo) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd VkResult vkCreateDebugUtilsMessengerEXT(
- VkInstance instance,
- const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkDebugUtilsMessengerEXT* pMessenger) {
- return ?
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkDestroyDebugUtilsMessengerEXT(
- VkInstance instance,
- VkDebugUtilsMessengerEXT messenger,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_EXT_debug_utils") // 129
-cmd void vkSubmitDebugUtilsMessageEXT(
- VkInstance instance,
- VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
- VkDebugUtilsMessageTypeFlagsEXT messageTypes,
- const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData) {
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-@vulkan1_1 // extension requires 1.1, and should become non-optional when 1.1 does
-cmd VkResult vkGetAndroidHardwareBufferPropertiesANDROID(
- VkDevice device,
- const platform.AHardwareBuffer* buffer,
- VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
- return ?
-}
-
-@extension("VK_ANDROID_external_memory_android_hardware_buffer") // 130
-@vulkan1_1 // extension requires 1.1, and should become non-optional when 1.1 does
-cmd VkResult vkGetMemoryAndroidHardwareBufferANDROID(
- VkDevice device,
- const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo,
- platform.AHardwareBuffer** pBuffer) {
- return ?
-}
-
-@extension("VK_EXT_sample_locations") // 144
-cmd void vkCmdSetSampleLocationsEXT(
- VkCommandBuffer commandBuffer,
- const VkSampleLocationsInfoEXT* pSampleLocationsInfo) {
-}
-
-@extension("VK_EXT_sample_locations") // 144
-cmd void vkGetPhysicalDeviceMultisamplePropertiesEXT(
- VkPhysicalDevice physicalDevice,
- VkSampleCountFlagBits samples,
- VkMultisamplePropertiesEXT* pMultisampleProperties) {
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-cmd void vkGetImageMemoryRequirements2KHR(
- VkDevice device,
- const VkImageMemoryRequirementsInfo2KHR* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements) {
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-cmd void vkGetBufferMemoryRequirements2KHR(
- VkDevice device,
- const VkBufferMemoryRequirementsInfo2KHR* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements) {
-}
-
-@extension("VK_KHR_get_memory_requirements2") // 147
-cmd void vkGetImageSparseMemoryRequirements2KHR(
- VkDevice device,
- const VkImageSparseMemoryRequirementsInfo2KHR* pInfo,
- u32* pSparseMemoryRequirementCount,
- VkSparseImageMemoryRequirements2KHR* pSparseMemoryRequirements) {
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-cmd VkResult vkCreateSamplerYcbcrConversionKHR(
- VkDevice device,
- const VkSamplerYcbcrConversionCreateInfoKHR* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSamplerYcbcrConversionKHR* pYcbcrConversion) {
- return ?
-}
-
-@extension("VK_KHR_sampler_ycbcr_conversion") // 157
-cmd void vkDestroySamplerYcbcrConversionKHR(
- VkDevice device,
- VkSamplerYcbcrConversionKHR ycbcrConversion,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_KHR_bind_memory2") // 158
-cmd VkResult vkBindBufferMemory2KHR(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindBufferMemoryInfoKHR* pBindInfos) {
- return ?
-}
-
-@extension("VK_KHR_bind_memory2") // 158
-cmd VkResult vkBindImageMemory2KHR(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindImageMemoryInfoKHR* pBindInfos) {
- return ?
-}
-
-@extension("VK_EXT_image_drm_format_modifier") // 159
-cmd VkResult vkGetImageDrmFormatModifierPropertiesEXT(
- VkDevice device,
- VkImage image,
- VkImageDrmFormatModifierPropertiesEXT* pProperties) {
- return ?
-}
-
-@extension("VK_EXT_validation_cache") // 161
-cmd VkResult vkCreateValidationCacheEXT(
- VkDevice device,
- const VkValidationCacheCreateInfoEXT* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkValidationCacheEXT* pValidationCache) {
- return ?
-}
-
-@extension("VK_EXT_validation_cache") // 161
-cmd void vkDestroyValidationCacheEXT(
- VkDevice device,
- VkValidationCacheEXT validationCache,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_EXT_validation_cache") // 161
-cmd VkResult vkMergeValidationCachesEXT(
- VkDevice device,
- VkValidationCacheEXT dstCache,
- u32 srcCacheCount,
- const VkValidationCacheEXT* pSrcCaches) {
- return ?
-}
-
-@extension("VK_EXT_validation_cache") // 161
-cmd VkResult vkGetValidationCacheDataEXT(
- VkDevice device,
- VkValidationCacheEXT validationCache,
- platform.size_t* pDataSize,
- void* pData) {
- return ?
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-cmd void vkCmdBindShadingRateImageNV(
- VkCommandBuffer commandBuffer,
- VkImageView imageView,
- VkImageLayout imageLayout) {
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-cmd void vkCmdSetViewportShadingRatePaletteNV(
- VkCommandBuffer commandBuffer,
- u32 firstViewport,
- u32 viewportCount,
- const VkShadingRatePaletteNV* pShadingRatePalettes) {
-}
-
-@extension("VK_NV_shading_rate_image") // 165
-cmd void vkCmdSetCoarseSampleOrderNV(
- VkCommandBuffer commandBuffer,
- VkCoarseSampleOrderTypeNV sampleOrderType,
- u32 customSampleOrderCount,
- const VkCoarseSampleOrderCustomNV* pCustomSampleOrders) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd VkResult vkCreateAccelerationStructureNV(
- VkDevice device,
- const VkAccelerationStructureCreateInfoNV* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkAccelerationStructureNV* pAccelerationStructure) {
- return ?
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd void vkDestroyAccelerationStructureNV(
- VkDevice device,
- VkAccelerationStructureNV accelerationStructure,
- const VkAllocationCallbacks* pAllocator) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd void vkGetAccelerationStructureMemoryRequirementsNV(
- VkDevice device,
- const VkAccelerationStructureMemoryRequirementsInfoNV* pInfo,
- VkMemoryRequirements2KHR* pMemoryRequirements) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd VkResult vkBindAccelerationStructureMemoryNV(
- VkDevice device,
- u32 bindInfoCount,
- const VkBindAccelerationStructureMemoryInfoNV* pBindInfos) {
- return ?
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd void vkCmdBuildAccelerationStructureNV(
- VkCommandBuffer commandBuffer,
- const VkAccelerationStructureInfoNV* pInfo,
- VkBuffer instanceData,
- VkDeviceSize instanceOffset,
- VkBool32 update,
- VkAccelerationStructureNV dst,
- VkAccelerationStructureNV src,
- VkBuffer scratch,
- VkDeviceSize scratchOffset) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd void vkCmdCopyAccelerationStructureNV(
- VkCommandBuffer commandBuffer,
- VkAccelerationStructureNV dst,
- VkAccelerationStructureNV src,
- VkCopyAccelerationStructureModeNV mode) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd void vkCmdTraceRaysNV(
- VkCommandBuffer commandBuffer,
- VkBuffer raygenShaderBindingTableBuffer,
- VkDeviceSize raygenShaderBindingOffset,
- VkBuffer missShaderBindingTableBuffer,
- VkDeviceSize missShaderBindingOffset,
- VkDeviceSize missShaderBindingStride,
- VkBuffer hitShaderBindingTableBuffer,
- VkDeviceSize hitShaderBindingOffset,
- VkDeviceSize hitShaderBindingStride,
- VkBuffer callableShaderBindingTableBuffer,
- VkDeviceSize callableShaderBindingOffset,
- VkDeviceSize callableShaderBindingStride,
- u32 width,
- u32 height,
- u32 depth) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd VkResult vkCreateRaytracingPipelinesNV(
- VkDevice device,
- VkPipelineCache pipelineCache,
- u32 createInfoCount,
- const VkRayTracingPipelineCreateInfoNV* pCreateInfos,
- const VkAllocationCallbacks* pAllocator,
- VkPipeline* pPipelines) {
- return ?
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd VkResult vkGetRaytracingShaderHandlesNV(
- VkDevice device,
- VkPipeline pipeline,
- u32 firstGroup,
- u32 groupCount,
- platform.size_t dataSize,
- void* pData) {
- return ?
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd VkResult vkGetAccelerationStructureHandleNV(
- VkDevice device,
- VkAccelerationStructureNV accelerationStructure,
- platform.size_t dataSize,
- void* pData) {
- return ?
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd void vkCmdWriteAccelerationStructurePropertiesNV(
- VkCommandBuffer commandBuffer,
- u32 accelerationStructureCount,
- const VkAccelerationStructureNV* pAccelerationStructures,
- VkQueryType queryType,
- VkQueryPool queryPool,
- u32 firstQuery) {
-}
-
-@extension("VK_NV_ray_tracing") // 166
-cmd VkResult vkCompileDeferredNV(
- VkDevice device,
- VkPipeline pipeline,
- u32 shader) {
- return ?
-}
-
-@extension("VK_KHR_maintenance3") // 169
-cmd void vkGetDescriptorSetLayoutSupportKHR(
- VkDevice device,
- const VkDescriptorSetLayoutCreateInfo* pCreateInfo,
- VkDescriptorSetLayoutSupportKHR* pSupport) {
-}
-
-@extension("VK_KHR_draw_indirect_count") // 170
-cmd void vkCmdDrawIndirectCountKHR(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_KHR_draw_indirect_count") // 170
-cmd void vkCmdDrawIndexedIndirectCountKHR(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_EXT_external_memory_host") // 179
-cmd VkResult vkGetMemoryHostPointerPropertiesEXT(
- VkDevice device,
- VkExternalMemoryHandleTypeFlagBits handleType,
- const void* pHostPointer,
- VkMemoryHostPointerPropertiesEXT* pMemoryHostPointerProperties) {
- return ?
-}
-
-@extension("VK_AMD_buffer_marker") // 180
-cmd void vkCmdWriteBufferMarkerAMD(
- VkCommandBuffer commandBuffer,
- VkPipelineStageFlagBits pipelineStage,
- VkBuffer dstBuffer,
- VkDeviceSize dstOffset,
- u32 marker) {
-}
-
-@extension("VK_EXT_calibrated_timestamps") // 185
-cmd VkResult vkGetPhysicalDeviceCalibrateableTimeDomainsEXT(
- VkPhysicalDevice physicalDevice,
- u32* pTimeDomainCount,
- VkTimeDomainEXT* pTimeDomains) {
- return ?
-}
-
-@extension("VK_EXT_calibrated_timestamps") // 185
-cmd VkResult vkGetCalibratedTimestampsEXT(
- VkDevice device,
- u32 timestampCount,
- const VkCalibratedTimestampInfoEXT* pTimestampInfos,
- u64* pTimestamps,
- u64* pMaxDeviation) {
- return ?
-}
-
-@extension("VK_NV_mesh_shader") // 203
-cmd void vkCmdDrawMeshTasksNV(
- VkCommandBuffer commandBuffer,
- u32 taskCount,
- u32 firstTask) {
-}
-
-@extension("VK_NV_mesh_shader") // 203
-cmd void vkCmdDrawMeshTasksIndirectNV(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- u32 drawCount,
- u32 stride) {
-}
-
-@extension("VK_NV_mesh_shader") // 203
-cmd void vkCmdDrawMeshTasksIndirectCountNV(
- VkCommandBuffer commandBuffer,
- VkBuffer buffer,
- VkDeviceSize offset,
- VkBuffer countBuffer,
- VkDeviceSize countBufferOffset,
- u32 maxDrawCount,
- u32 stride) {
-}
-
-@extension("VK_NV_scissor_exclusive") // 206
-cmd void vkCmdSetExclusiveScissorNV(
- VkCommandBuffer commandBuffer,
- u32 firstExclusiveScissor,
- u32 exclusiveScissorCount,
- const VkRect2D* pExclusiveScissors) {
-}
-
-@extension("VK_NV_device_diagnostic_checkpoints") // 207
-cmd void vkCmdSetCheckpointNV(
- VkCommandBuffer commandBuffer,
- const void* pCheckpointMarker) {
-}
-
-@extension("VK_NV_device_diagnostic_checkpoints") // 207
-cmd void vkGetQueueCheckpointDataNV(
- VkQueue queue,
- u32* pCheckpointDataCount,
- VkCheckpointDataNV* pCheckpointData) {
-}
-
-@extension("VK_FUCHSIA_imagepipe_surface") // 215
-cmd VkResult vkCreateImagePipeSurfaceFUCHSIA(
- VkInstance instance,
- const VkImagePipeSurfaceCreateInfoFUCHSIA* pCreateInfo,
- const VkAllocationCallbacks* pAllocator,
- VkSurfaceKHR* pSurface) {
- return ?
-}
-
-
-////////////////
-// Validation //
-////////////////
-
-extern void validate(string layerName, bool condition, string message)
-
-
-/////////////////////////////
-// Internal State Tracking //
-/////////////////////////////
-
-StateObject State
-
-@internal class StateObject {
- // Dispatchable objects.
- map!(VkInstance, ref!InstanceObject) Instances
- map!(VkPhysicalDevice, ref!PhysicalDeviceObject) PhysicalDevices
- map!(VkDevice, ref!DeviceObject) Devices
- map!(VkQueue, ref!QueueObject) Queues
- map!(VkCommandBuffer, ref!CommandBufferObject) CommandBuffers
-
- // Non-dispatchable objects.
- map!(VkDeviceMemory, ref!DeviceMemoryObject) DeviceMemories
- map!(VkBuffer, ref!BufferObject) Buffers
- map!(VkBufferView, ref!BufferViewObject) BufferViews
- map!(VkImage, ref!ImageObject) Images
- map!(VkImageView, ref!ImageViewObject) ImageViews
- map!(VkShaderModule, ref!ShaderModuleObject) ShaderModules
- map!(VkPipeline, ref!PipelineObject) Pipelines
- map!(VkPipelineLayout, ref!PipelineLayoutObject) PipelineLayouts
- map!(VkSampler, ref!SamplerObject) Samplers
- map!(VkDescriptorSet, ref!DescriptorSetObject) DescriptorSets
- map!(VkDescriptorSetLayout, ref!DescriptorSetLayoutObject) DescriptorSetLayouts
- map!(VkDescriptorPool, ref!DescriptorPoolObject) DescriptorPools
- map!(VkFence, ref!FenceObject) Fences
- map!(VkSemaphore, ref!SemaphoreObject) Semaphores
- map!(VkEvent, ref!EventObject) Events
- map!(VkQueryPool, ref!QueryPoolObject) QueryPools
- map!(VkFramebuffer, ref!FramebufferObject) Framebuffers
- map!(VkRenderPass, ref!RenderPassObject) RenderPasses
- map!(VkPipelineCache, ref!PipelineCacheObject) PipelineCaches
- map!(VkCommandPool, ref!CommandPoolObject) CommandPools
- map!(VkSurfaceKHR, ref!SurfaceObject) Surfaces
- map!(VkSwapchainKHR, ref!SwapchainObject) Swapchains
-}
-
-@internal class InstanceObject {
-}
-
-@internal class PhysicalDeviceObject {
- VkInstance instance
-}
-
-@internal class DeviceObject {
- VkPhysicalDevice physicalDevice
-}
-
-@internal class QueueObject {
- VkDevice device
- VkQueueFlags flags
-}
-
-@internal class CommandBufferObject {
- VkDevice device
- map!(u64, VkDeviceMemory) boundObjects
- VkQueueFlags queueFlags
-}
-
-@internal class DeviceMemoryObject {
- VkDevice device
- VkDeviceSize allocationSize
- map!(u64, VkDeviceSize) boundObjects
- map!(VkCommandBuffer, VkCommandBuffer) boundCommandBuffers
-}
-
-@internal class BufferObject {
- VkDevice device
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
-}
-
-@internal class BufferViewObject {
- VkDevice device
- VkBuffer buffer
-}
-
-@internal class ImageObject {
- VkDevice device
- VkDeviceMemory memory
- VkDeviceSize memoryOffset
-}
-
-@internal class ImageViewObject {
- VkDevice device
- VkImage image
-}
-
-@internal class ShaderObject {
- VkDevice device
-}
-
-@internal class ShaderModuleObject {
- VkDevice device
-}
-
-@internal class PipelineObject {
- VkDevice device
-}
-
-@internal class PipelineLayoutObject {
- VkDevice device
-}
-
-@internal class SamplerObject {
- VkDevice device
-}
-
-@internal class DescriptorSetObject {
- VkDevice device
-}
-
-@internal class DescriptorSetLayoutObject {
- VkDevice device
-}
-
-@internal class DescriptorPoolObject {
- VkDevice device
-}
-
-@internal class FenceObject {
- VkDevice device
- bool signaled
-}
-
-@internal class SemaphoreObject {
- VkDevice device
-}
-
-@internal class EventObject {
- VkDevice device
-}
-
-@internal class QueryPoolObject {
- VkDevice device
-}
-
-@internal class FramebufferObject {
- VkDevice device
-}
-
-@internal class RenderPassObject {
- VkDevice device
-}
-
-@internal class PipelineCacheObject {
- VkDevice device
-}
-
-@internal class CommandPoolObject {
- VkDevice device
-}
-
-@internal class SurfaceObject {
- VkInstance instance
-}
-
-@internal class SwapchainObject {
- VkDevice device
-}
-
-macro ref!InstanceObject GetInstance(VkInstance instance) {
- assert(instance in State.Instances)
- return State.Instances[instance]
-}
-
-macro ref!PhysicalDeviceObject GetPhysicalDevice(VkPhysicalDevice physicalDevice) {
- assert(physicalDevice in State.PhysicalDevices)
- return State.PhysicalDevices[physicalDevice]
-}
-
-macro ref!DeviceObject GetDevice(VkDevice device) {
- assert(device in State.Devices)
- return State.Devices[device]
-}
-
-macro ref!QueueObject GetQueue(VkQueue queue) {
- assert(queue in State.Queues)
- return State.Queues[queue]
-}
-
-macro ref!CommandBufferObject GetCommandBuffer(VkCommandBuffer commandBuffer) {
- assert(commandBuffer in State.CommandBuffers)
- return State.CommandBuffers[commandBuffer]
-}
-
-macro ref!DeviceMemoryObject GetDeviceMemory(VkDeviceMemory memory) {
- assert(memory in State.DeviceMemories)
- return State.DeviceMemories[memory]
-}
-
-macro ref!BufferObject GetBuffer(VkBuffer buffer) {
- assert(buffer in State.Buffers)
- return State.Buffers[buffer]
-}
-
-macro ref!BufferViewObject GetBufferView(VkBufferView bufferView) {
- assert(bufferView in State.BufferViews)
- return State.BufferViews[bufferView]
-}
-
-macro ref!ImageObject GetImage(VkImage image) {
- assert(image in State.Images)
- return State.Images[image]
-}
-
-macro ref!ImageViewObject GetImageView(VkImageView imageView) {
- assert(imageView in State.ImageViews)
- return State.ImageViews[imageView]
-}
-
-macro ref!ShaderModuleObject GetShaderModule(VkShaderModule shaderModule) {
- assert(shaderModule in State.ShaderModules)
- return State.ShaderModules[shaderModule]
-}
-
-macro ref!PipelineObject GetPipeline(VkPipeline pipeline) {
- assert(pipeline in State.Pipelines)
- return State.Pipelines[pipeline]
-}
-
-macro ref!PipelineLayoutObject GetPipelineLayout(VkPipelineLayout pipelineLayout) {
- assert(pipelineLayout in State.PipelineLayouts)
- return State.PipelineLayouts[pipelineLayout]
-}
-
-macro ref!SamplerObject GetSampler(VkSampler sampler) {
- assert(sampler in State.Samplers)
- return State.Samplers[sampler]
-}
-
-macro ref!DescriptorSetObject GetDescriptorSet(VkDescriptorSet descriptorSet) {
- assert(descriptorSet in State.DescriptorSets)
- return State.DescriptorSets[descriptorSet]
-}
-
-macro ref!DescriptorSetLayoutObject GetDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout) {
- assert(descriptorSetLayout in State.DescriptorSetLayouts)
- return State.DescriptorSetLayouts[descriptorSetLayout]
-}
-
-macro ref!DescriptorPoolObject GetDescriptorPool(VkDescriptorPool descriptorPool) {
- assert(descriptorPool in State.DescriptorPools)
- return State.DescriptorPools[descriptorPool]
-}
-
-macro ref!FenceObject GetFence(VkFence fence) {
- assert(fence in State.Fences)
- return State.Fences[fence]
-}
-
-macro ref!SemaphoreObject GetSemaphore(VkSemaphore semaphore) {
- assert(semaphore in State.Semaphores)
- return State.Semaphores[semaphore]
-}
-
-macro ref!EventObject GetEvent(VkEvent event) {
- assert(event in State.Events)
- return State.Events[event]
-}
-
-macro ref!QueryPoolObject GetQueryPool(VkQueryPool queryPool) {
- assert(queryPool in State.QueryPools)
- return State.QueryPools[queryPool]
-}
-
-macro ref!FramebufferObject GetFramebuffer(VkFramebuffer framebuffer) {
- assert(framebuffer in State.Framebuffers)
- return State.Framebuffers[framebuffer]
-}
-
-macro ref!RenderPassObject GetRenderPass(VkRenderPass renderPass) {
- assert(renderPass in State.RenderPasses)
- return State.RenderPasses[renderPass]
-}
-
-macro ref!PipelineCacheObject GetPipelineCache(VkPipelineCache pipelineCache) {
- assert(pipelineCache in State.PipelineCaches)
- return State.PipelineCaches[pipelineCache]
-}
-
-macro ref!CommandPoolObject GetCommandPool(VkCommandPool commandPool) {
- assert(commandPool in State.CommandPools)
- return State.CommandPools[commandPool]
-}
-
-macro ref!SurfaceObject GetSurface(VkSurfaceKHR surface) {
- assert(surface in State.Surfaces)
- return State.Surfaces[surface]
-}
-
-macro ref!SwapchainObject GetSwapchain(VkSwapchainKHR swapchain) {
- assert(swapchain in State.Swapchains)
- return State.Swapchains[swapchain]
-}
-
-macro VkQueueFlags AddQueueFlag(VkQueueFlags flags, VkQueueFlagBits bit) {
- return as!VkQueueFlags(as!u32(flags) | as!u32(bit))
-}
diff --git a/vulkan/doc/README b/vulkan/doc/README
deleted file mode 100644
index d1dc2e1..0000000
--- a/vulkan/doc/README
+++ /dev/null
@@ -1,2 +0,0 @@
-The former contents of implementors_guide/ are now at
-https://source.android.com/devices/graphics/implement-vulkan
diff --git a/vulkan/include/vulkan/vk_android_native_buffer.h b/vulkan/include/vulkan/vk_android_native_buffer.h
index 23006fa..9ffe83b 100644
--- a/vulkan/include/vulkan/vk_android_native_buffer.h
+++ b/vulkan/include/vulkan/vk_android_native_buffer.h
@@ -62,6 +62,11 @@
typedef VkFlags VkSwapchainImageUsageFlagsANDROID;
typedef struct {
+ uint64_t consumer;
+ uint64_t producer;
+} VkNativeBufferUsage2ANDROID;
+
+typedef struct {
VkStructureType sType; // must be VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID
const void* pNext;
@@ -73,10 +78,7 @@
int format;
int usage; // DEPRECATED in SPEC_VERSION 6
// -- Added in SPEC_VERSION 6 --
- struct {
- uint64_t consumer;
- uint64_t producer;
- } usage2;
+ VkNativeBufferUsage2ANDROID usage2;
} VkNativeBufferANDROID;
typedef struct {
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index b0c4f3f..5686891 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -76,6 +76,7 @@
header_libs: [
"hwvulkan_headers",
+ "libnativeloader-headers",
"vulkan_headers",
],
export_header_lib_headers: ["vulkan_headers"],
diff --git a/vulkan/libvulkan/api.cpp b/vulkan/libvulkan/api.cpp
index 71048db..48f26e7 100644
--- a/vulkan/libvulkan/api.cpp
+++ b/vulkan/libvulkan/api.cpp
@@ -664,6 +664,12 @@
return VK_ERROR_LAYER_NOT_PRESENT;
}
+ if (!layer.ref.GetGetInstanceProcAddr()) {
+ ALOGW("Failed to locate vkGetInstanceProcAddr in layer %s", name);
+ layer.ref.~LayerRef();
+ return VK_ERROR_LAYER_NOT_PRESENT;
+ }
+
ALOGI("Loaded layer %s", name);
return VK_SUCCESS;
@@ -1166,11 +1172,20 @@
std::call_once(once_flag, []() {
if (driver::OpenHAL()) {
- DiscoverLayers();
initialized = true;
}
});
+ {
+ static pid_t pid = getpid() + 1;
+ static std::mutex layer_lock;
+ std::lock_guard<std::mutex> lock(layer_lock);
+ if (pid != getpid()) {
+ pid = getpid();
+ DiscoverLayers();
+ }
+ }
+
return initialized;
}
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index df86af0..37b5368 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -16,12 +16,11 @@
// WARNING: This file is generated. See ../README.md for instructions.
+#include <log/log.h>
#include <string.h>
#include <algorithm>
-#include <log/log.h>
-
// to catch mismatches between vulkan.h and this file
#undef VK_NO_PROTOTYPES
#include "api.h"
@@ -55,6 +54,11 @@
// clang-format off
+VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) {
+ driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed.");
+ return VK_SUCCESS;
+}
+
VKAPI_ATTR void disabledDestroySurfaceKHR(VkInstance instance, VkSurfaceKHR, const VkAllocationCallbacks*) {
driver::Logger(instance).Err(instance, "VK_KHR_surface not enabled. Exported vkDestroySurfaceKHR not executed.");
}
@@ -113,18 +117,13 @@
return VK_SUCCESS;
}
-VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) {
- driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed.");
- return VK_SUCCESS;
-}
-
VKAPI_ATTR VkResult disabledAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR*, uint32_t*) {
driver::Logger(device).Err(device, "VK_KHR_swapchain not enabled. Exported vkAcquireNextImage2KHR not executed.");
return VK_SUCCESS;
}
-VKAPI_ATTR VkResult disabledCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR*, const VkAllocationCallbacks*, VkSurfaceKHR*) {
- driver::Logger(instance).Err(instance, "VK_KHR_android_surface not enabled. Exported vkCreateAndroidSurfaceKHR not executed.");
+VKAPI_ATTR VkResult disabledGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR, uint32_t*, VkRect2D*) {
+ driver::Logger(physicalDevice).Err(physicalDevice, "VK_KHR_swapchain not enabled. Exported vkGetPhysicalDevicePresentRectanglesKHR not executed.");
return VK_SUCCESS;
}
@@ -162,7 +161,12 @@
INIT_PROC(true, instance, CreateDevice);
INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
INIT_PROC(true, instance, GetPhysicalDeviceSparseImageFormatProperties);
- INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+ INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR);
+ INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR);
+ INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR);
+ INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
+ INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR);
+ INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR);
INIT_PROC(false, instance, GetPhysicalDeviceFeatures2);
INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
INIT_PROC(false, instance, GetPhysicalDeviceFormatProperties2);
@@ -171,15 +175,10 @@
INIT_PROC(false, instance, GetPhysicalDeviceMemoryProperties2);
INIT_PROC(false, instance, GetPhysicalDeviceSparseImageFormatProperties2);
INIT_PROC(false, instance, GetPhysicalDeviceExternalBufferProperties);
- INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties);
INIT_PROC(false, instance, GetPhysicalDeviceExternalSemaphoreProperties);
- INIT_PROC_EXT(KHR_surface, true, instance, DestroySurfaceKHR);
- INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceSupportKHR);
- INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceCapabilitiesKHR);
- INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfaceFormatsKHR);
- INIT_PROC_EXT(KHR_surface, true, instance, GetPhysicalDeviceSurfacePresentModesKHR);
+ INIT_PROC(false, instance, GetPhysicalDeviceExternalFenceProperties);
+ INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
INIT_PROC_EXT(KHR_swapchain, false, instance, GetPhysicalDevicePresentRectanglesKHR);
- INIT_PROC_EXT(KHR_android_surface, true, instance, CreateAndroidSurfaceKHR);
// clang-format on
return success;
@@ -314,32 +313,32 @@
INIT_PROC(true, dev, CmdNextSubpass);
INIT_PROC(true, dev, CmdEndRenderPass);
INIT_PROC(true, dev, CmdExecuteCommands);
- INIT_PROC(false, dev, BindBufferMemory2);
- INIT_PROC(false, dev, BindImageMemory2);
- INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures);
- INIT_PROC(false, dev, CmdSetDeviceMask);
- INIT_PROC(false, dev, CmdDispatchBase);
- INIT_PROC(false, dev, GetImageMemoryRequirements2);
- INIT_PROC(false, dev, GetBufferMemoryRequirements2);
- INIT_PROC(false, dev, GetImageSparseMemoryRequirements2);
- INIT_PROC(false, dev, TrimCommandPool);
- INIT_PROC(false, dev, GetDeviceQueue2);
- INIT_PROC(false, dev, CreateSamplerYcbcrConversion);
- INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
- INIT_PROC(false, dev, CreateDescriptorUpdateTemplate);
- INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate);
- INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate);
- INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
INIT_PROC_EXT(KHR_swapchain, true, dev, CreateSwapchainKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, DestroySwapchainKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, GetSwapchainImagesKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, AcquireNextImageKHR);
INIT_PROC_EXT(KHR_swapchain, true, dev, QueuePresentKHR);
+ INIT_PROC(false, dev, TrimCommandPool);
+ INIT_PROC(false, dev, GetDeviceGroupPeerMemoryFeatures);
+ INIT_PROC(false, dev, BindBufferMemory2);
+ INIT_PROC(false, dev, BindImageMemory2);
+ INIT_PROC(false, dev, CmdSetDeviceMask);
INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupPresentCapabilitiesKHR);
INIT_PROC_EXT(KHR_swapchain, false, dev, GetDeviceGroupSurfacePresentModesKHR);
INIT_PROC_EXT(KHR_swapchain, false, dev, AcquireNextImage2KHR);
- INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, false, dev, GetAndroidHardwareBufferPropertiesANDROID);
- INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, false, dev, GetMemoryAndroidHardwareBufferANDROID);
+ INIT_PROC(false, dev, CmdDispatchBase);
+ INIT_PROC(false, dev, CreateDescriptorUpdateTemplate);
+ INIT_PROC(false, dev, DestroyDescriptorUpdateTemplate);
+ INIT_PROC(false, dev, UpdateDescriptorSetWithTemplate);
+ INIT_PROC(false, dev, GetBufferMemoryRequirements2);
+ INIT_PROC(false, dev, GetImageMemoryRequirements2);
+ INIT_PROC(false, dev, GetImageSparseMemoryRequirements2);
+ INIT_PROC(false, dev, CreateSamplerYcbcrConversion);
+ INIT_PROC(false, dev, DestroySamplerYcbcrConversion);
+ INIT_PROC(false, dev, GetDeviceQueue2);
+ INIT_PROC(false, dev, GetDescriptorSetLayoutSupport);
+ INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetAndroidHardwareBufferPropertiesANDROID);
+ INIT_PROC_EXT(ANDROID_external_memory_android_hardware_buffer, true, dev, GetMemoryAndroidHardwareBufferANDROID);
// clang-format on
return success;
@@ -479,33 +478,7 @@
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
-VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
-VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
-VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
-VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
-VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
-VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
-VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
-VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
-VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
-VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
-VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
-VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
-VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
-VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
-VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
-VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
-VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
-VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
-VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
-VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
-VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
-VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
-VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
-VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, VkSurfaceKHR surface, VkBool32* pSupported);
VKAPI_ATTR VkResult GetPhysicalDeviceSurfaceCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, VkSurfaceCapabilitiesKHR* pSurfaceCapabilities);
@@ -516,11 +489,37 @@
VKAPI_ATTR VkResult GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pSwapchainImageCount, VkImage* pSwapchainImages);
VKAPI_ATTR VkResult AcquireNextImageKHR(VkDevice device, VkSwapchainKHR swapchain, uint64_t timeout, VkSemaphore semaphore, VkFence fence, uint32_t* pImageIndex);
VKAPI_ATTR VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* pPresentInfo);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities);
VKAPI_ATTR VkResult GetDeviceGroupSurfacePresentModesKHR(VkDevice device, VkSurfaceKHR surface, VkDeviceGroupPresentModeFlagsKHR* pModes);
-VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex);
-VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects);
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties);
VKAPI_ATTR VkResult GetMemoryAndroidHardwareBufferANDROID(VkDevice device, const VkMemoryGetAndroidHardwareBufferInfoANDROID* pInfo, struct AHardwareBuffer** pBuffer);
@@ -622,9 +621,9 @@
// global functions
if (instance == VK_NULL_HANDLE) {
if (strcmp(pName, "vkCreateInstance") == 0) return reinterpret_cast<PFN_vkVoidFunction>(CreateInstance);
+ if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion);
if (strcmp(pName, "vkEnumerateInstanceLayerProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceLayerProperties);
if (strcmp(pName, "vkEnumerateInstanceExtensionProperties") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceExtensionProperties);
- if (strcmp(pName, "vkEnumerateInstanceVersion") == 0) return reinterpret_cast<PFN_vkVoidFunction>(EnumerateInstanceVersion);
ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName);
return nullptr;
@@ -1313,112 +1312,8 @@
GetData(commandBuffer).dispatch.CmdExecuteCommands(commandBuffer, commandBufferCount, pCommandBuffers);
}
-VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
- return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos);
-}
-
-VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
- return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos);
-}
-
-VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
- GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
-}
-
-VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
- GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask);
-}
-
-VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
- GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
-}
-
-VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
- return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-}
-
-VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
- GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
-}
-
-VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
- GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
-}
-
-VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
- GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceProperties2(physicalDevice, pProperties);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
-}
-
-VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
- return GetData(physicalDevice).dispatch.GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
-}
-
-VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
- GetData(device).dispatch.TrimCommandPool(device, commandPool, flags);
-}
-
-VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
- GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue);
-}
-
-VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
- return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
-}
-
-VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
- GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
-}
-
-VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
- return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
-}
-
-VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
- GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
-}
-
-VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
- GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
-}
-
-VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
- GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
-}
-
-VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
- GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
+ return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
}
VKAPI_ATTR void DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR surface, const VkAllocationCallbacks* pAllocator) {
@@ -1461,6 +1356,70 @@
return GetData(queue).dispatch.QueuePresentKHR(queue, pPresentInfo);
}
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
+}
+
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+ return GetData(physicalDevice).dispatch.GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+ GetData(device).dispatch.TrimCommandPool(device, commandPool, flags);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+}
+
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+ GetData(physicalDevice).dispatch.GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ return GetData(instance).dispatch.EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+}
+
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+ GetData(device).dispatch.GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
+
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+ return GetData(device).dispatch.BindBufferMemory2(device, bindInfoCount, pBindInfos);
+}
+
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ return GetData(device).dispatch.BindImageMemory2(device, bindInfoCount, pBindInfos);
+}
+
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+ GetData(commandBuffer).dispatch.CmdSetDeviceMask(commandBuffer, deviceMask);
+}
+
VKAPI_ATTR VkResult GetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
return GetData(device).dispatch.GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
}
@@ -1469,16 +1428,56 @@
return GetData(device).dispatch.GetDeviceGroupSurfacePresentModesKHR(device, surface, pModes);
}
-VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
- return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
-}
-
VKAPI_ATTR VkResult AcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
return GetData(device).dispatch.AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
}
-VKAPI_ATTR VkResult CreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
- return GetData(instance).dispatch.CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+ GetData(commandBuffer).dispatch.CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
+}
+
+VKAPI_ATTR VkResult GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
+ return GetData(physicalDevice).dispatch.GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
+}
+
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+ return GetData(device).dispatch.CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+ GetData(device).dispatch.DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+ GetData(device).dispatch.UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
+
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ GetData(device).dispatch.GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ GetData(device).dispatch.GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+ GetData(device).dispatch.GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
+
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+ return GetData(device).dispatch.CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
+}
+
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+ GetData(device).dispatch.DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+}
+
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+ GetData(device).dispatch.GetDeviceQueue2(device, pQueueInfo, pQueue);
+}
+
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+ GetData(device).dispatch.GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
}
VKAPI_ATTR VkResult GetAndroidHardwareBufferPropertiesANDROID(VkDevice device, const struct AHardwareBuffer* buffer, VkAndroidHardwareBufferPropertiesANDROID* pProperties) {
@@ -1565,6 +1564,11 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) {
+ return vulkan::api::EnumerateInstanceVersion(pApiVersion);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkEnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties) {
return vulkan::api::EnumerateInstanceLayerProperties(pPropertyCount, pProperties);
}
@@ -2185,143 +2189,8 @@
}
__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkEnumerateInstanceVersion(uint32_t* pApiVersion) {
- return vulkan::api::EnumerateInstanceVersion(pApiVersion);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
- return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
- return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
- vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
- vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
- vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
- return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
- vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
- vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
- vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
- vulkan::api::GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
- vulkan::api::GetPhysicalDeviceProperties2(physicalDevice, pProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
- vulkan::api::GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
- return vulkan::api::GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
- vulkan::api::GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
- vulkan::api::GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
- vulkan::api::GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
- vulkan::api::TrimCommandPool(device, commandPool, flags);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
- vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
- return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
- vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
- return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
- vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
- vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
- vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
- vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
- vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
-}
-
-__attribute__((visibility("default")))
-VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
- vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
+VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
+ return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
}
__attribute__((visibility("default")))
@@ -2375,6 +2244,86 @@
}
__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures) {
+ vulkan::api::GetPhysicalDeviceFeatures2(physicalDevice, pFeatures);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties) {
+ vulkan::api::GetPhysicalDeviceProperties2(physicalDevice, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties) {
+ vulkan::api::GetPhysicalDeviceFormatProperties2(physicalDevice, format, pFormatProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties) {
+ return vulkan::api::GetPhysicalDeviceImageFormatProperties2(physicalDevice, pImageFormatInfo, pImageFormatProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties) {
+ vulkan::api::GetPhysicalDeviceQueueFamilyProperties2(physicalDevice, pQueueFamilyPropertyCount, pQueueFamilyProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties) {
+ vulkan::api::GetPhysicalDeviceMemoryProperties2(physicalDevice, pMemoryProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties) {
+ vulkan::api::GetPhysicalDeviceSparseImageFormatProperties2(physicalDevice, pFormatInfo, pPropertyCount, pProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkTrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags) {
+ vulkan::api::TrimCommandPool(device, commandPool, flags);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties) {
+ vulkan::api::GetPhysicalDeviceExternalBufferProperties(physicalDevice, pExternalBufferInfo, pExternalBufferProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties) {
+ vulkan::api::GetPhysicalDeviceExternalSemaphoreProperties(physicalDevice, pExternalSemaphoreInfo, pExternalSemaphoreProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties) {
+ vulkan::api::GetPhysicalDeviceExternalFenceProperties(physicalDevice, pExternalFenceInfo, pExternalFenceProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkEnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties) {
+ return vulkan::api::EnumeratePhysicalDeviceGroups(instance, pPhysicalDeviceGroupCount, pPhysicalDeviceGroupProperties);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures) {
+ vulkan::api::GetDeviceGroupPeerMemoryFeatures(device, heapIndex, localDeviceIndex, remoteDeviceIndex, pPeerMemoryFeatures);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkBindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos) {
+ return vulkan::api::BindBufferMemory2(device, bindInfoCount, pBindInfos);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkBindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ return vulkan::api::BindImageMemory2(device, bindInfoCount, pBindInfos);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkCmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask) {
+ vulkan::api::CmdSetDeviceMask(commandBuffer, deviceMask);
+}
+
+__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
return vulkan::api::GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
}
@@ -2385,18 +2334,68 @@
}
__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
- return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
-}
-
-__attribute__((visibility("default")))
VKAPI_ATTR VkResult vkAcquireNextImage2KHR(VkDevice device, const VkAcquireNextImageInfoKHR* pAcquireInfo, uint32_t* pImageIndex) {
return vulkan::api::AcquireNextImage2KHR(device, pAcquireInfo, pImageIndex);
}
__attribute__((visibility("default")))
-VKAPI_ATTR VkResult vkCreateAndroidSurfaceKHR(VkInstance instance, const VkAndroidSurfaceCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSurfaceKHR* pSurface) {
- return vulkan::api::CreateAndroidSurfaceKHR(instance, pCreateInfo, pAllocator, pSurface);
+VKAPI_ATTR void vkCmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ) {
+ vulkan::api::CmdDispatchBase(commandBuffer, baseGroupX, baseGroupY, baseGroupZ, groupCountX, groupCountY, groupCountZ);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkGetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR surface, uint32_t* pRectCount, VkRect2D* pRects) {
+ return vulkan::api::GetPhysicalDevicePresentRectanglesKHR(physicalDevice, surface, pRectCount, pRects);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate) {
+ return vulkan::api::CreateDescriptorUpdateTemplate(device, pCreateInfo, pAllocator, pDescriptorUpdateTemplate);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkDestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator) {
+ vulkan::api::DestroyDescriptorUpdateTemplate(device, descriptorUpdateTemplate, pAllocator);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkUpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData) {
+ vulkan::api::UpdateDescriptorSetWithTemplate(device, descriptorSet, descriptorUpdateTemplate, pData);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ vulkan::api::GetBufferMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements) {
+ vulkan::api::GetImageMemoryRequirements2(device, pInfo, pMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements) {
+ vulkan::api::GetImageSparseMemoryRequirements2(device, pInfo, pSparseMemoryRequirementCount, pSparseMemoryRequirements);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR VkResult vkCreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion) {
+ return vulkan::api::CreateSamplerYcbcrConversion(device, pCreateInfo, pAllocator, pYcbcrConversion);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkDestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator) {
+ vulkan::api::DestroySamplerYcbcrConversion(device, ycbcrConversion, pAllocator);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue) {
+ vulkan::api::GetDeviceQueue2(device, pQueueInfo, pQueue);
+}
+
+__attribute__((visibility("default")))
+VKAPI_ATTR void vkGetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport) {
+ vulkan::api::GetDescriptorSetLayoutSupport(device, pCreateInfo, pSupport);
}
__attribute__((visibility("default")))
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 4bedbeb..2195845 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -20,7 +20,9 @@
#define LIBVULKAN_API_GEN_H
#include <vulkan/vulkan.h>
+
#include <bitset>
+
#include "driver_gen.h"
namespace vulkan {
@@ -40,7 +42,12 @@
PFN_vkCreateDevice CreateDevice;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
- PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+ PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
+ PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
+ PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
+ PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
+ PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
+ PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
PFN_vkGetPhysicalDeviceFeatures2 GetPhysicalDeviceFeatures2;
PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
PFN_vkGetPhysicalDeviceFormatProperties2 GetPhysicalDeviceFormatProperties2;
@@ -49,15 +56,10 @@
PFN_vkGetPhysicalDeviceMemoryProperties2 GetPhysicalDeviceMemoryProperties2;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties2 GetPhysicalDeviceSparseImageFormatProperties2;
PFN_vkGetPhysicalDeviceExternalBufferProperties GetPhysicalDeviceExternalBufferProperties;
- PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties;
PFN_vkGetPhysicalDeviceExternalSemaphoreProperties GetPhysicalDeviceExternalSemaphoreProperties;
- PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
- PFN_vkGetPhysicalDeviceSurfaceSupportKHR GetPhysicalDeviceSurfaceSupportKHR;
- PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR GetPhysicalDeviceSurfaceCapabilitiesKHR;
- PFN_vkGetPhysicalDeviceSurfaceFormatsKHR GetPhysicalDeviceSurfaceFormatsKHR;
- PFN_vkGetPhysicalDeviceSurfacePresentModesKHR GetPhysicalDeviceSurfacePresentModesKHR;
+ PFN_vkGetPhysicalDeviceExternalFenceProperties GetPhysicalDeviceExternalFenceProperties;
+ PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
PFN_vkGetPhysicalDevicePresentRectanglesKHR GetPhysicalDevicePresentRectanglesKHR;
- PFN_vkCreateAndroidSurfaceKHR CreateAndroidSurfaceKHR;
// clang-format on
};
@@ -184,30 +186,30 @@
PFN_vkCmdNextSubpass CmdNextSubpass;
PFN_vkCmdEndRenderPass CmdEndRenderPass;
PFN_vkCmdExecuteCommands CmdExecuteCommands;
- PFN_vkBindBufferMemory2 BindBufferMemory2;
- PFN_vkBindImageMemory2 BindImageMemory2;
- PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures;
- PFN_vkCmdSetDeviceMask CmdSetDeviceMask;
- PFN_vkCmdDispatchBase CmdDispatchBase;
- PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2;
- PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2;
- PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2;
- PFN_vkTrimCommandPool TrimCommandPool;
- PFN_vkGetDeviceQueue2 GetDeviceQueue2;
- PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion;
- PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
- PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate;
- PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate;
- PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate;
- PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
PFN_vkCreateSwapchainKHR CreateSwapchainKHR;
PFN_vkDestroySwapchainKHR DestroySwapchainKHR;
PFN_vkGetSwapchainImagesKHR GetSwapchainImagesKHR;
PFN_vkAcquireNextImageKHR AcquireNextImageKHR;
PFN_vkQueuePresentKHR QueuePresentKHR;
+ PFN_vkTrimCommandPool TrimCommandPool;
+ PFN_vkGetDeviceGroupPeerMemoryFeatures GetDeviceGroupPeerMemoryFeatures;
+ PFN_vkBindBufferMemory2 BindBufferMemory2;
+ PFN_vkBindImageMemory2 BindImageMemory2;
+ PFN_vkCmdSetDeviceMask CmdSetDeviceMask;
PFN_vkGetDeviceGroupPresentCapabilitiesKHR GetDeviceGroupPresentCapabilitiesKHR;
PFN_vkGetDeviceGroupSurfacePresentModesKHR GetDeviceGroupSurfacePresentModesKHR;
PFN_vkAcquireNextImage2KHR AcquireNextImage2KHR;
+ PFN_vkCmdDispatchBase CmdDispatchBase;
+ PFN_vkCreateDescriptorUpdateTemplate CreateDescriptorUpdateTemplate;
+ PFN_vkDestroyDescriptorUpdateTemplate DestroyDescriptorUpdateTemplate;
+ PFN_vkUpdateDescriptorSetWithTemplate UpdateDescriptorSetWithTemplate;
+ PFN_vkGetBufferMemoryRequirements2 GetBufferMemoryRequirements2;
+ PFN_vkGetImageMemoryRequirements2 GetImageMemoryRequirements2;
+ PFN_vkGetImageSparseMemoryRequirements2 GetImageSparseMemoryRequirements2;
+ PFN_vkCreateSamplerYcbcrConversion CreateSamplerYcbcrConversion;
+ PFN_vkDestroySamplerYcbcrConversion DestroySamplerYcbcrConversion;
+ PFN_vkGetDeviceQueue2 GetDeviceQueue2;
+ PFN_vkGetDescriptorSetLayoutSupport GetDescriptorSetLayoutSupport;
PFN_vkGetAndroidHardwareBufferPropertiesANDROID GetAndroidHardwareBufferPropertiesANDROID;
PFN_vkGetMemoryAndroidHardwareBufferANDROID GetMemoryAndroidHardwareBufferANDROID;
// clang-format on
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
deleted file mode 100644
index bdd3573..0000000
--- a/vulkan/libvulkan/code-generator.tmpl
+++ /dev/null
@@ -1,1196 +0,0 @@
-{{define "Copyright"}}
-/*
-•* Copyright 2016 The Android Open Source Project
-•*
-•* Licensed under the Apache License, Version 2.0 (the "License");
-•* you may not use this file except in compliance with the License.
-•* You may obtain a copy of the License at
-•*
-•* http://www.apache.org/licenses/LICENSE-2.0
-•*
-•* Unless required by applicable law or agreed to in writing, software
-•* distributed under the License is distributed on an "AS IS" BASIS,
-•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-•* See the License for the specific language governing permissions and
-•* limitations under the License.
-•*/
-¶{{end}}
-
-{{Include "../api/templates/vulkan_common.tmpl"}}
-{{Global "clang-format" (Strings "clang-format" "-style=file")}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "api_gen.h" | Format (Global "clang-format") | Write "api_gen.h" }}
-{{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}}
-{{$ | Macro "driver_gen.h" | Format (Global "clang-format") | Write "driver_gen.h"}}
-{{$ | Macro "driver_gen.cpp" | Format (Global "clang-format") | Write "driver_gen.cpp"}}
-
-{{/*
--------------------------------------------------------------------------------
- api_gen.h
--------------------------------------------------------------------------------
-*/}}
-{{define "api_gen.h"}}
-{{Macro "Copyright"}}
-¶
-// WARNING: This file is generated. See ../README.md for instructions.
-¶
-#ifndef LIBVULKAN_API_GEN_H
-#define LIBVULKAN_API_GEN_H
-¶
-#include <bitset>
-#include <vulkan/vulkan.h>
-#include "driver_gen.h"
-¶
-namespace vulkan {«
-namespace api {«
-¶
-struct InstanceDispatchTable {
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}}
- {{Macro "C++.DeclareTableEntry" $f}};
- {{end}}
- {{end}}
- // clang-format on
-};
-¶
-struct DeviceDispatchTable {
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}}
- {{Macro "C++.DeclareTableEntry" $f}};
- {{end}}
- {{end}}
- // clang-format on
-};
-¶
-bool InitDispatchTable(
- VkInstance instance,
- PFN_vkGetInstanceProcAddr get_proc,
- const std::bitset<driver::ProcHook::EXTENSION_COUNT> &extensions);
-bool InitDispatchTable(
- VkDevice dev,
- PFN_vkGetDeviceProcAddr get_proc,
- const std::bitset<driver::ProcHook::EXTENSION_COUNT> &extensions);
-¶
-»} // namespace api
-»} // namespace vulkan
-¶
-#endif // LIBVULKAN_API_GEN_H
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- api_gen.cpp
--------------------------------------------------------------------------------
-*/}}
-{{define "api_gen.cpp"}}
-{{Macro "Copyright"}}
-¶
-// WARNING: This file is generated. See ../README.md for instructions.
-¶
-#include <string.h>
-¶
-#include <algorithm>
-¶
-#include <log/log.h>
-¶
-// to catch mismatches between vulkan.h and this file
-#undef VK_NO_PROTOTYPES
-#include "api.h"
-¶
-namespace vulkan {«
-namespace api {«
-¶
-{{Macro "C++.DefineInitProcMacro" "dispatch"}}
-¶
-{{Macro "api.C++.DefineInitProcExtMacro"}}
-¶
-namespace {«
-¶
-// clang-format off
-¶
-{{range $f := AllCommands $}}
- {{Macro "api.C++.DefineExtensionStub" $f}}
-{{end}}
-// clang-format on
-¶
-»} // anonymous
-¶
-bool InitDispatchTable(
- VkInstance instance,
- PFN_vkGetInstanceProcAddr get_proc,
- const std::bitset<driver::ProcHook::EXTENSION_COUNT> &extensions) {
- auto& data = GetData(instance);
- bool success = true;
- ¶
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}}
- {{Macro "C++.InitProc" $f}}
- {{end}}
- {{end}}
- // clang-format on
- ¶
- return success;
-}
-¶
-bool InitDispatchTable(
- VkDevice dev,
- PFN_vkGetDeviceProcAddr get_proc,
- const std::bitset<driver::ProcHook::EXTENSION_COUNT> &extensions) {
- auto& data = GetData(dev);
- bool success = true;
- ¶
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}}
- {{Macro "C++.InitProc" $f}}
- {{end}}
- {{end}}
- // clang-format on
- ¶
- return success;
-}
-¶
-// clang-format off
-¶
-namespace {«
-¶
-// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
-{{range $f := AllCommands $}}
- {{if and (Macro "IsFunctionExported" $f) (not (Macro "api.IsIntercepted" $f))}}
- VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}});
- {{end}}
-{{end}}
-¶
-{{range $f := AllCommands $}}
- {{if and (Macro "IsFunctionExported" $f) (not (Macro "api.IsIntercepted" $f))}}
- VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}}) {
- {{ if eq $f.Name "vkGetInstanceProcAddr"}}
- {{Macro "api.C++.InterceptInstanceProcAddr" $}}
- {{else if eq $f.Name "vkGetDeviceProcAddr"}}
- {{Macro "api.C++.InterceptDeviceProcAddr" $}}
- {{end}}
-
- {{Macro "api.C++.Dispatch" $f}}
- }
- ¶
- {{end}}
-{{end}}
-¶
-»} // anonymous namespace
-¶
-// clang-format on
-¶
-»} // namespace api
-»} // namespace vulkan
-¶
-// clang-format off
-¶
-{{range $f := AllCommands $}}
- {{if (Macro "IsFunctionExported" $f)}}
- __attribute__((visibility("default")))
- VKAPI_ATTR {{Node "Type" $f.Return}} {{$f.Name}}({{Macro "Parameters" $f}}) {
- {{if not (IsVoid $f.Return.Type)}}return §{{end}}
- vulkan::api::{{Macro "BaseName" $f}}({{Macro "Arguments" $f}});
- }
- ¶
- {{end}}
-{{end}}
-¶
-// clang-format on
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- driver_gen.h
--------------------------------------------------------------------------------
-*/}}
-{{define "driver_gen.h"}}
-{{Macro "Copyright"}}
-¶
-// WARNING: This file is generated. See ../README.md for instructions.
-¶
-#ifndef LIBVULKAN_DRIVER_GEN_H
-#define LIBVULKAN_DRIVER_GEN_H
-¶
-#include <bitset>
-#include <vulkan/vulkan.h>
-#include <vulkan/vk_android_native_buffer.h>
-¶
-namespace vulkan {«
-namespace driver {«
-¶
-{{Macro "driver.C++.DefineProcHookType"}}
-¶
-struct InstanceDriverTable {
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}}
- {{Macro "C++.DeclareTableEntry" $f}};
- {{end}}
- {{end}}
- // clang-format on
-};
-¶
-struct DeviceDriverTable {
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}}
- {{Macro "C++.DeclareTableEntry" $f}};
- {{end}}
- {{end}}
- // clang-format on
-};
-¶
-const ProcHook* GetProcHook(const char* name);
-ProcHook::Extension GetProcHookExtension(const char* name);
-¶
-bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc,
- const std::bitset<ProcHook::EXTENSION_COUNT> &extensions);
-bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc,
- const std::bitset<ProcHook::EXTENSION_COUNT> &extensions);
-¶
-»} // namespace driver
-»} // namespace vulkan
-¶
-#endif // LIBVULKAN_DRIVER_TABLE_H
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- driver_gen.cpp
--------------------------------------------------------------------------------
-*/}}
-{{define "driver_gen.cpp"}}
-{{Macro "Copyright"}}
-¶
-// WARNING: This file is generated. See ../README.md for instructions.
-¶
-#include <string.h>
-¶
-#include <algorithm>
-¶
-#include <log/log.h>
-¶
-#include "driver.h"
-¶
-namespace vulkan {«
-namespace driver {«
-¶
-namespace {«
-¶
-// clang-format off
-¶
-{{range $f := AllCommands $}}
- {{Macro "driver.C++.DefineProcHookStub" $f}}
-{{end}}
-// clang-format on
-¶
-const ProcHook g_proc_hooks[] = {
- // clang-format off
- {{range $f := SortBy (AllCommands $) "FunctionName"}}
- {{if (Macro "driver.IsIntercepted" $f)}}
- {{ if (Macro "IsGloballyDispatched" $f)}}
- {{Macro "driver.C++.DefineGlobalProcHook" $f}}
- {{else if (Macro "IsInstanceDispatched" $f)}}
- {{Macro "driver.C++.DefineInstanceProcHook" $f}}
- {{else if (Macro "IsDeviceDispatched" $f)}}
- {{Macro "driver.C++.DefineDeviceProcHook" $f}}
- {{end}}
- {{end}}
- {{end}}
- // clang-format on
-};
-¶
-»} // anonymous
-¶
-const ProcHook* GetProcHook(const char* name) {
- const auto& begin = g_proc_hooks;
- const auto& end = g_proc_hooks +
- sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
- const auto hook = std::lower_bound(begin, end, name,
- [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
- return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
-}
-¶
-ProcHook::Extension GetProcHookExtension(const char* name) {
- {{$exts := Strings (Macro "driver.KnownExtensions") | SplitOn "\n"}}
- // clang-format off
- {{range $e := $exts}}
- if (strcmp(name, "{{$e}}") == 0) return ProcHook::{{TrimPrefix "VK_" $e}};
- {{end}}
- // clang-format on
- return ProcHook::EXTENSION_UNKNOWN;
-}
-¶
-{{Macro "C++.DefineInitProcMacro" "driver"}}
-¶
-{{Macro "driver.C++.DefineInitProcExtMacro"}}
-¶
-bool InitDriverTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc,
- const std::bitset<ProcHook::EXTENSION_COUNT> &extensions)
-{
- auto& data = GetData(instance);
- bool success = true;
- ¶
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "driver.IsInstanceDriverTableEntry" $f)}}
- {{Macro "C++.InitProc" $f}}
- {{end}}
- {{end}}
- // clang-format on
- ¶
- return success;
-}
-¶
-bool InitDriverTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc,
- const std::bitset<ProcHook::EXTENSION_COUNT> &extensions)
-{
- auto& data = GetData(dev);
- bool success = true;
- ¶
- // clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "driver.IsDeviceDriverTableEntry" $f)}}
- {{Macro "C++.InitProc" $f}}
- {{end}}
- {{end}}
- // clang-format on
- ¶
- return success;
-}
-¶
-»} // namespace driver
-»} // namespace vulkan
-¶
-// clang-format on
-¶{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits a declaration of a dispatch/driver table entry.
-------------------------------------------------------------------------------
-*/}}
-{{define "C++.DeclareTableEntry"}}
- {{AssertType $ "Function"}}
-
- {{Macro "FunctionPtrName" $}} {{Macro "BaseName" $}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits INIT_PROC macro.
--------------------------------------------------------------------------------
-*/}}
-{{define "C++.DefineInitProcMacro"}}
- #define UNLIKELY(expr) __builtin_expect((expr), 0)
- ¶
- #define INIT_PROC(required, obj, proc) do { \
- data.{{$}}.proc = reinterpret_cast<PFN_vk ## proc>( \
- get_proc(obj, "vk" # proc)); \
- if (UNLIKELY(required && !data.{{$}}.proc)) { \
- ALOGE("missing " # obj " proc: vk" # proc); \
- success = false; \
- } \
- } while(0)
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits code to invoke INIT_PROC or INIT_PROC_EXT.
--------------------------------------------------------------------------------
-*/}}
-{{define "C++.InitProc"}}
- {{AssertType $ "Function"}}
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- INIT_PROC_EXT({{Macro "BaseName" $ext}}, §
- {{else}}
- INIT_PROC(§
- {{end}}
-
- {{if GetAnnotation $ "optional"}}false{{else if GetAnnotation $ "vulkan1_1"}}false{{else}}true{{end}}, §
-
- {{if (Macro "IsInstanceDispatched" $)}}
- instance, §
- {{else}}
- dev, §
- {{end}}
-
- {{Macro "BaseName" $}});
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if a function is exported and instance-dispatched.
-------------------------------------------------------------------------------
-*/}}
-{{define "api.IsInstanceDispatchTableEntry"}}
- {{AssertType $ "Function"}}
-
- {{if and (Macro "IsFunctionExported" $) (Macro "IsInstanceDispatched" $)}}
- {{/* deprecated and unused internally */}}
- {{if not (eq $.Name "vkEnumerateDeviceLayerProperties")}}
- true
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if a function is exported and device-dispatched.
-------------------------------------------------------------------------------
-*/}}
-{{define "api.IsDeviceDispatchTableEntry"}}
- {{AssertType $ "Function"}}
-
- {{if and (Macro "IsFunctionExported" $) (Macro "IsDeviceDispatched" $)}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if a function is intercepted by vulkan::api.
-------------------------------------------------------------------------------
-*/}}
-{{define "api.IsIntercepted"}}
- {{AssertType $ "Function"}}
-
- {{if (Macro "IsFunctionSupported" $)}}
- {{/* Global functions cannot be dispatched at all */}}
- {{ if (Macro "IsGloballyDispatched" $)}}true
-
- {{/* VkPhysicalDevice functions that manage device layers */}}
- {{else if eq $.Name "vkCreateDevice"}}true
- {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true
- {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
-
- {{/* Destroy functions of dispatchable objects */}}
- {{else if eq $.Name "vkDestroyInstance"}}true
- {{else if eq $.Name "vkDestroyDevice"}}true
-
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits INIT_PROC_EXT macro for vulkan::api.
--------------------------------------------------------------------------------
-*/}}
-{{define "api.C++.DefineInitProcExtMacro"}}
- // Exported extension functions may be invoked even when their extensions
- // are disabled. Dispatch to stubs when that happens.
- #define INIT_PROC_EXT(ext, required, obj, proc) do { \
- if (extensions[driver::ProcHook::ext]) \
- INIT_PROC(required, obj, proc); \
- else \
- data.dispatch.proc = disabled ## proc; \
- } while(0)
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a stub for an exported extension function.
--------------------------------------------------------------------------------
-*/}}
-{{define "api.C++.DefineExtensionStub"}}
- {{AssertType $ "Function"}}
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if and $ext (Macro "IsFunctionExported" $)}}
- {{$ext_name := index $ext.Arguments 0}}
-
- {{$base := (Macro "BaseName" $)}}
-
- {{$p0 := (index $.CallParameters 0)}}
- {{$ptail := (Tail 1 $.CallParameters)}}
-
- {{$first_type := (Macro "Parameter" $p0)}}
- {{$tail_types := (ForEach $ptail "ParameterType" | JoinWith ", ")}}
-
- VKAPI_ATTR {{Node "Type" $.Return}} disabled{{$base}}({{$first_type}}, {{$tail_types}}) {
- driver::Logger({{$p0.Name}}).Err({{$p0.Name}}, §
- "{{$ext_name}} not enabled. Exported {{$.Name}} not executed.");
- {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}}
- }
- ¶
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits code for vkGetInstanceProcAddr for function interception.
-------------------------------------------------------------------------------
-*/}}
-{{define "api.C++.InterceptInstanceProcAddr"}}
- {{AssertType $ "API"}}
-
- // global functions
- if (instance == VK_NULL_HANDLE) {
- {{range $f := AllCommands $}}
- {{if (Macro "IsGloballyDispatched" $f)}}
- if (strcmp(pName, "{{$f.Name}}") == 0) return §
- reinterpret_cast<PFN_vkVoidFunction>({{Macro "BaseName" $f}});
- {{end}}
- {{end}}
- ¶
- ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \"%s\") call", pName);
- return nullptr;
- }
- ¶
- static const struct Hook {
- const char* name;
- PFN_vkVoidFunction proc;
- } hooks[] = {
- {{range $f := SortBy (AllCommands $) "FunctionName"}}
- {{if (Macro "IsFunctionExported" $f)}}
- {{/* hide global functions */}}
- {{if (Macro "IsGloballyDispatched" $f)}}
- { "{{$f.Name}}", nullptr },
-
- {{/* redirect intercepted functions */}}
- {{else if (Macro "api.IsIntercepted" $f)}}
- { "{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
- {{Macro "BaseName" $f}}) },
-
- {{/* redirect vkGetInstanceProcAddr to itself */}}
- {{else if eq $f.Name "vkGetInstanceProcAddr"}}
- { "{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>({{Macro "BaseName" $f}}) },
-
- {{/* redirect device functions to themselves as a workaround for
- layers that do not intercept in their vkGetInstanceProcAddr */}}
- {{else if (Macro "IsDeviceDispatched" $f)}}
- { "{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>({{Macro "BaseName" $f}}) },
-
- {{end}}
- {{end}}
- {{end}}
- };
- // clang-format on
- constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
- auto hook = std::lower_bound(
- hooks, hooks + count, pName,
- [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
- if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
- if (!hook->proc) {
- vulkan::driver::Logger(instance).Err(
- instance, "invalid vkGetInstanceProcAddr(%p, \"%s\") call",
- instance, pName);
- }
- return hook->proc;
- }
- // clang-format off
- ¶
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits code for vkGetDeviceProcAddr for function interception.
-------------------------------------------------------------------------------
-*/}}
-{{define "api.C++.InterceptDeviceProcAddr"}}
- {{AssertType $ "API"}}
-
- if (device == VK_NULL_HANDLE) {
- ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
- return nullptr;
- }
- ¶
- static const char* const known_non_device_names[] = {
- {{range $f := SortBy (AllCommands $) "FunctionName"}}
- {{if (Macro "IsFunctionSupported" $f)}}
- {{if not (Macro "IsDeviceDispatched" $f)}}
- "{{$f.Name}}",
- {{end}}
- {{end}}
- {{end}}
- };
- // clang-format on
- constexpr size_t count = sizeof(known_non_device_names) /
- sizeof(known_non_device_names[0]);
- if (!pName ||
- std::binary_search(
- known_non_device_names, known_non_device_names + count, pName,
- [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
- vulkan::driver::Logger(device).Err(§
- device, "invalid vkGetDeviceProcAddr(%p, \"%s\") call", device,§
- (pName) ? pName : "(null)");
- return nullptr;
- }
- // clang-format off
- ¶
- {{range $f := AllCommands $}}
- {{if (Macro "IsDeviceDispatched" $f)}}
- {{ if (Macro "api.IsIntercepted" $f)}}
- if (strcmp(pName, "{{$f.Name}}") == 0) return §
- reinterpret_cast<PFN_vkVoidFunction>(§
- {{Macro "BaseName" $f}});
- {{else if eq $f.Name "vkGetDeviceProcAddr"}}
- if (strcmp(pName, "{{$f.Name}}") == 0) return §
- reinterpret_cast<PFN_vkVoidFunction>(§
- {{Macro "BaseName" $f}});
- {{end}}
- {{end}}
- {{end}}
- ¶
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits code to dispatch a function.
-------------------------------------------------------------------------------
-*/}}
-{{define "api.C++.Dispatch"}}
- {{AssertType $ "Function"}}
- {{if (Macro "api.IsIntercepted" $)}}
- {{Error "$.Name should not be generated"}}
- {{end}}
-
- {{if not (IsVoid $.Return.Type)}}return §{{end}}
-
- {{$p0 := index $.CallParameters 0}}
- GetData({{$p0.Name}}).dispatch.§
- {{Macro "BaseName" $}}({{Macro "Arguments" $}});
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits a list of extensions intercepted by vulkan::driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.InterceptedExtensions"}}
-VK_ANDROID_native_buffer
-VK_EXT_debug_report
-VK_EXT_hdr_metadata
-VK_EXT_swapchain_colorspace
-VK_GOOGLE_display_timing
-VK_KHR_android_surface
-VK_KHR_incremental_present
-VK_KHR_shared_presentable_image
-VK_KHR_surface
-VK_KHR_swapchain
-VK_KHR_get_surface_capabilities2
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits a list of extensions known to vulkan::driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.KnownExtensions"}}
-{{Macro "driver.InterceptedExtensions"}}
-VK_KHR_get_physical_device_properties2
-VK_ANDROID_external_memory_android_hardware_buffer
-VK_KHR_bind_memory2
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if an extension is intercepted by vulkan::driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.IsExtensionIntercepted"}}
- {{$ext_name := index $.Arguments 0}}
- {{$filters := Strings (Macro "driver.InterceptedExtensions") | SplitOn "\n"}}
-
- {{range $f := $filters}}
- {{if eq $ext_name $f}}true{{end}}
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if a function is intercepted by vulkan::driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.IsIntercepted"}}
- {{AssertType $ "Function"}}
-
- {{if (Macro "IsFunctionSupported" $)}}
- {{/* Create functions of dispatchable objects */}}
- {{ if eq $.Name "vkCreateInstance"}}true
- {{else if eq $.Name "vkCreateDevice"}}true
- {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
- {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true
- {{else if eq $.Name "vkGetDeviceQueue"}}true
- {{else if eq $.Name "vkGetDeviceQueue2"}}true
- {{else if eq $.Name "vkAllocateCommandBuffers"}}true
-
- {{/* Destroy functions of dispatchable objects */}}
- {{else if eq $.Name "vkDestroyInstance"}}true
- {{else if eq $.Name "vkDestroyDevice"}}true
-
- {{/* Enumeration of extensions */}}
- {{else if eq $.Name "vkEnumerateInstanceExtensionProperties"}}true
- {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
-
- {{else if eq $.Name "vkGetInstanceProcAddr"}}true
- {{else if eq $.Name "vkGetDeviceProcAddr"}}true
-
- {{/* VK_KHR_swapchain v69 requirement */}}
- {{else if eq $.Name "vkBindImageMemory2"}}true
- {{else if eq $.Name "vkBindImageMemory2KHR"}}true
- {{end}}
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- {{Macro "driver.IsExtensionIntercepted" $ext}}
- {{end}}
-
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if a function needs a ProcHook stub.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.NeedProcHookStub"}}
- {{AssertType $ "Function"}}
-
- {{if and (Macro "driver.IsIntercepted" $) (Macro "IsDeviceDispatched" $)}}
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- {{if not (Macro "IsExtensionInternal" $ext)}}true{{end}}
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits definition of struct ProcHook.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.C++.DefineProcHookType"}}
- struct ProcHook {
- enum Type {
- GLOBAL,
- INSTANCE,
- DEVICE,
- };
-
- enum Extension {
- {{$exts := Strings (Macro "driver.KnownExtensions") | SplitOn "\n"}}
- {{range $e := $exts}}
- {{TrimPrefix "VK_" $e}},
- {{end}}
- ¶
- EXTENSION_CORE, // valid bit
- EXTENSION_COUNT,
- EXTENSION_UNKNOWN,
- };
- ¶
- const char* name;
- Type type;
- Extension extension;
- ¶
- PFN_vkVoidFunction proc;
- PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks
- };
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits INIT_PROC_EXT macro for vulkan::driver.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.C++.DefineInitProcExtMacro"}}
- #define INIT_PROC_EXT(ext, required, obj, proc) do { \
- if (extensions[ProcHook::ext]) \
- INIT_PROC(required, obj, proc); \
- } while(0)
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a stub for ProcHook::checked_proc.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.C++.DefineProcHookStub"}}
- {{AssertType $ "Function"}}
-
- {{if (Macro "driver.NeedProcHookStub" $)}}
- {{$ext := GetAnnotation $ "extension"}}
- {{$ext_name := index $ext.Arguments 0}}
-
- {{$base := (Macro "BaseName" $)}}
-
- VKAPI_ATTR {{Node "Type" $.Return}} checked{{$base}}({{Macro "Parameters" $}}) {
- {{$p0 := index $.CallParameters 0}}
- {{$ext_hook := Strings ("ProcHook::") (Macro "BaseName" $ext)}}
-
- if (GetData({{$p0.Name}}).hook_extensions[{{$ext_hook}}]) {
- {{if not (IsVoid $.Return.Type)}}return §{{end}}
- {{$base}}({{Macro "Arguments" $}});
- } else {
- Logger({{$p0.Name}}).Err({{$p0.Name}}, "{{$ext_name}} not enabled. {{$.Name}} not executed.");
- {{if not (IsVoid $.Return.Type)}}return VK_SUCCESS;{{end}}
- }
- }
- ¶
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits definition of a global ProcHook.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.C++.DefineGlobalProcHook"}}
- {{AssertType $ "Function"}}
-
- {{$base := (Macro "BaseName" $)}}
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- {{Error "invalid global extension"}}
- {{end}}
-
- {
- "{{$.Name}}",
- ProcHook::GLOBAL,
- ProcHook::EXTENSION_CORE,
- reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
- nullptr,
- },
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits definition of an instance ProcHook.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.C++.DefineInstanceProcHook"}}
- {{AssertType $ "Function"}}
-
- {{$base := (Macro "BaseName" $)}}
-
- {
- "{{$.Name}}",
- ProcHook::INSTANCE,
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- ProcHook::{{Macro "BaseName" $ext}},
-
- {{if (Macro "IsExtensionInternal" $ext)}}
- nullptr,
- nullptr,
- {{else}}
- reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
- nullptr,
- {{end}}
- {{else}}
- ProcHook::EXTENSION_CORE,
- reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
- nullptr,
- {{end}}
- },
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits definition of a device ProcHook.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.C++.DefineDeviceProcHook"}}
- {{AssertType $ "Function"}}
-
- {{$base := (Macro "BaseName" $)}}
-
- {
- "{{$.Name}}",
- ProcHook::DEVICE,
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- ProcHook::{{Macro "BaseName" $ext}},
-
- {{if (Macro "IsExtensionInternal" $ext)}}
- nullptr,
- nullptr,
- {{else}}
- reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
- reinterpret_cast<PFN_vkVoidFunction>(checked{{$base}}),
- {{end}}
- {{else}}
- ProcHook::EXTENSION_CORE,
- reinterpret_cast<PFN_vkVoidFunction>({{$base}}),
- nullptr,
- {{end}}
- },
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits true if a function is needed by vulkan::driver.
--------------------------------------------------------------------------------
-*/}}
-{{define "driver.IsDriverTableEntry"}}
- {{AssertType $ "Function"}}
-
- {{if (Macro "IsFunctionSupported" $)}}
- {{/* Create functions of dispatchable objects */}}
- {{ if eq $.Name "vkCreateDevice"}}true
- {{else if eq $.Name "vkGetDeviceQueue"}}true
- {{else if eq $.Name "vkGetDeviceQueue2"}}true
- {{else if eq $.Name "vkAllocateCommandBuffers"}}true
-
- {{/* Destroy functions of dispatchable objects */}}
- {{else if eq $.Name "vkDestroyInstance"}}true
- {{else if eq $.Name "vkDestroyDevice"}}true
-
- {{/* Enumeration of extensions */}}
- {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
-
- {{/* We cache physical devices in loader.cpp */}}
- {{else if eq $.Name "vkEnumeratePhysicalDevices"}}true
- {{else if eq $.Name "vkEnumeratePhysicalDeviceGroups"}}true
-
- {{else if eq $.Name "vkGetInstanceProcAddr"}}true
- {{else if eq $.Name "vkGetDeviceProcAddr"}}true
-
- {{/* VK_KHR_swapchain->VK_ANDROID_native_buffer translation */}}
- {{else if eq $.Name "vkCreateImage"}}true
- {{else if eq $.Name "vkDestroyImage"}}true
-
- {{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
- {{else if eq $.Name "vkGetPhysicalDeviceProperties2"}}true
- {{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true
-
- {{/* VK_KHR_swapchain v69 requirement */}}
- {{else if eq $.Name "vkBindImageMemory2"}}true
- {{else if eq $.Name "vkBindImageMemory2KHR"}}true
- {{end}}
-
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- {{$ext_name := index $ext.Arguments 0}}
- {{ if eq $ext_name "VK_ANDROID_native_buffer"}}true
- {{else if eq $ext_name "VK_EXT_debug_report"}}true
- {{end}}
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if an instance-dispatched function is needed by vulkan::driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.IsInstanceDriverTableEntry"}}
- {{AssertType $ "Function"}}
-
- {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsInstanceDispatched" $)}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits true if a device-dispatched function is needed by vulkan::driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "driver.IsDeviceDriverTableEntry"}}
- {{AssertType $ "Function"}}
-
- {{if and (Macro "driver.IsDriverTableEntry" $) (Macro "IsDeviceDispatched" $)}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a function/extension name without the "vk"/"VK_" prefix.
--------------------------------------------------------------------------------
-*/}}
-{{define "BaseName"}}
- {{ if IsFunction $}}{{TrimPrefix "vk" $.Name}}
- {{else if eq $.Name "extension"}}{{TrimPrefix "VK_" (index $.Arguments 0)}}
- {{else}}{{Error "invalid use of BaseName"}}
- {{end}}
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a comma-separated list of C parameter names for the given command.
--------------------------------------------------------------------------------
-*/}}
-{{define "Arguments"}}
- {{AssertType $ "Function"}}
-
- {{ForEach $.CallParameters "ParameterName" | JoinWith ", "}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-*/}}
-{{define "IsGloballyDispatched"}}
- {{AssertType $ "Function"}}
- {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Global")}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emit "true" for supported functions that undergo table dispatch. Only global
- functions and functions handled in the loader top without calling into
- lower layers are not dispatched.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsInstanceDispatched"}}
- {{AssertType $ "Function"}}
- {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emit "true" for supported functions that can have device-specific dispatch.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsDeviceDispatched"}}
- {{AssertType $ "Function"}}
- {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Device")}}
- true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emit "true" if a function is core or from a supportable extension.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsFunctionSupported"}}
- {{AssertType $ "Function"}}
- {{if not (GetAnnotation $ "pfn")}}
- {{$ext := GetAnnotation $ "extension"}}
- {{if not $ext}}true
- {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Decides whether a function should be exported from the Android Vulkan
- library. Functions in the core API and in loader extensions are exported.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsFunctionExported"}}
- {{AssertType $ "Function"}}
-
- {{if (Macro "IsFunctionSupported" $)}}
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- {{Macro "IsExtensionExported" $ext}}
- {{else}}
- true
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emit "true" if an extension is unsupportable on Android.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsExtensionBlacklisted"}}
- {{$ext := index $.Arguments 0}}
- {{ if eq $ext "VK_KHR_display"}}true
- {{else if eq $ext "VK_KHR_display_swapchain"}}true
- {{else if eq $ext "VK_KHR_mir_surface"}}true
- {{else if eq $ext "VK_KHR_xcb_surface"}}true
- {{else if eq $ext "VK_KHR_xlib_surface"}}true
- {{else if eq $ext "VK_KHR_wayland_surface"}}true
- {{else if eq $ext "VK_KHR_win32_surface"}}true
- {{else if eq $ext "VK_KHR_external_memory_win32"}}true
- {{else if eq $ext "VK_KHR_win32_keyed_mutex"}}true
- {{else if eq $ext "VK_KHR_external_semaphore_win32"}}true
- {{else if eq $ext "VK_KHR_external_fence_win32"}}true
- {{else if eq $ext "VK_EXT_acquire_xlib_display"}}true
- {{else if eq $ext "VK_EXT_direct_mode_display"}}true
- {{else if eq $ext "VK_EXT_display_surface_counter"}}true
- {{else if eq $ext "VK_EXT_display_control"}}true
- {{else if eq $ext "VK_FUCHSIA_imagepipe_surface"}}true
- {{else if eq $ext "VK_MVK_ios_surface"}}true
- {{else if eq $ext "VK_MVK_macos_surface"}}true
- {{else if eq $ext "VK_NN_vi_surface"}}true
- {{else if eq $ext "VK_NV_external_memory_win32"}}true
- {{else if eq $ext "VK_NV_win32_keyed_mutex"}}true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Reports whether an extension has functions exported by the loader.
- E.g. applications can directly link to an extension function.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsExtensionExported"}}
- {{$ext := index $.Arguments 0}}
- {{ if eq $ext "VK_KHR_surface"}}true
- {{else if eq $ext "VK_KHR_swapchain"}}true
- {{else if eq $ext "VK_KHR_android_surface"}}true
- {{else if eq $ext "VK_ANDROID_external_memory_android_hardware_buffer"}}true
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Reports whether an extension is internal to the loader and drivers,
- so the loader should not enumerate it.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsExtensionInternal"}}
- {{$ext := index $.Arguments 0}}
- {{ if eq $ext "VK_ANDROID_native_buffer"}}true
- {{end}}
-{{end}}
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index a53bb59..b413ac9 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -16,40 +16,35 @@
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "driver.h"
+
+#include <dlfcn.h>
#include <malloc.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/prctl.h>
-
-#include <dlfcn.h>
-#include <algorithm>
-#include <array>
-#include <new>
-
-#include <log/log.h>
#include <android/dlext.h>
#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android-base/properties.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <graphicsenv/GraphicsEnv.h>
+#include <log/log.h>
+#include <nativeloader/dlext_namespaces.h>
+#include <sys/prctl.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
-#include <utils/Vector.h>
-#include "android-base/properties.h"
+#include <algorithm>
+#include <array>
+#include <new>
+#include <vector>
-#include "driver.h"
#include "stubhal.h"
using namespace android::hardware::configstore;
using namespace android::hardware::configstore::V1_0;
-// TODO(b/37049319) Get this from a header once one exists
-extern "C" {
-android_namespace_t* android_get_exported_namespace(const char*);
-}
-
// #define ENABLE_ALLOC_CALLSTACKS 1
#if ENABLE_ALLOC_CALLSTACKS
#include <utils/CallStack.h>
@@ -212,7 +207,7 @@
if (!ns)
return -ENOENT;
android::GraphicsEnv::getInstance().setDriverToLoad(
- android::GraphicsEnv::Driver::VULKAN);
+ android::GpuStatsInfo::Driver::VULKAN);
return LoadDriver(ns, module);
}
@@ -223,7 +218,7 @@
if (!ns)
return -ENOENT;
android::GraphicsEnv::getInstance().setDriverToLoad(
- android::GraphicsEnv::Driver::VULKAN_UPDATED);
+ android::GpuStatsInfo::Driver::VULKAN_UPDATED);
return LoadDriver(ns, module);
}
@@ -258,7 +253,7 @@
}
if (result != 0) {
android::GraphicsEnv::getInstance().setDriverLoaded(
- android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime);
+ android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime);
ALOGV("unable to load Vulkan HAL, using stub HAL (result=%d)", result);
return true;
}
@@ -272,7 +267,7 @@
ATRACE_END();
if (result != 0) {
android::GraphicsEnv::getInstance().setDriverLoaded(
- android::GraphicsEnv::Api::API_VK, false, systemTime() - openTime);
+ android::GpuStatsInfo::Api::API_VK, false, systemTime() - openTime);
// Any device with a Vulkan HAL should be able to open the device.
ALOGE("failed to open Vulkan HAL device: %s (%d)", strerror(-result),
result);
@@ -284,7 +279,7 @@
hal_.InitDebugReportIndex();
android::GraphicsEnv::getInstance().setDriverLoaded(
- android::GraphicsEnv::Api::API_VK, true, systemTime() - openTime);
+ android::GpuStatsInfo::Api::API_VK, true, systemTime() - openTime);
return true;
}
@@ -809,8 +804,7 @@
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties) {
-
- android::Vector<VkExtensionProperties> loader_extensions;
+ std::vector<VkExtensionProperties> loader_extensions;
loader_extensions.push_back({
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_SURFACE_SPEC_VERSION});
@@ -833,7 +827,7 @@
uint32_t count = std::min(
*pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
- std::copy_n(loader_extensions.begin(), count, pProperties);
+ std::copy_n(loader_extensions.data(), count, pProperties);
if (count < loader_extensions.size()) {
*pPropertyCount = count;
@@ -879,8 +873,7 @@
bool QueryPresentationProperties(
VkPhysicalDevice physicalDevice,
- VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties)
-{
+ VkPhysicalDevicePresentationPropertiesANDROID *presentation_properties) {
const InstanceData& data = GetData(physicalDevice);
// GPDP2 must be present and enabled on the instance.
@@ -920,7 +913,7 @@
VkExtensionProperties* pProperties) {
const InstanceData& data = GetData(physicalDevice);
// extensions that are unconditionally exposed by the loader
- android::Vector<VkExtensionProperties> loader_extensions;
+ std::vector<VkExtensionProperties> loader_extensions;
loader_extensions.push_back({
VK_KHR_INCREMENTAL_PRESENT_EXTENSION_NAME,
VK_KHR_INCREMENTAL_PRESENT_SPEC_VERSION});
@@ -956,7 +949,7 @@
uint32_t count = std::min(
*pPropertyCount, static_cast<uint32_t>(loader_extensions.size()));
- std::copy_n(loader_extensions.begin(), count, pProperties);
+ std::copy_n(loader_extensions.data(), count, pProperties);
if (count < loader_extensions.size()) {
*pPropertyCount = count;
@@ -1177,7 +1170,7 @@
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_CPU) {
// Log that the app is hitting software Vulkan implementation
android::GraphicsEnv::getInstance().setTargetStats(
- android::GraphicsEnv::Stats::CPU_VULKAN_IN_USE);
+ android::GpuStatsInfo::Stats::CPU_VULKAN_IN_USE);
}
data->driver_device = dev;
@@ -1246,11 +1239,10 @@
if (!device_count)
return VK_INCOMPLETE;
- android::Vector<VkPhysicalDevice> devices;
- devices.resize(device_count);
+ std::vector<VkPhysicalDevice> devices(device_count);
*pPhysicalDeviceGroupCount = device_count;
- result = EnumeratePhysicalDevices(instance, &device_count,
- devices.editArray());
+ result =
+ EnumeratePhysicalDevices(instance, &device_count, devices.data());
if (result < 0)
return result;
@@ -1321,5 +1313,16 @@
return result;
}
+VKAPI_ATTR VkResult QueueSubmit(VkQueue queue,
+ uint32_t submitCount,
+ const VkSubmitInfo* pSubmits,
+ VkFence fence) {
+ ATRACE_CALL();
+
+ const auto& data = GetData(queue);
+
+ return data.driver.QueueSubmit(queue, submitCount, pSubmits, fence);
+}
+
} // namespace driver
} // namespace vulkan
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 57c956d..f058c47 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -131,6 +131,7 @@
VKAPI_ATTR void GetDeviceQueue(VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);
VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
VKAPI_ATTR VkResult AllocateCommandBuffers(VkDevice device, const VkCommandBufferAllocateInfo* pAllocateInfo, VkCommandBuffer* pCommandBuffers);
+VKAPI_ATTR VkResult QueueSubmit(VkQueue queue, uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence);
// clang-format on
template <typename DispatchableType>
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 574c327..d829e41 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -16,12 +16,11 @@
// WARNING: This file is generated. See ../README.md for instructions.
+#include <log/log.h>
#include <string.h>
#include <algorithm>
-#include <log/log.h>
-
#include "driver.h"
namespace vulkan {
@@ -75,6 +74,15 @@
}
}
+VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos) {
+ if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) {
+ return BindImageMemory2KHR(device, bindInfoCount, pBindInfos);
+ } else {
+ Logger(device).Err(device, "VK_KHR_bind_memory2 not enabled. vkBindImageMemory2KHR not executed.");
+ return VK_SUCCESS;
+ }
+}
+
VKAPI_ATTR VkResult checkedGetDeviceGroupPresentCapabilitiesKHR(VkDevice device, VkDeviceGroupPresentCapabilitiesKHR* pDeviceGroupPresentCapabilities) {
if (GetData(device).hook_extensions[ProcHook::KHR_swapchain]) {
return GetDeviceGroupPresentCapabilitiesKHR(device, pDeviceGroupPresentCapabilities);
@@ -102,24 +110,6 @@
}
}
-VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
- if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) {
- return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
- } else {
- Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetRefreshCycleDurationGOOGLE not executed.");
- return VK_SUCCESS;
- }
-}
-
-VKAPI_ATTR VkResult checkedGetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings) {
- if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) {
- return GetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings);
- } else {
- Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetPastPresentationTimingGOOGLE not executed.");
- return VK_SUCCESS;
- }
-}
-
VKAPI_ATTR void checkedSetHdrMetadataEXT(VkDevice device, uint32_t swapchainCount, const VkSwapchainKHR* pSwapchains, const VkHdrMetadataEXT* pMetadata) {
if (GetData(device).hook_extensions[ProcHook::EXT_hdr_metadata]) {
SetHdrMetadataEXT(device, swapchainCount, pSwapchains, pMetadata);
@@ -137,11 +127,20 @@
}
}
-VKAPI_ATTR VkResult checkedBindImageMemory2KHR(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfoKHR* pBindInfos) {
- if (GetData(device).hook_extensions[ProcHook::KHR_bind_memory2]) {
- return BindImageMemory2KHR(device, bindInfoCount, pBindInfos);
+VKAPI_ATTR VkResult checkedGetRefreshCycleDurationGOOGLE(VkDevice device, VkSwapchainKHR swapchain, VkRefreshCycleDurationGOOGLE* pDisplayTimingProperties) {
+ if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) {
+ return GetRefreshCycleDurationGOOGLE(device, swapchain, pDisplayTimingProperties);
} else {
- Logger(device).Err(device, "VK_KHR_bind_memory2 not enabled. vkBindImageMemory2KHR not executed.");
+ Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetRefreshCycleDurationGOOGLE not executed.");
+ return VK_SUCCESS;
+ }
+}
+
+VKAPI_ATTR VkResult checkedGetPastPresentationTimingGOOGLE(VkDevice device, VkSwapchainKHR swapchain, uint32_t* pPresentationTimingCount, VkPastPresentationTimingGOOGLE* pPresentationTimings) {
+ if (GetData(device).hook_extensions[ProcHook::GOOGLE_display_timing]) {
+ return GetPastPresentationTimingGOOGLE(device, swapchain, pPresentationTimingCount, pPresentationTimings);
+ } else {
+ Logger(device).Err(device, "VK_GOOGLE_display_timing not enabled. vkGetPastPresentationTimingGOOGLE not executed.");
return VK_SUCCESS;
}
}
@@ -445,6 +444,13 @@
nullptr,
},
{
+ "vkQueueSubmit",
+ ProcHook::DEVICE,
+ ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(QueueSubmit),
+ nullptr,
+ },
+ {
"vkSetHdrMetadataEXT",
ProcHook::DEVICE,
ProcHook::EXT_hdr_metadata,
@@ -517,12 +523,12 @@
INIT_PROC(true, instance, GetPhysicalDeviceProperties);
INIT_PROC(true, instance, CreateDevice);
INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
- INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
- INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
+ INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
INIT_PROC_EXT(KHR_get_physical_device_properties2, true, instance, GetPhysicalDeviceProperties2KHR);
+ INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
// clang-format on
return success;
@@ -538,16 +544,17 @@
INIT_PROC(true, dev, GetDeviceProcAddr);
INIT_PROC(true, dev, DestroyDevice);
INIT_PROC(true, dev, GetDeviceQueue);
+ INIT_PROC(true, dev, QueueSubmit);
INIT_PROC(true, dev, CreateImage);
INIT_PROC(true, dev, DestroyImage);
INIT_PROC(true, dev, AllocateCommandBuffers);
INIT_PROC(false, dev, BindImageMemory2);
+ INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR);
INIT_PROC(false, dev, GetDeviceQueue2);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, false, dev, GetSwapchainGrallocUsage2ANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, AcquireImageANDROID);
INIT_PROC_EXT(ANDROID_native_buffer, true, dev, QueueSignalReleaseImageANDROID);
- INIT_PROC_EXT(KHR_bind_memory2, true, dev, BindImageMemory2KHR);
// clang-format on
return success;
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 3faf6c0..fb2f257 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -21,6 +21,7 @@
#include <vulkan/vk_android_native_buffer.h>
#include <vulkan/vulkan.h>
+
#include <bitset>
namespace vulkan {
@@ -69,12 +70,12 @@
PFN_vkGetPhysicalDeviceProperties GetPhysicalDeviceProperties;
PFN_vkCreateDevice CreateDevice;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
- PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
- PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
PFN_vkDebugReportMessageEXT DebugReportMessageEXT;
+ PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
PFN_vkGetPhysicalDeviceProperties2KHR GetPhysicalDeviceProperties2KHR;
+ PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
// clang-format on
};
@@ -83,16 +84,17 @@
PFN_vkGetDeviceProcAddr GetDeviceProcAddr;
PFN_vkDestroyDevice DestroyDevice;
PFN_vkGetDeviceQueue GetDeviceQueue;
+ PFN_vkQueueSubmit QueueSubmit;
PFN_vkCreateImage CreateImage;
PFN_vkDestroyImage DestroyImage;
PFN_vkAllocateCommandBuffers AllocateCommandBuffers;
PFN_vkBindImageMemory2 BindImageMemory2;
+ PFN_vkBindImageMemory2KHR BindImageMemory2KHR;
PFN_vkGetDeviceQueue2 GetDeviceQueue2;
PFN_vkGetSwapchainGrallocUsageANDROID GetSwapchainGrallocUsageANDROID;
PFN_vkGetSwapchainGrallocUsage2ANDROID GetSwapchainGrallocUsage2ANDROID;
PFN_vkAcquireImageANDROID AcquireImageANDROID;
PFN_vkQueueSignalReleaseImageANDROID QueueSignalReleaseImageANDROID;
- PFN_vkBindImageMemory2KHR BindImageMemory2KHR;
// clang-format on
};
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 5f4c6b1..d60eaa7 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -18,13 +18,13 @@
#include <android/hardware/graphics/common/1.0/types.h>
#include <grallocusage/GrallocUsageConversion.h>
+#include <graphicsenv/GraphicsEnv.h>
#include <log/log.h>
#include <sync/sync.h>
#include <system/window.h>
#include <ui/BufferQueueDefs.h>
#include <utils/StrongPointer.h>
#include <utils/Trace.h>
-#include <utils/Vector.h>
#include <algorithm>
#include <unordered_set>
@@ -34,10 +34,6 @@
using android::hardware::graphics::common::V1_0::BufferUsage;
-// TODO(jessehall): Currently we don't have a good error code for when a native
-// window operation fails. Just returning INITIALIZATION_FAILED for now. Later
-// versions (post SDK 0.9) of the API/extension have a better error code.
-// When updating to that version, audit all error returns.
namespace vulkan {
namespace driver {
@@ -48,29 +44,12 @@
VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR |
VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR |
VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
- // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
- // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
- // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
- // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
- // VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
+ VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR |
+ VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
+ VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR |
+ VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR |
VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR;
-int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform) {
- switch (transform) {
- // TODO: See TODO in TranslateNativeToVulkanTransform
- case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
- return NATIVE_WINDOW_TRANSFORM_ROT_90;
- case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
- return NATIVE_WINDOW_TRANSFORM_ROT_180;
- case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
- return NATIVE_WINDOW_TRANSFORM_ROT_270;
- case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
- case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
- default:
- return 0;
- }
-}
-
VkSurfaceTransformFlagBitsKHR TranslateNativeToVulkanTransform(int native) {
// Native and Vulkan transforms are isomorphic, but are represented
// differently. Vulkan transforms are built up of an optional horizontal
@@ -78,27 +57,22 @@
// transforms are built up from a horizontal flip, vertical flip, and
// 90-degree rotation, all optional but always in that order.
- // TODO(jessehall): For now, only support pure rotations, not
- // flip or flip-and-rotate, until I have more time to test them and build
- // sample code. As far as I know we never actually use anything besides
- // pure rotations anyway.
-
switch (native) {
- case 0: // 0x0
+ case 0:
return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- // case NATIVE_WINDOW_TRANSFORM_FLIP_H: // 0x1
- // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
- // case NATIVE_WINDOW_TRANSFORM_FLIP_V: // 0x2
- // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
- case NATIVE_WINDOW_TRANSFORM_ROT_180: // FLIP_H | FLIP_V
+ case NATIVE_WINDOW_TRANSFORM_FLIP_H:
+ return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_FLIP_V:
+ return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
- case NATIVE_WINDOW_TRANSFORM_ROT_90: // 0x4
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
- // case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
- // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
- // case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
- // return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
- case NATIVE_WINDOW_TRANSFORM_ROT_270: // FLIP_H | FLIP_V | ROT_90
+ case NATIVE_WINDOW_TRANSFORM_FLIP_H | NATIVE_WINDOW_TRANSFORM_ROT_90:
+ return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_FLIP_V | NATIVE_WINDOW_TRANSFORM_ROT_90:
+ return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
case NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY:
default:
@@ -106,6 +80,31 @@
}
}
+int TranslateVulkanToNativeTransform(VkSurfaceTransformFlagBitsKHR transform) {
+ switch (transform) {
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_180;
+ case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_270;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_H |
+ NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_V;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+ case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
+ default:
+ return 0;
+ }
+}
+
int InvertTransformToNative(VkSurfaceTransformFlagBitsKHR transform) {
switch (transform) {
case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
@@ -114,17 +113,16 @@
return NATIVE_WINDOW_TRANSFORM_ROT_180;
case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
return NATIVE_WINDOW_TRANSFORM_ROT_90;
- // TODO(jessehall): See TODO in TranslateNativeToVulkanTransform.
- // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
- // return NATIVE_WINDOW_TRANSFORM_FLIP_H;
- // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
- // return NATIVE_WINDOW_TRANSFORM_FLIP_H |
- // NATIVE_WINDOW_TRANSFORM_ROT_90;
- // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
- // return NATIVE_WINDOW_TRANSFORM_FLIP_V;
- // case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
- // return NATIVE_WINDOW_TRANSFORM_FLIP_V |
- // NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_H;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_H |
+ NATIVE_WINDOW_TRANSFORM_ROT_90;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_V;
+ case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_FLIP_V |
+ NATIVE_WINDOW_TRANSFORM_ROT_90;
case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
default:
@@ -134,7 +132,6 @@
class TimingInfo {
public:
- TimingInfo() = default;
TimingInfo(const VkPresentTimeGOOGLE* qp, uint64_t nativeFrameId)
: vals_{qp->presentID, qp->desiredPresentTime, 0, 0, 0},
native_frame_id_(nativeFrameId) {}
@@ -201,8 +198,6 @@
{ NATIVE_WINDOW_TIMESTAMP_PENDING };
};
-// ----------------------------------------------------------------------------
-
struct Surface {
android::sp<ANativeWindow> window;
VkSwapchainKHR swapchain_handle;
@@ -270,7 +265,7 @@
bool dequeued;
} images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
- android::Vector<TimingInfo> timing;
+ std::vector<TimingInfo> timing;
};
VkSwapchainKHR HandleFromSwapchain(Swapchain* swapchain) {
@@ -285,6 +280,8 @@
ANativeWindow* window,
int release_fence,
Swapchain::Image& image) {
+ ATRACE_CALL();
+
ALOG_ASSERT(release_fence == -1 || image.dequeued,
"ReleaseSwapchainImage: can't provide a release fence for "
"non-dequeued images");
@@ -323,7 +320,9 @@
}
if (image.image) {
+ ATRACE_BEGIN("DestroyImage");
GetData(device).driver.DestroyImage(device, image.image, nullptr);
+ ATRACE_END();
image.image = VK_NULL_HANDLE;
}
@@ -349,7 +348,7 @@
uint32_t num_ready = 0;
const size_t num_timings = swapchain.timing.size() - MIN_NUM_FRAMES_AGO + 1;
for (uint32_t i = 0; i < num_timings; i++) {
- TimingInfo& ti = swapchain.timing.editItemAt(i);
+ TimingInfo& ti = swapchain.timing[i];
if (ti.ready()) {
// This TimingInfo is ready to be reported to the user. Add it
// to the num_ready.
@@ -371,9 +370,6 @@
nullptr, //&first_composition_start_time,
nullptr, //&last_composition_start_time,
nullptr, //&composition_finish_time,
- // TODO(ianelliott): Maybe ask if this one is
- // supported, at startup time (since it may not be
- // supported):
&actual_present_time,
nullptr, //&dequeue_ready_time,
nullptr /*&reads_done_time*/);
@@ -400,7 +396,6 @@
return num_ready;
}
-// TODO(ianelliott): DEAL WITH RETURN VALUE (e.g. VK_INCOMPLETE)!!!
void copy_ready_timings(Swapchain& swapchain,
uint32_t* count,
VkPastPresentationTimingGOOGLE* timings) {
@@ -419,7 +414,7 @@
}
uint32_t num_copied = 0;
- size_t num_to_remove = 0;
+ int32_t num_to_remove = 0;
for (uint32_t i = 0; i <= last_ready && num_copied < *count; i++) {
const TimingInfo& ti = swapchain.timing[i];
if (ti.ready()) {
@@ -431,7 +426,8 @@
// Discard old frames that aren't ready if newer frames are ready.
// We don't expect to get the timing info for those old frames.
- swapchain.timing.removeItemsAt(0, num_to_remove);
+ swapchain.timing.erase(swapchain.timing.begin(),
+ swapchain.timing.begin() + num_to_remove);
*count = num_copied;
}
@@ -539,15 +535,12 @@
strerror(-err), err);
surface->~Surface();
allocator->pfnFree(allocator->pUserData, surface);
- return VK_ERROR_INITIALIZATION_FAILED;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
- // TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
err =
native_window_api_connect(surface->window.get(), NATIVE_WINDOW_API_EGL);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_api_connect() failed: %s (%d)", strerror(-err),
err);
surface->~Surface();
@@ -656,7 +649,6 @@
return VK_ERROR_SURFACE_LOST_KHR;
}
- // TODO(jessehall): Figure out what the min/max values should be.
int max_buffer_count;
err = window->query(window, NATIVE_WINDOW_MAX_BUFFER_COUNT, &max_buffer_count);
if (err != 0) {
@@ -670,8 +662,7 @@
capabilities->currentExtent =
VkExtent2D{static_cast<uint32_t>(width), static_cast<uint32_t>(height)};
- // TODO(jessehall): Figure out what the max extent should be. Maximum
- // texture dimension maybe?
+ // TODO(http://b/134182502): Figure out what the max extent should be.
capabilities->minImageExtent = VkExtent2D{1, 1};
capabilities->maxImageExtent = VkExtent2D{4096, 4096};
@@ -685,11 +676,6 @@
// associated with the bufferqueue. It can't be changed from here.
capabilities->supportedCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
- // TODO(jessehall): I think these are right, but haven't thought hard about
- // it. Do we need to query the driver for support of any of these?
- // Currently not included:
- // - VK_IMAGE_USAGE_DEPTH_STENCIL_BIT: definitely not
- // - VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT: definitely not
capabilities->supportedUsageFlags =
VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT |
@@ -729,8 +715,7 @@
int err = native_window_get_wide_color_support(surface.window.get(),
&wide_color_support);
if (err) {
- // Not allowed to return a more sensible error code, so do this
- return VK_ERROR_OUT_OF_HOST_MEMORY;
+ return VK_ERROR_SURFACE_LOST_KHR;
}
ALOGV("wide_color_support is: %d", wide_color_support);
wide_color_support =
@@ -828,11 +813,10 @@
} else {
// temp vector for forwarding; we'll marshal it into the pSurfaceFormats
// after the call.
- android::Vector<VkSurfaceFormatKHR> surface_formats;
- surface_formats.resize(*pSurfaceFormatCount);
+ std::vector<VkSurfaceFormatKHR> surface_formats(*pSurfaceFormatCount);
VkResult result = GetPhysicalDeviceSurfaceFormatsKHR(
physicalDevice, pSurfaceInfo->surface, pSurfaceFormatCount,
- &surface_formats.editItemAt(0));
+ surface_formats.data());
if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
// marshal results individually due to stride difference.
@@ -874,7 +858,7 @@
}
uint32_t max_buffer_count = static_cast<uint32_t>(query_value);
- android::Vector<VkPresentModeKHR> present_modes;
+ std::vector<VkPresentModeKHR> present_modes;
if (min_undequeued_buffers + 1 < max_buffer_count)
present_modes.push_back(VK_PRESENT_MODE_MAILBOX_KHR);
present_modes.push_back(VK_PRESENT_MODE_FIFO_KHR);
@@ -894,7 +878,7 @@
if (*count < num_modes)
result = VK_INCOMPLETE;
*count = std::min(*count, num_modes);
- std::copy(present_modes.begin(), present_modes.begin() + int(*count), modes);
+ std::copy_n(present_modes.data(), *count, modes);
} else {
*count = num_modes;
}
@@ -978,6 +962,40 @@
return VK_SUCCESS;
}
+static void DestroySwapchainInternal(VkDevice device,
+ VkSwapchainKHR swapchain_handle,
+ const VkAllocationCallbacks* allocator) {
+ ATRACE_CALL();
+
+ const auto& dispatch = GetData(device).driver;
+ Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
+ if (!swapchain) {
+ return;
+ }
+
+ bool active = swapchain->surface.swapchain_handle == swapchain_handle;
+ ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
+
+ if (window && swapchain->frame_timestamps_enabled) {
+ native_window_enable_frame_timestamps(window, false);
+ }
+
+ for (uint32_t i = 0; i < swapchain->num_images; i++) {
+ ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
+ }
+
+ if (active) {
+ swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
+ }
+
+ if (!allocator) {
+ allocator = &GetData(device).allocator;
+ }
+
+ swapchain->~Swapchain();
+ allocator->pfnFree(allocator->pUserData, swapchain);
+}
+
VKAPI_ATTR
VkResult CreateSwapchainKHR(VkDevice device,
const VkSwapchainCreateInfoKHR* create_info,
@@ -1052,6 +1070,8 @@
// non-FREE state at any given time. Disconnecting and re-connecting
// orphans the previous buffers, getting us back to the state where we can
// dequeue all buffers.
+ //
+ // TODO(http://b/134186185) recycle swapchain images more efficiently
err = native_window_api_disconnect(surface.window.get(),
NATIVE_WINDOW_API_EGL);
ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
@@ -1072,8 +1092,6 @@
create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR ? 0 : 1;
err = surface.window->setSwapInterval(surface.window.get(), swap_interval);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window->setSwapInterval(1) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1100,8 +1118,6 @@
err = native_window_set_buffers_format(surface.window.get(),
native_pixel_format);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffers_format(%d) failed: %s (%d)",
native_pixel_format, strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1109,8 +1125,6 @@
err = native_window_set_buffers_data_space(surface.window.get(),
native_dataspace);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffers_data_space(%d) failed: %s (%d)",
native_dataspace, strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1120,8 +1134,6 @@
surface.window.get(), static_cast<int>(create_info->imageExtent.width),
static_cast<int>(create_info->imageExtent.height));
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
create_info->imageExtent.width, create_info->imageExtent.height,
strerror(-err), err);
@@ -1140,8 +1152,6 @@
surface.window.get(),
InvertTransformToNative(create_info->preTransform));
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
InvertTransformToNative(create_info->preTransform),
strerror(-err), err);
@@ -1151,8 +1161,6 @@
err = native_window_set_scaling_mode(
surface.window.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_scaling_mode(SCALE_TO_WINDOW) failed: %s (%d)",
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1182,8 +1190,6 @@
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
&query_value);
if (err != 0 || query_value < 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("window->query failed: %s (%d) value=%d", strerror(-err), err,
query_value);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1201,8 +1207,6 @@
// can't actually use!).
err = native_window_set_buffer_count(surface.window.get(), std::max(2u, num_images));
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_buffer_count(%d) failed: %s (%d)", num_images,
strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
@@ -1211,7 +1215,7 @@
int32_t legacy_usage = 0;
if (dispatch.GetSwapchainGrallocUsage2ANDROID) {
uint64_t consumer_usage, producer_usage;
- ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsage2ANDROID");
+ ATRACE_BEGIN("GetSwapchainGrallocUsage2ANDROID");
result = dispatch.GetSwapchainGrallocUsage2ANDROID(
device, create_info->imageFormat, create_info->imageUsage,
swapchain_image_usage, &consumer_usage, &producer_usage);
@@ -1223,7 +1227,7 @@
legacy_usage =
android_convertGralloc1To0Usage(producer_usage, consumer_usage);
} else if (dispatch.GetSwapchainGrallocUsageANDROID) {
- ATRACE_BEGIN("dispatch.GetSwapchainGrallocUsageANDROID");
+ ATRACE_BEGIN("GetSwapchainGrallocUsageANDROID");
result = dispatch.GetSwapchainGrallocUsageANDROID(
device, create_info->imageFormat, create_info->imageUsage,
&legacy_usage);
@@ -1242,12 +1246,19 @@
}
err = native_window_set_usage(surface.window.get(), native_usage);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
+ int transform_hint;
+ err = surface.window->query(surface.window.get(),
+ NATIVE_WINDOW_TRANSFORM_HINT, &transform_hint);
+ if (err != 0) {
+ ALOGE("NATIVE_WINDOW_TRANSFORM_HINT query failed: %s (%d)",
+ strerror(-err), err);
+ return VK_ERROR_SURFACE_LOST_KHR;
+ }
+
// -- Allocate our Swapchain object --
// After this point, we must deallocate the swapchain on error.
@@ -1301,8 +1312,6 @@
err = surface.window->dequeueBuffer(surface.window.get(), &buffer,
&img.dequeue_fence);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate
- // possible errors and translate them to valid Vulkan result codes?
ALOGE("dequeueBuffer[%u] failed: %s (%d)", i, strerror(-err), err);
result = VK_ERROR_SURFACE_LOST_KHR;
break;
@@ -1322,7 +1331,7 @@
&image_native_buffer.usage2.producer,
&image_native_buffer.usage2.consumer);
- ATRACE_BEGIN("dispatch.CreateImage");
+ ATRACE_BEGIN("CreateImage");
result =
dispatch.CreateImage(device, &image_create, nullptr, &img.image);
ATRACE_END();
@@ -1335,9 +1344,6 @@
// -- Cancel all buffers, returning them to the queue --
// If an error occurred before, also destroy the VkImage and release the
// buffer reference. Otherwise, we retain a strong reference to the buffer.
- //
- // TODO(jessehall): The error path here is the same as DestroySwapchain,
- // but not the non-error path. Should refactor/unify.
for (uint32_t i = 0; i < num_images; i++) {
Swapchain::Image& img = swapchain->images[i];
if (img.dequeued) {
@@ -1348,21 +1354,20 @@
img.dequeued = false;
}
}
- if (result != VK_SUCCESS) {
- if (img.image) {
- ATRACE_BEGIN("dispatch.DestroyImage");
- dispatch.DestroyImage(device, img.image, nullptr);
- ATRACE_END();
- }
- }
}
if (result != VK_SUCCESS) {
- swapchain->~Swapchain();
- allocator->pfnFree(allocator->pUserData, swapchain);
+ DestroySwapchainInternal(device, HandleFromSwapchain(swapchain),
+ allocator);
return result;
}
+ if (transform_hint != swapchain->pre_transform) {
+ // Log that the app is not doing pre-rotation.
+ android::GraphicsEnv::getInstance().setTargetStats(
+ android::GpuStatsInfo::Stats::FALSE_PREROTATION);
+ }
+
surface.swapchain_handle = HandleFromSwapchain(swapchain);
*swapchain_handle = surface.swapchain_handle;
return VK_SUCCESS;
@@ -1374,24 +1379,7 @@
const VkAllocationCallbacks* allocator) {
ATRACE_CALL();
- const auto& dispatch = GetData(device).driver;
- Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
- if (!swapchain)
- return;
- bool active = swapchain->surface.swapchain_handle == swapchain_handle;
- ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
-
- if (window && swapchain->frame_timestamps_enabled) {
- native_window_enable_frame_timestamps(window, false);
- }
- for (uint32_t i = 0; i < swapchain->num_images; i++)
- ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
- if (active)
- swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
- if (!allocator)
- allocator = &GetData(device).allocator;
- swapchain->~Swapchain();
- allocator->pfnFree(allocator->pUserData, swapchain);
+ DestroySwapchainInternal(device, swapchain_handle, allocator);
}
VKAPI_ATTR
@@ -1457,8 +1445,6 @@
int fence_fd;
err = window->dequeueBuffer(window, &buffer, &fence_fd);
if (err != 0) {
- // TODO(jessehall): Improve error reporting. Can we enumerate possible
- // errors and translate them to valid Vulkan result codes?
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
return VK_ERROR_SURFACE_LOST_KHR;
}
@@ -1513,8 +1499,6 @@
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,
pAcquireInfo->timeout, pAcquireInfo->semaphore,
pAcquireInfo->fence, pImageIndex);
@@ -1673,9 +1657,9 @@
// Add a new timing record with the user's presentID and
// the nativeFrameId.
- swapchain.timing.push_back(TimingInfo(time, nativeFrameId));
+ swapchain.timing.emplace_back(time, nativeFrameId);
while (swapchain.timing.size() > MAX_TIMING_INFOS) {
- swapchain.timing.removeAt(0);
+ swapchain.timing.erase(swapchain.timing.begin());
}
if (time->desiredPresentTime) {
// Set the desiredPresentTime:
@@ -1692,17 +1676,16 @@
err = window->queueBuffer(window, img.buffer.get(), fence);
// queueBuffer always closes fence, even on error
if (err != 0) {
- // TODO(jessehall): What now? We should probably cancel the
- // buffer, I guess?
ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
swapchain_result = WorstPresentResult(
swapchain_result, VK_ERROR_OUT_OF_DATE_KHR);
+ } else {
+ if (img.dequeue_fence >= 0) {
+ close(img.dequeue_fence);
+ img.dequeue_fence = -1;
+ }
+ img.dequeued = false;
}
- if (img.dequeue_fence >= 0) {
- close(img.dequeue_fence);
- img.dequeue_fence = -1;
- }
- img.dequeued = false;
// If the swapchain is in shared mode, immediately dequeue the
// buffer so it can be presented again without an intervening
@@ -1729,7 +1712,6 @@
}
}
if (swapchain_result != VK_SUCCESS) {
- ReleaseSwapchainImage(device, window, fence, img);
OrphanSwapchain(device, &swapchain);
}
int window_transform_hint;
@@ -1787,6 +1769,10 @@
ATRACE_CALL();
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
+ if (swapchain.surface.swapchain_handle != swapchain_handle) {
+ return VK_ERROR_OUT_OF_DATE_KHR;
+ }
+
ANativeWindow* window = swapchain.surface.window.get();
VkResult result = VK_SUCCESS;
@@ -1797,8 +1783,15 @@
}
if (timings) {
- // TODO(ianelliott): plumb return value (e.g. VK_INCOMPLETE)
+ // Get the latest ready timing count before copying, since the copied
+ // timing info will be erased in copy_ready_timings function.
+ uint32_t n = get_num_ready_timings(swapchain);
copy_ready_timings(swapchain, count, timings);
+ // Check the *count here against the recorded ready timing count, since
+ // *count can be overwritten per spec describes.
+ if (*count < n) {
+ result = VK_INCOMPLETE;
+ }
} else {
*count = get_num_ready_timings(swapchain);
}
diff --git a/vulkan/nulldrv/null_driver.tmpl b/vulkan/nulldrv/null_driver.tmpl
deleted file mode 100644
index ce15517..0000000
--- a/vulkan/nulldrv/null_driver.tmpl
+++ /dev/null
@@ -1,210 +0,0 @@
-{{/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */}}
-
-{{Include "../api/templates/vulkan_common.tmpl"}}
-{{Global "clang-format" (Strings "clang-format" "-style=file")}}
-{{Macro "DefineGlobals" $}}
-{{$ | Macro "null_driver_gen.h" | Format (Global "clang-format") | Write "null_driver_gen.h" }}
-{{$ | Macro "null_driver_gen.cpp" | Format (Global "clang-format") | Write "null_driver_gen.cpp"}}
-
-
-{{/*
--------------------------------------------------------------------------------
- null_driver_gen.h
--------------------------------------------------------------------------------
-*/}}
-{{define "null_driver_gen.h"}}
-/*
-•* Copyright 2015 The Android Open Source Project
-•*
-•* Licensed under the Apache License, Version 2.0 (the "License");
-•* you may not use this file except in compliance with the License.
-•* You may obtain a copy of the License at
-•*
-•* http://www.apache.org/licenses/LICENSE-2.0
-•*
-•* Unless required by applicable law or agreed to in writing, software
-•* distributed under the License is distributed on an "AS IS" BASIS,
-•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-•* See the License for the specific language governing permissions and
-•* limitations under the License.
-•*/
-¶
-// WARNING: This file is generated. See ../README.md for instructions.
-¶
-#ifndef NULLDRV_NULL_DRIVER_H
-#define NULLDRV_NULL_DRIVER_H 1
-¶
-#include <vulkan/vk_android_native_buffer.h>
-#include <vulkan/vulkan.h>
-¶
-namespace null_driver {«
-¶
-PFN_vkVoidFunction GetGlobalProcAddr(const char* name);
-PFN_vkVoidFunction GetInstanceProcAddr(const char* name);
-¶
-// clang-format off
- {{range $f := AllCommands $}}
- {{if (Macro "IsDriverFunction" $f)}}
-VKAPI_ATTR {{Node "Type" $f.Return}} {{Macro "BaseName" $f}}({{Macro "Parameters" $f}});
- {{end}}
- {{end}}
-VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
-VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
-VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
-// clang-format on
-¶
-»} // namespace null_driver
-¶
-#endif // NULLDRV_NULL_DRIVER_H
-¶{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- null_driver_gen.cpp
--------------------------------------------------------------------------------
-*/}}
-{{define "null_driver_gen.cpp"}}
-/*
-•* Copyright 2015 The Android Open Source Project
-•*
-•* Licensed under the Apache License, Version 2.0 (the "License");
-•* you may not use this file except in compliance with the License.
-•* You may obtain a copy of the License at
-•*
-•* http://www.apache.org/licenses/LICENSE-2.0
-•*
-•* Unless required by applicable law or agreed to in writing, software
-•* distributed under the License is distributed on an "AS IS" BASIS,
-•* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-•* See the License for the specific language governing permissions and
-•* limitations under the License.
-•*/
-¶
-// WARNING: This file is generated. See ../README.md for instructions.
-¶
-#include "null_driver_gen.h"
-#include <algorithm>
-¶
-using namespace null_driver;
-¶
-namespace {
-¶
-struct NameProc {
- const char* name;
- PFN_vkVoidFunction proc;
-};
-¶
-PFN_vkVoidFunction Lookup(const char* name,
- const NameProc* begin,
- const NameProc* end) {
- const auto& entry = std::lower_bound(
- begin, end, name,
- [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
- if (entry == end || strcmp(entry->name, name) != 0)
- return nullptr;
- return entry->proc;
-}
-¶
-template <size_t N>
-PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
- return Lookup(name, procs, procs + N);
-}
-¶
-const NameProc kGlobalProcs[] = {«
- // clang-format off
- {{range $f := SortBy (AllCommands $) "FunctionName"}}
- {{if and (Macro "IsDriverFunction" $f) (eq (Macro "Vtbl" $f) "Global")}}
- {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
- static_cast<{{Macro "FunctionPtrName" $f}}>(§
- {{Macro "BaseName" $f}}))},
- {{end}}
- {{end}}
- // clang-format on
-»};
-¶
-const NameProc kInstanceProcs[] = {«
- // clang-format off
- {{range $f := SortBy (AllCommands $) "FunctionName"}}
- {{if (Macro "IsDriverFunction" $f)}}
- {"{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
- static_cast<{{Macro "FunctionPtrName" $f}}>(§
- {{Macro "BaseName" $f}}))},
- {{end}}
- {{end}}
- // clang-format on
-»};
-¶
-} // namespace
-¶
-namespace null_driver {
-¶
-PFN_vkVoidFunction GetGlobalProcAddr(const char* name) {
- return Lookup(name, kGlobalProcs);
-}
-¶
-PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {«
- return Lookup(name, kInstanceProcs);
-»}
-¶
-} // namespace null_driver
-¶
-{{end}}
-
-
-{{/*
--------------------------------------------------------------------------------
- Emits a function name without the "vk" prefix.
--------------------------------------------------------------------------------
-*/}}
-{{define "BaseName"}}
- {{AssertType $ "Function"}}
- {{TrimPrefix "vk" $.Name}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Emits 'true' if the API function is implemented by the driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsDriverFunction"}}
- {{AssertType $ "Function"}}
-
- {{if not (GetAnnotation $ "pfn")}}
- {{$ext := GetAnnotation $ "extension"}}
- {{if $ext}}
- {{Macro "IsDriverExtension" $ext}}
- {{else}}
- true
- {{end}}
- {{end}}
-{{end}}
-
-
-{{/*
-------------------------------------------------------------------------------
- Reports whether an extension is implemented by the driver.
-------------------------------------------------------------------------------
-*/}}
-{{define "IsDriverExtension"}}
- {{$ext := index $.Arguments 0}}
- {{ if eq $ext "VK_ANDROID_native_buffer"}}true
- {{else if eq $ext "VK_EXT_debug_report"}}true
- {{else if eq $ext "VK_KHR_get_physical_device_properties2"}}true
- {{end}}
-{{end}}
diff --git a/vulkan/nulldrv/null_driver_gen.cpp b/vulkan/nulldrv/null_driver_gen.cpp
index 92b7468..b8d7d2b 100644
--- a/vulkan/nulldrv/null_driver_gen.cpp
+++ b/vulkan/nulldrv/null_driver_gen.cpp
@@ -17,6 +17,7 @@
// WARNING: This file is generated. See ../README.md for instructions.
#include <algorithm>
+
#include "null_driver_gen.h"
using namespace null_driver;
diff --git a/vulkan/nulldrv/null_driver_gen.h b/vulkan/nulldrv/null_driver_gen.h
index c6ad537..668dc7d 100644
--- a/vulkan/nulldrv/null_driver_gen.h
+++ b/vulkan/nulldrv/null_driver_gen.h
@@ -41,6 +41,7 @@
VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties(VkPhysicalDevice physicalDevice, VkFormat format, VkImageType type, VkImageTiling tiling, VkImageUsageFlags usage, VkImageCreateFlags flags, VkImageFormatProperties* pImageFormatProperties);
VKAPI_ATTR VkResult CreateDevice(VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);
VKAPI_ATTR void DestroyDevice(VkDevice device, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion);
VKAPI_ATTR VkResult EnumerateInstanceLayerProperties(uint32_t* pPropertyCount, VkLayerProperties* pProperties);
VKAPI_ATTR VkResult EnumerateInstanceExtensionProperties(const char* pLayerName, uint32_t* pPropertyCount, VkExtensionProperties* pProperties);
VKAPI_ATTR VkResult EnumerateDeviceLayerProperties(VkPhysicalDevice physicalDevice, uint32_t* pPropertyCount, VkLayerProperties* pProperties);
@@ -165,48 +166,47 @@
VKAPI_ATTR void CmdNextSubpass(VkCommandBuffer commandBuffer, VkSubpassContents contents);
VKAPI_ATTR void CmdEndRenderPass(VkCommandBuffer commandBuffer);
VKAPI_ATTR void CmdExecuteCommands(VkCommandBuffer commandBuffer, uint32_t commandBufferCount, const VkCommandBuffer* pCommandBuffers);
-VKAPI_ATTR VkResult EnumerateInstanceVersion(uint32_t* pApiVersion);
-VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
-VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
-VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
-VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
-VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
-VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
-VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
-VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
-VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
-VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
-VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
-VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
-VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
-VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
-VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
-VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
-VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
-VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
-VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
-VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
-VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
-VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
-VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
-VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
-VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
-VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
-VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int32_t* grallocUsage);
-VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
-VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
-VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
VKAPI_ATTR VkResult CreateDebugReportCallbackEXT(VkInstance instance, const VkDebugReportCallbackCreateInfoEXT* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDebugReportCallbackEXT* pCallback);
VKAPI_ATTR void DestroyDebugReportCallbackEXT(VkInstance instance, VkDebugReportCallbackEXT callback, const VkAllocationCallbacks* pAllocator);
VKAPI_ATTR void DebugReportMessageEXT(VkInstance instance, VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char* pLayerPrefix, const char* pMessage);
-VKAPI_ATTR void GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2KHR* pFeatures);
-VKAPI_ATTR void GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2KHR* pProperties);
-VKAPI_ATTR void GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2KHR* pFormatProperties);
-VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2KHR* pImageFormatInfo, VkImageFormatProperties2KHR* pImageFormatProperties);
-VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2KHR* pQueueFamilyProperties);
-VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2KHR* pMemoryProperties);
-VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2KHR* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2KHR* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceFeatures2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceFeatures2* pFeatures);
+VKAPI_ATTR void GetPhysicalDeviceProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceFormatProperties2KHR(VkPhysicalDevice physicalDevice, VkFormat format, VkFormatProperties2* pFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR VkResult GetPhysicalDeviceImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceImageFormatInfo2* pImageFormatInfo, VkImageFormatProperties2* pImageFormatProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceQueueFamilyProperties2KHR(VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceMemoryProperties2KHR(VkPhysicalDevice physicalDevice, VkPhysicalDeviceMemoryProperties2* pMemoryProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void GetPhysicalDeviceSparseImageFormatProperties2KHR(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceSparseImageFormatInfo2* pFormatInfo, uint32_t* pPropertyCount, VkSparseImageFormatProperties2* pProperties);
+VKAPI_ATTR void TrimCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolTrimFlags flags);
+VKAPI_ATTR void GetPhysicalDeviceExternalBufferProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalBufferInfo* pExternalBufferInfo, VkExternalBufferProperties* pExternalBufferProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalSemaphoreProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalSemaphoreInfo* pExternalSemaphoreInfo, VkExternalSemaphoreProperties* pExternalSemaphoreProperties);
+VKAPI_ATTR void GetPhysicalDeviceExternalFenceProperties(VkPhysicalDevice physicalDevice, const VkPhysicalDeviceExternalFenceInfo* pExternalFenceInfo, VkExternalFenceProperties* pExternalFenceProperties);
+VKAPI_ATTR VkResult EnumeratePhysicalDeviceGroups(VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);
+VKAPI_ATTR void GetDeviceGroupPeerMemoryFeatures(VkDevice device, uint32_t heapIndex, uint32_t localDeviceIndex, uint32_t remoteDeviceIndex, VkPeerMemoryFeatureFlags* pPeerMemoryFeatures);
+VKAPI_ATTR VkResult BindBufferMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindBufferMemoryInfo* pBindInfos);
+VKAPI_ATTR VkResult BindImageMemory2(VkDevice device, uint32_t bindInfoCount, const VkBindImageMemoryInfo* pBindInfos);
+VKAPI_ATTR void CmdSetDeviceMask(VkCommandBuffer commandBuffer, uint32_t deviceMask);
+VKAPI_ATTR void CmdDispatchBase(VkCommandBuffer commandBuffer, uint32_t baseGroupX, uint32_t baseGroupY, uint32_t baseGroupZ, uint32_t groupCountX, uint32_t groupCountY, uint32_t groupCountZ);
+VKAPI_ATTR VkResult CreateDescriptorUpdateTemplate(VkDevice device, const VkDescriptorUpdateTemplateCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDescriptorUpdateTemplate* pDescriptorUpdateTemplate);
+VKAPI_ATTR void DestroyDescriptorUpdateTemplate(VkDevice device, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void UpdateDescriptorSetWithTemplate(VkDevice device, VkDescriptorSet descriptorSet, VkDescriptorUpdateTemplate descriptorUpdateTemplate, const void* pData);
+VKAPI_ATTR void GetBufferMemoryRequirements2(VkDevice device, const VkBufferMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageMemoryRequirements2(VkDevice device, const VkImageMemoryRequirementsInfo2* pInfo, VkMemoryRequirements2* pMemoryRequirements);
+VKAPI_ATTR void GetImageSparseMemoryRequirements2(VkDevice device, const VkImageSparseMemoryRequirementsInfo2* pInfo, uint32_t* pSparseMemoryRequirementCount, VkSparseImageMemoryRequirements2* pSparseMemoryRequirements);
+VKAPI_ATTR VkResult CreateSamplerYcbcrConversion(VkDevice device, const VkSamplerYcbcrConversionCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSamplerYcbcrConversion* pYcbcrConversion);
+VKAPI_ATTR void DestroySamplerYcbcrConversion(VkDevice device, VkSamplerYcbcrConversion ycbcrConversion, const VkAllocationCallbacks* pAllocator);
+VKAPI_ATTR void GetDeviceQueue2(VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);
+VKAPI_ATTR void GetDescriptorSetLayoutSupport(VkDevice device, const VkDescriptorSetLayoutCreateInfo* pCreateInfo, VkDescriptorSetLayoutSupport* pSupport);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
+VKAPI_ATTR VkResult GetSwapchainGrallocUsage2ANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, VkSwapchainImageUsageFlagsANDROID swapchainImageUsage, uint64_t* grallocConsumerUsage, uint64_t* grallocProducerUsage);
+VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
+VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);
diff --git a/vulkan/scripts/api_generator.py b/vulkan/scripts/api_generator.py
new file mode 100644
index 0000000..a0c648c
--- /dev/null
+++ b/vulkan/scripts/api_generator.py
@@ -0,0 +1,346 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script provides the functions required for generating the
+# vulkan api framework directly from the vulkan registry (vk.xml)
+
+import os
+import generator_common as gencom
+
+def isInstanceDispatchTableEntry(functionName):
+ if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc
+ return False
+ if gencom.gencom.isFunctionExported(functionName) and gencom.isInstanceDispatched(functionName):
+ return True
+ return False
+
+def isDeviceDispatchTableEntry(functionName):
+ if gencom.gencom.isFunctionExported(functionName) and gencom.gencom.isDeviceDispatched(functionName):
+ return True
+ return False
+
+def api_genh():
+
+ header = """#ifndef LIBVULKAN_API_GEN_H
+#define LIBVULKAN_API_GEN_H
+
+#include <vulkan/vulkan.h>
+
+#include <bitset>
+
+#include "driver_gen.h"
+
+namespace vulkan {
+namespace api {
+
+"""
+
+ tail = """
+bool InitDispatchTable(
+ VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
+bool InitDispatchTable(
+ VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
+
+} // namespace api
+} // namespace vulkan
+
+#endif // LIBVULKAN_API_GEN_H
+"""
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.h')
+ with open(genfile, 'w') as f:
+ instanceDispatchTableEntries = []
+ deviceDispatchTableEntries = []
+ for commands in gencom.allCommandsList:
+ if commands not in gencom.aliasDict:
+ if gencom.isInstanceDispatchTableEntry(commands):
+ instanceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
+ elif gencom.isDeviceDispatchTableEntry(commands):
+ deviceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
+
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write (header)
+ f.write ('struct InstanceDispatchTable {\n')
+ gencom.clang_off(f,1)
+ for functions in instanceDispatchTableEntries:
+ f.write(gencom.clang_off_spaces + functions + '\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n\n')
+
+ f.write ('struct DeviceDispatchTable {\n')
+ gencom.clang_off(f,1)
+ for functions in deviceDispatchTableEntries:
+ f.write(gencom.clang_off_spaces + functions + '\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n')
+
+ f.write (tail)
+ f.close()
+ gencom.runClangFormat(genfile)
+
+def defineInitProc(name, f):
+ f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
+ f.write ('\n')
+ f.write ("""#define INIT_PROC(required, obj, proc) \\
+ do { \\
+ data.""" + name + """.proc = \\
+ reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
+ if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
+ ALOGE("missing " #obj " proc: vk" #proc); \\
+ success = false; \\
+ } \\
+ } while (0)\n\n""")
+
+def defineInitProcExt(f):
+ f.write ('// Exported extension functions may be invoked even when their extensions\n')
+ f.write ('// are disabled. Dispatch to stubs when that happens.\n')
+ f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
+ do { \\
+ if (extensions[driver::ProcHook::ext]) \\
+ INIT_PROC(required, obj, proc); \\
+ else \\
+ data.dispatch.proc = disabled##proc; \\
+ } while (0)\n\n""")
+
+def defineExtensionStub(functionName, f):
+ if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName):
+ extname = gencom.extensionsDict[functionName]
+ base_name = functionName[2:]
+ pList = gencom.paramDict[functionName]
+ firstParam = pList[0][0] + pList[0][1]
+ tailParams = [x[0][:-1] for x in pList[1:]]
+ tailP = ', '.join(tailParams)
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n')
+ f.write (gencom.clang_off_spaces)
+ f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n')
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n')
+ f.write ('}\n\n')
+
+def isIntercepted(functionName):
+ if gencom.isFunctionSupported(functionName):
+ if gencom.isGloballyDispatched(functionName):
+ return True
+ elif functionName == 'vkCreateDevice':
+ return True
+ elif functionName == 'vkEnumerateDeviceLayerProperties':
+ return True
+ elif functionName == 'vkEnumerateDeviceExtensionProperties':
+ return True
+ elif functionName == 'vkDestroyInstance':
+ return True
+ elif functionName == 'vkDestroyDevice':
+ return True
+ return False
+
+def interceptInstanceProcAddr(functionName, f):
+ indent = 1
+ f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n')
+ indent = indent + 1
+ for cmds in gencom.allCommandsList:
+ if gencom.isGloballyDispatched(cmds):
+ f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
+
+ f.write ('\n')
+ f.write (""" ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
+ return nullptr;
+ }
+
+ static const struct Hook {
+ const char* name;
+ PFN_vkVoidFunction proc;
+ } hooks[] = {\n""")
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if gencom.isFunctionExported(cmds):
+ if gencom.isGloballyDispatched(cmds):
+ f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n')
+ elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds):
+ f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ') },\n')
+ f.write (gencom.clang_off_spaces + """};
+ // clang-format on
+ constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
+ auto hook = std::lower_bound(
+ hooks, hooks + count, pName,
+ [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
+ if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
+ if (!hook->proc) {
+ vulkan::driver::Logger(instance).Err(
+ instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
+ instance, pName);
+ }
+ return hook->proc;
+ }
+ // clang-format off\n\n""")
+
+def interceptDeviceProcAddr(functionName, f):
+ f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) {
+ ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
+ return nullptr;
+ }\n\n""")
+ f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n')
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if gencom.isFunctionSupported(cmds):
+ if not gencom.isDeviceDispatched(cmds):
+ f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n')
+ f.write(gencom.clang_off_spaces + '};\n')
+ f.write(gencom.clang_off_spaces + """// clang-format on
+ constexpr size_t count =
+ sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
+ if (!pName ||
+ std::binary_search(
+ known_non_device_names, known_non_device_names + count, pName,
+ [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
+ vulkan::driver::Logger(device).Err(
+ device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
+ (pName) ? pName : "(null)");
+ return nullptr;
+ }
+ // clang-format off\n\n""")
+ for cmds in gencom.allCommandsList:
+ if gencom.isDeviceDispatched(cmds):
+ if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr':
+ f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
+ f.write ('\n')
+
+def apiDispatch(functionName, f):
+ assert not isIntercepted(functionName)
+
+ f.write (gencom.clang_off_spaces)
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write ('return ')
+
+ paramList = gencom.paramDict[functionName]
+ p0 = paramList[0][1]
+ f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
+
+
+def api_gencpp():
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.cpp')
+ header = """#include <log/log.h>
+#include <string.h>
+
+#include <algorithm>
+
+// to catch mismatches between vulkan.h and this file
+#undef VK_NO_PROTOTYPES
+#include "api.h"
+
+namespace vulkan {
+namespace api {
+
+"""
+ with open(genfile, 'w') as f:
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write ("""#include <log/log.h>
+#include <string.h>
+
+#include <algorithm>
+
+// to catch mismatches between vulkan.h and this file
+#undef VK_NO_PROTOTYPES
+#include "api.h"
+
+namespace vulkan {
+namespace api {\n\n""")
+ defineInitProc('dispatch',f)
+ defineInitProcExt(f)
+ f.write ('namespace {\n\n')
+ gencom.clang_off(f,0)
+ f.write ('\n')
+ for cmds in gencom.allCommandsList:
+ defineExtensionStub(cmds,f)
+ gencom.clang_on(f,0)
+ f.write ('\n} // namespace\n\n')
+ f.write ("""bool InitDispatchTable(
+ VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(instance);
+ bool success = true;\n\n""")
+ gencom.clang_off(f,1)
+ for cmds in gencom.allCommandsList:
+ if gencom.isInstanceDispatchTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f,1)
+ f.write ('\n')
+ f.write (' return success;\n}\n\n')
+ f.write ("""bool InitDispatchTable(
+ VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(dev);
+ bool success = true;\n\n""")
+
+ gencom.clang_off(f,1)
+ for cmds in gencom.allCommandsList:
+ if gencom.isDeviceDispatchTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f,1)
+ f.write ('\n')
+ f.write (' return success;\n}\n\n')
+
+ gencom.clang_off(f,0)
+
+ f.write ('\nnamespace {\n\n')
+ f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n')
+ for cmds in gencom.allCommandsList:
+ if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n')
+
+ f.write ('\n')
+
+ for cmds in gencom.allCommandsList:
+ if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n')
+ if cmds == 'vkGetInstanceProcAddr':
+ interceptInstanceProcAddr(cmds, f)
+ elif cmds == 'vkGetDeviceProcAddr':
+ interceptDeviceProcAddr(cmds, f)
+ apiDispatch(cmds, f)
+ f.write('}\n\n')
+ f.write ("""\n} // anonymous namespace
+
+// clang-format on
+
+} // namespace api
+} // namespace vulkan
+
+// clang-format off\n\n""")
+
+ for cmds in gencom.allCommandsList:
+ if gencom.isFunctionExported(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('__attribute__((visibility("default")))\n')
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n')
+ f.write (gencom.clang_off_spaces)
+ if gencom.returnTypeDict[cmds] != 'void':
+ f.write ('return ')
+ paramList = gencom.paramDict[cmds]
+ f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
+ f.write ('}\n\n')
+
+ gencom.clang_on(f, 0)
+ f.close()
+ gencom.runClangFormat(genfile)
diff --git a/vulkan/scripts/code_generator.py b/vulkan/scripts/code_generator.py
new file mode 100755
index 0000000..39fedf4
--- /dev/null
+++ b/vulkan/scripts/code_generator.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script provides the main function for generating
+# vulkan framework directly from the vulkan registry (vk.xml).
+
+import generator_common as gencom
+import api_generator as apigen
+import driver_generator as drivergen
+import null_generator as nullgen
+
+if __name__ == '__main__':
+ gencom.parseVulkanRegistry()
+ apigen.api_genh()
+ apigen.api_gencpp()
+ drivergen.driver_genh()
+ drivergen.driver_gencpp()
+ nullgen.null_driver_genh()
+ nullgen.null_driver_gencpp()
diff --git a/vulkan/scripts/driver_generator.py b/vulkan/scripts/driver_generator.py
new file mode 100644
index 0000000..ef36f8c
--- /dev/null
+++ b/vulkan/scripts/driver_generator.py
@@ -0,0 +1,400 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script provides the functions for generating the
+# vulkan driver framework directly from the vulkan registry (vk.xml).
+
+import generator_common as gencom
+import os
+
+interceptedExtensions = [
+ 'VK_ANDROID_native_buffer',
+ 'VK_EXT_debug_report',
+ 'VK_EXT_hdr_metadata',
+ 'VK_EXT_swapchain_colorspace',
+ 'VK_GOOGLE_display_timing',
+ 'VK_KHR_android_surface',
+ 'VK_KHR_incremental_present',
+ 'VK_KHR_shared_presentable_image',
+ 'VK_KHR_surface',
+ 'VK_KHR_swapchain',
+ 'VK_KHR_get_surface_capabilities2'
+]
+
+knownExtensions = interceptedExtensions + [
+ 'VK_KHR_get_physical_device_properties2',
+ 'VK_ANDROID_external_memory_android_hardware_buffer',
+ 'VK_KHR_bind_memory2'
+]
+
+def defineProcHookType(f):
+ f.write ("""struct ProcHook {
+ enum Type {
+ GLOBAL,
+ INSTANCE,
+ DEVICE,
+ };
+ enum Extension {\n""")
+ for exts in knownExtensions:
+ f.write (gencom.clang_off_spaces*2 + exts[3:] + ',\n')
+ f.write ('\n')
+ f.write (gencom.clang_off_spaces*2 + """EXTENSION_CORE, // valid bit
+ EXTENSION_COUNT,
+ EXTENSION_UNKNOWN,
+ };
+
+ const char* name;
+ Type type;
+ Extension extension;
+
+ PFN_vkVoidFunction proc;
+ PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks
+};\n\n""")
+
+def isExtensionIntercepted(extensionName):
+ if extensionName in interceptedExtensions:
+ return True
+ return False
+
+def isDriverTableEntry(functionName):
+ switchCase = {
+ # Create functions of dispatchable objects
+ 'vkCreateDevice' : True,
+ 'vkGetDeviceQueue' : True,
+ 'vkGetDeviceQueue2' : True,
+ 'vkAllocateCommandBuffers' : True,
+
+ # Destroy functions of dispatchable objects
+ 'vkDestroyInstance' : True,
+ 'vkDestroyDevice' : True,
+
+ # Enumeration of extensions
+ 'vkEnumerateDeviceExtensionProperties' : True,
+
+ # We cache physical devices in loader.cpp
+ 'vkEnumeratePhysicalDevices' : True,
+ 'vkEnumeratePhysicalDeviceGroups' : True,
+
+ 'vkGetInstanceProcAddr' : True,
+ 'vkGetDeviceProcAddr' : True,
+
+ 'vkQueueSubmit' : True,
+
+ # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
+ 'vkCreateImage' : True,
+ 'vkDestroyImage' : True,
+
+ 'vkGetPhysicalDeviceProperties' : True,
+ 'vkGetPhysicalDeviceProperties2' : True,
+ 'vkGetPhysicalDeviceProperties2KHR' : True,
+
+ # VK_KHR_swapchain v69 requirement
+ 'vkBindImageMemory2' : True,
+ 'vkBindImageMemory2KHR' : True
+ }
+ if gencom.isFunctionSupported(functionName):
+ if functionName in switchCase:
+ return True
+ if functionName in gencom.extensionsDict:
+ if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report':
+ return True
+ return False
+
+def isInstanceDriverTableEntry(functionName):
+ if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName):
+ return True
+ return False
+
+def isDeviceDriverTableEntry(functionName):
+ if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName):
+ return True
+ return False
+
+def driver_genh():
+ header = """#ifndef LIBVULKAN_DRIVER_GEN_H
+#define LIBVULKAN_DRIVER_GEN_H
+
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+
+#include <bitset>
+
+namespace vulkan {
+namespace driver {\n\n"""
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.h')
+ with open(genfile, 'w') as f:
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write (header)
+ defineProcHookType(f)
+ f.write ('struct InstanceDriverTable {\n')
+ gencom.clang_off(f, 1)
+ for cmds in gencom.allCommandsList:
+ if isInstanceDriverTableEntry(cmds):
+ f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
+ gencom.clang_on(f, 1)
+ f.write ('};\n\n')
+ f.write ('struct DeviceDriverTable {\n')
+ gencom.clang_off(f,1)
+ for cmds in gencom.allCommandsList:
+ if isDeviceDriverTableEntry(cmds):
+ f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n\n')
+ f.write ("""const ProcHook* GetProcHook(const char* name);
+ProcHook::Extension GetProcHookExtension(const char* name);
+
+bool InitDriverTable(VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
+bool InitDriverTable(VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
+
+} // namespace driver
+} // namespace vulkan
+
+#endif // LIBVULKAN_DRIVER_TABLE_H\n""")
+ f.close()
+ gencom.runClangFormat(genfile)
+
+def isIntercepted(functionName):
+ switchCase = {
+ # Create functions of dispatchable objects
+ 'vkCreateInstance' : True,
+ 'vkCreateDevice' : True,
+ 'vkEnumeratePhysicalDevices' : True,
+ 'vkEnumeratePhysicalDeviceGroups' : True,
+ 'vkGetDeviceQueue' : True,
+ 'vkGetDeviceQueue2' : True,
+ 'vkAllocateCommandBuffers' : True,
+
+ # Destroy functions of dispatchable objects
+ 'vkDestroyInstance' : True,
+ 'vkDestroyDevice' : True,
+
+ # Enumeration of extensions
+ 'vkEnumerateInstanceExtensionProperties' : True,
+ 'vkEnumerateDeviceExtensionProperties' : True,
+
+ 'vkGetInstanceProcAddr' : True,
+ 'vkGetDeviceProcAddr' : True,
+
+ 'vkQueueSubmit' : True,
+
+ # VK_KHR_swapchain v69 requirement
+ 'vkBindImageMemory2' : True,
+ 'vkBindImageMemory2KHR' : True
+ }
+ if gencom.isFunctionSupported(functionName):
+ if functionName in switchCase:
+ return switchCase[functionName]
+
+ if functionName in gencom.extensionsDict:
+ return isExtensionIntercepted(gencom.extensionsDict[functionName])
+ return False
+
+def needProcHookStub(functionName):
+ if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName):
+ if functionName in gencom.extensionsDict:
+ if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]):
+ return True
+ return False
+
+def defineInitProc(name, f):
+ f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
+ f.write ('\n')
+ f.write ("""#define INIT_PROC(required, obj, proc) \\
+ do { \\
+ data.""" + name + """.proc = \\
+ reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
+ if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
+ ALOGE("missing " #obj " proc: vk" #proc); \\
+ success = false; \\
+ } \\
+ } while (0)\n\n""")
+
+def defineInitProcExt(f):
+ f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
+ do { \\
+ if (extensions[ProcHook::ext]) \\
+ INIT_PROC(required, obj, proc); \\
+ } while (0)\n\n""")
+
+def defineProcHookStub(functionName, f):
+ if needProcHookStub(functionName):
+ ext_name = gencom.extensionsDict[functionName]
+ base_name = functionName[2:]
+ paramList = [''.join(i) for i in gencom.paramDict[functionName]]
+ p0 = gencom.paramDict[functionName][0][1]
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n')
+ ext_hook = 'ProcHook::' + ext_name[3:]
+
+ f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n')
+ f.write (gencom.clang_off_spaces *2)
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write ('return ')
+ paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]]
+ f.write (base_name + '(' + ', '.join(paramNames) + ');\n')
+ f.write (gencom.clang_off_spaces + '} else {\n')
+ f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n')
+ if gencom.returnTypeDict[functionName] != 'void':
+ f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n')
+ f.write (gencom.clang_off_spaces + '}\n')
+ f.write ('}\n\n')
+
+def defineGlobalProcHook(functionName, f):
+ base_name = functionName[2:]
+ assert (functionName not in gencom.extensionsDict)
+ f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2)
+ f.write ("""ProcHook::GLOBAL,
+ ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+ nullptr,
+ },\n""")
+
+def defineInstanceProcHook(functionName, f):
+ base_name = functionName[2:]
+ f.write (gencom.clang_off_spaces + '{\n')
+ f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n')
+
+ if functionName in gencom.extensionsDict:
+ ext_name = gencom.extensionsDict[functionName]
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
+ if gencom.isExtensionInternal(ext_name):
+ f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+ else:
+ f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+
+ else:
+ f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+ nullptr,\n""")
+
+ f.write (gencom.clang_off_spaces + '},\n')
+
+def defineDeviceProcHook(functionName, f):
+ base_name = functionName[2:]
+ f.write (gencom.clang_off_spaces + '{\n')
+ f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n')
+
+ if functionName in gencom.extensionsDict:
+ ext_name = gencom.extensionsDict[functionName]
+ f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
+ if gencom.isExtensionInternal(ext_name):
+ f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
+ else:
+ f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(checked' + base_name + '),\n')
+
+ else:
+ f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
+ reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
+ nullptr,\n""")
+
+ f.write (gencom.clang_off_spaces + '},\n')
+
+def driver_gencpp():
+ header = """#include <log/log.h>
+#include <string.h>
+
+#include <algorithm>
+
+#include "driver.h"
+
+namespace vulkan {
+namespace driver {
+
+namespace {
+
+// clang-format off\n\n"""
+
+ genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.cpp')
+
+ with open(genfile, 'w') as f:
+ f.write (gencom.copyright)
+ f.write (gencom.warning)
+ f.write (header)
+
+ for cmds in gencom.allCommandsList:
+ defineProcHookStub(cmds, f)
+ gencom.clang_on(f, 0)
+ f.write ('\n')
+
+ f.write ('const ProcHook g_proc_hooks[] = {\n')
+ gencom.clang_off(f, 1)
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if isIntercepted(cmds):
+ if gencom.isGloballyDispatched(cmds):
+ defineGlobalProcHook(cmds, f)
+ elif gencom.isInstanceDispatched(cmds):
+ defineInstanceProcHook(cmds, f)
+ elif gencom.isDeviceDispatched(cmds):
+ defineDeviceProcHook(cmds, f)
+ gencom.clang_on(f, 1)
+ f.write ('};\n\n} // namespace\n\n')
+
+ f.write ("""const ProcHook* GetProcHook(const char* name) {
+ const auto& begin = g_proc_hooks;
+ const auto& end =
+ g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
+ const auto hook = std::lower_bound(
+ begin, end, name,
+ [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
+ return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
+}\n\n""")
+
+ f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n')
+ gencom.clang_off(f, 1)
+ for exts in knownExtensions:
+ f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n')
+ gencom.clang_on(f, 1)
+ f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n')
+ f.write ('}\n\n')
+
+ defineInitProc('driver', f)
+ defineInitProcExt(f)
+
+ f.write ("""bool InitDriverTable(VkInstance instance,
+ PFN_vkGetInstanceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(instance);
+ bool success = true;\n\n""")
+ gencom.clang_off(f, 1)
+ for cmds in gencom.allCommandsList:
+ if isInstanceDriverTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f, 1)
+ f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
+ f.write ('}\n\n')
+
+ f.write ("""bool InitDriverTable(VkDevice dev,
+ PFN_vkGetDeviceProcAddr get_proc,
+ const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
+ auto& data = GetData(dev);
+ bool success = true;\n\n""")
+ gencom.clang_off(f, 1)
+ for cmds in gencom.allCommandsList:
+ if isDeviceDriverTableEntry(cmds):
+ gencom.initProc(cmds, f)
+ gencom.clang_on(f, 1)
+ f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
+ f.write ('}\n\n} // namespace driver\n} // namespace vulkan\n\n')
+ gencom.clang_on(f, 0)
+ f.close()
+ gencom.runClangFormat(genfile)
diff --git a/vulkan/scripts/generator_common.py b/vulkan/scripts/generator_common.py
new file mode 100644
index 0000000..fe9dab4
--- /dev/null
+++ b/vulkan/scripts/generator_common.py
@@ -0,0 +1,255 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script provides the common functions for generating the
+# vulkan framework directly from the vulkan registry (vk.xml).
+
+from subprocess import check_call
+
+copyright = """/*
+ * Copyright 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+"""
+
+warning = '// WARNING: This file is generated. See ../README.md for instructions.\n\n'
+
+blacklistedExtensions = [
+ 'VK_KHR_display',
+ 'VK_KHR_display_swapchain',
+ 'VK_KHR_mir_surface',
+ 'VK_KHR_xcb_surface',
+ 'VK_KHR_xlib_surface',
+ 'VK_KHR_wayland_surface',
+ 'VK_KHR_win32_surface',
+ 'VK_KHR_external_memory_win32',
+ 'VK_KHR_win32_keyed_mutex',
+ 'VK_KHR_external_semaphore_win32',
+ 'VK_KHR_external_fence_win32',
+ 'VK_EXT_acquire_xlib_display',
+ 'VK_EXT_direct_mode_display',
+ 'VK_EXT_display_surface_counter',
+ 'VK_EXT_display_control',
+ 'VK_FUCHSIA_imagepipe_surface',
+ 'VK_MVK_ios_surface',
+ 'VK_MVK_macos_surface',
+ 'VK_NN_vi_surface',
+ 'VK_NV_external_memory_win32',
+ 'VK_NV_win32_keyed_mutex',
+ 'VK_EXT_metal_surface', #not present in vulkan.api
+ 'VK_NVX_image_view_handle', #not present in vulkan.api
+ 'VK_NV_cooperative_matrix', #not present in vulkan.api
+ 'VK_EXT_headless_surface', #not present in vulkan.api
+ 'VK_GGP_stream_descriptor_surface', #not present in vulkan.api
+ 'VK_NV_coverage_reduction_mode', #not present in vulkan.api
+ 'VK_EXT_full_screen_exclusive' #not present in vulkan.api
+]
+
+exportedExtensions = [
+ 'VK_KHR_surface',
+ 'VK_KHR_swapchain',
+ 'VK_KHR_android_surface',
+ 'VK_ANDROID_external_memory_android_hardware_buffer'
+]
+
+def runClangFormat(args):
+ clang_call = ["clang-format", "--style", "file", "-i", args]
+ check_call (clang_call)
+
+def isExtensionInternal(extensionName):
+ if extensionName == 'VK_ANDROID_native_buffer':
+ return True
+ return False
+
+def isFunctionSupported(functionName):
+ if functionName not in extensionsDict:
+ return True
+ else:
+ if extensionsDict[functionName] not in blacklistedExtensions:
+ return True
+ return False
+
+def isInstanceDispatched(functionName):
+ return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Instance'
+
+def isDeviceDispatched(functionName):
+ return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Device'
+
+def isGloballyDispatched(functionName):
+ return isFunctionSupported(functionName) and getDispatchTableType(functionName) == 'Global'
+
+def isExtensionExported(extensionName):
+ if extensionName in exportedExtensions:
+ return True
+ return False
+
+def isFunctionExported(functionName):
+ if isFunctionSupported(functionName):
+ if functionName in extensionsDict:
+ return isExtensionExported(extensionsDict[functionName])
+ return True
+ return False
+
+def getDispatchTableType(functionName):
+ if functionName not in paramDict:
+ return None
+
+ switchCase = {
+ 'VkInstance ' : 'Instance',
+ 'VkPhysicalDevice ' : 'Instance',
+ 'VkDevice ' : 'Device',
+ 'VkQueue ' : 'Device',
+ 'VkCommandBuffer ' : 'Device'
+ }
+
+ if len(paramDict[functionName]) > 0:
+ return switchCase.get(paramDict[functionName][0][0], 'Global')
+ return 'Global'
+
+def isInstanceDispatchTableEntry(functionName):
+ if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc
+ return False
+ if isFunctionExported(functionName) and isInstanceDispatched(functionName):
+ return True
+ return False
+
+def isDeviceDispatchTableEntry(functionName):
+ if isFunctionExported(functionName) and isDeviceDispatched(functionName):
+ return True
+ return False
+
+
+def clang_on(f, indent):
+ f.write (clang_off_spaces * indent + '// clang-format on\n')
+
+def clang_off(f, indent):
+ f.write (clang_off_spaces * indent + '// clang-format off\n')
+
+clang_off_spaces = ' ' * 4
+
+parametersList = []
+paramDict = {}
+allCommandsList = []
+extensionsDict = {}
+returnTypeDict = {}
+versionDict = {}
+aliasDict = {}
+
+def parseVulkanRegistry():
+ import xml.etree.ElementTree as ET
+ import os
+ vulkan_registry = os.path.join(os.path.dirname(__file__),'..','..','..','..','external','vulkan-headers','registry','vk.xml')
+ tree = ET.parse(vulkan_registry)
+ root = tree.getroot()
+ for commands in root.iter('commands'):
+ for command in commands:
+ if command.tag == 'command':
+ parametersList.clear()
+ protoset = False
+ fnName = ""
+ fnType = ""
+ if command.get('alias') != None:
+ alias = command.get('alias')
+ fnName = command.get('name')
+ aliasDict[fnName] = alias
+ allCommandsList.append(fnName)
+ paramDict[fnName] = paramDict[alias].copy()
+ returnTypeDict[fnName] = returnTypeDict[alias]
+ for params in command:
+ if params.tag == 'param':
+ paramtype = ""
+ if params.text != None and params.text.strip() != '':
+ paramtype = params.text.strip() + ' '
+ typeval = params.find('type')
+ paramtype = paramtype + typeval.text
+ if typeval.tail != None:
+ paramtype += typeval.tail.strip() + ' '
+ pname = params.find('name')
+ paramname = pname.text
+ if pname.tail != None and pname.tail.strip() != '':
+ parametersList.append((paramtype, paramname, pname.tail.strip()))
+ else:
+ parametersList.append((paramtype, paramname))
+ if params.tag == 'proto':
+ for c in params:
+ if c.tag == 'type':
+ fnType = c.text
+ if c.tag == 'name':
+ fnName = c.text
+ protoset = True
+ allCommandsList.append(fnName)
+ returnTypeDict[fnName] = fnType
+ if protoset == True:
+ paramDict[fnName] = parametersList.copy()
+
+ for exts in root.iter('extensions'):
+ for extension in exts:
+ apiversion = ""
+ if extension.tag == 'extension':
+ extname = extension.get('name')
+ for req in extension:
+ if req.get('feature') != None:
+ apiversion = req.get('feature')
+ for commands in req:
+ if commands.tag == 'command':
+ commandname = commands.get('name')
+ if commandname not in extensionsDict:
+ extensionsDict[commandname] = extname
+ if apiversion != "":
+ versionDict[commandname] = apiversion
+
+ for feature in root.iter('feature'):
+ apiversion = feature.get('name')
+ for req in feature:
+ for command in req:
+ if command.tag == 'command':
+ cmdName = command.get('name')
+ if cmdName in allCommandsList:
+ versionDict[cmdName] = apiversion
+
+
+def initProc(name, f):
+ if name in extensionsDict:
+ f.write (' INIT_PROC_EXT(' + extensionsDict[name][3:] + ', ')
+ else:
+ f.write (' INIT_PROC(')
+
+ if name in versionDict and versionDict[name] == 'VK_VERSION_1_1':
+ f.write('false, ')
+ elif name == 'vkGetSwapchainGrallocUsageANDROID' or name == 'vkGetSwapchainGrallocUsage2ANDROID': # optional in vulkan.api
+ f.write('false, ')
+ else:
+ f.write('true, ')
+
+ if isInstanceDispatched(name):
+ f.write('instance, ')
+ else:
+ f.write('dev, ')
+
+ f.write(name[2:] + ');\n')
+
diff --git a/vulkan/scripts/null_generator.py b/vulkan/scripts/null_generator.py
new file mode 100644
index 0000000..ee8762e
--- /dev/null
+++ b/vulkan/scripts/null_generator.py
@@ -0,0 +1,158 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# This script provides the functions for generating the null driver
+# framework directly from the vulkan registry (vk.xml).
+
+import generator_common as gencom
+import os
+
+copyright = """/*
+ * Copyright 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+"""
+
+def isDriverExtension(extensionName):
+ switchCase = {
+ 'VK_ANDROID_native_buffer' : True,
+ 'VK_EXT_debug_report' : True,
+ 'VK_KHR_get_physical_device_properties2' : True
+ }
+
+ if extensionName in switchCase:
+ return switchCase[extensionName]
+ return False
+
+def isDriverFunction(functionName):
+ if functionName in gencom.extensionsDict:
+ return isDriverExtension(gencom.extensionsDict[functionName])
+ return True
+
+def null_driver_genh():
+ header = """#ifndef NULLDRV_NULL_DRIVER_H
+#define NULLDRV_NULL_DRIVER_H 1
+
+#include <vulkan/vk_android_native_buffer.h>
+#include <vulkan/vulkan.h>
+
+namespace null_driver {
+
+PFN_vkVoidFunction GetGlobalProcAddr(const char* name);
+PFN_vkVoidFunction GetInstanceProcAddr(const char* name);
+
+"""
+ genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen.h')
+ with open(genfile, 'w') as f:
+ f.write (copyright)
+ f.write (gencom.warning)
+ f.write (header)
+ gencom.clang_off(f,0)
+
+ for cmds in gencom.allCommandsList:
+ if isDriverFunction(cmds):
+ paramList = [''.join(i) for i in gencom.paramDict[cmds]]
+ f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' +', '.join(paramList) + ');\n')
+ f.write ("""VKAPI_ATTR VkResult GetSwapchainGrallocUsageANDROID(VkDevice device, VkFormat format, VkImageUsageFlags imageUsage, int* grallocUsage);
+VKAPI_ATTR VkResult AcquireImageANDROID(VkDevice device, VkImage image, int nativeFenceFd, VkSemaphore semaphore, VkFence fence);
+VKAPI_ATTR VkResult QueueSignalReleaseImageANDROID(VkQueue queue, uint32_t waitSemaphoreCount, const VkSemaphore* pWaitSemaphores, VkImage image, int* pNativeFenceFd);\n""")
+ gencom.clang_on(f,0)
+
+ f.write ('\n} // namespace null_driver\n')
+ f.write ('\n#endif // NULLDRV_NULL_DRIVER_H\n')
+ f.close()
+ gencom.runClangFormat(genfile)
+
+def null_driver_gencpp():
+ header = """#include <algorithm>
+
+#include "null_driver_gen.h"
+
+using namespace null_driver;
+
+namespace {
+
+struct NameProc {
+ const char* name;
+ PFN_vkVoidFunction proc;
+};
+
+PFN_vkVoidFunction Lookup(const char* name,
+ const NameProc* begin,
+ const NameProc* end) {
+ const auto& entry = std::lower_bound(
+ begin, end, name,
+ [](const NameProc& e, const char* n) { return strcmp(e.name, n) < 0; });
+ if (entry == end || strcmp(entry->name, name) != 0)
+ return nullptr;
+ return entry->proc;
+}
+
+template <size_t N>
+PFN_vkVoidFunction Lookup(const char* name, const NameProc (&procs)[N]) {
+ return Lookup(name, procs, procs + N);
+}
+
+const NameProc kGlobalProcs[] = {
+"""
+ genfile = os.path.join(os.path.dirname(__file__),'..','nulldrv','null_driver_gen.cpp')
+ with open(genfile, 'w') as f:
+ f.write (copyright)
+ f.write (gencom.warning)
+ f.write (header)
+ gencom.clang_off(f,1)
+
+ sortedCommandsList = sorted(gencom.allCommandsList)
+ for cmds in sortedCommandsList:
+ if isDriverFunction(cmds) and gencom.getDispatchTableType(cmds) == 'Global':
+ f.write (gencom.clang_off_spaces + '{\"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_' + cmds + '>(' + cmds[2:] + '))},\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n\n')
+
+ f.write ('const NameProc kInstanceProcs[] = {\n')
+ gencom.clang_off(f,1)
+ for cmds in sortedCommandsList:
+ if isDriverFunction(cmds):
+ f.write (gencom.clang_off_spaces + '{\"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(static_cast<PFN_' + cmds + '>(' + cmds[2:] + '))},\n')
+ gencom.clang_on(f,1)
+ f.write ('};\n\n} // namespace\n\n')
+
+ f.write ("""namespace null_driver {
+
+PFN_vkVoidFunction GetGlobalProcAddr(const char* name) {
+ return Lookup(name, kGlobalProcs);
+}
+
+PFN_vkVoidFunction GetInstanceProcAddr(const char* name) {
+ return Lookup(name, kInstanceProcs);
+}
+
+} // namespace null_driver\n""")
+ f.close()
+ gencom.runClangFormat(genfile)
+
diff --git a/vulkan/tools/Android.bp b/vulkan/tools/Android.bp
deleted file mode 100644
index 2514094..0000000
--- a/vulkan/tools/Android.bp
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright 2015 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-cc_binary {
- name: "vkinfo",
-
- clang: true,
- cflags: [
- "-fvisibility=hidden",
- "-fstrict-aliasing",
-
- "-DLOG_TAG=\"vkinfo\"",
-
- "-Weverything",
- "-Werror",
- "-Wno-padded",
- "-Wno-undef",
- "-Wno-switch-enum",
- ],
- cppflags: [
- "-Wno-c++98-compat-pedantic",
- "-Wno-c99-extensions",
- "-Wno-old-style-cast",
- ],
-
- srcs: ["vkinfo.cpp"],
-
- shared_libs: [
- "libvulkan",
- "liblog",
- ],
-}
diff --git a/vulkan/tools/vkinfo.cpp b/vulkan/tools/vkinfo.cpp
deleted file mode 100644
index 89bc926..0000000
--- a/vulkan/tools/vkinfo.cpp
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <inttypes.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <algorithm>
-#include <array>
-#include <sstream>
-#include <vector>
-
-#include <vulkan/vulkan.h>
-
-namespace {
-
-struct Options {
- bool layer_description;
- bool layer_extensions;
- bool unsupported_features;
- bool validate;
-};
-
-struct GpuInfo {
- VkPhysicalDeviceProperties properties;
- VkPhysicalDeviceMemoryProperties memory;
- VkPhysicalDeviceFeatures features;
- std::vector<VkQueueFamilyProperties> queue_families;
- std::vector<VkExtensionProperties> extensions;
- std::vector<VkLayerProperties> layers;
- std::vector<std::vector<VkExtensionProperties>> layer_extensions;
-};
-struct VulkanInfo {
- std::vector<VkExtensionProperties> extensions;
- std::vector<VkLayerProperties> layers;
- std::vector<std::vector<VkExtensionProperties>> layer_extensions;
- std::vector<GpuInfo> gpus;
-};
-
-// ----------------------------------------------------------------------------
-
-[[noreturn]] void die(const char* proc, VkResult result) {
- const char* result_str;
- switch (result) {
- // clang-format off
- case VK_SUCCESS: result_str = "VK_SUCCESS"; break;
- case VK_NOT_READY: result_str = "VK_NOT_READY"; break;
- case VK_TIMEOUT: result_str = "VK_TIMEOUT"; break;
- case VK_EVENT_SET: result_str = "VK_EVENT_SET"; break;
- case VK_EVENT_RESET: result_str = "VK_EVENT_RESET"; break;
- case VK_INCOMPLETE: result_str = "VK_INCOMPLETE"; break;
- case VK_ERROR_OUT_OF_HOST_MEMORY: result_str = "VK_ERROR_OUT_OF_HOST_MEMORY"; break;
- case VK_ERROR_OUT_OF_DEVICE_MEMORY: result_str = "VK_ERROR_OUT_OF_DEVICE_MEMORY"; break;
- case VK_ERROR_INITIALIZATION_FAILED: result_str = "VK_ERROR_INITIALIZATION_FAILED"; break;
- case VK_ERROR_DEVICE_LOST: result_str = "VK_ERROR_DEVICE_LOST"; break;
- case VK_ERROR_MEMORY_MAP_FAILED: result_str = "VK_ERROR_MEMORY_MAP_FAILED"; break;
- case VK_ERROR_LAYER_NOT_PRESENT: result_str = "VK_ERROR_LAYER_NOT_PRESENT"; break;
- case VK_ERROR_EXTENSION_NOT_PRESENT: result_str = "VK_ERROR_EXTENSION_NOT_PRESENT"; break;
- case VK_ERROR_INCOMPATIBLE_DRIVER: result_str = "VK_ERROR_INCOMPATIBLE_DRIVER"; break;
- default: result_str = "<unknown VkResult>"; break;
- // clang-format on
- }
- fprintf(stderr, "%s failed: %s (%d)\n", proc, result_str, result);
- exit(1);
-}
-
-bool HasExtension(const std::vector<VkExtensionProperties>& extensions,
- const char* name) {
- return std::find_if(extensions.cbegin(), extensions.cend(),
- [=](const VkExtensionProperties& prop) {
- return strcmp(prop.extensionName, name) == 0;
- }) != extensions.end();
-}
-
-void EnumerateInstanceExtensions(
- const char* layer_name,
- std::vector<VkExtensionProperties>* extensions) {
- VkResult result;
- uint32_t count;
- result =
- vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceExtensionProperties (count)", result);
- do {
- extensions->resize(count);
- result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
- extensions->data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceExtensionProperties (data)", result);
-}
-
-void EnumerateDeviceExtensions(VkPhysicalDevice gpu,
- const char* layer_name,
- std::vector<VkExtensionProperties>* extensions) {
- VkResult result;
- uint32_t count;
- result =
- vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceExtensionProperties (count)", result);
- do {
- extensions->resize(count);
- result = vkEnumerateDeviceExtensionProperties(gpu, layer_name, &count,
- extensions->data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceExtensionProperties (data)", result);
-}
-
-void GatherGpuInfo(VkPhysicalDevice gpu,
- const Options &options,
- GpuInfo& info) {
- VkResult result;
- uint32_t count;
-
- vkGetPhysicalDeviceProperties(gpu, &info.properties);
- vkGetPhysicalDeviceMemoryProperties(gpu, &info.memory);
- vkGetPhysicalDeviceFeatures(gpu, &info.features);
-
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count, nullptr);
- info.queue_families.resize(count);
- vkGetPhysicalDeviceQueueFamilyProperties(gpu, &count,
- info.queue_families.data());
-
- result = vkEnumerateDeviceLayerProperties(gpu, &count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (count)", result);
- do {
- info.layers.resize(count);
- result =
- vkEnumerateDeviceLayerProperties(gpu, &count, info.layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateDeviceLayerProperties (data)", result);
- info.layer_extensions.resize(info.layers.size());
-
- EnumerateDeviceExtensions(gpu, nullptr, &info.extensions);
- for (size_t i = 0; i < info.layers.size(); i++) {
- EnumerateDeviceExtensions(gpu, info.layers[i].layerName,
- &info.layer_extensions[i]);
- }
-
- const std::array<const char*, 1> kDesiredExtensions = {
- {VK_KHR_SWAPCHAIN_EXTENSION_NAME},
- };
- const char* extensions[kDesiredExtensions.size()];
- uint32_t num_extensions = 0;
- for (const auto& desired_ext : kDesiredExtensions) {
- bool available = HasExtension(info.extensions, desired_ext);
- if (options.validate) {
- for (size_t i = 0; !available && i < info.layer_extensions.size();
- i++)
- available = HasExtension(info.layer_extensions[i], desired_ext);
- }
- if (available)
- extensions[num_extensions++] = desired_ext;
- }
-
- VkDevice device;
- float queue_priorities[] = {0.0};
- const VkDeviceQueueCreateInfo queue_create_info = {
- .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
- .queueFamilyIndex = 0,
- .queueCount = 1,
- .pQueuePriorities = queue_priorities
- };
- // clang-format off
- const char *kValidationLayers[] = {
- "VK_LAYER_GOOGLE_threading",
- "VK_LAYER_LUNARG_parameter_validation",
- "VK_LAYER_LUNARG_device_limits",
- "VK_LAYER_LUNARG_object_tracker",
- "VK_LAYER_LUNARG_image",
- "VK_LAYER_LUNARG_core_validation",
- "VK_LAYER_LUNARG_swapchain",
- "VK_LAYER_GOOGLE_unique_objects"
- };
- // clang-format on
- uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
- const VkDeviceCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
- .queueCreateInfoCount = 1,
- .pQueueCreateInfos = &queue_create_info,
- .enabledExtensionCount = num_extensions,
- .ppEnabledExtensionNames = extensions,
- .enabledLayerCount = (options.validate) ? num_layers : 0,
- .ppEnabledLayerNames = kValidationLayers,
- .pEnabledFeatures = &info.features,
- };
- result = vkCreateDevice(gpu, &create_info, nullptr, &device);
- if (result != VK_SUCCESS)
- die("vkCreateDevice", result);
- vkDestroyDevice(device, nullptr);
-}
-
-void GatherInfo(VulkanInfo* info, const Options& options) {
- VkResult result;
- uint32_t count;
-
- result = vkEnumerateInstanceLayerProperties(&count, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceLayerProperties (count)", result);
- do {
- info->layers.resize(count);
- result =
- vkEnumerateInstanceLayerProperties(&count, info->layers.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumerateInstanceLayerProperties (data)", result);
- info->layer_extensions.resize(info->layers.size());
-
- EnumerateInstanceExtensions(nullptr, &info->extensions);
- for (size_t i = 0; i < info->layers.size(); i++) {
- EnumerateInstanceExtensions(info->layers[i].layerName,
- &info->layer_extensions[i]);
- }
-
- const char* kDesiredExtensions[] = {
- VK_EXT_DEBUG_REPORT_EXTENSION_NAME,
- };
- const char*
- extensions[sizeof(kDesiredExtensions) / sizeof(kDesiredExtensions[0])];
- uint32_t num_extensions = 0;
- for (const auto& desired_ext : kDesiredExtensions) {
- bool available = HasExtension(info->extensions, desired_ext);
- if (options.validate) {
- for (size_t i = 0; !available && i < info->layer_extensions.size();
- i++)
- available =
- HasExtension(info->layer_extensions[i], desired_ext);
- }
- if (available)
- extensions[num_extensions++] = desired_ext;
- }
-
- // clang-format off
- const char *kValidationLayers[] = {
- "VK_LAYER_GOOGLE_threading",
- "VK_LAYER_LUNARG_parameter_validation",
- "VK_LAYER_LUNARG_device_limits",
- "VK_LAYER_LUNARG_object_tracker",
- "VK_LAYER_LUNARG_image",
- "VK_LAYER_LUNARG_core_validation",
- "VK_LAYER_LUNARG_swapchain",
- "VK_LAYER_GOOGLE_unique_objects"
- };
- // clang-format on
- uint32_t num_layers = sizeof(kValidationLayers) / sizeof(char*);
-
- const VkApplicationInfo application_info = {
- .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
- .pApplicationName = "vkinfo",
- .applicationVersion = 0,
- .pEngineName = "vkinfo",
- .engineVersion = 0,
- .apiVersion = VK_API_VERSION_1_0,
- };
- const VkInstanceCreateInfo create_info = {
- .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
- .pApplicationInfo = &application_info,
- .enabledExtensionCount = num_extensions,
- .ppEnabledExtensionNames = extensions,
- .enabledLayerCount = (options.validate) ? num_layers : 0,
- .ppEnabledLayerNames = kValidationLayers,
- };
- VkInstance instance;
- result = vkCreateInstance(&create_info, nullptr, &instance);
- if (result != VK_SUCCESS)
- die("vkCreateInstance", result);
-
- uint32_t num_gpus;
- result = vkEnumeratePhysicalDevices(instance, &num_gpus, nullptr);
- if (result != VK_SUCCESS)
- die("vkEnumeratePhysicalDevices (count)", result);
- std::vector<VkPhysicalDevice> gpus(num_gpus, VK_NULL_HANDLE);
- do {
- gpus.resize(num_gpus, VK_NULL_HANDLE);
- result = vkEnumeratePhysicalDevices(instance, &num_gpus, gpus.data());
- } while (result == VK_INCOMPLETE);
- if (result != VK_SUCCESS)
- die("vkEnumeratePhysicalDevices (data)", result);
-
- info->gpus.resize(num_gpus);
- for (size_t i = 0; i < gpus.size(); i++)
- GatherGpuInfo(gpus[i], options, info->gpus.at(i));
-
- vkDestroyInstance(instance, nullptr);
-}
-
-// ----------------------------------------------------------------------------
-
-const size_t kMaxIndent = 8;
-const size_t kIndentSize = 3;
-std::array<char, kMaxIndent * kIndentSize + 1> kIndent;
-const char* Indent(size_t n) {
- static bool initialized = false;
- if (!initialized) {
- kIndent.fill(' ');
- kIndent.back() = '\0';
- initialized = true;
- }
- return kIndent.data() +
- (kIndent.size() - (kIndentSize * std::min(n, kMaxIndent) + 1));
-}
-
-const char* VkPhysicalDeviceTypeStr(VkPhysicalDeviceType type) {
- switch (type) {
- case VK_PHYSICAL_DEVICE_TYPE_OTHER:
- return "OTHER";
- case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
- return "INTEGRATED_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
- return "DISCRETE_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
- return "VIRTUAL_GPU";
- case VK_PHYSICAL_DEVICE_TYPE_CPU:
- return "CPU";
- default:
- return "<UNKNOWN>";
- }
-}
-
-void PrintExtensions(const std::vector<VkExtensionProperties>& extensions,
- const Options& /*options*/,
- size_t indent) {
- for (const auto& e : extensions)
- printf("%s%s (v%u)\n", Indent(indent), e.extensionName, e.specVersion);
-}
-
-void PrintLayers(
- const std::vector<VkLayerProperties>& layers,
- const std::vector<std::vector<VkExtensionProperties>> extensions,
- const Options& options,
- size_t indent) {
- for (size_t i = 0; i < layers.size(); i++) {
- printf("%s%s %u.%u.%u/%u\n", Indent(indent), layers[i].layerName,
- VK_VERSION_MAJOR(layers[i].specVersion),
- VK_VERSION_MINOR(layers[i].specVersion),
- VK_VERSION_PATCH(layers[i].specVersion),
- layers[i].implementationVersion);
- if (options.layer_description)
- printf("%s%s\n", Indent(indent + 1), layers[i].description);
- if (options.layer_extensions && !extensions[i].empty()) {
- if (!extensions[i].empty()) {
- printf("%sExtensions [%zu]:\n", Indent(indent + 1),
- extensions[i].size());
- PrintExtensions(extensions[i], options, indent + 2);
- }
- }
- }
-}
-
-void PrintAllFeatures(const char* indent,
- const VkPhysicalDeviceFeatures& features) {
- // clang-format off
- printf("%srobustBufferAccess: %s\n", indent, features.robustBufferAccess ? "YES" : "NO");
- printf("%sfullDrawIndexUint32: %s\n", indent, features.fullDrawIndexUint32 ? "YES" : "NO");
- printf("%simageCubeArray: %s\n", indent, features.imageCubeArray ? "YES" : "NO");
- printf("%sindependentBlend: %s\n", indent, features.independentBlend ? "YES" : "NO");
- printf("%sgeometryShader: %s\n", indent, features.geometryShader ? "YES" : "NO");
- printf("%stessellationShader: %s\n", indent, features.tessellationShader ? "YES" : "NO");
- printf("%ssampleRateShading: %s\n", indent, features.sampleRateShading ? "YES" : "NO");
- printf("%sdualSrcBlend: %s\n", indent, features.dualSrcBlend ? "YES" : "NO");
- printf("%slogicOp: %s\n", indent, features.logicOp ? "YES" : "NO");
- printf("%smultiDrawIndirect: %s\n", indent, features.multiDrawIndirect ? "YES" : "NO");
- printf("%sdrawIndirectFirstInstance: %s\n", indent, features.drawIndirectFirstInstance ? "YES" : "NO");
- printf("%sdepthClamp: %s\n", indent, features.depthClamp ? "YES" : "NO");
- printf("%sdepthBiasClamp: %s\n", indent, features.depthBiasClamp ? "YES" : "NO");
- printf("%sfillModeNonSolid: %s\n", indent, features.fillModeNonSolid ? "YES" : "NO");
- printf("%sdepthBounds: %s\n", indent, features.depthBounds ? "YES" : "NO");
- printf("%swideLines: %s\n", indent, features.wideLines ? "YES" : "NO");
- printf("%slargePoints: %s\n", indent, features.largePoints ? "YES" : "NO");
- printf("%salphaToOne: %s\n", indent, features.alphaToOne ? "YES" : "NO");
- printf("%smultiViewport: %s\n", indent, features.multiViewport ? "YES" : "NO");
- printf("%ssamplerAnisotropy: %s\n", indent, features.samplerAnisotropy ? "YES" : "NO");
- printf("%stextureCompressionETC2: %s\n", indent, features.textureCompressionETC2 ? "YES" : "NO");
- printf("%stextureCompressionASTC_LDR: %s\n", indent, features.textureCompressionASTC_LDR ? "YES" : "NO");
- printf("%stextureCompressionBC: %s\n", indent, features.textureCompressionBC ? "YES" : "NO");
- printf("%socclusionQueryPrecise: %s\n", indent, features.occlusionQueryPrecise ? "YES" : "NO");
- printf("%spipelineStatisticsQuery: %s\n", indent, features.pipelineStatisticsQuery ? "YES" : "NO");
- printf("%svertexPipelineStoresAndAtomics: %s\n", indent, features.vertexPipelineStoresAndAtomics ? "YES" : "NO");
- printf("%sfragmentStoresAndAtomics: %s\n", indent, features.fragmentStoresAndAtomics ? "YES" : "NO");
- printf("%sshaderTessellationAndGeometryPointSize: %s\n", indent, features.shaderTessellationAndGeometryPointSize ? "YES" : "NO");
- printf("%sshaderImageGatherExtended: %s\n", indent, features.shaderImageGatherExtended ? "YES" : "NO");
- printf("%sshaderStorageImageExtendedFormats: %s\n", indent, features.shaderStorageImageExtendedFormats ? "YES" : "NO");
- printf("%sshaderStorageImageMultisample: %s\n", indent, features.shaderStorageImageMultisample ? "YES" : "NO");
- printf("%sshaderStorageImageReadWithoutFormat: %s\n", indent, features.shaderStorageImageReadWithoutFormat ? "YES" : "NO");
- printf("%sshaderStorageImageWriteWithoutFormat: %s\n", indent, features.shaderStorageImageWriteWithoutFormat ? "YES" : "NO");
- printf("%sshaderUniformBufferArrayDynamicIndexing: %s\n", indent, features.shaderUniformBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderSampledImageArrayDynamicIndexing: %s\n", indent, features.shaderSampledImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageBufferArrayDynamicIndexing: %s\n", indent, features.shaderStorageBufferArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderStorageImageArrayDynamicIndexing: %s\n", indent, features.shaderStorageImageArrayDynamicIndexing ? "YES" : "NO");
- printf("%sshaderClipDistance: %s\n", indent, features.shaderClipDistance ? "YES" : "NO");
- printf("%sshaderCullDistance: %s\n", indent, features.shaderCullDistance ? "YES" : "NO");
- printf("%sshaderFloat64: %s\n", indent, features.shaderFloat64 ? "YES" : "NO");
- printf("%sshaderInt64: %s\n", indent, features.shaderInt64 ? "YES" : "NO");
- printf("%sshaderInt16: %s\n", indent, features.shaderInt16 ? "YES" : "NO");
- printf("%sshaderResourceResidency: %s\n", indent, features.shaderResourceResidency ? "YES" : "NO");
- printf("%sshaderResourceMinLod: %s\n", indent, features.shaderResourceMinLod ? "YES" : "NO");
- printf("%ssparseBinding: %s\n", indent, features.sparseBinding ? "YES" : "NO");
- printf("%ssparseResidencyBuffer: %s\n", indent, features.sparseResidencyBuffer ? "YES" : "NO");
- printf("%ssparseResidencyImage2D: %s\n", indent, features.sparseResidencyImage2D ? "YES" : "NO");
- printf("%ssparseResidencyImage3D: %s\n", indent, features.sparseResidencyImage3D ? "YES" : "NO");
- printf("%ssparseResidency2Samples: %s\n", indent, features.sparseResidency2Samples ? "YES" : "NO");
- printf("%ssparseResidency4Samples: %s\n", indent, features.sparseResidency4Samples ? "YES" : "NO");
- printf("%ssparseResidency8Samples: %s\n", indent, features.sparseResidency8Samples ? "YES" : "NO");
- printf("%ssparseResidency16Samples: %s\n", indent, features.sparseResidency16Samples ? "YES" : "NO");
- printf("%ssparseResidencyAliased: %s\n", indent, features.sparseResidencyAliased ? "YES" : "NO");
- printf("%svariableMultisampleRate: %s\n", indent, features.variableMultisampleRate ? "YES" : "NO");
- printf("%sinheritedQueries: %s\n", indent, features.inheritedQueries ? "YES" : "NO");
- // clang-format on
-}
-
-void PrintSupportedFeatures(const char* indent,
- const VkPhysicalDeviceFeatures& features) {
- // clang-format off
- if (features.robustBufferAccess) printf("%srobustBufferAccess\n", indent);
- if (features.fullDrawIndexUint32) printf("%sfullDrawIndexUint32\n", indent);
- if (features.imageCubeArray) printf("%simageCubeArray\n", indent);
- if (features.independentBlend) printf("%sindependentBlend\n", indent);
- if (features.geometryShader) printf("%sgeometryShader\n", indent);
- if (features.tessellationShader) printf("%stessellationShader\n", indent);
- if (features.sampleRateShading) printf("%ssampleRateShading\n", indent);
- if (features.dualSrcBlend) printf("%sdualSrcBlend\n", indent);
- if (features.logicOp) printf("%slogicOp\n", indent);
- if (features.multiDrawIndirect) printf("%smultiDrawIndirect\n", indent);
- if (features.drawIndirectFirstInstance) printf("%sdrawIndirectFirstInstance\n", indent);
- if (features.depthClamp) printf("%sdepthClamp\n", indent);
- if (features.depthBiasClamp) printf("%sdepthBiasClamp\n", indent);
- if (features.fillModeNonSolid) printf("%sfillModeNonSolid\n", indent);
- if (features.depthBounds) printf("%sdepthBounds\n", indent);
- if (features.wideLines) printf("%swideLines\n", indent);
- if (features.largePoints) printf("%slargePoints\n", indent);
- if (features.alphaToOne) printf("%salphaToOne\n", indent);
- if (features.multiViewport) printf("%smultiViewport\n", indent);
- if (features.samplerAnisotropy) printf("%ssamplerAnisotropy\n", indent);
- if (features.textureCompressionETC2) printf("%stextureCompressionETC2\n", indent);
- if (features.textureCompressionASTC_LDR) printf("%stextureCompressionASTC_LDR\n", indent);
- if (features.textureCompressionBC) printf("%stextureCompressionBC\n", indent);
- if (features.occlusionQueryPrecise) printf("%socclusionQueryPrecise\n", indent);
- if (features.pipelineStatisticsQuery) printf("%spipelineStatisticsQuery\n", indent);
- if (features.vertexPipelineStoresAndAtomics) printf("%svertexPipelineStoresAndAtomics\n", indent);
- if (features.fragmentStoresAndAtomics) printf("%sfragmentStoresAndAtomics\n", indent);
- if (features.shaderTessellationAndGeometryPointSize) printf("%sshaderTessellationAndGeometryPointSize\n", indent);
- if (features.shaderImageGatherExtended) printf("%sshaderImageGatherExtended\n", indent);
- if (features.shaderStorageImageExtendedFormats) printf("%sshaderStorageImageExtendedFormats\n", indent);
- if (features.shaderStorageImageMultisample) printf("%sshaderStorageImageMultisample\n", indent);
- if (features.shaderStorageImageReadWithoutFormat) printf("%sshaderStorageImageReadWithoutFormat\n", indent);
- if (features.shaderStorageImageWriteWithoutFormat) printf("%sshaderStorageImageWriteWithoutFormat\n", indent);
- if (features.shaderUniformBufferArrayDynamicIndexing) printf("%sshaderUniformBufferArrayDynamicIndexing\n", indent);
- if (features.shaderSampledImageArrayDynamicIndexing) printf("%sshaderSampledImageArrayDynamicIndexing\n", indent);
- if (features.shaderStorageBufferArrayDynamicIndexing) printf("%sshaderStorageBufferArrayDynamicIndexing\n", indent);
- if (features.shaderStorageImageArrayDynamicIndexing) printf("%sshaderStorageImageArrayDynamicIndexing\n", indent);
- if (features.shaderClipDistance) printf("%sshaderClipDistance\n", indent);
- if (features.shaderCullDistance) printf("%sshaderCullDistance\n", indent);
- if (features.shaderFloat64) printf("%sshaderFloat64\n", indent);
- if (features.shaderInt64) printf("%sshaderInt64\n", indent);
- if (features.shaderInt16) printf("%sshaderInt16\n", indent);
- if (features.shaderResourceResidency) printf("%sshaderResourceResidency\n", indent);
- if (features.shaderResourceMinLod) printf("%sshaderResourceMinLod\n", indent);
- if (features.sparseBinding) printf("%ssparseBinding\n", indent);
- if (features.sparseResidencyBuffer) printf("%ssparseResidencyBuffer\n", indent);
- if (features.sparseResidencyImage2D) printf("%ssparseResidencyImage2D\n", indent);
- if (features.sparseResidencyImage3D) printf("%ssparseResidencyImage3D\n", indent);
- if (features.sparseResidency2Samples) printf("%ssparseResidency2Samples\n", indent);
- if (features.sparseResidency4Samples) printf("%ssparseResidency4Samples\n", indent);
- if (features.sparseResidency8Samples) printf("%ssparseResidency8Samples\n", indent);
- if (features.sparseResidency16Samples) printf("%ssparseResidency16Samples\n", indent);
- if (features.sparseResidencyAliased) printf("%ssparseResidencyAliased\n", indent);
- if (features.variableMultisampleRate) printf("%svariableMultisampleRate\n", indent);
- if (features.inheritedQueries) printf("%sinheritedQueries\n", indent);
- // clang-format on
-}
-
-void PrintGpuInfo(const GpuInfo& info, const Options& options, size_t indent) {
- VkResult result;
- std::ostringstream strbuf;
-
- printf("%s\"%s\" (%s) %u.%u.%u/%#x [%04x:%04x]\n", Indent(indent),
- info.properties.deviceName,
- VkPhysicalDeviceTypeStr(info.properties.deviceType),
- VK_VERSION_MAJOR(info.properties.apiVersion),
- VK_VERSION_MINOR(info.properties.apiVersion),
- VK_VERSION_PATCH(info.properties.apiVersion),
- info.properties.driverVersion, info.properties.vendorID,
- info.properties.deviceID);
-
- for (uint32_t heap = 0; heap < info.memory.memoryHeapCount; heap++) {
- if ((info.memory.memoryHeaps[heap].flags &
- VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0)
- strbuf << "DEVICE_LOCAL";
- printf("%sHeap %u: %" PRIu64 " MiB (0x%" PRIx64 " B) %s\n",
- Indent(indent + 1), heap,
- info.memory.memoryHeaps[heap].size / 0x100000,
- info.memory.memoryHeaps[heap].size, strbuf.str().c_str());
- strbuf.str(std::string());
-
- for (uint32_t type = 0; type < info.memory.memoryTypeCount; type++) {
- if (info.memory.memoryTypes[type].heapIndex != heap)
- continue;
- VkMemoryPropertyFlags flags =
- info.memory.memoryTypes[type].propertyFlags;
- if ((flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 0)
- strbuf << " DEVICE_LOCAL";
- if ((flags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) != 0)
- strbuf << " HOST_VISIBLE";
- if ((flags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) != 0)
- strbuf << " COHERENT";
- if ((flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) != 0)
- strbuf << " CACHED";
- if ((flags & VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT) != 0)
- strbuf << " LAZILY_ALLOCATED";
- printf("%sType %u:%s\n", Indent(indent + 2), type,
- strbuf.str().c_str());
- strbuf.str(std::string());
- }
- }
-
- for (uint32_t family = 0; family < info.queue_families.size(); family++) {
- const VkQueueFamilyProperties& qprops = info.queue_families[family];
- VkQueueFlags flags = qprops.queueFlags;
- char flags_str[5];
- flags_str[0] = (flags & VK_QUEUE_GRAPHICS_BIT) ? 'G' : '_';
- flags_str[1] = (flags & VK_QUEUE_COMPUTE_BIT) ? 'C' : '_';
- flags_str[2] = (flags & VK_QUEUE_TRANSFER_BIT) ? 'T' : '_';
- flags_str[3] = (flags & VK_QUEUE_SPARSE_BINDING_BIT) ? 'S' : '_';
- flags_str[4] = '\0';
- printf(
- "%sQueue Family %u: %ux %s\n"
- "%stimestampValidBits: %ub\n"
- "%sminImageTransferGranularity: (%u,%u,%u)\n",
- Indent(indent + 1), family, qprops.queueCount, flags_str,
- Indent(indent + 2), qprops.timestampValidBits, Indent(indent + 2),
- qprops.minImageTransferGranularity.width,
- qprops.minImageTransferGranularity.height,
- qprops.minImageTransferGranularity.depth);
- }
-
- printf("%sFeatures:\n", Indent(indent + 1));
- if (options.unsupported_features) {
- PrintAllFeatures(Indent(indent + 2), info.features);
- } else {
- PrintSupportedFeatures(Indent(indent + 2), info.features);
- }
-
- printf("%sExtensions [%zu]:\n", Indent(indent + 1), info.extensions.size());
- if (!info.extensions.empty())
- PrintExtensions(info.extensions, options, indent + 2);
- printf("%sLayers [%zu]:\n", Indent(indent + 1), info.layers.size());
- if (!info.layers.empty())
- PrintLayers(info.layers, info.layer_extensions, options, indent + 2);
-}
-
-void PrintInfo(const VulkanInfo& info, const Options& options) {
- std::ostringstream strbuf;
- size_t indent = 0;
-
- printf("%sInstance Extensions [%zu]:\n", Indent(indent),
- info.extensions.size());
- PrintExtensions(info.extensions, options, indent + 1);
- printf("%sInstance Layers [%zu]:\n", Indent(indent), info.layers.size());
- if (!info.layers.empty())
- PrintLayers(info.layers, info.layer_extensions, options, indent + 1);
-
- printf("%sPhysicalDevices [%zu]:\n", Indent(indent), info.gpus.size());
- for (const auto& gpu : info.gpus)
- PrintGpuInfo(gpu, options, indent + 1);
-}
-
-const char kUsageString[] =
- "usage: vkinfo [options]\n"
- " -v enable all the following verbose options\n"
- " -layer_description print layer description strings\n"
- " -layer_extensions print extensions supported by each layer\n"
- " -unsupported_features print all physical device features\n"
- " -validate enable validation layers if present\n"
- " -debug_pause pause at start until resumed via debugger\n";
-
-} // namespace
-
-// ----------------------------------------------------------------------------
-
-int main(int argc, char const* argv[]) {
- static volatile bool startup_pause = false;
- Options options = {
- .layer_description = false, .layer_extensions = false,
- .unsupported_features = false,
- .validate = false,
- };
- for (int argi = 1; argi < argc; argi++) {
- if (strcmp(argv[argi], "-h") == 0) {
- fputs(kUsageString, stdout);
- return 0;
- }
- if (strcmp(argv[argi], "-v") == 0) {
- options.layer_description = true;
- options.layer_extensions = true;
- options.unsupported_features = true;
- } else if (strcmp(argv[argi], "-layer_description") == 0) {
- options.layer_description = true;
- } else if (strcmp(argv[argi], "-layer_extensions") == 0) {
- options.layer_extensions = true;
- } else if (strcmp(argv[argi], "-unsupported_features") == 0) {
- options.unsupported_features = true;
- } else if (strcmp(argv[argi], "-validate") == 0) {
- options.validate = true;
- } else if (strcmp(argv[argi], "-debug_pause") == 0) {
- startup_pause = true;
- }
- }
-
- while (startup_pause) {
- sleep(0);
- }
-
- VulkanInfo info;
- GatherInfo(&info, options);
- PrintInfo(info, options);
- return 0;
-}
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 3da4336..8f714d8 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -21,11 +21,14 @@
#include "vkjson.h"
#include <assert.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
-#include <cmath>
+#include <json/json.h>
+
+#include <algorithm>
#include <cinttypes>
+#include <cmath>
#include <cstdio>
#include <limits>
#include <memory>
@@ -33,8 +36,6 @@
#include <type_traits>
#include <utility>
-#include <json/json.h>
-
namespace {
inline bool IsIntegral(double value) {
@@ -46,6 +47,14 @@
#endif
}
+// Floating point fields of Vulkan structure use single precision. The string
+// output of max double value in c++ will be larger than Java double's infinity
+// value. Below fake double max/min values are only to serve the safe json text
+// parsing in between C++ and Java, becasue Java json library simply cannot
+// handle infinity.
+static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits<double>::max();
+static const double SAFE_DOUBLE_MIN = -SAFE_DOUBLE_MAX;
+
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {
static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
@@ -851,7 +860,8 @@
template <typename T, typename = EnableForArithmetic<T>>
inline Json::Value ToJsonValue(const T& value) {
- return Json::Value(static_cast<double>(value));
+ return Json::Value(
+ std::clamp(static_cast<double>(value), SAFE_DOUBLE_MIN, SAFE_DOUBLE_MAX));
}
inline Json::Value ToJsonValue(const uint64_t& value) {