Add support for dummy draws for Vulkan webview and texture views.

Test: manual testing
Change-Id: Iaec8c3a34367673c281665ff6c6e97d1ce532265
This commit is contained in:
Greg Daniel
2017-01-04 14:27:00 -05:00
parent 8cd3edfa15
commit 45ec62ba72
13 changed files with 177 additions and 48 deletions

View File

@@ -116,6 +116,7 @@ hwui_src_files := \
Texture.cpp \
TextureCache.cpp \
VectorDrawable.cpp \
VkLayer.cpp \
protos/hwui.proto
hwui_test_common_src_files := \

View File

@@ -16,6 +16,7 @@
#include "DeferredLayerUpdater.h"
#include "GlLayer.h"
#include "VkLayer.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderTask.h"
#include "utils/PaintUtils.h"
@@ -56,16 +57,23 @@ void DeferredLayerUpdater::apply() {
mLayer->setAlpha(mAlpha, mMode);
if (mSurfaceTexture.get()) {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
"apply surfaceTexture with non GL backend %x, GL %x, VK %x",
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(static_cast<GlLayer*>(mLayer)->getTextureId());
}
if (mUpdateTexImage) {
mUpdateTexImage = false;
doUpdateTexImage();
if (mLayer->getApi() == Layer::Api::Vulkan) {
if (mUpdateTexImage) {
mUpdateTexImage = false;
doUpdateVkTexImage();
}
} else {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
"apply surfaceTexture with non GL backend %x, GL %x, VK %x",
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
if (mNeedsGLContextAttach) {
mNeedsGLContextAttach = false;
mSurfaceTexture->attachToContext(static_cast<GlLayer*>(mLayer)->getTextureId());
}
if (mUpdateTexImage) {
mUpdateTexImage = false;
doUpdateTexImage();
}
}
if (mTransform) {
mLayer->getTransform().load(*mTransform);
@@ -117,16 +125,25 @@ void DeferredLayerUpdater::doUpdateTexImage() {
}
}
void DeferredLayerUpdater::doUpdateVkTexImage() {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
"updateLayer non Vulkan backend %x, GL %x, VK %x",
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
updateLayer(false, identityMatrix.data);
VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
vkLayer->updateTexture();
}
void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
const float* textureTransform) {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
"updateLayer non GL backend %x, GL %x, VK %x",
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform().load(textureTransform);
updateLayer(forceFilter, textureTransform);
GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
if (renderTarget != glLayer->getRenderTarget()) {
@@ -137,18 +154,24 @@ void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
}
}
void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform().load(textureTransform);
}
void DeferredLayerUpdater::detachSurfaceTexture() {
if (mSurfaceTexture.get()) {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
"detachSurfaceTexture with non GL backend %x, GL %x, VK %x",
mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
status_t err = mSurfaceTexture->detachFromContext();
if (err != 0) {
// TODO: Elevate to fatal exception
ALOGE("Failed to detach SurfaceTexture from context %d", err);
if (mLayer->getApi() == Layer::Api::OpenGL) {
status_t err = mSurfaceTexture->detachFromContext();
if (err != 0) {
// TODO: Elevate to fatal exception
ALOGE("Failed to detach SurfaceTexture from context %d", err);
}
static_cast<GlLayer*>(mLayer)->clearTexture();
}
mSurfaceTexture = nullptr;
static_cast<GlLayer*>(mLayer)->clearTexture();
}
}

View File

@@ -63,8 +63,8 @@ public:
ANDROID_API void setSurfaceTexture(const sp<GLConsumer>& texture, bool needsAttach) {
if (texture.get() != mSurfaceTexture.get()) {
mSurfaceTexture = texture;
mNeedsGLContextAttach = needsAttach;
mSurfaceTexture = texture;
GLenum target = texture->getCurrentTextureTarget();
LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
@@ -113,6 +113,8 @@ private:
Layer* mLayer;
void doUpdateTexImage();
void doUpdateVkTexImage();
void updateLayer(bool forceFilter, const float* textureTransform);
};
} /* namespace uirenderer */

View File

@@ -67,13 +67,13 @@ void GpuMemoryTracker::stopTrackingObject() {
gObjectStats[static_cast<int>(mType)].count--;
}
void GpuMemoryTracker::onGLContextCreated() {
LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a GL thread? "
"current = %lu, gl thread = %lu", pthread_self(), gGpuThread);
void GpuMemoryTracker::onGpuContextCreated() {
LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? "
"current = %lu, gpu thread = %lu", pthread_self(), gGpuThread);
gGpuThread = pthread_self();
}
void GpuMemoryTracker::onGLContextDestroyed() {
void GpuMemoryTracker::onGpuContextDestroyed() {
gGpuThread = 0;
if (CC_UNLIKELY(gObjectSet.size() > 0)) {
std::stringstream os;

View File

@@ -43,8 +43,8 @@ public:
GpuObjectType objectType() { return mType; }
int objectSize() { return mSize; }
static void onGLContextCreated();
static void onGLContextDestroyed();
static void onGpuContextCreated();
static void onGpuContextDestroyed();
static void dump();
static void dump(std::ostream& stream);
static int getInstanceCount(GpuObjectType type);

40
libs/hwui/VkLayer.cpp Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2017 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 "VkLayer.h"
#include "renderstate/RenderState.h"
#include <SkCanvas.h>
#include <SkSurface.h>
namespace android {
namespace uirenderer {
void VkLayer::updateTexture() {
sk_sp<SkSurface> surface;
SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType);
surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info);
surface->getCanvas()->clear(SK_ColorBLUE);
mImage = surface->makeImageSnapshot(SkBudgeted::kNo, SkSurface::kNo_ForceUnique);
}
void VkLayer::onVkContextDestroyed() {
mImage = nullptr;
}
}; // namespace uirenderer
}; // namespace android

View File

@@ -18,7 +18,7 @@
#include "Layer.h"
#include <SkSurface.h>
#include <SkImage.h>
namespace android {
namespace uirenderer {
@@ -53,16 +53,22 @@ public:
return mBlend;
}
sk_sp<SkSurface> getSurface() {
return mSurface;
sk_sp<SkImage> getImage() {
return mImage;
}
void updateTexture();
// If we've destroyed the vulkan context (VkInstance, VkDevice, etc.), we must make sure to
// destroy any VkImages that were made with that context.
void onVkContextDestroyed();
private:
int mWidth;
int mHeight;
bool mBlend;
sk_sp<SkSurface> mSurface;
sk_sp<SkImage> mImage;
}; // struct VkLayer

View File

@@ -52,6 +52,11 @@ void GLFunctorDrawable::onDraw(SkCanvas* canvas) {
canvas->flush();
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
canvas->clear(SK_ColorRED);
return;
}
SkImageInfo canvasInfo = canvas->imageInfo();
SkMatrix44 mat4(canvas->getTotalMatrix());

View File

@@ -16,7 +16,10 @@
#include "GlLayer.h"
#include "LayerDrawable.h"
#include "VkLayer.h"
#include "SkColorFilter.h"
#include "SkSurface.h"
#include "gl/GrGLTypes.h"
namespace android {
@@ -37,17 +40,26 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer
canvas->concat(transform);
}
GlLayer* glLayer = static_cast<GlLayer*>(layer);
GrGLTextureInfo externalTexture;
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
GrBackendTextureDesc textureDescription;
textureDescription.fWidth = glLayer->getWidth();
textureDescription.fHeight = glLayer->getHeight();
textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
sk_sp<SkImage> layerImage = SkImage::MakeFromTexture(context, textureDescription);
sk_sp<SkImage> layerImage;
if (layer->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layer);
GrGLTextureInfo externalTexture;
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
GrBackendTextureDesc textureDescription;
textureDescription.fWidth = glLayer->getWidth();
textureDescription.fHeight = glLayer->getHeight();
textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
layerImage = SkImage::MakeFromTexture(context, textureDescription);
} else {
SkASSERT(layer->getApi() == Layer::Api::Vulkan);
VkLayer* vkLayer = static_cast<VkLayer*>(layer);
canvas->clear(SK_ColorGREEN);
layerImage = vkLayer->getImage();
}
if (layerImage) {
SkPaint paint;
paint.setAlpha(layer->getAlpha());

View File

@@ -14,6 +14,7 @@
* limitations under the License.
*/
#include "GlLayer.h"
#include "VkLayer.h"
#include <GpuMemoryTracker.h>
#include "renderstate/RenderState.h"
@@ -41,7 +42,7 @@ RenderState::~RenderState() {
void RenderState::onGLContextCreated() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
"State object lifecycle not managed correctly");
GpuMemoryTracker::onGLContextCreated();
GpuMemoryTracker::onGpuContextCreated();
mBlend = new Blend();
mMeshState = new MeshState();
@@ -78,7 +79,29 @@ void RenderState::onGLContextDestroyed() {
delete mStencil;
mStencil = nullptr;
GpuMemoryTracker::onGLContextDestroyed();
GpuMemoryTracker::onGpuContextDestroyed();
}
void RenderState::onVkContextCreated() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
"State object lifecycle not managed correctly");
GpuMemoryTracker::onGpuContextCreated();
}
static void layerDestroyedVkContext(Layer* layer) {
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::Vulkan,
"layerLostVkContext on non Vulkan layer");
static_cast<VkLayer*>(layer)->onVkContextDestroyed();
}
void RenderState::onVkContextDestroyed() {
mLayerPool.clear();
std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext);
GpuMemoryTracker::onGpuContextDestroyed();
}
GrContext* RenderState::getGrContext() const {
return mRenderThread.getGrContext();
}
void RenderState::flush(Caches::FlushMode mode) {

View File

@@ -35,6 +35,8 @@
#include <utils/RefBase.h>
#include <private/hwui/DrawGlInfo.h>
class GrContext;
namespace android {
namespace uirenderer {
@@ -56,6 +58,9 @@ public:
void onGLContextCreated();
void onGLContextDestroyed();
void onVkContextCreated();
void onVkContextDestroyed();
void flush(Caches::FlushMode flushMode);
void setViewport(GLsizei width, GLsizei height);
@@ -98,6 +103,8 @@ public:
OffscreenBufferPool& layerPool() { return mLayerPool; }
GrContext* getGrContext() const;
void dump();
private:

View File

@@ -19,6 +19,7 @@
#include "DeviceInfo.h"
#include "Properties.h"
#include "RenderThread.h"
#include "renderstate/RenderState.h"
#include <GrContext.h>
#include <GrTypes.h>
@@ -37,10 +38,14 @@ VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {
void VulkanManager::destroy() {
if (!hasVkContext()) return;
mRenderThread.renderState().onVkContextDestroyed();
mRenderThread.setGrContext(nullptr);
if (VK_NULL_HANDLE != mCommandPool) {
mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr);
mCommandPool = VK_NULL_HANDLE;
}
mBackendContext.reset();
}
void VulkanManager::initialize() {
@@ -105,6 +110,8 @@ void VulkanManager::initialize() {
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
mSwapBehavior = SwapBehavior::BufferAge;
}
mRenderThread.renderState().onVkContextCreated();
}
// Returns the next BackbufferInfo to use for the next draw. The function will make sure all
@@ -156,6 +163,9 @@ SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
if (!createSwapchain(surface)) {
return nullptr;
}
backbuffer = getAvailableBackbuffer(surface);
res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
SkASSERT(VK_SUCCESS == res);
// acquire the image
res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,

View File

@@ -51,7 +51,7 @@ static void destroyEglContext() {
TEST(GpuMemoryTracker, sizeCheck) {
destroyEglContext();
GpuMemoryTracker::onGLContextCreated();
GpuMemoryTracker::onGpuContextCreated();
ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
{
@@ -66,5 +66,5 @@ TEST(GpuMemoryTracker, sizeCheck) {
}
ASSERT_EQ(0, GpuMemoryTracker::getTotalSize(GpuObjectType::Texture));
ASSERT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::Texture));
GpuMemoryTracker::onGLContextDestroyed();
GpuMemoryTracker::onGpuContextDestroyed();
}