Make buffer age work in Vulkan
Test: manual testing in skiavk mode Change-Id: I5b9d8af7d9cecf2f022ef104ec33a5b7477e9e0c
This commit is contained in:
committed by
Derek Sollenberger
parent
e03b8124d0
commit
cd55852fcd
@@ -46,6 +46,7 @@ hwui_src_files := \
|
||||
renderthread/RenderTask.cpp \
|
||||
renderthread/RenderThread.cpp \
|
||||
renderthread/TimeLord.cpp \
|
||||
renderthread/Frame.cpp \
|
||||
thread/TaskManager.cpp \
|
||||
utils/Blur.cpp \
|
||||
utils/GLUtils.cpp \
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "Bitmap.h"
|
||||
|
||||
#include "Caches.h"
|
||||
#include "renderthread/EglManager.h"
|
||||
#include "renderthread/RenderThread.h"
|
||||
#include "renderthread/RenderProxy.h"
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "DeferredLayerUpdater.h"
|
||||
#include "LayerDrawable.h"
|
||||
#include "renderthread/EglManager.h"
|
||||
#include "renderthread/Frame.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "SkiaPipeline.h"
|
||||
#include "SkiaProfileRenderer.h"
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "SkiaVulkanPipeline.h"
|
||||
|
||||
#include "DeferredLayerUpdater.h"
|
||||
#include "renderthread/EglManager.h" // needed for Frame
|
||||
#include "renderthread/Frame.h"
|
||||
#include "Readback.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "SkiaPipeline.h"
|
||||
@@ -58,8 +58,7 @@ Frame SkiaVulkanPipeline::getFrame() {
|
||||
return Frame(-1, -1, 0);
|
||||
}
|
||||
|
||||
// TODO: support buffer age if Vulkan API can do it
|
||||
Frame frame(backBuffer->width(), backBuffer->height(), 0);
|
||||
Frame frame(backBuffer->width(), backBuffer->height(), mVkManager.getAge(mVkSurface));
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "AnimationContext.h"
|
||||
#include "Caches.h"
|
||||
#include "EglManager.h"
|
||||
#include "Frame.h"
|
||||
#include "LayerUpdateQueue.h"
|
||||
#include "Properties.h"
|
||||
#include "RenderThread.h"
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "Texture.h"
|
||||
#include "Caches.h"
|
||||
#include "DeviceInfo.h"
|
||||
#include "Frame.h"
|
||||
#include "Properties.h"
|
||||
#include "RenderThread.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
@@ -74,24 +75,6 @@ static struct {
|
||||
bool setDamage = false;
|
||||
} EglExtensions;
|
||||
|
||||
void Frame::map(const SkRect& in, EGLint* out) const {
|
||||
/* The rectangles are specified relative to the bottom-left of the surface
|
||||
* and the x and y components of each rectangle specify the bottom-left
|
||||
* position of that rectangle.
|
||||
*
|
||||
* HWUI does everything with 0,0 being top-left, so need to map
|
||||
* the rect
|
||||
*/
|
||||
SkIRect idirty;
|
||||
in.roundOut(&idirty);
|
||||
EGLint y = mHeight - (idirty.y() + idirty.height());
|
||||
// layout: {x, y, width, height}
|
||||
out[0] = idirty.x();
|
||||
out[1] = y;
|
||||
out[2] = idirty.width();
|
||||
out[3] = idirty.height();
|
||||
}
|
||||
|
||||
EglManager::EglManager(RenderThread& thread)
|
||||
: mRenderThread(thread)
|
||||
, mEglDisplay(EGL_NO_DISPLAY)
|
||||
|
||||
@@ -26,36 +26,8 @@ namespace android {
|
||||
namespace uirenderer {
|
||||
namespace renderthread {
|
||||
|
||||
class Frame;
|
||||
class RenderThread;
|
||||
class EglManager;
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
Frame(EGLint width, EGLint height, EGLint bufferAge)
|
||||
: mWidth(width)
|
||||
, mHeight(height)
|
||||
, mBufferAge(bufferAge) { }
|
||||
|
||||
EGLint width() const { return mWidth; }
|
||||
EGLint height() const { return mHeight; }
|
||||
|
||||
// See: https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_buffer_age.txt
|
||||
// for what this means
|
||||
EGLint bufferAge() const { return mBufferAge; }
|
||||
|
||||
private:
|
||||
Frame() {}
|
||||
friend class EglManager;
|
||||
|
||||
EGLSurface mSurface;
|
||||
EGLint mWidth;
|
||||
EGLint mHeight;
|
||||
EGLint mBufferAge;
|
||||
|
||||
// Maps from 0,0 in top-left to 0,0 in bottom-left
|
||||
// If out is not an EGLint[4] you're going to have a bad time
|
||||
void map(const SkRect& in, EGLint* out) const;
|
||||
};
|
||||
|
||||
// This class contains the shared global EGL objects, such as EGLDisplay
|
||||
// and EGLConfig, which are re-used by CanvasContext
|
||||
|
||||
44
libs/hwui/renderthread/Frame.cpp
Normal file
44
libs/hwui/renderthread/Frame.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "Frame.h"
|
||||
#include <SkRect.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace renderthread {
|
||||
|
||||
void Frame::map(const SkRect& in, int32_t* out) const {
|
||||
/* The rectangles are specified relative to the bottom-left of the surface
|
||||
* and the x and y components of each rectangle specify the bottom-left
|
||||
* position of that rectangle.
|
||||
*
|
||||
* HWUI does everything with 0,0 being top-left, so need to map
|
||||
* the rect
|
||||
*/
|
||||
SkIRect idirty;
|
||||
in.roundOut(&idirty);
|
||||
int32_t y = mHeight - (idirty.y() + idirty.height());
|
||||
// layout: {x, y, width, height}
|
||||
out[0] = idirty.x();
|
||||
out[1] = y;
|
||||
out[2] = idirty.width();
|
||||
out[3] = idirty.height();
|
||||
}
|
||||
|
||||
} /* namespace renderthread */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
60
libs/hwui/renderthread/Frame.h
Normal file
60
libs/hwui/renderthread/Frame.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2016 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct SkRect;
|
||||
typedef void *EGLSurface;
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace renderthread {
|
||||
|
||||
class Frame {
|
||||
public:
|
||||
Frame(int32_t width, int32_t height, int32_t bufferAge)
|
||||
: mWidth(width)
|
||||
, mHeight(height)
|
||||
, mBufferAge(bufferAge) { }
|
||||
|
||||
int32_t width() const { return mWidth; }
|
||||
int32_t height() const { return mHeight; }
|
||||
|
||||
// See: https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_buffer_age.txt
|
||||
// for what this means
|
||||
int32_t bufferAge() const { return mBufferAge; }
|
||||
|
||||
private:
|
||||
Frame() {}
|
||||
friend class EglManager;
|
||||
|
||||
int32_t mWidth;
|
||||
int32_t mHeight;
|
||||
int32_t mBufferAge;
|
||||
|
||||
EGLSurface mSurface;
|
||||
|
||||
// Maps from 0,0 in top-left to 0,0 in bottom-left
|
||||
// If out is not an int32_t[4] you're going to have a bad time
|
||||
void map(const SkRect& in, int32_t* out) const;
|
||||
};
|
||||
|
||||
} /* namespace renderthread */
|
||||
} /* namespace uirenderer */
|
||||
} /* namespace android */
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "FrameInfoVisualizer.h"
|
||||
#include "EglManager.h"
|
||||
|
||||
#include <SkRect.h>
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "DeferredLayerUpdater.h"
|
||||
#include "EglManager.h"
|
||||
#include "Frame.h"
|
||||
#include "ProfileRenderer.h"
|
||||
#include "renderstate/RenderState.h"
|
||||
#include "OpenGLReadback.h"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "VulkanManager.h"
|
||||
|
||||
#include "DeviceInfo.h"
|
||||
#include "Properties.h"
|
||||
#include "RenderThread.h"
|
||||
|
||||
#include <GrContext.h>
|
||||
@@ -100,6 +101,10 @@ void VulkanManager::initialize() {
|
||||
mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend,
|
||||
(GrBackendContext) mBackendContext.get()));
|
||||
DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
|
||||
|
||||
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
|
||||
mSwapBehavior = SwapBehavior::BufferAge;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
|
||||
@@ -162,7 +167,7 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
|
||||
}
|
||||
|
||||
// set up layout transfer from initial to color attachment
|
||||
VkImageLayout layout = surface->mImageLayouts[backbuffer->mImageIndex];
|
||||
VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
|
||||
SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
|
||||
VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
|
||||
VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
|
||||
@@ -215,7 +220,7 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
|
||||
|
||||
// We need to notify Skia that we changed the layout of the wrapped VkImage
|
||||
GrVkImageInfo* imageInfo;
|
||||
sk_sp<SkSurface> skSurface = surface->mSurfaces[backbuffer->mImageIndex];
|
||||
sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
|
||||
skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
|
||||
SkSurface::kFlushRead_BackendHandleAccess);
|
||||
imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
@@ -243,10 +248,8 @@ void VulkanManager::destroyBuffers(VulkanSurface* surface) {
|
||||
|
||||
delete[] surface->mBackbuffers;
|
||||
surface->mBackbuffers = nullptr;
|
||||
delete[] surface->mSurfaces;
|
||||
surface->mSurfaces = nullptr;
|
||||
delete[] surface->mImageLayouts;
|
||||
surface->mImageLayouts = nullptr;
|
||||
delete[] surface->mImageInfos;
|
||||
surface->mImageInfos = nullptr;
|
||||
delete[] surface->mImages;
|
||||
surface->mImages = nullptr;
|
||||
}
|
||||
@@ -286,8 +289,7 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
|
||||
GrPixelConfig config = wantSRGB ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
|
||||
|
||||
// set up initial image layouts and create surfaces
|
||||
surface->mImageLayouts = new VkImageLayout[surface->mImageCount];
|
||||
surface->mSurfaces = new sk_sp<SkSurface>[surface->mImageCount];
|
||||
surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
|
||||
for (uint32_t i = 0; i < surface->mImageCount; ++i) {
|
||||
GrBackendRenderTargetDesc desc;
|
||||
GrVkImageInfo info;
|
||||
@@ -306,9 +308,9 @@ void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExt
|
||||
desc.fStencilBits = 0;
|
||||
desc.fRenderTargetHandle = (GrBackendObject) &info;
|
||||
|
||||
surface->mSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
|
||||
VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
|
||||
imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
|
||||
desc, &props);
|
||||
surface->mImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
}
|
||||
|
||||
SkASSERT(mCommandPool != VK_NULL_HANDLE);
|
||||
@@ -595,7 +597,7 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
|
||||
VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
|
||||
surface->mCurrentBackbufferIndex;
|
||||
GrVkImageInfo* imageInfo;
|
||||
SkSurface* skSurface = surface->mSurfaces[backbuffer->mImageIndex].get();
|
||||
SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
|
||||
skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
|
||||
SkSurface::kFlushRead_BackendHandleAccess);
|
||||
// Check to make sure we never change the actually wrapped image
|
||||
@@ -632,7 +634,7 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
|
||||
0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
|
||||
mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
|
||||
|
||||
surface->mImageLayouts[backbuffer->mImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
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;
|
||||
@@ -668,6 +670,20 @@ void VulkanManager::swapBuffers(VulkanSurface* surface) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
} /* namespace renderthread */
|
||||
|
||||
@@ -46,6 +46,13 @@ private:
|
||||
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;
|
||||
@@ -56,8 +63,8 @@ private:
|
||||
|
||||
uint32_t mImageCount;
|
||||
VkImage* mImages;
|
||||
VkImageLayout* mImageLayouts;
|
||||
sk_sp<SkSurface>* mSurfaces;
|
||||
ImageInfo* mImageInfos;
|
||||
uint16_t mCurrentTime = 0;
|
||||
};
|
||||
|
||||
// This class contains the shared global Vulkan objects, such as VkInstance, VkDevice and VkQueue,
|
||||
@@ -87,6 +94,8 @@ public:
|
||||
// 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.
|
||||
@@ -161,6 +170,12 @@ private:
|
||||
uint32_t mPresentQueueIndex;
|
||||
VkQueue mPresentQueue = VK_NULL_HANDLE;
|
||||
VkCommandPool mCommandPool = VK_NULL_HANDLE;
|
||||
|
||||
enum class SwapBehavior {
|
||||
Discard,
|
||||
BufferAge,
|
||||
};
|
||||
SwapBehavior mSwapBehavior = SwapBehavior::Discard;
|
||||
};
|
||||
|
||||
} /* namespace renderthread */
|
||||
|
||||
Reference in New Issue
Block a user