HWUI-VK: Use auto prerotation for Vulkan backend
The consumer driven resizing now works as below: 1. Query the cached transform hint for this draw cycle 2. dequeuBuffer first to get the actual size 3. Cancel the pre-rotation done on the buffer 4. Update logical window size according to the transform Bug: 136110987 Test: manually test split screen with resizing and rotation Test: CtsUiRenderingTestCases and CtsGraphicsTestCases Change-Id: Ia7f1a53fd761b90cb3ff429086a060d48e40919c
This commit is contained in:
@@ -27,15 +27,6 @@ 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:
|
||||
@@ -68,28 +59,6 @@ static SkMatrix GetPreTransformMatrix(SkISize windowSize, int 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 & NATIVE_WINDOW_TRANSFORM_ROT_90) {
|
||||
windowInfo->actualSize.set(windowSize.height(), windowSize.width());
|
||||
}
|
||||
|
||||
windowInfo->preTransform = GetPreTransformMatrix(windowInfo->size, windowInfo->transform);
|
||||
}
|
||||
|
||||
static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
|
||||
ATRACE_CALL();
|
||||
|
||||
@@ -125,6 +94,24 @@ static bool ConnectAndSetWindowDefaults(ANativeWindow* window) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Let consumer drive the size of the buffers.
|
||||
err = native_window_set_buffers_dimensions(window, 0, 0);
|
||||
if (err != 0) {
|
||||
ALOGE("native_window_set_buffers_dimensions(0,0) failed: %s (%d)", strerror(-err), err);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable auto prerotation, so when buffer size is driven by the consumer
|
||||
// and the transform hint specifies a 90 or 270 degree rotation, the width
|
||||
// and height used for buffer pre-allocation and dequeueBuffer will be
|
||||
// additionally swapped.
|
||||
err = native_window_set_auto_prerotation(window, true);
|
||||
if (err != 0) {
|
||||
ALOGE("VulkanSurface::UpdateWindow() native_window_set_auto_prerotation failed: %s (%d)",
|
||||
strerror(-err), err);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -132,10 +119,6 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
|
||||
SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
|
||||
GrContext* grContext, const VulkanManager& vkManager,
|
||||
uint32_t extraBuffers) {
|
||||
// TODO(http://b/134182502)
|
||||
const SkISize minSize = SkISize::Make(1, 1);
|
||||
const SkISize maxSize = SkISize::Make(4096, 4096);
|
||||
|
||||
// Connect and set native window to default configurations.
|
||||
if (!ConnectAndSetWindowDefaults(window)) {
|
||||
return nullptr;
|
||||
@@ -144,7 +127,7 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
|
||||
// Initialize WindowInfo struct.
|
||||
WindowInfo windowInfo;
|
||||
if (!InitializeWindowInfoStruct(window, colorMode, colorType, colorSpace, vkManager,
|
||||
extraBuffers, minSize, maxSize, &windowInfo)) {
|
||||
extraBuffers, &windowInfo)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -153,15 +136,14 @@ VulkanSurface* VulkanSurface::Create(ANativeWindow* window, ColorMode colorMode,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new VulkanSurface(window, windowInfo, minSize, maxSize, grContext);
|
||||
return new VulkanSurface(window, windowInfo, grContext);
|
||||
}
|
||||
|
||||
bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
|
||||
SkColorType colorType,
|
||||
sk_sp<SkColorSpace> colorSpace,
|
||||
const VulkanManager& vkManager,
|
||||
uint32_t extraBuffers, const SkISize& minSize,
|
||||
const SkISize& maxSize, WindowInfo* outWindowInfo) {
|
||||
uint32_t extraBuffers, WindowInfo* outWindowInfo) {
|
||||
ATRACE_CALL();
|
||||
|
||||
int width, height;
|
||||
@@ -185,7 +167,13 @@ bool VulkanSurface::InitializeWindowInfoStruct(ANativeWindow* window, ColorMode
|
||||
}
|
||||
outWindowInfo->transform = query_value;
|
||||
|
||||
ComputeWindowSizeAndTransform(outWindowInfo, minSize, maxSize);
|
||||
outWindowInfo->actualSize = outWindowInfo->size;
|
||||
if (outWindowInfo->transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
|
||||
outWindowInfo->actualSize.set(outWindowInfo->size.height(), outWindowInfo->size.width());
|
||||
}
|
||||
|
||||
outWindowInfo->preTransform =
|
||||
GetPreTransformMatrix(outWindowInfo->size, outWindowInfo->transform);
|
||||
|
||||
err = window->query(window, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &query_value);
|
||||
if (err != 0 || query_value < 0) {
|
||||
@@ -290,15 +278,6 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window
|
||||
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
|
||||
@@ -331,12 +310,8 @@ bool VulkanSurface::UpdateWindow(ANativeWindow* window, const WindowInfo& window
|
||||
}
|
||||
|
||||
VulkanSurface::VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo,
|
||||
SkISize minWindowSize, SkISize maxWindowSize, GrContext* grContext)
|
||||
: mNativeWindow(window)
|
||||
, mWindowInfo(windowInfo)
|
||||
, mGrContext(grContext)
|
||||
, mMinWindowSize(minWindowSize)
|
||||
, mMaxWindowSize(maxWindowSize) {}
|
||||
GrContext* grContext)
|
||||
: mNativeWindow(window), mWindowInfo(windowInfo), mGrContext(grContext) {}
|
||||
|
||||
VulkanSurface::~VulkanSurface() {
|
||||
releaseBuffers();
|
||||
@@ -379,58 +354,51 @@ VulkanSurface::NativeBufferInfo* VulkanSurface::dequeueNativeBuffer() {
|
||||
// value at the end of the function if everything dequeued correctly.
|
||||
mCurrentBufferInfo = nullptr;
|
||||
|
||||
// check if the native window has been resized or rotated and update accordingly
|
||||
SkISize newSize = SkISize::MakeEmpty();
|
||||
// Query the transform hint synced from the initial Surface connect or last queueBuffer. The
|
||||
// auto prerotation on the buffer is based on the same transform hint in use by the producer.
|
||||
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;
|
||||
}
|
||||
int err =
|
||||
mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_TRANSFORM_HINT, &transformHint);
|
||||
|
||||
// Since auto pre-rotation is enabled, dequeueBuffer to get the consumer driven buffer size
|
||||
// from ANativeWindowBuffer.
|
||||
ANativeWindowBuffer* buffer;
|
||||
int fence_fd;
|
||||
int err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
|
||||
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buffer, &fence_fd);
|
||||
if (err != 0) {
|
||||
ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), err);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SkISize actualSize = SkISize::Make(buffer->width, buffer->height);
|
||||
if (actualSize != mWindowInfo.actualSize || transformHint != mWindowInfo.transform) {
|
||||
if (actualSize != mWindowInfo.actualSize) {
|
||||
// reset the NativeBufferInfo (including SkSurface) associated with the old buffers. The
|
||||
// new NativeBufferInfo storage will be populated lazily as we dequeue each new buffer.
|
||||
mWindowInfo.actualSize = actualSize;
|
||||
releaseBuffers();
|
||||
}
|
||||
|
||||
if (transformHint != mWindowInfo.transform) {
|
||||
err = native_window_set_buffers_transform(mNativeWindow.get(),
|
||||
InvertTransform(transformHint));
|
||||
if (err != 0) {
|
||||
ALOGE("native_window_set_buffers_transform(%d) failed: %s (%d)", transformHint,
|
||||
strerror(-err), err);
|
||||
mNativeWindow->cancelBuffer(mNativeWindow.get(), buffer, fence_fd);
|
||||
return nullptr;
|
||||
}
|
||||
mWindowInfo.transform = transformHint;
|
||||
}
|
||||
|
||||
mWindowInfo.size = actualSize;
|
||||
if (mWindowInfo.transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
|
||||
mWindowInfo.size.set(actualSize.height(), actualSize.width());
|
||||
}
|
||||
|
||||
mWindowInfo.preTransform = GetPreTransformMatrix(mWindowInfo.size, mWindowInfo.transform);
|
||||
}
|
||||
|
||||
uint32_t idx;
|
||||
for (idx = 0; idx < mWindowInfo.bufferCount; idx++) {
|
||||
if (mNativeBuffers[idx].buffer.get() == buffer) {
|
||||
|
||||
@@ -101,16 +101,12 @@ private:
|
||||
SkMatrix preTransform;
|
||||
};
|
||||
|
||||
VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, SkISize minWindowSize,
|
||||
SkISize maxWindowSize, GrContext* grContext);
|
||||
VulkanSurface(ANativeWindow* window, const WindowInfo& windowInfo, GrContext* grContext);
|
||||
static bool InitializeWindowInfoStruct(ANativeWindow* window, ColorMode colorMode,
|
||||
SkColorType colorType, sk_sp<SkColorSpace> colorSpace,
|
||||
const VulkanManager& vkManager, uint32_t extraBuffers,
|
||||
const SkISize& minSize, const SkISize& maxSize,
|
||||
WindowInfo* outWindowInfo);
|
||||
static bool UpdateWindow(ANativeWindow* window, const WindowInfo& windowInfo);
|
||||
static void ComputeWindowSizeAndTransform(WindowInfo* windowInfo, const SkISize& minSize,
|
||||
const SkISize& maxSize);
|
||||
void releaseBuffers();
|
||||
|
||||
// TODO: Just use a vector?
|
||||
@@ -122,11 +118,8 @@ private:
|
||||
|
||||
uint32_t mPresentCount = 0;
|
||||
NativeBufferInfo* mCurrentBufferInfo = nullptr;
|
||||
|
||||
const SkISize mMinWindowSize;
|
||||
const SkISize mMaxWindowSize;
|
||||
};
|
||||
|
||||
} /* namespace renderthread */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
} /* namespace android */
|
||||
|
||||
Reference in New Issue
Block a user