/*
* Copyright (C) 2014 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 "DeferredLayerUpdater.h"
#include "renderstate/RenderState.h"
#include "utils/PaintUtils.h"
namespace android {
namespace uirenderer {
DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState)
: mRenderState(renderState)
, mBlend(false)
, mSurfaceTexture(nullptr)
, mTransform(nullptr)
, mGLContextAttached(false)
, mUpdateTexImage(false)
, mLayer(nullptr) {
renderState.registerContextCallback(this);
}
DeferredLayerUpdater::~DeferredLayerUpdater() {
setTransform(nullptr);
mRenderState.removeContextCallback(this);
destroyLayer();
}
void DeferredLayerUpdater::onContextDestroyed() {
destroyLayer();
}
void DeferredLayerUpdater::destroyLayer() {
if (!mLayer) {
return;
}
if (mSurfaceTexture.get() && mGLContextAttached) {
mSurfaceTexture->detachFromView();
mGLContextAttached = false;
}
mLayer->postDecStrong();
mLayer = nullptr;
}
void DeferredLayerUpdater::setPaint(const SkPaint* paint) {
mAlpha = PaintUtils::getAlphaDirect(paint);
mMode = PaintUtils::getBlendModeDirect(paint);
if (paint) {
mColorFilter = paint->refColorFilter();
} else {
mColorFilter.reset();
}
}
void DeferredLayerUpdater::apply() {
if (!mLayer) {
mLayer = new Layer(mRenderState, mColorFilter, mAlpha, mMode);
}
mLayer->setColorFilter(mColorFilter);
mLayer->setAlpha(mAlpha, mMode);
if (mSurfaceTexture.get()) {
if (!mGLContextAttached) {
mGLContextAttached = true;
mUpdateTexImage = true;
mSurfaceTexture->attachToView();
}
if (mUpdateTexImage) {
mUpdateTexImage = false;
sk_sp<SkImage> layerImage;
SkMatrix textureTransform;
bool queueEmpty = true;
// If the SurfaceTexture queue is in synchronous mode, need to discard all
// but latest frame. Since we can't tell which mode it is in,
// do this unconditionally.
do {
layerImage = mSurfaceTexture->dequeueImage(textureTransform, &queueEmpty,
mRenderState);
} while (layerImage.get() && (!queueEmpty));
if (layerImage.get()) {
// force filtration if buffer size != layer size
bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height();
updateLayer(forceFilter, textureTransform, layerImage);
}
}
if (mTransform) {
mLayer->getTransform() = *mTransform;
setTransform(nullptr);
}
}
}
void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform,
const sk_sp<SkImage>& layerImage) {
mLayer->setBlend(mBlend);
mLayer->setForceFilter(forceFilter);
mLayer->setSize(mWidth, mHeight);
mLayer->getTexTransform() = textureTransform;
mLayer->setImage(layerImage);
}
void DeferredLayerUpdater::detachSurfaceTexture() {
if (mSurfaceTexture.get()) {
destroyLayer();
mSurfaceTexture = nullptr;
}
}
} /* namespace uirenderer */
} /* namespace android */