Merge "SF: Also edit currentState in doTransaction" into nyc-dev
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 34b570a..c0c91da 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -29,6 +29,7 @@
#include <unistd.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include <cutils/fs.h>
@@ -69,6 +70,12 @@
return strcmp(tmp_property_value, "true") == 0;
}
+// Keep profile paths in sync with ActivityThread.
+constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof";
+static std::string create_primary_profile(const std::string& profile_dir) {
+ return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
+}
+
int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags,
appid_t appid, const char* seinfo, int target_sdk_version) {
uid_t uid = multiuser_get_uid(userid, appid);
@@ -104,6 +111,12 @@
PLOG(ERROR) << "Failed to prepare " << profile_path;
return -1;
}
+ std::string profile_file = create_primary_profile(profile_path);
+ // read-write only for the app user.
+ if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
+ PLOG(ERROR) << "Failed to prepare " << profile_path;
+ return -1;
+ }
const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname);
// dex2oat/profman runs under the shared app gid and it needs to read/write reference
// profiles.
@@ -156,12 +169,6 @@
return 0;
}
-// Keep profile paths in sync with ActivityThread.
-constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof";
-static std::string create_primary_profile(const std::string& profile_dir) {
- return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME);
-}
-
static bool clear_profile(const std::string& profile) {
base::unique_fd ufd(open(profile.c_str(), O_WRONLY | O_NOFOLLOW | O_CLOEXEC));
if (ufd.get() < 0) {
@@ -1085,7 +1092,7 @@
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
-static void run_profman(const std::vector<fd_t>& profiles_fd, fd_t reference_profile_fd) {
+static void run_profman_merge(const std::vector<fd_t>& profiles_fd, fd_t reference_profile_fd) {
static const size_t MAX_INT_LEN = 32;
static const char* PROFMAN_BIN = "/system/bin/profman";
@@ -1133,13 +1140,13 @@
return false;
}
- ALOGV("PROFMAN: --- BEGIN '%s' ---\n", pkgname);
+ ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname);
pid_t pid = fork();
if (pid == 0) {
/* child -- drop privileges before continuing */
drop_capabilities(uid);
- run_profman(profiles_fd, reference_profile_fd);
+ run_profman_merge(profiles_fd, reference_profile_fd);
exit(68); /* only get here on exec failure */
}
/* parent */
@@ -1199,6 +1206,110 @@
return need_to_compile;
}
+static void run_profman_dump(const std::vector<fd_t>& profile_fds,
+ fd_t reference_profile_fd,
+ const std::vector<std::string>& code_locations,
+ const std::vector<fd_t>& code_location_fds,
+ fd_t output_fd) {
+ static const char* PROFMAN_BIN = "/system/bin/profman";
+ const bool has_reference_profile = (reference_profile_fd != -1);
+ // program name
+ // --dump-only
+ // --dump-output-to-fd=<output_fd>
+ // (optionally, --reference-profile-file-fd=<reference_profile_fd>)
+ const size_t fixed_args = (has_reference_profile ? 4 : 3);
+ // Fixed arguments, profiles, code paths, code path fds, and final NULL.
+ const size_t argc = fixed_args + profile_fds.size() + code_locations.size() +
+ code_location_fds.size() + 1;
+ const char **argv = new const char*[argc];
+ int i = 0;
+ argv[i++] = PROFMAN_BIN;
+ argv[i++] = "--dump-only";
+ std::string dump_output = StringPrintf("--dump-output-to-fd=%d", output_fd);
+ argv[i++] = dump_output.c_str();
+ if (has_reference_profile) {
+ std::string reference =
+ StringPrintf("--reference-profile-file-fd=%d", reference_profile_fd);
+ argv[i++] = reference.c_str();
+ }
+ for (fd_t profile_fd : profile_fds) {
+ std::string profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+ argv[i++] = strdup(profile_arg.c_str());
+ }
+ for (const std::string& code_location : code_locations) {
+ std::string path_str = StringPrintf("--code-location=%s", code_location.c_str());
+ argv[i++] = strdup(path_str.c_str());
+ }
+ for (fd_t code_location_fd : code_location_fds) {
+ std::string fd_str = StringPrintf("--code-location-fd=%d", code_location_fd);
+ argv[i++] = strdup(fd_str.c_str());
+ }
+ argv[i] = NULL;
+ assert(i == argc - 1);
+
+ execv(PROFMAN_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno));
+ exit(68); /* only get here on exec failure */
+}
+
+// Dumps the contents of a profile file, using pkgname's dex files for pretty
+// printing the result.
+bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) {
+ std::vector<fd_t> profile_fds;
+ fd_t reference_profile_fd = -1;
+ std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname);
+
+ ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname);
+
+ open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
+
+ const bool has_reference_profile = (reference_profile_fd != -1);
+ const bool has_profiles = !profile_fds.empty();
+
+ if (!has_reference_profile && !has_profiles) {
+ ALOGE("profman dump: no profiles to dump for '%s'", pkgname);
+ return false;
+ }
+
+ fd_t output_fd = open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW);
+ if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
+ ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str());
+ return false;
+ }
+ std::vector<std::string> code_locations = base::Split(code_path_string, ";");
+ std::vector<fd_t> code_location_fds;
+ for (const std::string& code_location : code_locations) {
+ fd_t code_location_fd = open(code_location.c_str(), O_RDONLY | O_NOFOLLOW);
+ if (code_location_fd == -1) {
+ ALOGE("installd cannot open '%s'\n", code_location.c_str());
+ return false;
+ }
+ code_location_fds.push_back(code_location_fd);
+ }
+
+ pid_t pid = fork();
+ if (pid == 0) {
+ /* child -- drop privileges before continuing */
+ drop_capabilities(uid);
+ run_profman_dump(profile_fds, reference_profile_fd, code_locations,
+ code_location_fds, output_fd);
+ exit(68); /* only get here on exec failure */
+ }
+ /* parent */
+ close_all_fds(code_location_fds, "code_location_fds");
+ close_all_fds(profile_fds, "profile_fds");
+ if (close(reference_profile_fd) != 0) {
+ PLOG(WARNING) << "Failed to close fd for reference profile";
+ }
+ int return_code = wait_child(pid);
+ if (!WIFEXITED(return_code)) {
+ LOG(WARNING) << "profman failed for package " << pkgname << ": "
+ << return_code;
+ return false;
+ }
+ return true;
+}
+
static void trim_extension(char* path) {
// Trim the extension.
int pos = strlen(path);
diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h
index 41cc209..7a42c5c 100644
--- a/cmds/installd/commands.h
+++ b/cmds/installd/commands.h
@@ -54,6 +54,8 @@
bool merge_profiles(uid_t uid, const char *pkgname);
+bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files);
+
int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set,
int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter,
const char* volume_uuid, const char* shared_libraries);
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index e8fce91..061359e 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -282,6 +282,19 @@
return 0;
}
+static int do_dump_profiles(char **arg, char reply[REPLY_MAX])
+{
+ uid_t uid = static_cast<uid_t>(atoi(arg[0]));
+ const char* pkgname = arg[1];
+ const char* dex_files = arg[2];
+ if (dump_profile(uid, pkgname, dex_files)) {
+ strncpy(reply, "true", REPLY_MAX);
+ } else {
+ strncpy(reply, "false", REPLY_MAX);
+ }
+ return 0;
+}
+
static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED)
{
return mark_boot_complete(arg[0] /* instruction set */);
@@ -428,6 +441,7 @@
{ "linkfile", 3, do_link_file },
{ "move_ab", 3, do_move_ab },
{ "merge_profiles", 2, do_merge_profiles },
+ { "dump_profiles", 3, do_dump_profiles },
};
static int readx(int s, void *_buf, int count)
diff --git a/docs/Doxyfile b/docs/Doxyfile
index 46d6d84..3ea453f 100644
--- a/docs/Doxyfile
+++ b/docs/Doxyfile
@@ -677,7 +677,7 @@
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../include/android
+INPUT = ../include/android ../../av/include/ndk ../../av/include/camera/ndk
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/docs/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png b/docs/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png
new file mode 100644
index 0000000..7578b48
--- /dev/null
+++ b/docs/images/camera2/metadata/android.colorCorrection.mode/processing_pipeline.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png b/docs/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png
new file mode 100644
index 0000000..7b10f6b
--- /dev/null
+++ b/docs/images/camera2/metadata/android.statistics.lensShadingMap/blue_shading.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png b/docs/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png
new file mode 100644
index 0000000..41972cf
--- /dev/null
+++ b/docs/images/camera2/metadata/android.statistics.lensShadingMap/green_e_shading.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png b/docs/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png
new file mode 100644
index 0000000..d26600b
--- /dev/null
+++ b/docs/images/camera2/metadata/android.statistics.lensShadingMap/green_o_shading.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png b/docs/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png
new file mode 100644
index 0000000..1e7208e
--- /dev/null
+++ b/docs/images/camera2/metadata/android.statistics.lensShadingMap/inv_shading.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png b/docs/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png
new file mode 100644
index 0000000..ecef3ae
--- /dev/null
+++ b/docs/images/camera2/metadata/android.statistics.lensShadingMap/red_shading.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
new file mode 100644
index 0000000..a02fd89
--- /dev/null
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/gamma_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
new file mode 100644
index 0000000..c309ac5
--- /dev/null
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/inverse_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
new file mode 100644
index 0000000..414fad4
--- /dev/null
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/linear_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
new file mode 100644
index 0000000..c147a87
--- /dev/null
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/rec709_tonemap.png
Binary files differ
diff --git a/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png b/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
new file mode 100644
index 0000000..4ce2125
--- /dev/null
+++ b/docs/images/camera2/metadata/android.tonemap.curveRed/srgb_tonemap.png
Binary files differ
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 3e26e05..69a408c 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -444,14 +444,6 @@
mSlots[found].mBufferState.dequeue();
- // If shared buffer mode has just been enabled, cache the slot of the
- // first buffer that is dequeued and mark it as the shared buffer.
- if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
- BufferQueueCore::INVALID_BUFFER_SLOT) {
- mCore->mSharedBufferSlot = found;
- mSlots[found].mBufferState.mShared = true;
- }
-
if ((buffer == NULL) ||
buffer->needsReallocation(width, height, format, usage))
{
@@ -483,9 +475,21 @@
eglDisplay = mSlots[found].mEglDisplay;
eglFence = mSlots[found].mEglFence;
- *outFence = mSlots[found].mFence;
+ // Don't return a fence in shared buffer mode, except for the first
+ // frame.
+ *outFence = (mCore->mSharedBufferMode &&
+ mCore->mSharedBufferSlot == found) ?
+ Fence::NO_FENCE : mSlots[found].mFence;
mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
mSlots[found].mFence = Fence::NO_FENCE;
+
+ // If shared buffer mode has just been enabled, cache the slot of the
+ // first buffer that is dequeued and mark it as the shared buffer.
+ if (mCore->mSharedBufferMode && mCore->mSharedBufferSlot ==
+ BufferQueueCore::INVALID_BUFFER_SLOT) {
+ mCore->mSharedBufferSlot = found;
+ mSlots[found].mBufferState.mShared = true;
+ }
} // Autolock scope
if (returnFlags & BUFFER_NEEDS_REALLOCATION) {
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 6811269..9d130cd 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -162,6 +162,9 @@
ANativeWindowBuffer* buf;
int fenceFd = -1;
int result = c->dequeueBuffer(&buf, &fenceFd);
+ if (result != OK) {
+ return result;
+ }
sp<Fence> fence(new Fence(fenceFd));
int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
if (waitResult != OK) {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 00bfc24..24394a9 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1794,9 +1794,9 @@
uint32_t blue_size = 0;
uint32_t alpha_size = 0;
-#define GET_POSITIVE_VALUE(case_name, target) \
+#define GET_NONNEGATIVE_VALUE(case_name, target) \
case case_name: \
- if (value > 0) { \
+ if (value >= 0) { \
target = value; \
} else { \
return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0); \
@@ -1808,12 +1808,12 @@
GLint attr = *attrib_list++;
GLint value = *attrib_list++;
switch (attr) {
- GET_POSITIVE_VALUE(EGL_WIDTH, width);
- GET_POSITIVE_VALUE(EGL_HEIGHT, height);
- GET_POSITIVE_VALUE(EGL_RED_SIZE, red_size);
- GET_POSITIVE_VALUE(EGL_GREEN_SIZE, green_size);
- GET_POSITIVE_VALUE(EGL_BLUE_SIZE, blue_size);
- GET_POSITIVE_VALUE(EGL_ALPHA_SIZE, alpha_size);
+ GET_NONNEGATIVE_VALUE(EGL_WIDTH, width);
+ GET_NONNEGATIVE_VALUE(EGL_HEIGHT, height);
+ GET_NONNEGATIVE_VALUE(EGL_RED_SIZE, red_size);
+ GET_NONNEGATIVE_VALUE(EGL_GREEN_SIZE, green_size);
+ GET_NONNEGATIVE_VALUE(EGL_BLUE_SIZE, blue_size);
+ GET_NONNEGATIVE_VALUE(EGL_ALPHA_SIZE, alpha_size);
case EGL_NATIVE_BUFFER_USAGE_ANDROID:
if (value & EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID) {
usage |= GRALLOC_USAGE_PROTECTED;
@@ -1836,7 +1836,7 @@
}
}
}
-#undef GET_POSITIVE_VALUE
+#undef GET_NONNEGATIVE_VALUE
// Validate format.
if (red_size == 8 && green_size == 8 && blue_size == 8) {
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index 320fddb..f8d4d13 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -66,6 +66,8 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sp<IBinder> display(sf->getBuiltInDisplay(
ISurfaceComposer::eDisplayIdMain));
+ SurfaceComposerClient::openGlobalTransaction();
+ SurfaceComposerClient::closeGlobalTransaction(true);
ASSERT_EQ(NO_ERROR, sf->captureScreen(display, producer, Rect(), 0, 0,
0, INT_MAX, false));
*sc = new ScreenCapture(cpuConsumer);
diff --git a/vulkan/libvulkan/api_gen.cpp b/vulkan/libvulkan/api_gen.cpp
index ff00f32..0a1dda2 100644
--- a/vulkan/libvulkan/api_gen.cpp
+++ b/vulkan/libvulkan/api_gen.cpp
@@ -128,7 +128,6 @@
INIT_PROC(instance, GetPhysicalDeviceFormatProperties);
INIT_PROC(instance, GetPhysicalDeviceImageFormatProperties);
INIT_PROC(instance, CreateDevice);
- INIT_PROC(instance, EnumerateDeviceLayerProperties);
INIT_PROC(instance, EnumerateDeviceExtensionProperties);
INIT_PROC(instance, GetPhysicalDeviceSparseImageFormatProperties);
INIT_PROC_EXT(KHR_surface, instance, DestroySurfaceKHR);
diff --git a/vulkan/libvulkan/api_gen.h b/vulkan/libvulkan/api_gen.h
index 779b654..7f8d274 100644
--- a/vulkan/libvulkan/api_gen.h
+++ b/vulkan/libvulkan/api_gen.h
@@ -38,7 +38,6 @@
PFN_vkGetPhysicalDeviceFormatProperties GetPhysicalDeviceFormatProperties;
PFN_vkGetPhysicalDeviceImageFormatProperties GetPhysicalDeviceImageFormatProperties;
PFN_vkCreateDevice CreateDevice;
- PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkGetPhysicalDeviceSparseImageFormatProperties GetPhysicalDeviceSparseImageFormatProperties;
PFN_vkDestroySurfaceKHR DestroySurfaceKHR;
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 307f0e4..f9a4670 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -434,7 +434,10 @@
{{AssertType $ "Function"}}
{{if and (Macro "IsFunctionExported" $) (Macro "IsInstanceDispatched" $)}}
- true
+ {{/* deprecated and unused internally */}}
+ {{if not (eq $.Name "vkEnumerateDeviceLayerProperties")}}
+ true
+ {{end}}
{{end}}
{{end}}
@@ -938,8 +941,6 @@
{{else if eq $.Name "vkDestroyInstance"}}true
{{else if eq $.Name "vkDestroyDevice"}}true
- {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true
-
{{/* Enumeration of extensions */}}
{{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index eabbf1f..2555272 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -124,7 +124,7 @@
Hal Hal::hal_;
bool Hal::Open() {
- ALOG_ASSERT(!dev_, "OpenHAL called more than once");
+ ALOG_ASSERT(!hal_.dev_, "OpenHAL called more than once");
// Use a stub device unless we successfully open a real HAL device.
hal_.dev_ = &stubhal::kDevice;
@@ -797,6 +797,7 @@
return VK_ERROR_INCOMPATIBLE_DRIVER;
}
+ data->driver_device = dev;
*pDevice = dev;
diff --git a/vulkan/libvulkan/driver.h b/vulkan/libvulkan/driver.h
index 210c3c7..a02ebd7 100644
--- a/vulkan/libvulkan/driver.h
+++ b/vulkan/libvulkan/driver.h
@@ -98,6 +98,7 @@
std::bitset<ProcHook::EXTENSION_COUNT> hook_extensions;
+ VkDevice driver_device;
DeviceDriverTable driver;
};
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 29351a1..d979a34 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -328,7 +328,6 @@
INIT_PROC(instance, EnumeratePhysicalDevices);
INIT_PROC(instance, GetInstanceProcAddr);
INIT_PROC(instance, CreateDevice);
- INIT_PROC(instance, EnumerateDeviceLayerProperties);
INIT_PROC(instance, EnumerateDeviceExtensionProperties);
INIT_PROC_EXT(EXT_debug_report, instance, CreateDebugReportCallbackEXT);
INIT_PROC_EXT(EXT_debug_report, instance, DestroyDebugReportCallbackEXT);
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index ca17d57..a60b2fe 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -58,7 +58,6 @@
PFN_vkEnumeratePhysicalDevices EnumeratePhysicalDevices;
PFN_vkGetInstanceProcAddr GetInstanceProcAddr;
PFN_vkCreateDevice CreateDevice;
- PFN_vkEnumerateDeviceLayerProperties EnumerateDeviceLayerProperties;
PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index c3d71d5..adc7d5c 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -109,6 +109,7 @@
struct Surface {
android::sp<ANativeWindow> window;
+ VkSwapchainKHR swapchain_handle;
};
VkSurfaceKHR HandleFromSurface(Surface* surface) {
@@ -147,6 +148,65 @@
return reinterpret_cast<Swapchain*>(handle);
}
+void ReleaseSwapchainImage(VkDevice device,
+ ANativeWindow* window,
+ int release_fence,
+ Swapchain::Image& image) {
+ ALOG_ASSERT(release_fence == -1 || image.dequeued,
+ "ReleaseSwapchainImage: can't provide a release fence for "
+ "non-dequeued images");
+
+ if (image.dequeued) {
+ if (release_fence >= 0) {
+ // We get here from vkQueuePresentKHR. The application is
+ // responsible for creating an execution dependency chain from
+ // vkAcquireNextImage (dequeue_fence) to vkQueuePresentKHR
+ // (release_fence), so we can drop the dequeue_fence here.
+ if (image.dequeue_fence >= 0)
+ close(image.dequeue_fence);
+ } else {
+ // We get here during swapchain destruction, or various serious
+ // error cases e.g. when we can't create the release_fence during
+ // vkQueuePresentKHR. In non-error cases, the dequeue_fence should
+ // have already signalled, since the swapchain images are supposed
+ // to be idle before the swapchain is destroyed. In error cases,
+ // there may be rendering in flight to the image, but since we
+ // weren't able to create a release_fence, waiting for the
+ // dequeue_fence is about the best we can do.
+ release_fence = image.dequeue_fence;
+ }
+ image.dequeue_fence = -1;
+
+ if (window) {
+ window->cancelBuffer(window, image.buffer.get(), release_fence);
+ } else {
+ if (release_fence >= 0) {
+ sync_wait(release_fence, -1 /* forever */);
+ close(release_fence);
+ }
+ }
+
+ image.dequeued = false;
+ }
+
+ if (image.image) {
+ GetData(device).driver.DestroyImage(device, image.image, nullptr);
+ image.image = VK_NULL_HANDLE;
+ }
+
+ image.buffer.clear();
+}
+
+void OrphanSwapchain(VkDevice device, Swapchain* swapchain) {
+ if (swapchain->surface.swapchain_handle != HandleFromSwapchain(swapchain))
+ return;
+ for (uint32_t i = 0; i < swapchain->num_images; i++) {
+ if (!swapchain->images[i].dequeued)
+ ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
+ }
+ swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
+}
+
} // anonymous namespace
VKAPI_ATTR
@@ -165,6 +225,7 @@
Surface* surface = new (mem) Surface;
surface->window = pCreateInfo->window;
+ surface->swapchain_handle = VK_NULL_HANDLE;
// TODO(jessehall): Create and use NATIVE_WINDOW_API_VULKAN.
int err =
@@ -191,6 +252,11 @@
if (!surface)
return;
native_window_api_disconnect(surface->window.get(), NATIVE_WINDOW_API_EGL);
+ ALOGV_IF(surface->swapchain_handle != VK_NULL_HANDLE,
+ "destroyed VkSurfaceKHR 0x%" PRIx64
+ " has active VkSwapchainKHR 0x%" PRIx64,
+ reinterpret_cast<uint64_t>(surface_handle),
+ reinterpret_cast<uint64_t>(surface->swapchain_handle));
surface->~Surface();
if (!allocator)
allocator = &GetData(instance).allocator;
@@ -344,29 +410,53 @@
allocator = &GetData(device).allocator;
ALOGV_IF(create_info->imageArrayLayers != 1,
- "Swapchain imageArrayLayers (%u) != 1 not supported",
+ "swapchain imageArrayLayers=%u not supported",
create_info->imageArrayLayers);
-
- ALOGE_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
- "color spaces other than SRGB_NONLINEAR not yet implemented");
- ALOGE_IF(create_info->oldSwapchain,
- "swapchain re-creation not yet implemented");
- ALOGE_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
- "swapchain preTransform %d not supported",
+ ALOGV_IF(create_info->imageColorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
+ "swapchain imageColorSpace=%u not supported",
+ create_info->imageColorSpace);
+ ALOGV_IF((create_info->preTransform & ~kSupportedTransforms) != 0,
+ "swapchain preTransform=%#x not supported",
create_info->preTransform);
- ALOGW_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
+ ALOGV_IF(!(create_info->presentMode == VK_PRESENT_MODE_FIFO_KHR ||
create_info->presentMode == VK_PRESENT_MODE_MAILBOX_KHR),
- "swapchain present mode %d not supported",
+ "swapchain presentMode=%u not supported",
create_info->presentMode);
Surface& surface = *SurfaceFromHandle(create_info->surface);
+ if (surface.swapchain_handle != create_info->oldSwapchain) {
+ ALOGV("Can't create a swapchain for VkSurfaceKHR 0x%" PRIx64
+ " because it already has active swapchain 0x%" PRIx64
+ " but VkSwapchainCreateInfo::oldSwapchain=0x%" PRIx64,
+ reinterpret_cast<uint64_t>(create_info->surface),
+ reinterpret_cast<uint64_t>(surface.swapchain_handle),
+ reinterpret_cast<uint64_t>(create_info->oldSwapchain));
+ return VK_ERROR_NATIVE_WINDOW_IN_USE_KHR;
+ }
+ if (create_info->oldSwapchain != VK_NULL_HANDLE)
+ OrphanSwapchain(device, SwapchainFromHandle(create_info->oldSwapchain));
+
// -- 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_UNDEQUED_BUFFERS. Reset to a known/default state before we
// attempt such queries.
+ // The native window only allows dequeueing all buffers before any have
+ // been queued, since after that point at least one is assumed to be in
+ // 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.
+ err = native_window_api_disconnect(surface.window.get(),
+ NATIVE_WINDOW_API_EGL);
+ ALOGW_IF(err != 0, "native_window_api_disconnect failed: %s (%d)",
+ strerror(-err), err);
+ err =
+ native_window_api_connect(surface.window.get(), NATIVE_WINDOW_API_EGL);
+ ALOGW_IF(err != 0, "native_window_api_connect failed: %s (%d)",
+ strerror(-err), err);
+
err = native_window_set_buffer_count(surface.window.get(), 0);
if (err != 0) {
ALOGE("native_window_set_buffer_count(0) failed: %s (%d)",
@@ -397,7 +487,7 @@
native_format = HAL_PIXEL_FORMAT_RGB_565;
break;
default:
- ALOGE("unsupported swapchain format %d", create_info->imageFormat);
+ ALOGV("unsupported swapchain format %d", create_info->imageFormat);
break;
}
err = native_window_set_buffers_format(surface.window.get(), native_format);
@@ -618,7 +708,8 @@
return result;
}
- *swapchain_handle = HandleFromSwapchain(swapchain);
+ surface.swapchain_handle = HandleFromSwapchain(swapchain);
+ *swapchain_handle = surface.swapchain_handle;
return VK_SUCCESS;
}
@@ -628,21 +719,13 @@
const VkAllocationCallbacks* allocator) {
const auto& dispatch = GetData(device).driver;
Swapchain* swapchain = SwapchainFromHandle(swapchain_handle);
- const android::sp<ANativeWindow>& window = swapchain->surface.window;
+ bool active = swapchain->surface.swapchain_handle == swapchain_handle;
+ ANativeWindow* window = active ? swapchain->surface.window.get() : nullptr;
- for (uint32_t i = 0; i < swapchain->num_images; i++) {
- Swapchain::Image& img = swapchain->images[i];
- if (img.dequeued) {
- window->cancelBuffer(window.get(), img.buffer.get(),
- img.dequeue_fence);
- img.dequeue_fence = -1;
- img.dequeued = false;
- }
- if (img.image) {
- dispatch.DestroyImage(device, img.image, nullptr);
- }
- }
-
+ 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();
@@ -655,6 +738,10 @@
uint32_t* count,
VkImage* images) {
Swapchain& swapchain = *SwapchainFromHandle(swapchain_handle);
+ ALOGW_IF(swapchain.surface.swapchain_handle != swapchain_handle,
+ "getting images for non-active swapchain 0x%" PRIx64
+ "; only dequeued image handles are valid",
+ reinterpret_cast<uint64_t>(swapchain_handle));
VkResult result = VK_SUCCESS;
if (images) {
uint32_t n = swapchain.num_images;
@@ -681,6 +768,9 @@
VkResult result;
int err;
+ if (swapchain.surface.swapchain_handle != swapchain_handle)
+ return VK_ERROR_OUT_OF_DATE_KHR;
+
ALOGW_IF(
timeout != UINT64_MAX,
"vkAcquireNextImageKHR: non-infinite timeouts not yet implemented");
@@ -739,6 +829,26 @@
return VK_SUCCESS;
}
+static VkResult WorstPresentResult(VkResult a, VkResult b) {
+ // See the error ranking for vkQueuePresentKHR at the end of section 29.6
+ // (in spec version 1.0.14).
+ static const VkResult kWorstToBest[] = {
+ VK_ERROR_DEVICE_LOST,
+ VK_ERROR_SURFACE_LOST_KHR,
+ VK_ERROR_OUT_OF_DATE_KHR,
+ VK_ERROR_OUT_OF_DEVICE_MEMORY,
+ VK_ERROR_OUT_OF_HOST_MEMORY,
+ VK_SUBOPTIMAL_KHR,
+ };
+ for (auto result : kWorstToBest) {
+ if (a == result || b == result)
+ return result;
+ }
+ ALOG_ASSERT(a == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", a);
+ ALOG_ASSERT(b == VK_SUCCESS, "invalid vkQueuePresentKHR result %d", b);
+ return a != VK_SUCCESS ? a : b;
+}
+
VKAPI_ATTR
VkResult QueuePresentKHR(VkQueue queue, const VkPresentInfoKHR* present_info) {
ALOGV_IF(present_info->sType != VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
@@ -746,14 +856,16 @@
present_info->sType);
ALOGV_IF(present_info->pNext, "VkPresentInfo::pNext != NULL");
+ VkDevice device = GetData(queue).driver_device;
const auto& dispatch = GetData(queue).driver;
VkResult final_result = VK_SUCCESS;
+
for (uint32_t sc = 0; sc < present_info->swapchainCount; sc++) {
Swapchain& swapchain =
*SwapchainFromHandle(present_info->pSwapchains[sc]);
- ANativeWindow* window = swapchain.surface.window.get();
uint32_t image_idx = present_info->pImageIndices[sc];
Swapchain::Image& img = swapchain.images[image_idx];
+ VkResult swapchain_result = VK_SUCCESS;
VkResult result;
int err;
@@ -763,37 +875,42 @@
present_info->pWaitSemaphores, img.image, &fence);
if (result != VK_SUCCESS) {
ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
- if (present_info->pResults)
- present_info->pResults[sc] = result;
- if (final_result == VK_SUCCESS)
- final_result = result;
- // TODO(jessehall): What happens to the buffer here? Does the app
- // still own it or not, i.e. should we cancel the buffer? Hard to
- // do correctly without synchronizing, though I guess we could wait
- // for the queue to idle.
- continue;
+ swapchain_result = result;
}
- err = window->queueBuffer(window, img.buffer.get(), fence);
- if (err != 0) {
- // TODO(jessehall): What now? We should probably cancel the buffer,
- // I guess?
- ALOGE("queueBuffer failed: %s (%d)", strerror(-err), err);
- if (present_info->pResults)
- present_info->pResults[sc] = result;
- if (final_result == VK_SUCCESS)
- final_result = VK_ERROR_INITIALIZATION_FAILED;
- continue;
+ if (swapchain.surface.swapchain_handle ==
+ present_info->pSwapchains[sc]) {
+ ANativeWindow* window = swapchain.surface.window.get();
+ if (swapchain_result == VK_SUCCESS) {
+ 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);
+ }
+ if (img.dequeue_fence >= 0) {
+ close(img.dequeue_fence);
+ img.dequeue_fence = -1;
+ }
+ img.dequeued = false;
+ }
+ if (swapchain_result != VK_SUCCESS) {
+ ReleaseSwapchainImage(device, window, fence, img);
+ OrphanSwapchain(device, &swapchain);
+ }
+ } else {
+ ReleaseSwapchainImage(device, nullptr, fence, img);
+ swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
}
- if (img.dequeue_fence != -1) {
- close(img.dequeue_fence);
- img.dequeue_fence = -1;
- }
- img.dequeued = false;
-
if (present_info->pResults)
- present_info->pResults[sc] = VK_SUCCESS;
+ present_info->pResults[sc] = swapchain_result;
+
+ if (swapchain_result != final_result)
+ final_result = WorstPresentResult(final_result, swapchain_result);
}
return final_result;