Merge "Separate vibration log buffers"
diff --git a/api/system-current.txt b/api/system-current.txt
index 0f1ab29..0597dba 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1576,6 +1576,7 @@
method public boolean getAllocateAggressive();
method @Deprecated public boolean getAllowDowngrade();
method public boolean getDontKillApp();
+ method public boolean getEnableRollback();
method @Nullable public String[] getGrantedRuntimePermissions();
method public boolean getInstallAsFullApp(boolean);
method public boolean getInstallAsInstantApp(boolean);
@@ -1587,7 +1588,7 @@
method @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public void setAllocateAggressive(boolean);
method @Deprecated public void setAllowDowngrade(boolean);
method public void setDontKillApp(boolean);
- method public void setEnableRollback();
+ method public void setEnableRollback(boolean);
method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
method public void setInstallAsInstantApp(boolean);
@@ -1822,18 +1823,18 @@
public final class PackageRollbackInfo implements android.os.Parcelable {
method public int describeContents();
- method public String getPackageName();
- method public android.content.pm.VersionedPackage getVersionRolledBackFrom();
- method public android.content.pm.VersionedPackage getVersionRolledBackTo();
+ method @NonNull public String getPackageName();
+ method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackFrom();
+ method @NonNull public android.content.pm.VersionedPackage getVersionRolledBackTo();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.content.rollback.PackageRollbackInfo> CREATOR;
}
public final class RollbackInfo implements android.os.Parcelable {
method public int describeContents();
- method public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
+ method @NonNull public java.util.List<android.content.pm.VersionedPackage> getCausePackages();
method public int getCommittedSessionId();
- method public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
+ method @NonNull public java.util.List<android.content.rollback.PackageRollbackInfo> getPackages();
method public int getRollbackId();
method public boolean isStaged();
method public void writeToParcel(android.os.Parcel, int);
@@ -1843,7 +1844,7 @@
public final class RollbackManager {
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void commitRollback(int, @NonNull java.util.List<android.content.pm.VersionedPackage>, @NonNull android.content.IntentSender);
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void expireRollbackForPackage(@NonNull String);
- method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getAvailableRollbacks();
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) @NonNull public java.util.List<android.content.rollback.RollbackInfo> getRecentlyCommittedRollbacks();
method @RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS) public void reloadPersistedData();
field public static final String EXTRA_STATUS = "android.content.rollback.extra.STATUS";
@@ -5187,7 +5188,7 @@
public static interface Binder.ProxyTransactListener {
method public void onTransactEnded(@Nullable Object);
- method public Object onTransactStarted(android.os.IBinder, int);
+ method @Nullable public Object onTransactStarted(@NonNull android.os.IBinder, int);
}
public class BugreportManager {
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 7e04469..18d0ec0 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -60,6 +60,14 @@
}
+package android.content.pm {
+
+ public static class PackageInstaller.SessionParams implements android.os.Parcelable {
+ method @Deprecated public void setEnableRollback();
+ }
+
+}
+
package android.location {
public class LocationManager {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index d758c4d..7b4dd19 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1448,14 +1448,33 @@
/**
* Request that rollbacks be enabled for the given upgrade.
+ *
+ * @removed
+ * @deprecated use {@link #setEnableRollback(boolean)} instead.
* @hide
*/
+ @Deprecated
@SystemApi
public void setEnableRollback() {
installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
}
/**
+ * Request that rollbacks be enabled or disabled for the given upgrade.
+ *
+ * @param enable set to {@code true} to enable, {@code false} to disable
+ * @hide
+ */
+ @SystemApi
+ public void setEnableRollback(boolean enable) {
+ if (enable) {
+ installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
+ } else {
+ installFlags &= ~PackageManager.INSTALL_ENABLE_ROLLBACK;
+ }
+ }
+
+ /**
* @deprecated use {@link #setRequestDowngrade(boolean)}.
* {@hide}
*/
@@ -2058,6 +2077,16 @@
}
/**
+ * Return whether rollback is enabled or disabled for the given upgrade.
+ *
+ * @hide
+ */
+ @SystemApi
+ public boolean getEnableRollback() {
+ return (installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0;
+ }
+
+ /**
* Get the value set in {@link SessionParams#setAllocateAggressive(boolean)}.
*
* @hide
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 03810f5..c0414fc 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -89,6 +89,7 @@
/**
* Returns the name of the package to roll back from.
*/
+ @NonNull
public String getPackageName() {
return mVersionRolledBackFrom.getPackageName();
}
@@ -96,6 +97,7 @@
/**
* Returns the version of the package rolled back from.
*/
+ @NonNull
public VersionedPackage getVersionRolledBackFrom() {
return mVersionRolledBackFrom;
}
@@ -103,6 +105,7 @@
/**
* Returns the version of the package rolled back to.
*/
+ @NonNull
public VersionedPackage getVersionRolledBackTo() {
return mVersionRolledBackTo;
}
diff --git a/core/java/android/content/rollback/RollbackInfo.java b/core/java/android/content/rollback/RollbackInfo.java
index 29b99e0..a363718 100644
--- a/core/java/android/content/rollback/RollbackInfo.java
+++ b/core/java/android/content/rollback/RollbackInfo.java
@@ -16,6 +16,7 @@
package android.content.rollback;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.pm.VersionedPackage;
import android.os.Parcel;
@@ -72,6 +73,7 @@
/**
* Returns the list of package that are rolled back.
*/
+ @NonNull
public List<PackageRollbackInfo> getPackages() {
return mPackages;
}
@@ -105,6 +107,7 @@
* As provided to {@link #commitRollback} when the rollback was committed.
* This is only applicable for rollbacks that have been committed.
*/
+ @NonNull
public List<VersionedPackage> getCausePackages() {
return mCausePackages;
}
diff --git a/core/java/android/content/rollback/RollbackManager.java b/core/java/android/content/rollback/RollbackManager.java
index c043491..4e8c254 100644
--- a/core/java/android/content/rollback/RollbackManager.java
+++ b/core/java/android/content/rollback/RollbackManager.java
@@ -57,6 +57,7 @@
* MANAGE_ROLLBACKS permission.
*/
@RequiresPermission(android.Manifest.permission.MANAGE_ROLLBACKS)
+ @NonNull
public List<RollbackInfo> getAvailableRollbacks() {
try {
return mBinder.getAvailableRollbacks().getList();
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index b28c2f4..d5ef249 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -653,7 +653,8 @@
*
* @return an object that will be passed back to #onTransactEnded (or null).
*/
- Object onTransactStarted(IBinder binder, int transactionCode);
+ @Nullable
+ Object onTransactStarted(@NonNull IBinder binder, int transactionCode);
/**
* Called after onTranact (even when an exception is thrown).
diff --git a/core/res/res/values-night/values.xml b/core/res/res/values-night/values.xml
index a2ad3b9..4e6b712 100644
--- a/core/res/res/values-night/values.xml
+++ b/core/res/res/values-night/values.xml
@@ -24,6 +24,7 @@
<item name="colorError">@color/error_color_device_default_dark</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+ <item name="forceDarkAllowed">false</item>
<!-- QS panel background -->
<item name="colorBackgroundFloating">@color/black</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b7f594e..442ad7e 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3943,4 +3943,8 @@
<!-- The default peak refresh rate for a given device. Change this value if you want to allow
for higher refresh rates to be automatically used out of the box -->
<integer name="config_defaultPeakRefreshRate">60</integer>
+
+ <!-- The type of the light sensor to be used by the display framework for things like
+ auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
+ <string name="config_displayLightSensorType" translatable="false" />
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 96a3d96..c7e19c5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3693,5 +3693,9 @@
<java-symbol type="string" name="mime_type_presentation" />
<java-symbol type="string" name="mime_type_presentation_ext" />
+ <!-- For high refresh rate displays -->
<java-symbol type="integer" name="config_defaultPeakRefreshRate" />
+
+ <!-- For Auto-Brightness -->
+ <java-symbol type="string" name="config_displayLightSensorType" />
</resources>
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 793dd8d..4f1b2a4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -69,6 +69,7 @@
"libminikin",
"libandroidfw",
"libcrypto",
+ "libsync",
],
static_libs: [
"libEGL_blobCache",
@@ -180,6 +181,7 @@
"renderthread/EglManager.cpp",
"renderthread/ReliableSurface.cpp",
"renderthread/VulkanManager.cpp",
+ "renderthread/VulkanSurface.cpp",
"renderthread/RenderProxy.cpp",
"renderthread/RenderTask.cpp",
"renderthread/RenderThread.cpp",
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 87cffb5..edde6d3 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -55,20 +55,8 @@
}
Frame SkiaVulkanPipeline::getFrame() {
- LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
- "drawRenderNode called on a context with no surface!");
-
- SkSurface* backBuffer = mVkManager.getBackbufferSurface(&mVkSurface);
- LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
- "drawRenderNode called on a context with an invalid surface");
- if (backBuffer == nullptr) {
- SkDebugf("failed to get backbuffer");
- return Frame(-1, -1, 0);
- }
-
- Frame frame(mVkSurface->windowWidth(), mVkSurface->windowHeight(),
- mVkManager.getAge(mVkSurface));
- return frame;
+ LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr, "getFrame() called on a context with no surface!");
+ return mVkManager.dequeueNextBuffer(mVkSurface);
}
bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
@@ -77,13 +65,13 @@
bool opaque, const LightInfo& lightInfo,
const std::vector<sp<RenderNode>>& renderNodes,
FrameInfoVisualizer* profiler) {
- sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
+ sk_sp<SkSurface> backBuffer = mVkSurface->getCurrentSkSurface();
if (backBuffer.get() == nullptr) {
return false;
}
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, contentDrawBounds,
- backBuffer, mVkSurface->preTransform());
+ backBuffer, mVkSurface->getCurrentPreTransform());
ShaderCache::get().onVkFrameFlushed(mRenderThread.getGrContext());
layerUpdateQueue->clear();
@@ -113,7 +101,7 @@
currentFrameInfo->markSwapBuffers();
if (*requireSwap) {
- mVkManager.swapBuffers(mVkSurface);
+ mVkManager.swapBuffers(mVkSurface, screenDirty);
}
return *requireSwap;
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 2c24edd..77a7ab1 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -18,6 +18,7 @@
#include "SkiaPipeline.h"
#include "renderthread/VulkanManager.h"
+#include "renderthread/VulkanSurface.h"
#include "renderstate/RenderState.h"
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 5af660c..d4c6eae 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -16,6 +16,7 @@
#include "VulkanManager.h"
+#include <android/sync.h>
#include <gui/Surface.h>
#include "Properties.h"
@@ -23,6 +24,7 @@
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
+#include <GrBackendSemaphore.h>
#include <GrBackendSurface.h>
#include <GrContext.h>
#include <GrTypes.h>
@@ -142,6 +144,7 @@
GET_INST_PROC(GetPhysicalDeviceProperties);
GET_INST_PROC(GetPhysicalDeviceQueueFamilyProperties);
GET_INST_PROC(GetPhysicalDeviceFeatures2);
+ GET_INST_PROC(GetPhysicalDeviceImageFormatProperties2);
GET_INST_PROC(CreateDevice);
GET_INST_PROC(EnumerateDeviceExtensionProperties);
GET_INST_PROC(CreateAndroidSurfaceKHR);
@@ -318,11 +321,6 @@
GET_DEV_PROC(GetDeviceQueue);
GET_DEV_PROC(DeviceWaitIdle);
GET_DEV_PROC(DestroyDevice);
- GET_DEV_PROC(CreateSwapchainKHR);
- GET_DEV_PROC(DestroySwapchainKHR);
- GET_DEV_PROC(GetSwapchainImagesKHR);
- GET_DEV_PROC(AcquireNextImageKHR);
- GET_DEV_PROC(QueuePresentKHR);
GET_DEV_PROC(CreateCommandPool);
GET_DEV_PROC(DestroyCommandPool);
GET_DEV_PROC(AllocateCommandBuffers);
@@ -426,201 +424,102 @@
};
}
-// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
-// previous uses have finished before returning.
-VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
- SkASSERT(surface->mBackbuffers);
+Frame VulkanManager::dequeueNextBuffer(VulkanSurface* surface) {
- ++surface->mCurrentBackbufferIndex;
- if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
- surface->mCurrentBackbufferIndex = 0;
+ VulkanSurface::NativeBufferInfo* bufferInfo = surface->dequeueNativeBuffer();
+
+ if (bufferInfo == nullptr) {
+ ALOGE("VulkanSurface::dequeueNativeBuffer called with an invalid surface!");
+ return Frame(-1, -1, 0);
}
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
+ LOG_ALWAYS_FATAL_IF(!bufferInfo->dequeued);
- // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
- // reuse its commands buffers.
- VkResult res = mWaitForFences(mDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
- if (res != VK_SUCCESS) {
- return nullptr;
+ if (bufferInfo->dequeue_fence != -1) {
+ int fence_clone = dup(bufferInfo->dequeue_fence);
+ if (fence_clone == -1) {
+ ALOGE("dup(fence) failed, stalling until signalled: %s (%d)", strerror(errno), errno);
+ sync_wait(bufferInfo->dequeue_fence, -1 /* forever */);
+ } else {
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = nullptr;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+ VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to create import semaphore, err: %d",
+ err);
+
+ VkImportSemaphoreFdInfoKHR importInfo;
+ importInfo.sType = VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FD_INFO_KHR;
+ importInfo.pNext = nullptr;
+ importInfo.semaphore = semaphore;
+ importInfo.flags = VK_SEMAPHORE_IMPORT_TEMPORARY_BIT;
+ importInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
+ importInfo.fd = fence_clone;
+
+ err = mImportSemaphoreFdKHR(mDevice, &importInfo);
+ LOG_ALWAYS_FATAL_IF(VK_SUCCESS != err, "Failed to import semaphore, err: %d", err);
+
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
+ bufferInfo->skSurface->wait(1, &backendSemaphore);
+ }
}
- return backbuffer;
+ int bufferAge = (mSwapBehavior == SwapBehavior::Discard) ? 0 : surface->getCurrentBuffersAge();
+ return Frame(surface->logicalWidth(), surface->logicalHeight(), bufferAge);
}
-static SkMatrix getPreTransformMatrix(int width, int height,
- VkSurfaceTransformFlagBitsKHR transform) {
- switch (transform) {
- case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
- return SkMatrix::I();
- case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
- return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
- return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
- return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
- return SkMatrix::MakeAll(-1, 0, width, 0, 1, 0, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR:
- return SkMatrix::MakeAll(0, -1, height, -1, 0, width, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
- return SkMatrix::MakeAll(1, 0, 0, 0, -1, height, 0, 0, 1);
- case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR:
- return SkMatrix::MakeAll(0, 1, 0, 1, 0, 0, 0, 0, 1);
- default:
- LOG_ALWAYS_FATAL("Unsupported pre transform of swapchain.");
- }
- return SkMatrix::I();
-}
-
-
-SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface** surfaceOut) {
- // Recreate VulkanSurface, if ANativeWindow has been resized.
- VulkanSurface* surface = *surfaceOut;
- int windowWidth = 0, windowHeight = 0;
- ANativeWindow* window = surface->mNativeWindow;
- window->query(window, NATIVE_WINDOW_WIDTH, &windowWidth);
- window->query(window, NATIVE_WINDOW_HEIGHT, &windowHeight);
- if (windowWidth != surface->mWindowWidth || windowHeight != surface->mWindowHeight) {
- ColorMode colorMode = surface->mColorMode;
- sk_sp<SkColorSpace> colorSpace = surface->mColorSpace;
- SkColorType colorType = surface->mColorType;
- GrContext* grContext = surface->mGrContext;
- destroySurface(surface);
- *surfaceOut = createSurface(window, colorMode, colorSpace, colorType, grContext);
- surface = *surfaceOut;
- if (!surface) {
- return nullptr;
- }
+void VulkanManager::swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect) {
+ if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
+ ATRACE_NAME("Finishing GPU work");
+ mDeviceWaitIdle(mDevice);
}
- VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
- SkASSERT(backbuffer);
+ VkExportSemaphoreCreateInfo exportInfo;
+ exportInfo.sType = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO;
+ exportInfo.pNext = nullptr;
+ exportInfo.handleTypes = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- VkResult res;
+ VkSemaphoreCreateInfo semaphoreInfo;
+ semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
+ semaphoreInfo.pNext = &exportInfo;
+ semaphoreInfo.flags = 0;
+ VkSemaphore semaphore;
+ VkResult err = mCreateSemaphore(mDevice, &semaphoreInfo, nullptr, &semaphore);
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to create semaphore");
- res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
- SkASSERT(VK_SUCCESS == res);
+ GrBackendSemaphore backendSemaphore;
+ backendSemaphore.initVulkan(semaphore);
- // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
- // finished presenting and that it is safe to begin sending new commands to the returned image.
- res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
- &backbuffer->mImageIndex);
+ VulkanSurface::NativeBufferInfo* bufferInfo = surface->getCurrentBufferInfo();
- if (VK_ERROR_SURFACE_LOST_KHR == res) {
- // need to figure out how to create a new vkSurface without the platformData*
- // maybe use attach somehow? but need a Window
- return nullptr;
- }
- if (VK_ERROR_OUT_OF_DATE_KHR == res || VK_SUBOPTIMAL_KHR == res) {
- // tear swapchain down and try again
- if (!createSwapchain(surface)) {
- return nullptr;
- }
- backbuffer = getAvailableBackbuffer(surface);
- res = mResetFences(mDevice, 2, backbuffer->mUsageFences);
- SkASSERT(VK_SUCCESS == res);
+ int fenceFd = -1;
+ GrSemaphoresSubmitted submitted =
+ bufferInfo->skSurface->flush(SkSurface::BackendSurfaceAccess::kPresent,
+ SkSurface::kNone_FlushFlags, 1, &backendSemaphore);
+ if (submitted == GrSemaphoresSubmitted::kYes) {
+ VkSemaphoreGetFdInfoKHR getFdInfo;
+ getFdInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_GET_FD_INFO_KHR;
+ getFdInfo.pNext = nullptr;
+ getFdInfo.semaphore = semaphore;
+ getFdInfo.handleType = VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
- // acquire the image
- res = mAcquireNextImageKHR(mDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
- &backbuffer->mImageIndex);
-
- if (VK_SUCCESS != res) {
- return nullptr;
- }
+ err = mGetSemaphoreFdKHR(mDevice, &getFdInfo, &fenceFd);
+ ALOGE_IF(VK_SUCCESS != err, "VulkanManager::swapBuffers(): Failed to get semaphore Fd");
+ } else {
+ ALOGE("VulkanManager::swapBuffers(): Semaphore submission failed");
+ mQueueWaitIdle(mGraphicsQueue);
}
- // set up layout transfer from initial to color attachment
- VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
- SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
- VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkAccessFlags srcAccessMask = 0;
- VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
- VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
+ surface->presentCurrentBuffer(dirtyRect, fenceFd);
- VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
- mPresentQueueIndex, // srcQueueFamilyIndex
- mGraphicsQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
- };
- mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
-
- VkCommandBufferBeginInfo info;
- memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
- info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- info.flags = 0;
- mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
-
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
- nullptr, 0, nullptr, 1, &imageMemoryBarrier);
-
- mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
-
- VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- // insert the layout transfer into the queue and wait on the acquire
- VkSubmitInfo submitInfo;
- memset(&submitInfo, 0, sizeof(VkSubmitInfo));
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 1;
- // Wait to make sure aquire semaphore set above has signaled.
- submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
- submitInfo.pWaitDstStageMask = &waitDstStageFlags;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
- submitInfo.signalSemaphoreCount = 0;
-
- // Attach first fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
-
- // We need to notify Skia that we changed the layout of the wrapped VkImage
- sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
- GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
- SkSurface::kFlushRead_BackendHandleAccess);
- if (!backendRT.isValid()) {
- SkASSERT(backendRT.isValid());
- return nullptr;
- }
- backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
-
- surface->mPreTransform = getPreTransformMatrix(surface->windowWidth(),
- surface->windowHeight(),
- surface->mTransform);
-
- surface->mBackbuffer = std::move(skSurface);
- return surface->mBackbuffer.get();
-}
-
-void VulkanManager::destroyBuffers(VulkanSurface* surface) {
- if (surface->mBackbuffers) {
- for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- mWaitForFences(mDevice, 2, surface->mBackbuffers[i].mUsageFences, true, UINT64_MAX);
- surface->mBackbuffers[i].mImageIndex = -1;
- mDestroySemaphore(mDevice, surface->mBackbuffers[i].mAcquireSemaphore, nullptr);
- mDestroySemaphore(mDevice, surface->mBackbuffers[i].mRenderSemaphore, nullptr);
- mFreeCommandBuffers(mDevice, mCommandPool, 2,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
- mDestroyFence(mDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
- }
- }
-
- delete[] surface->mBackbuffers;
- surface->mBackbuffers = nullptr;
- delete[] surface->mImageInfos;
- surface->mImageInfos = nullptr;
- delete[] surface->mImages;
- surface->mImages = nullptr;
+ // Exporting a semaphore with copy transference via vkGetSemaphoreFdKHR, has the same effect of
+ // destroying the semaphore and creating a new one with the same handle, and the payloads
+ // ownership is move to the Fd we created. Thus the semaphore is in a state that we can delete
+ // it and we don't need to wait on the command buffer we submitted to finish.
+ mDestroySemaphore(mDevice, semaphore, nullptr);
}
void VulkanManager::destroySurface(VulkanSurface* surface) {
@@ -630,271 +529,9 @@
}
mDeviceWaitIdle(mDevice);
- destroyBuffers(surface);
-
- if (VK_NULL_HANDLE != surface->mSwapchain) {
- mDestroySwapchainKHR(mDevice, surface->mSwapchain, nullptr);
- surface->mSwapchain = VK_NULL_HANDLE;
- }
-
- if (VK_NULL_HANDLE != surface->mVkSurface) {
- mDestroySurfaceKHR(mInstance, surface->mVkSurface, nullptr);
- surface->mVkSurface = VK_NULL_HANDLE;
- }
delete surface;
}
-void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
- mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, nullptr);
- SkASSERT(surface->mImageCount);
- surface->mImages = new VkImage[surface->mImageCount];
- mGetSwapchainImagesKHR(mDevice, surface->mSwapchain, &surface->mImageCount, surface->mImages);
-
- SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
-
- // set up initial image layouts and create surfaces
- surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
- for (uint32_t i = 0; i < surface->mImageCount; ++i) {
- GrVkImageInfo info;
- info.fImage = surface->mImages[i];
- info.fAlloc = GrVkAlloc();
- info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
- info.fFormat = format;
- info.fLevelCount = 1;
-
- GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
-
- VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
- imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
- surface->mGrContext, backendRT, kTopLeft_GrSurfaceOrigin,
- surface->mColorType, surface->mColorSpace, &props);
- }
-
- SkASSERT(mCommandPool != VK_NULL_HANDLE);
-
- // set up the backbuffers
- VkSemaphoreCreateInfo semaphoreInfo;
- memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
- semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
- semaphoreInfo.pNext = nullptr;
- semaphoreInfo.flags = 0;
- VkCommandBufferAllocateInfo commandBuffersInfo;
- memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
- commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
- commandBuffersInfo.pNext = nullptr;
- commandBuffersInfo.commandPool = mCommandPool;
- commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
- commandBuffersInfo.commandBufferCount = 2;
- VkFenceCreateInfo fenceInfo;
- memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
- fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
- fenceInfo.pNext = nullptr;
- fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
-
- // we create one additional backbuffer structure here, because we want to
- // give the command buffers they contain a chance to finish before we cycle back
- surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
- for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
- SkDEBUGCODE(VkResult res);
- surface->mBackbuffers[i].mImageIndex = -1;
- SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mAcquireSemaphore);
- SkDEBUGCODE(res =) mCreateSemaphore(mDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mRenderSemaphore);
- SkDEBUGCODE(res =) mAllocateCommandBuffers(mDevice, &commandBuffersInfo,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[0]);
- SkDEBUGCODE(res =) mCreateFence(mDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[1]);
- SkASSERT(VK_SUCCESS == res);
- }
- surface->mCurrentBackbufferIndex = surface->mImageCount;
-}
-
-bool VulkanManager::createSwapchain(VulkanSurface* surface) {
- // check for capabilities
- VkSurfaceCapabilitiesKHR caps;
- VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mPhysicalDevice,
- surface->mVkSurface, &caps);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- uint32_t surfaceFormatCount;
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
- res = mGetPhysicalDeviceSurfaceFormatsKHR(mPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, surfaceFormats.data());
- if (VK_SUCCESS != res) {
- return false;
- }
-
- uint32_t presentModeCount;
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
- surface->mVkSurface, &presentModeCount, nullptr);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
- res = mGetPhysicalDeviceSurfacePresentModesKHR(mPhysicalDevice,
- surface->mVkSurface, &presentModeCount,
- presentModes.data());
- if (VK_SUCCESS != res) {
- return false;
- }
-
- if (!SkToBool(caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR)) {
- return false;
- }
- VkSurfaceTransformFlagBitsKHR transform;
- if (SkToBool(caps.supportedTransforms & caps.currentTransform) &&
- !SkToBool(caps.currentTransform & VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR)) {
- transform = caps.currentTransform;
- } else {
- transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- }
-
- VkExtent2D extent = caps.currentExtent;
- // clamp width; to handle currentExtent of -1 and protect us from broken hints
- if (extent.width < caps.minImageExtent.width) {
- extent.width = caps.minImageExtent.width;
- }
- SkASSERT(extent.width <= caps.maxImageExtent.width);
- // clamp height
- if (extent.height < caps.minImageExtent.height) {
- extent.height = caps.minImageExtent.height;
- }
- SkASSERT(extent.height <= caps.maxImageExtent.height);
-
- VkExtent2D swapExtent = extent;
- if (transform == VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR ||
- transform == VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR) {
- swapExtent.width = extent.height;
- swapExtent.height = extent.width;
- }
-
- surface->mWindowWidth = extent.width;
- surface->mWindowHeight = extent.height;
-
- uint32_t imageCount = std::max<uint32_t>(3, caps.minImageCount);
- if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
- // Application must settle for fewer images than desired:
- imageCount = caps.maxImageCount;
- }
-
- // Currently Skia requires the images to be color attchments and support all transfer
- // operations.
- VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
- VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
- VK_IMAGE_USAGE_TRANSFER_DST_BIT;
- SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
-
- SkASSERT(caps.supportedCompositeAlpha &
- (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
- VkCompositeAlphaFlagBitsKHR composite_alpha =
- (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
- ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
- : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
-
- VkFormat surfaceFormat = VK_FORMAT_R8G8B8A8_UNORM;
- VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
- if (surface->mColorType == SkColorType::kRGBA_F16_SkColorType) {
- surfaceFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
- }
-
- if (surface->mColorMode == ColorMode::WideColorGamut) {
- skcms_Matrix3x3 surfaceGamut;
- LOG_ALWAYS_FATAL_IF(!surface->mColorSpace->toXYZD50(&surfaceGamut),
- "Could not get gamut matrix from color space");
- if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
- colorSpace = VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
- } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
- colorSpace = VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
- } else {
- LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
- }
- }
-
- bool foundSurfaceFormat = false;
- for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
- if (surfaceFormat == surfaceFormats[i].format
- && colorSpace == surfaceFormats[i].colorSpace) {
- foundSurfaceFormat = true;
- break;
- }
- }
-
- if (!foundSurfaceFormat) {
- return false;
- }
-
- // FIFO is always available and will match what we do on GL so just pick that here.
- VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
-
- VkSwapchainCreateInfoKHR swapchainCreateInfo;
- memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
- swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
- swapchainCreateInfo.surface = surface->mVkSurface;
- swapchainCreateInfo.minImageCount = imageCount;
- swapchainCreateInfo.imageFormat = surfaceFormat;
- swapchainCreateInfo.imageColorSpace = colorSpace;
- swapchainCreateInfo.imageExtent = swapExtent;
- swapchainCreateInfo.imageArrayLayers = 1;
- swapchainCreateInfo.imageUsage = usageFlags;
-
- uint32_t queueFamilies[] = {mGraphicsQueueIndex, mPresentQueueIndex};
- if (mGraphicsQueueIndex != mPresentQueueIndex) {
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
- swapchainCreateInfo.queueFamilyIndexCount = 2;
- swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
- } else {
- swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
- swapchainCreateInfo.queueFamilyIndexCount = 0;
- swapchainCreateInfo.pQueueFamilyIndices = nullptr;
- }
-
- swapchainCreateInfo.preTransform = transform;
- swapchainCreateInfo.compositeAlpha = composite_alpha;
- swapchainCreateInfo.presentMode = mode;
- swapchainCreateInfo.clipped = true;
- swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
-
- res = mCreateSwapchainKHR(mDevice, &swapchainCreateInfo, nullptr, &surface->mSwapchain);
- if (VK_SUCCESS != res) {
- return false;
- }
-
- surface->mTransform = transform;
-
- // destroy the old swapchain
- if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
- mDeviceWaitIdle(mDevice);
-
- destroyBuffers(surface);
-
- mDestroySwapchainKHR(mDevice, swapchainCreateInfo.oldSwapchain, nullptr);
- }
-
- createBuffers(surface, surfaceFormat, swapExtent);
-
- // The window content is not updated (frozen) until a buffer of the window size is received.
- // This prevents temporary stretching of the window after it is resized, but before the first
- // buffer with new size is enqueued.
- native_window_set_scaling_mode(surface->mNativeWindow, NATIVE_WINDOW_SCALING_MODE_FREEZE);
-
- return true;
-}
-
VulkanSurface* VulkanManager::createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
SkColorType surfaceColorType,
@@ -904,185 +541,8 @@
return nullptr;
}
- VulkanSurface* surface = new VulkanSurface(colorMode, window, surfaceColorSpace,
- surfaceColorType, grContext);
-
- VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
- memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
- surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
- surfaceCreateInfo.pNext = nullptr;
- surfaceCreateInfo.flags = 0;
- surfaceCreateInfo.window = window;
-
- VkResult res = mCreateAndroidSurfaceKHR(mInstance, &surfaceCreateInfo, nullptr,
- &surface->mVkSurface);
- if (VK_SUCCESS != res) {
- delete surface;
- return nullptr;
- }
-
- SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
- mPhysicalDevice, mPresentQueueIndex, surface->mVkSurface, &supported);
- // All physical devices and queue families on Android must be capable of
- // presentation with any native window.
- SkASSERT(VK_SUCCESS == res && supported););
-
- if (!createSwapchain(surface)) {
- destroySurface(surface);
- return nullptr;
- }
-
- return surface;
-}
-
-// Helper to know which src stage flags we need to set when transitioning to the present layout
-static VkPipelineStageFlags layoutToPipelineSrcStageFlags(const VkImageLayout layout) {
- if (VK_IMAGE_LAYOUT_GENERAL == layout) {
- return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
- VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_TRANSFER_BIT;
- } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
- VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
- } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- return VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
- } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
- return VK_PIPELINE_STAGE_HOST_BIT;
- }
-
- SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
- return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
-}
-
-// Helper to know which src access mask we need to set when transitioning to the present layout
-static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
- VkAccessFlags flags = 0;
- if (VK_IMAGE_LAYOUT_GENERAL == layout) {
- flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
- VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
- VK_ACCESS_HOST_READ_BIT;
- } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
- flags = VK_ACCESS_HOST_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
- flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
- flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
- flags = VK_ACCESS_TRANSFER_WRITE_BIT;
- } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
- flags = VK_ACCESS_TRANSFER_READ_BIT;
- } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
- flags = VK_ACCESS_SHADER_READ_BIT;
- }
- return flags;
-}
-
-void VulkanManager::swapBuffers(VulkanSurface* surface) {
- if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
- ATRACE_NAME("Finishing GPU work");
- mDeviceWaitIdle(mDevice);
- }
-
- SkASSERT(surface->mBackbuffers);
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
-
- SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
- GrBackendRenderTarget backendRT = skSurface->getBackendRenderTarget(
- SkSurface::kFlushRead_BackendHandleAccess);
- SkASSERT(backendRT.isValid());
-
- GrVkImageInfo imageInfo;
- SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
-
- // Check to make sure we never change the actually wrapped image
- SkASSERT(imageInfo.fImage == surface->mImages[backbuffer->mImageIndex]);
-
- // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
- // previous work is complete for before presenting. So we first add the necessary barrier here.
- VkImageLayout layout = imageInfo.fImageLayout;
- VkPipelineStageFlags srcStageMask = layoutToPipelineSrcStageFlags(layout);
- VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
- VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
- VkAccessFlags dstAccessMask = 0;
-
- VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
- mGraphicsQueueIndex, // srcQueueFamilyIndex
- mPresentQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
- };
-
- mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
- VkCommandBufferBeginInfo info;
- memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
- info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
- info.flags = 0;
- mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
- nullptr, 0, nullptr, 1, &imageMemoryBarrier);
- mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
-
- surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
-
- // insert the layout transfer into the queue and wait on the acquire
- VkSubmitInfo submitInfo;
- memset(&submitInfo, 0, sizeof(VkSubmitInfo));
- submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
- submitInfo.waitSemaphoreCount = 0;
- submitInfo.pWaitDstStageMask = 0;
- submitInfo.commandBufferCount = 1;
- submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
- submitInfo.signalSemaphoreCount = 1;
- // When this command buffer finishes we will signal this semaphore so that we know it is now
- // safe to present the image to the screen.
- submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
-
- // Attach second fence to submission here so we can track when the command buffer finishes.
- mQueueSubmit(mGraphicsQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
-
- // Submit present operation to present queue. We use a semaphore here to make sure all rendering
- // to the image is complete and that the layout has been change to present on the graphics
- // queue.
- const VkPresentInfoKHR presentInfo = {
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
- NULL, // pNext
- 1, // waitSemaphoreCount
- &backbuffer->mRenderSemaphore, // pWaitSemaphores
- 1, // swapchainCount
- &surface->mSwapchain, // pSwapchains
- &backbuffer->mImageIndex, // pImageIndices
- NULL // pResults
- };
-
- mQueuePresentKHR(mPresentQueue, &presentInfo);
-
- surface->mBackbuffer.reset();
- surface->mImageInfos[backbuffer->mImageIndex].mLastUsed = surface->mCurrentTime;
- surface->mImageInfos[backbuffer->mImageIndex].mInvalid = false;
- surface->mCurrentTime++;
-}
-
-int VulkanManager::getAge(VulkanSurface* surface) {
- SkASSERT(surface->mBackbuffers);
- VulkanSurface::BackbufferInfo* backbuffer =
- surface->mBackbuffers + surface->mCurrentBackbufferIndex;
- if (mSwapBehavior == SwapBehavior::Discard ||
- surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
- return 0;
- }
- uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
- return surface->mCurrentTime - lastUsed;
+ return VulkanSurface::Create(window, colorMode, surfaceColorType, surfaceColorSpace, grContext,
+ *this);
}
bool VulkanManager::setupDummyCommandBuffer() {
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index 95c9630..c3d2891 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -28,7 +28,9 @@
#include <ui/Fence.h>
#include <utils/StrongPointer.h>
#include <vk/GrVkBackendContext.h>
+#include "Frame.h"
#include "IRenderPipeline.h"
+#include "VulkanSurface.h"
class GrVkExtensions;
@@ -38,66 +40,6 @@
class RenderThread;
-class VulkanSurface {
-public:
- VulkanSurface(ColorMode colorMode, ANativeWindow* window, sk_sp<SkColorSpace> colorSpace,
- SkColorType colorType, GrContext* grContext)
- : mColorMode(colorMode), mNativeWindow(window), mColorSpace(colorSpace),
- mColorType(colorType), mGrContext(grContext) {}
-
- sk_sp<SkSurface> getBackBufferSurface() { return mBackbuffer; }
-
- // The width and height are are the logical width and height for when submitting draws to the
- // surface. In reality if the window is rotated the underlying VkImage may have the width and
- // height swapped.
- int windowWidth() const { return mWindowWidth; }
- int windowHeight() const { return mWindowHeight; }
-
- SkMatrix& preTransform() { return mPreTransform; }
-
-private:
- friend class VulkanManager;
- struct BackbufferInfo {
- uint32_t mImageIndex; // image this is associated with
- VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
- VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
- VkCommandBuffer
- mTransitionCmdBuffers[2]; // to transition layout between present and render
- // We use these fences to make sure the above Command buffers have finished their work
- // before attempting to reuse them or destroy them.
- VkFence mUsageFences[2];
- };
-
- struct ImageInfo {
- VkImageLayout mImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- sk_sp<SkSurface> mSurface;
- uint16_t mLastUsed = 0;
- bool mInvalid = true;
- };
-
- sk_sp<SkSurface> mBackbuffer;
-
- VkSurfaceKHR mVkSurface = VK_NULL_HANDLE;
- VkSwapchainKHR mSwapchain = VK_NULL_HANDLE;
-
- BackbufferInfo* mBackbuffers = nullptr;
- uint32_t mCurrentBackbufferIndex;
-
- uint32_t mImageCount;
- VkImage* mImages = nullptr;
- ImageInfo* mImageInfos;
- uint16_t mCurrentTime = 0;
- ColorMode mColorMode;
- ANativeWindow* mNativeWindow;
- int mWindowWidth = 0;
- int mWindowHeight = 0;
- sk_sp<SkColorSpace> mColorSpace;
- SkColorType mColorType;
- VkSurfaceTransformFlagBitsKHR mTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
- SkMatrix mPreTransform;
- GrContext* mGrContext;
-};
-
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
// which are re-used by CanvasContext. This class is created once and should be used by all vulkan
// windowing contexts. The VulkanManager must be initialized before use.
@@ -114,33 +56,19 @@
// Quick check to see if the VulkanManager has been initialized.
bool hasVkContext() { return mDevice != VK_NULL_HANDLE; }
- // Given a window this creates a new VkSurfaceKHR and VkSwapchain and stores them inside a new
- // VulkanSurface object which is returned.
+ // Create and destroy functions for wrapping an ANativeWindow in a VulkanSurface
VulkanSurface* createSurface(ANativeWindow* window, ColorMode colorMode,
sk_sp<SkColorSpace> surfaceColorSpace,
SkColorType surfaceColorType,
GrContext* grContext);
-
- // Destroy the VulkanSurface and all associated vulkan objects.
void destroySurface(VulkanSurface* surface);
+ Frame dequeueNextBuffer(VulkanSurface* surface);
+ void swapBuffers(VulkanSurface* surface, const SkRect& dirtyRect);
+
// Cleans up all the global state in the VulkanManger.
void destroy();
- // No work is needed to make a VulkanSurface current, and all functions require that a
- // VulkanSurface is passed into them so we just return true here.
- bool isCurrent(VulkanSurface* surface) { return true; }
-
- int getAge(VulkanSurface* surface);
-
- // Returns an SkSurface which wraps the next image returned from vkAcquireNextImageKHR. It also
- // will transition the VkImage from a present layout to color attachment so that it can be used
- // by the client for drawing.
- SkSurface* getBackbufferSurface(VulkanSurface** surface);
-
- // Presents the current VkImage.
- void swapBuffers(VulkanSurface* surface);
-
// Inserts a wait on fence command into the Vulkan command buffer.
status_t fenceWait(sp<Fence>& fence);
@@ -153,17 +81,10 @@
sk_sp<GrContext> createContext(const GrContextOptions& options);
private:
+ friend class VulkanSurface;
// Sets up the VkInstance and VkDevice objects. Also fills out the passed in
// VkPhysicalDeviceFeatures struct.
void setupDevice(GrVkExtensions&, VkPhysicalDeviceFeatures2&);
-
- void destroyBuffers(VulkanSurface* surface);
-
- bool createSwapchain(VulkanSurface* surface);
- void createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent);
-
- VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
-
bool setupDummyCommandBuffer();
// simple wrapper class that exists only to initialize a pointer to NULL
@@ -190,13 +111,6 @@
VkPtr<PFN_vkGetPhysicalDeviceSurfaceFormatsKHR> mGetPhysicalDeviceSurfaceFormatsKHR;
VkPtr<PFN_vkGetPhysicalDeviceSurfacePresentModesKHR> mGetPhysicalDeviceSurfacePresentModesKHR;
- VkPtr<PFN_vkCreateSwapchainKHR> mCreateSwapchainKHR;
- VkPtr<PFN_vkDestroySwapchainKHR> mDestroySwapchainKHR;
- VkPtr<PFN_vkGetSwapchainImagesKHR> mGetSwapchainImagesKHR;
- VkPtr<PFN_vkAcquireNextImageKHR> mAcquireNextImageKHR;
- VkPtr<PFN_vkQueuePresentKHR> mQueuePresentKHR;
- VkPtr<PFN_vkCreateSharedSwapchainsKHR> mCreateSharedSwapchainsKHR;
-
// Instance Functions
VkPtr<PFN_vkEnumerateInstanceVersion> mEnumerateInstanceVersion;
VkPtr<PFN_vkEnumerateInstanceExtensionProperties> mEnumerateInstanceExtensionProperties;
@@ -207,6 +121,7 @@
VkPtr<PFN_vkGetPhysicalDeviceProperties> mGetPhysicalDeviceProperties;
VkPtr<PFN_vkGetPhysicalDeviceQueueFamilyProperties> mGetPhysicalDeviceQueueFamilyProperties;
VkPtr<PFN_vkGetPhysicalDeviceFeatures2> mGetPhysicalDeviceFeatures2;
+ VkPtr<PFN_vkGetPhysicalDeviceImageFormatProperties2> mGetPhysicalDeviceImageFormatProperties2;
VkPtr<PFN_vkCreateDevice> mCreateDevice;
VkPtr<PFN_vkEnumerateDeviceExtensionProperties> mEnumerateDeviceExtensionProperties;
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
new file mode 100644
index 0000000..c03c3a8
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -0,0 +1,536 @@
+/*
+ * 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 "VulkanSurface.h"
+
+#include <algorithm>
+#include <SkSurface.h>
+
+#include "VulkanManager.h"
+#include "utils/TraceUtils.h"
+#include "utils/Color.h"
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+static bool IsTransformSupported(int transform) {
+ // For now, only support pure rotations, not flip or flip-and-rotate, until we have
+ // more time to test them and build sample code. As far as I know we never actually
+ // use anything besides pure rotations anyway.
+ return transform == 0
+ || transform == NATIVE_WINDOW_TRANSFORM_ROT_90
+ || transform == NATIVE_WINDOW_TRANSFORM_ROT_180
+ || transform == NATIVE_WINDOW_TRANSFORM_ROT_270;
+}
+
+static int InvertTransform(int transform) {
+ switch (transform) {
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
+ return NATIVE_WINDOW_TRANSFORM_ROT_270;
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
+ return NATIVE_WINDOW_TRANSFORM_ROT_180;
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
+ return NATIVE_WINDOW_TRANSFORM_ROT_90;
+ default:
+ return 0;
+ }
+}
+
+static int ConvertVkTransformToNative(VkSurfaceTransformFlagsKHR transform) {
+ switch (transform) {
+ case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
+ return NATIVE_WINDOW_TRANSFORM_ROT_270;
+ 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_90;
+ case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
+ case VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR:
+ default:
+ return 0;
+ }
+}
+
+static SkMatrix GetPreTransformMatrix(SkISize windowSize, int transform) {
+ const int width = windowSize.width();
+ const int height = windowSize.height();
+
+ switch (transform) {
+ case 0:
+ return SkMatrix::I();
+ case NATIVE_WINDOW_TRANSFORM_ROT_90:
+ return SkMatrix::MakeAll(0, -1, height, 1, 0, 0, 0, 0, 1);
+ case NATIVE_WINDOW_TRANSFORM_ROT_180:
+ return SkMatrix::MakeAll(-1, 0, width, 0, -1, height, 0, 0, 1);
+ case NATIVE_WINDOW_TRANSFORM_ROT_270:
+ return SkMatrix::MakeAll(0, 1, 0, -1, 0, width, 0, 0, 1);
+ default:
+ LOG_ALWAYS_FATAL("Unsupported Window Transform (%d)", transform);
+ }
+ return SkMatrix::I();
+}
+
+void VulkanSurface::ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
+ const SkISize& maxSize) {
+ SkISize& windowSize = windowInfo->size;
+
+ // clamp width & height to handle currentExtent of -1 and protect us from broken hints
+ if (windowSize.width() < minSize.width() || windowSize.width() > maxSize.width()
+ || windowSize.height() < minSize.height() || windowSize.height() > maxSize.height()) {
+ int width = std::min(maxSize.width(), std::max(minSize.width(), windowSize.width()));
+ int height = std::min(maxSize.height(), std::max(minSize.height(), windowSize.height()));
+ ALOGE("Invalid Window Dimensions [%d, %d]; clamping to [%d, %d]",
+ windowSize.width(), windowSize.height(), width, height);
+ windowSize.set(width, height);
+ }
+
+ windowInfo->actualSize = windowSize;
+ if (windowInfo->transform & HAL_TRANSFORM_ROT_90) {
+ windowInfo->actualSize.set(windowSize.height(), windowSize.width());
+ }
+
+ windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
+}
+
+static bool ResetNativeWindow(ANativeWindow* window) {
+ // -- Reset the native window --
+ // The native window might have been used previously, and had its properties
+ // changed from defaults. That will affect the answer we get for queries
+ // like MIN_UNDEQUEUED_BUFFERS. Reset to a known/default state before we
+ // attempt such queries.
+
+ int err = native_window_api_connect(window, NATIVE_WINDOW_API_EGL);
+ if (err != 0) {
+ ALOGW("native_window_api_connect failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ // this will match what we do on GL so pick that here.
+ err = window->setSwapInterval(window, 1);
+ if (err != 0) {
+ ALOGW("native_window->setSwapInterval(1) failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_shared_buffer_mode(window, false);
+ if (err != 0) {
+ ALOGW("native_window_set_shared_buffer_mode(false) failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_auto_refresh(window, false);
+ if (err != 0) {
+ ALOGW("native_window_set_auto_refresh(false) failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ return true;
+}
+
+class VkSurfaceAutoDeleter {
+public:
+ VkSurfaceAutoDeleter(VkInstance instance, VkSurfaceKHR surface,
+ PFN_vkDestroySurfaceKHR destroySurfaceKHR)
+ : mInstance(instance)
+ , mSurface(surface)
+ , mDestroySurfaceKHR(destroySurfaceKHR) {}
+ ~VkSurfaceAutoDeleter() {
+ destroy();
+ }
+
+ void destroy() {
+ if (mSurface != VK_NULL_HANDLE) {
+ mDestroySurfaceKHR(mInstance, mSurface, nullptr);
+ mSurface = VK_NULL_HANDLE;
+ }
+ }
+
+private:
+ VkInstance mInstance;
+ VkSurfaceKHR mSurface;
+ PFN_vkDestroySurfaceKHR mDestroySurfaceKHR;
+};
+
+VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
+ SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
+ GrContext* grContext, const VulkanManager& vkManager) {
+
+ VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
+ memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
+ surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
+ surfaceCreateInfo.pNext = nullptr;
+ surfaceCreateInfo.flags = 0;
+ surfaceCreateInfo.window = window;
+
+ VkSurfaceKHR vkSurface = VK_NULL_HANDLE;
+ VkResult res = vkManager.mCreateAndroidSurfaceKHR(vkManager.mInstance, &surfaceCreateInfo,
+ nullptr, &vkSurface);
+ if (VK_SUCCESS != res) {
+ ALOGE("VulkanSurface::Create() vkCreateAndroidSurfaceKHR failed (%d)", res);
+ return nullptr;
+ }
+
+ VkSurfaceAutoDeleter vkSurfaceDeleter(vkManager.mInstance, vkSurface,
+ vkManager.mDestroySurfaceKHR);
+
+ SkDEBUGCODE(VkBool32 supported; res = vkManager.mGetPhysicalDeviceSurfaceSupportKHR(
+ vkManager.mPhysicalDevice, vkManager.mPresentQueueIndex, vkSurface, &supported);
+ // All physical devices and queue families on Android must be capable of
+ // presentation with any native window.
+ SkASSERT(VK_SUCCESS == res && supported););
+
+ // check for capabilities
+ VkSurfaceCapabilitiesKHR caps;
+ res = vkManager.mGetPhysicalDeviceSurfaceCapabilitiesKHR(vkManager.mPhysicalDevice, vkSurface,
+ &caps);
+ if (VK_SUCCESS != res) {
+ ALOGE("VulkanSurface::Create() vkGetPhysicalDeviceSurfaceCapabilitiesKHR failed (%d)", res);
+ return nullptr;
+ }
+
+ LOG_ALWAYS_FATAL_IF(0 == (caps.supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR));
+
+ /*
+ * We must destroy the VK Surface before attempting to update the window as doing so after
+ * will cause the native window to be modified in unexpected ways.
+ */
+ vkSurfaceDeleter.destroy();
+
+ /*
+ * Populate Window Info struct
+ */
+ WindowInfo windowInfo;
+
+ windowInfo.transform = ConvertVkTransformToNative(caps.supportedTransforms);
+ windowInfo.size = SkISize::Make(caps.currentExtent.width, caps.currentExtent.height);
+
+ const SkISize minSize = SkISize::Make(caps.minImageExtent.width, caps.minImageExtent.height);
+ const SkISize maxSize = SkISize::Make(caps.maxImageExtent.width, caps.maxImageExtent.height);
+ ComputeWindowSizeAndTransform(&windowInfo, minSize, maxSize);
+
+ windowInfo.bufferCount = std::max<uint32_t>(VulkanSurface::sMaxBufferCount, caps.minImageCount);
+ if (caps.maxImageCount > 0 && windowInfo.bufferCount > caps.maxImageCount) {
+ // Application must settle for fewer images than desired:
+ windowInfo.bufferCount = caps.maxImageCount;
+ }
+
+ // Currently Skia requires the images to be color attachments and support all transfer
+ // operations.
+ VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
+ VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT;
+ LOG_ALWAYS_FATAL_IF((caps.supportedUsageFlags & usageFlags) != usageFlags);
+
+ windowInfo.dataspace = HAL_DATASPACE_V0_SRGB;
+ if (colorMode == ColorMode::WideColorGamut) {
+ skcms_Matrix3x3 surfaceGamut;
+ LOG_ALWAYS_FATAL_IF(!colorSpace->toXYZD50(&surfaceGamut),
+ "Could not get gamut matrix from color space");
+ if (memcmp(&surfaceGamut, &SkNamedGamut::kSRGB, sizeof(surfaceGamut)) == 0) {
+ windowInfo.dataspace = HAL_DATASPACE_V0_SCRGB;
+ } else if (memcmp(&surfaceGamut, &SkNamedGamut::kDCIP3, sizeof(surfaceGamut)) == 0) {
+ windowInfo.dataspace = HAL_DATASPACE_DISPLAY_P3;
+ } else {
+ LOG_ALWAYS_FATAL("Unreachable: unsupported wide color space.");
+ }
+ }
+
+ windowInfo.pixelFormat = ColorTypeToPixelFormat(colorType);
+ VkFormat vkPixelFormat = VK_FORMAT_R8G8B8A8_UNORM;
+ if (windowInfo.pixelFormat == PIXEL_FORMAT_RGBA_FP16) {
+ vkPixelFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
+ }
+
+ uint64_t producerUsage =
+ AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER | AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE;
+ uint64_t consumerUsage;
+ native_window_get_consumer_usage(window, &consumerUsage);
+ windowInfo.windowUsageFlags = consumerUsage | producerUsage;
+
+ /*
+ * Now we attempt to modify the window!
+ */
+ if (!UpdateWindow(window, windowInfo)) {
+ return nullptr;
+ }
+
+ return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
+}
+
+bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo) {
+ ATRACE_CALL();
+
+ if (!ResetNativeWindow(window)) {
+ return false;
+ }
+
+ // -- Configure the native window --
+ int err = native_window_set_buffers_format(window, windowInfo.pixelFormat);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_format(%d) failed: %s (%d)",
+ windowInfo.pixelFormat, strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_buffers_data_space(window, windowInfo.dataspace);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_data_space(%d) "
+ "failed: %s (%d)", windowInfo.dataspace, strerror(-err), err);
+ return false;
+ }
+
+ const SkISize& size = windowInfo.actualSize;
+ err = native_window_set_buffers_dimensions(window, size.width(), size.height());
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_dimensions(%d,%d) "
+ "failed: %s (%d)", size.width(), size.height(), strerror(-err), err);
+ return false;
+ }
+
+ // native_window_set_buffers_transform() expects the transform the app is requesting that
+ // the compositor perform during composition. With native windows, pre-transform works by
+ // rendering with the same transform the compositor is applying (as in Vulkan), but
+ // then requesting the inverse transform, so that when the compositor does
+ // it's job the two transforms cancel each other out and the compositor ends
+ // up applying an identity transform to the app's buffer.
+ err = native_window_set_buffers_transform(window, InvertTransform(windowInfo.transform));
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffers_transform(%d) "
+ "failed: %s (%d)", windowInfo.transform, strerror(-err), err);
+ return false;
+ }
+
+ // Vulkan defaults to NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW, but this is different than
+ // HWUI's expectation
+ err = native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_FREEZE);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_scaling_mode(SCALE_TO_WINDOW) "
+ "failed: %s (%d)", strerror(-err), err);
+ return false;
+ }
+
+ // Lower layer insists that we have at least two buffers.
+ err = native_window_set_buffer_count(window, std::max(2, windowInfo.bufferCount));
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_buffer_count(%d) failed: %s (%d)",
+ windowInfo.bufferCount, strerror(-err), err);
+ return false;
+ }
+
+ err = native_window_set_usage(window, windowInfo.windowUsageFlags);
+ if (err != 0) {
+ ALOGE("VulkanSurface::UpdateWindow() native_window_set_usage failed: %s (%d)",
+ strerror(-err), err);
+ return false;
+ }
+
+ return err == 0;
+}
+
+VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
+ SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
+ : mNativeWindow(window)
+ , mWindowInfo(windowInfo)
+ , mGrContext(grContext)
+ , mMinWindowSize(minWindowSize)
+ , mMaxWindowSize(maxWindowSize) { }
+
+VulkanSurface::~VulkanSurface() {
+ releaseBuffers();
+
+ // release the native window to be available for use by other clients
+ int err = native_window_api_disconnect(mNativeWindow.get(), NATIVE_WINDOW_API_EGL);
+ ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)", strerror(-err), err);
+}
+
+void VulkanSurface::releaseBuffers() {
+ for (uint32_t i = 0; i < VulkanSurface::sMaxBufferCount; i++) {
+ VulkanSurface::NativeBufferInfo& bufferInfo = mNativeBuffers[i];
+
+ if (bufferInfo.buffer.get() != nullptr && bufferInfo.dequeued) {
+ int err = mNativeWindow->cancelBuffer(mNativeWindow.get(), bufferInfo.buffer.get(),
+ bufferInfo.dequeue_fence);
+ if (err != 0) {
+ ALOGE("cancelBuffer[%u] failed during destroy: %s (%d)", i, strerror(-err), err);
+ }
+ bufferInfo.dequeued = false;
+
+ if (bufferInfo.dequeue_fence >= 0) {
+ close(bufferInfo.dequeue_fence);
+ bufferInfo.dequeue_fence = -1;
+ }
+ }
+
+ LOG_ALWAYS_FATAL_IF(bufferInfo.dequeued);
+ LOG_ALWAYS_FATAL_IF(bufferInfo.dequeue_fence != -1);
+
+ bufferInfo.skSurface.reset();
+ bufferInfo.buffer.clear();
+ bufferInfo.hasValidContents = false;
+ bufferInfo.lastPresentedCount = 0;
+ }
+}
+
+VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
+ // Set the dequeue index to invalid in case of error and only reset it to the correct
+ // value at the end of the function if everything dequeued correctly.
+ mDequeuedIndex = -1;
+
+ //check if the native window has been resized or rotated and update accordingly
+ SkISize newSize = SkISize::MakeEmpty();
+ int transformHint = 0;
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &newSize.fWidth);
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &newSize.fHeight);
+ mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
+ if (newSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
+ WindowInfo newWindowInfo = mWindowInfo;
+ newWindowInfo.size = newSize;
+ newWindowInfo.transform = IsTransformSupported(transformHint) ? transformHint : 0;
+ ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
+
+ int err = 0;
+ if (newWindowInfo.actualSize != mWindowInfo.actualSize) {
+ // reset the native buffers and update the window
+ err = native_window_set_buffers_dimensions(mNativeWindow.get(),
+ newWindowInfo.actualSize.width(),
+ newWindowInfo.actualSize.height());
+ if (err != 0) {
+ ALOGE("native_window_set_buffers_dimensions(%d,%d) failed: %s (%d)",
+ newWindowInfo.actualSize.width(),
+ newWindowInfo.actualSize.height(), strerror(-err), err);
+ return nullptr;
+ }
+ // reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
+ // new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
+ releaseBuffers();
+ // TODO should we ask the nativewindow to allocate buffers?
+ }
+
+ if (newWindowInfo.transform != mWindowInfo.transform) {
+ err = native_window_set_buffers_transform(mNativeWindow.get(),
+ InvertTransform(newWindowInfo.transform));
+ if (err != 0) {
+ ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)",
+ newWindowInfo.transform, strerror(-err), err);
+ newWindowInfo.transform = mWindowInfo.transform;
+ ComputeWindowSizeAndTransform(&newWindowInfo, mMinWindowSize, mMaxWindowSize);
+ }
+ }
+
+ mWindowInfo = newWindowInfo;
+ }
+
+ ANativeWindowBuffer* buffer;
+ int fence_fd;
+ int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
+ if (err != 0) {
+ ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
+ return nullptr;
+ }
+
+ uint32_t idx;
+ for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
+ if (mNativeBuffers[idx].buffer.get() == buffer) {
+ mNativeBuffers[idx].dequeued = true;
+ mNativeBuffers[idx].dequeue_fence = fence_fd;
+ break;
+ } else if (mNativeBuffers[idx].buffer.get() == nullptr) {
+ // increasing the number of buffers we have allocated
+ mNativeBuffers[idx].buffer = buffer;
+ mNativeBuffers[idx].dequeued = true;
+ mNativeBuffers[idx].dequeue_fence = fence_fd;
+ break;
+ }
+ }
+ if (idx == mWindowInfo.bufferCount) {
+ ALOGE("dequeueBuffer returned unrecognized buffer");
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
+ return nullptr;
+ }
+
+ VulkanSurface::NativeBufferInfo* bufferInfo = &mNativeBuffers[idx];
+
+ if (bufferInfo->skSurface.get() == nullptr) {
+ bufferInfo->skSurface =
+ SkSurface::MakeFromAHardwareBuffer(mGrContext,
+ ANativeWindowBuffer_getHardwareBuffer(bufferInfo->buffer.get()),
+ kTopLeft_GrSurfaceOrigin, DataSpaceToColorSpace(mWindowInfo.dataspace),
+ nullptr);
+ if (bufferInfo->skSurface.get() == nullptr) {
+ ALOGE("SkSurface::MakeFromAHardwareBuffer failed");
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
+ return nullptr;
+ }
+ }
+
+ mDequeuedIndex = idx;
+ return bufferInfo;
+}
+
+bool VulkanSurface::presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd) {
+ if (!dirtyRect.isEmpty()) {
+ SkRect transformedRect;
+ mWindowInfo.preTransform.mapRect(&transformedRect, dirtyRect);
+
+ SkIRect transformedIRect;
+ transformedRect.roundOut(&transformedIRect);
+ transformedIRect.intersect(0, 0, mWindowInfo.size.fWidth, mWindowInfo.size.fHeight);
+
+ // map to bottom-left coordinate system
+ android_native_rect_t aRect;
+ aRect.left = transformedIRect.x();
+ aRect.top = mWindowInfo.size.fHeight - (transformedIRect.y() + transformedIRect.height());
+ aRect.right = aRect.left + transformedIRect.width();
+ aRect.bottom = aRect.top - transformedIRect.height();
+
+ int err = native_window_set_surface_damage(mNativeWindow.get(), &aRect, 1);
+ ALOGE_IF(err != 0, "native_window_set_surface_damage failed: %s (%d)", strerror(-err), err);
+ }
+
+ VulkanSurface::NativeBufferInfo& currentBuffer = mNativeBuffers[mDequeuedIndex];
+ int queuedFd = (semaphoreFd != -1) ? semaphoreFd : currentBuffer.dequeue_fence;
+ int err = mNativeWindow->queueBuffer(mNativeWindow.get(), currentBuffer.buffer.get(), queuedFd);
+
+ currentBuffer.dequeued = false;
+ // queueBuffer always closes fence, even on error
+ if (err != 0) {
+ ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), currentBuffer.buffer.get(),
+ currentBuffer.dequeue_fence);
+ } else {
+ currentBuffer.hasValidContents = true;
+ currentBuffer.lastPresentedCount = mPresentCount;
+ mPresentCount++;
+ }
+
+ if (currentBuffer.dequeue_fence >= 0) {
+ close(currentBuffer.dequeue_fence);
+ currentBuffer.dequeue_fence = -1;
+ }
+
+ return err == 0;
+}
+
+int VulkanSurface::getCurrentBuffersAge() {
+ VulkanSurface::NativeBufferInfo& currentBuffer = mNativeBuffers[mDequeuedIndex];
+ return currentBuffer.hasValidContents ? (mPresentCount - currentBuffer.lastPresentedCount) : 0;
+}
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/VulkanSurface.h b/libs/hwui/renderthread/VulkanSurface.h
new file mode 100644
index 0000000..4fd9cd2
--- /dev/null
+++ b/libs/hwui/renderthread/VulkanSurface.h
@@ -0,0 +1,127 @@
+/*
+ * 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 <system/graphics.h>
+#include <system/window.h>
+#include <vulkan/vulkan.h>
+
+#include <SkSize.h>
+#include <SkRefCnt.h>
+
+#include "IRenderPipeline.h"
+
+class SkSurface;
+
+namespace android {
+namespace uirenderer {
+namespace renderthread {
+
+class VulkanManager;
+
+class VulkanSurface {
+public:
+ static VulkanSurface* Create(ANativeWindow* window,
+ ColorMode colorMode,
+ SkColorType colorType,
+ sk_sp<SkColorSpace> colorSpace,
+ GrContext* grContext,
+ const VulkanManager& vkManager);
+ ~VulkanSurface();
+
+ sk_sp<SkSurface> getCurrentSkSurface() { return mNativeBuffers[mDequeuedIndex].skSurface; }
+ const SkMatrix& getCurrentPreTransform() { return mWindowInfo.preTransform; }
+
+private:
+ /*
+ * All structs/methods in this private section are specifically for use by the VulkanManager
+ *
+ */
+ friend VulkanManager;
+ struct NativeBufferInfo {
+ sk_sp<SkSurface> skSurface;
+ sp<ANativeWindowBuffer> buffer;
+ // The fence is only valid when the buffer is dequeued, and should be
+ // -1 any other time. When valid, we own the fd, and must ensure it is
+ // closed: either by closing it explicitly when queueing the buffer,
+ // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
+ int dequeue_fence = -1;
+ bool dequeued = false;
+ uint32_t lastPresentedCount = 0;
+ bool hasValidContents = false;
+ };
+
+ NativeBufferInfo* dequeueNativeBuffer();
+ NativeBufferInfo* getCurrentBufferInfo() { return &mNativeBuffers[mDequeuedIndex]; }
+ bool presentCurrentBuffer(const SkRect& dirtyRect, int semaphoreFd);
+
+ // The width and height are are the logical width and height for when submitting draws to the
+ // surface. In reality if the window is rotated the underlying window may have the width and
+ // height swapped.
+ int logicalWidth() const { return mWindowInfo.size.width(); }
+ int logicalHeight() const { return mWindowInfo.size.height(); }
+ int getCurrentBuffersAge();
+
+private:
+ /*
+ * All code below this line while logically available to VulkanManager should not be treated
+ * as private to this class.
+ *
+ */
+ static constexpr int sMaxBufferCount = 3;
+
+ struct WindowInfo {
+ SkISize size;
+ PixelFormat pixelFormat;
+ android_dataspace dataspace;
+ int transform;
+ int bufferCount;
+ uint64_t windowUsageFlags;
+
+ // size of the ANativeWindow if the inverse of transform requires us to swap width/height
+ SkISize actualSize;
+ // transform to be applied to the SkSurface to map the coordinates to the provided transform
+ SkMatrix preTransform;
+ };
+
+ VulkanSurface(ANativeWindow* window,
+ const WindowInfo& windowInfo,
+ SkISize minWindowSize,
+ SkISize maxWindowSize,
+ GrContext* grContext);
+ static bool UpdateWindow(ANativeWindow* window,
+ const WindowInfo& windowInfo);
+ static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo,
+ const SkISize& minSize,
+ const SkISize& maxSize);
+ void releaseBuffers();
+
+ NativeBufferInfo mNativeBuffers[VulkanSurface::sMaxBufferCount];
+
+ sp<ANativeWindow> mNativeWindow;
+ WindowInfo mWindowInfo;
+ GrContext* mGrContext;
+
+ int mDequeuedIndex = -1;
+ uint32_t mPresentCount = 0;
+
+ const SkISize mMinWindowSize;
+ const SkISize mMaxWindowSize;
+};
+
+} /* namespace renderthread */
+} /* namespace uirenderer */
+} /* namespace android */
\ No newline at end of file
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index f0a7eaa..4cd8971 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -73,6 +73,12 @@
* Supported formats are: JPEG, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF and HEIF.
* <p>
* Attribute mutation is supported for JPEG image files.
+ * <p>
+ * Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
+ * Library</a> since it is a superset of this class. In addition to the functionalities of this
+ * class, it supports parsing extra metadata such as exposure and data compression information
+ * as well as setting extra metadata such as GPS and datetime information.
*/
public class ExifInterface {
private static final String TAG = "ExifInterface";
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b985b6b..4adece9 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -287,7 +287,6 @@
<item name="*android:lockPatternStyle">@style/LockPatternStyle</item>
<item name="passwordStyle">@style/PasswordTheme</item>
<item name="backgroundProtectedStyle">@style/BackgroundProtectedStyle</item>
- <item name="android:forceDarkAllowed">false</item>
<!-- Needed for MediaRoute chooser dialog -->
<item name="*android:isLightTheme">false</item>
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
index 7295008..9df6ba5 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
@@ -29,6 +29,7 @@
import android.opengl.GLSurfaceView;
import android.os.Build;
import android.util.Log;
+import android.util.MathUtils;
import com.android.systemui.ImageWallpaper;
import com.android.systemui.ImageWallpaper.ImageGLView;
@@ -43,6 +44,8 @@
public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
ImageWallpaper.WallpaperStatusListener, ImageRevealHelper.RevealStateListener {
private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
+ private static final float SCALE_VIEWPORT_MIN = 0.98f;
+ private static final float SCALE_VIEWPORT_MAX = 1f;
private final WallpaperManager mWallpaperManager;
private final ImageGLProgram mProgram;
@@ -52,6 +55,8 @@
private final ImageGLView mGLView;
private float mXOffset = 0f;
private float mYOffset = 0f;
+ private int mWidth = 0;
+ private int mHeight = 0;
public ImageWallpaperRenderer(Context context, ImageGLView glView) {
mWallpaperManager = context.getSystemService(WallpaperManager.class);
@@ -87,6 +92,8 @@
Log.d(TAG, "onSurfaceChanged: width=" + width + ", height=" + height
+ ", xOffset=" + mXOffset + ", yOffset=" + mYOffset);
}
+ mWidth = width;
+ mHeight = height;
mWallpaper.adjustTextureCoordinates(mWallpaperManager.getBitmap(),
width, height, mXOffset, mYOffset);
}
@@ -102,10 +109,21 @@
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_PER85), per85);
glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal);
+ scaleViewport(reveal);
mWallpaper.useTexture();
mWallpaper.draw();
}
+ private void scaleViewport(float reveal) {
+ // Interpolation between SCALE_VIEWPORT_MAX and SCALE_VIEWPORT_MIN by reveal.
+ float vpScaled = MathUtils.lerp(SCALE_VIEWPORT_MAX, SCALE_VIEWPORT_MIN, reveal);
+ // Calculate the offset amount from the lower left corner.
+ float offset = (SCALE_VIEWPORT_MAX - vpScaled) / 2;
+ // Change the viewport.
+ glViewport((int) (mWidth * offset), (int) (mHeight * offset),
+ (int) (mWidth * vpScaled), (int) (mHeight * vpScaled));
+ }
+
@Override
public void onAmbientModeChanged(boolean inAmbientMode, long duration) {
mImageRevealHelper.updateAwake(!inAmbientMode, duration);
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 9789688..1ac09ad 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -70,9 +70,8 @@
private static final long MAX_PAC_SIZE = 20 * 1000 * 1000;
// Return values for #setCurrentProxyScriptUrl
- enum ToSendOrNotToSendBroadcast {
- DONT_SEND_BROADCAST, DO_SEND_BROADCAST
- }
+ public static final boolean DONT_SEND_BROADCAST = false;
+ public static final boolean DO_SEND_BROADCAST = true;
private String mCurrentPac;
@GuardedBy("mProxyLock")
@@ -176,11 +175,11 @@
* @param proxy Proxy information that is about to be broadcast.
* @return Returns whether the broadcast should be sent : either DO_ or DONT_SEND_BROADCAST
*/
- synchronized ToSendOrNotToSendBroadcast setCurrentProxyScriptUrl(ProxyInfo proxy) {
+ synchronized boolean setCurrentProxyScriptUrl(ProxyInfo proxy) {
if (!Uri.EMPTY.equals(proxy.getPacFileUrl())) {
if (proxy.getPacFileUrl().equals(mPacUrl) && (proxy.getPort() > 0)) {
// Allow to send broadcast, nothing to do.
- return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
+ return DO_SEND_BROADCAST;
}
mPacUrl = proxy.getPacFileUrl();
mCurrentDelay = DELAY_1;
@@ -188,7 +187,7 @@
mHasDownloaded = false;
getAlarmManager().cancel(mPacRefreshIntent);
bind();
- return ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST;
+ return DONT_SEND_BROADCAST;
} else {
getAlarmManager().cancel(mPacRefreshIntent);
synchronized (mProxyLock) {
@@ -204,7 +203,7 @@
}
}
}
- return ToSendOrNotToSendBroadcast.DO_SEND_BROADCAST;
+ return DO_SEND_BROADCAST;
}
}
diff --git a/services/core/java/com/android/server/connectivity/ProxyTracker.java b/services/core/java/com/android/server/connectivity/ProxyTracker.java
index a671287..e715890 100644
--- a/services/core/java/com/android/server/connectivity/ProxyTracker.java
+++ b/services/core/java/com/android/server/connectivity/ProxyTracker.java
@@ -208,8 +208,7 @@
public void sendProxyBroadcast() {
final ProxyInfo defaultProxy = getDefaultProxy();
final ProxyInfo proxyInfo = null != defaultProxy ? defaultProxy : new ProxyInfo("", 0, "");
- if (mPacManager.setCurrentProxyScriptUrl(proxyInfo)
- == PacManager.ToSendOrNotToSendBroadcast.DONT_SEND_BROADCAST) {
+ if (mPacManager.setCurrentProxyScriptUrl(proxyInfo) == PacManager.DONT_SEND_BROADCAST) {
return;
}
if (DBG) Slog.d(TAG, "sending Proxy Broadcast for " + proxyInfo);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 1f28a6c..6d7dff5 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -216,7 +216,7 @@
private PackageManager mPackageManager;
public AutomaticBrightnessController(Callbacks callbacks, Looper looper,
- SensorManager sensorManager, BrightnessMappingStrategy mapper,
+ SensorManager sensorManager, Sensor lightSensor, BrightnessMappingStrategy mapper,
int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor,
int lightSensorRate, int initialLightSensorRate, long brighteningLightDebounceConfig,
long darkeningLightDebounceConfig, boolean resetAmbientLuxAfterWarmUpConfig,
@@ -249,7 +249,7 @@
new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon);
if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
- mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ mLightSensor = lightSensor;
}
mActivityTaskManager = ActivityTaskManager.getService();
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 74cda9d..b79ead0 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -44,6 +44,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
+import android.text.TextUtils;
import android.util.MathUtils;
import android.util.Slog;
import android.util.TimeUtils;
@@ -58,6 +59,7 @@
import com.android.server.policy.WindowManagerPolicy;
import java.io.PrintWriter;
+import java.util.List;
/**
* Controls the power state of the display.
@@ -474,10 +476,14 @@
int shortTermModelTimeout = resources.getInteger(
com.android.internal.R.integer.config_autoBrightnessShortTermModelTimeout);
+ String lightSensorType = resources.getString(
+ com.android.internal.R.string.config_displayLightSensorType);
+ Sensor lightSensor = findDisplayLightSensor(lightSensorType);
+
mBrightnessMapper = BrightnessMappingStrategy.create(resources);
if (mBrightnessMapper != null) {
mAutomaticBrightnessController = new AutomaticBrightnessController(this,
- handler.getLooper(), sensorManager, mBrightnessMapper,
+ handler.getLooper(), sensorManager, lightSensor, mBrightnessMapper,
lightSensorWarmUpTimeConfig, mScreenBrightnessRangeMinimum,
mScreenBrightnessRangeMaximum, dozeScaleFactor, lightSensorRate,
initialLightSensorRate, brighteningLightDebounce, darkeningLightDebounce,
@@ -530,6 +536,19 @@
mDisplayWhiteBalanceController = displayWhiteBalanceController;
}
+ private Sensor findDisplayLightSensor(String sensorType) {
+ if (!TextUtils.isEmpty(sensorType)) {
+ List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ALL);
+ for (int i = 0; i < sensors.size(); i++) {
+ Sensor sensor = sensors.get(i);
+ if (sensorType.equals(sensor.getStringType())) {
+ return sensor;
+ }
+ }
+ }
+ return mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
+ }
+
/**
* Returns true if the proximity sensor screen-off function is available.
*/
diff --git a/services/tests/uiservicestests/Android.bp b/services/tests/uiservicestests/Android.bp
index 92198fa..0ef2d15 100644
--- a/services/tests/uiservicestests/Android.bp
+++ b/services/tests/uiservicestests/Android.bp
@@ -18,6 +18,7 @@
"services.usage",
"guava",
"androidx.test.rules", "hamcrest-library",
+ "compatibility-device-util-axt",
"mockito-target-inline-minus-junit4",
"platform-test-annotations",
"hamcrest-library",
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7df52b2..49d8ad0 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -42,6 +42,8 @@
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
+
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
@@ -4178,7 +4180,7 @@
mService.setNotificationAssistantAccessGrantedCallback(
mNotificationAssistantAccessGrantedCallback);
- mService.setDefaultAssistantForUser(0);
+ runWithShellPermissionIdentity(() -> mService.setDefaultAssistantForUser(0));
verify(mNotificationAssistantAccessGrantedCallback)
.onGranted(eq(xmlConfig), eq(0), eq(true));
@@ -4198,7 +4200,7 @@
mService.setNotificationAssistantAccessGrantedCallback(
mNotificationAssistantAccessGrantedCallback);
- mService.setDefaultAssistantForUser(0);
+ runWithShellPermissionIdentity(() -> mService.setDefaultAssistantForUser(0));
verify(mNotificationAssistantAccessGrantedCallback)
.onGranted(eq(deviceConfig), eq(0), eq(true));
@@ -4219,22 +4221,22 @@
mService.setNotificationAssistantAccessGrantedCallback(
mNotificationAssistantAccessGrantedCallback);
- mService.setDefaultAssistantForUser(0);
+ runWithShellPermissionIdentity(() -> mService.setDefaultAssistantForUser(0));
verify(mNotificationAssistantAccessGrantedCallback)
.onGranted(eq(xmlConfig), eq(0), eq(true));
}
private void clearDeviceConfig() {
- DeviceConfig.resetToDefaults(
- Settings.RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_SYSTEMUI);
+ runWithShellPermissionIdentity(() -> DeviceConfig.resetToDefaults(
+ Settings.RESET_MODE_PACKAGE_DEFAULTS, DeviceConfig.NAMESPACE_SYSTEMUI));
}
private void setDefaultAssistantInDeviceConfig(String componentName) {
- DeviceConfig.setProperty(
+ runWithShellPermissionIdentity(() -> DeviceConfig.setProperty(
DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.NAS_DEFAULT_SERVICE,
componentName,
- false);
+ false));
}
}
diff --git a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
index ed8a533..a03fae0 100644
--- a/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
+++ b/tests/RollbackTest/RollbackTest/src/com/android/tests/rollback/RollbackTestUtils.java
@@ -165,9 +165,7 @@
PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
PackageInstaller.SessionParams params = new PackageInstaller.SessionParams(
PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- if (enableRollback) {
- params.setEnableRollback();
- }
+ params.setEnableRollback(enableRollback);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);
@@ -224,11 +222,9 @@
if (staged) {
multiPackageParams.setStaged();
}
- if (enableRollback) {
- // TODO: Do we set this on the parent params, the child params, or
- // both?
- multiPackageParams.setEnableRollback();
- }
+ // TODO: Do we set this on the parent params, the child params, or
+ // both?
+ multiPackageParams.setEnableRollback(enableRollback);
int multiPackageId = packageInstaller.createSession(multiPackageParams);
PackageInstaller.Session multiPackage = packageInstaller.openSession(multiPackageId);
@@ -242,9 +238,7 @@
if (resourceName.endsWith(".apex")) {
params.setInstallAsApex();
}
- if (enableRollback) {
- params.setEnableRollback();
- }
+ params.setEnableRollback(enableRollback);
int sessionId = packageInstaller.createSession(params);
session = packageInstaller.openSession(sessionId);