LayerCompositingThread.cpp [plain text]
#include "config.h"
#if USE(ACCELERATED_COMPOSITING)
#include "LayerCompositingThread.h"
#include "LayerCompositingThreadClient.h"
#include "LayerMessage.h"
#include "LayerRenderer.h"
#include "LayerRendererClient.h"
#include "LayerUtilities.h"
#include "LayerWebKitThread.h"
#if ENABLE(VIDEO)
#include "MediaPlayer.h"
#include "MediaPlayerPrivateBlackBerry.h"
#endif
#include "PluginView.h"
#include "StdLibExtras.h"
#include "TextureCacheCompositingThread.h"
#include <BlackBerryPlatformGLES2ContextState.h>
#include <BlackBerryPlatformGraphics.h>
#include <BlackBerryPlatformLog.h>
#include <wtf/Assertions.h>
using BlackBerry::Platform::Graphics::GLES2Program;
namespace WebCore {
void LayerOverride::removeAnimation(const String& name)
{
for (size_t i = 0; i < m_animations.size(); ++i) {
if (m_animations[i]->name() == name) {
m_animations.remove(i);
return;
}
}
}
PassRefPtr<LayerCompositingThread> LayerCompositingThread::create(LayerType type, LayerCompositingThreadClient* client)
{
return adoptRef(new LayerCompositingThread(type, client));
}
LayerCompositingThread::LayerCompositingThread(LayerType type, LayerCompositingThreadClient* client)
: LayerData(type)
, m_layerRenderer(0)
, m_superlayer(0)
, m_centerW(0)
, m_pluginBuffer(0)
, m_drawOpacity(0)
, m_visible(false)
, m_commitScheduled(false)
, m_client(client)
#if ENABLE(CSS_FILTERS)
, m_filterOperationsChanged(false)
#endif
{
}
LayerCompositingThread::~LayerCompositingThread()
{
ASSERT(isCompositingThread());
ASSERT(!superlayer());
while (m_sublayers.size())
m_sublayers[0]->removeFromSuperlayer();
deleteTextures();
if (m_layerRenderer)
m_layerRenderer->removeLayer(this);
if (m_client)
m_client->layerCompositingThreadDestroyed(this);
}
void LayerCompositingThread::setLayerRenderer(LayerRenderer* renderer)
{
ASSERT(!renderer || !m_layerRenderer || renderer == m_layerRenderer);
m_layerRenderer = renderer;
if (m_layerRenderer)
m_layerRenderer->addLayer(this);
}
void LayerCompositingThread::deleteTextures()
{
releaseTextureResources();
if (m_client)
m_client->deleteTextures(this);
}
void LayerCompositingThread::setDrawTransform(double scale, const TransformationMatrix& matrix, const TransformationMatrix& projectionMatrix)
{
m_drawTransform = projectionMatrix * matrix;
FloatRect boundsRect(-origin(), bounds());
if (sizeIsScaleInvariant())
boundsRect.scale(1 / scale);
m_centerW = 0;
m_transformedBounds.clear();
m_ws.clear();
m_textureCoordinates.clear();
if (matrix.hasPerspective() && !m_layerRendererSurface) {
const float epsilon = 1e-3;
Vector<FloatPoint3D, 4> quad = toVector<FloatPoint3D, 4>(boundsRect);
Vector<FloatPoint3D, 4> polygon = intersect(quad, LayerClipPlane(FloatPoint3D(matrix.m14(), matrix.m24(), matrix.m34()), matrix.m44() - epsilon));
if (polygon != quad) {
for (size_t i = 0; i < polygon.size(); ++i) {
FloatPoint3D& p = polygon[i];
m_textureCoordinates.append(FloatPoint(p.x() / boundsRect.width() + 0.5f, p.y() / boundsRect.height() + 0.5f));
}
}
for (size_t i = 0; i < polygon.size(); ++i) {
float w;
FloatPoint3D p = multVecMatrix(matrix, polygon[i], w);
if (w != 1) {
p.setX(p.x() / w);
p.setY(p.y() / w);
p.setZ(p.z() / w);
}
FloatPoint3D q = projectionMatrix.mapPoint(p);
m_transformedBounds.append(FloatPoint(q.x(), q.y()));
m_ws.append(w);
}
m_centerW = matrix.m44();
} else
m_transformedBounds = toVector<FloatPoint, 4>(m_drawTransform.mapQuad(boundsRect));
m_boundingBox = WebCore::boundingBox(m_transformedBounds);
}
const Vector<FloatPoint>& LayerCompositingThread::textureCoordinates(TextureCoordinateOrientation orientation) const
{
if (m_textureCoordinates.size()) {
if (orientation == UpsideDown) {
static Vector<FloatPoint> upsideDownCoordinates;
upsideDownCoordinates = m_textureCoordinates;
for (size_t i = 0; i < upsideDownCoordinates.size(); ++i)
upsideDownCoordinates[i].setY(1 - upsideDownCoordinates[i].y());
return upsideDownCoordinates;
}
return m_textureCoordinates;
}
if (orientation == UpsideDown) {
static FloatPoint data[4] = { FloatPoint(0, 1), FloatPoint(1, 1), FloatPoint(1, 0), FloatPoint(0, 0) };
static Vector<FloatPoint>* upsideDownCoordinates = 0;
if (!upsideDownCoordinates) {
upsideDownCoordinates = new Vector<FloatPoint>();
upsideDownCoordinates->append(data, 4);
}
return *upsideDownCoordinates;
}
static FloatPoint data[4] = { FloatPoint(0, 0), FloatPoint(1, 0), FloatPoint(1, 1), FloatPoint(0, 1) };
static Vector<FloatPoint>* coordinates = 0;
if (!coordinates) {
coordinates = new Vector<FloatPoint>();
coordinates->append(data, 4);
}
return *coordinates;
}
FloatQuad LayerCompositingThread::transformedHolePunchRect() const
{
FloatRect holePunchRect(m_holePunchRect);
holePunchRect.moveBy(-origin());
return m_drawTransform.mapQuad(holePunchRect);
}
void LayerCompositingThread::drawTextures(const GLES2Program& program, double scale, const FloatRect& visibleRect, const FloatRect& clipRect)
{
if (m_pluginView) {
if (m_isVisible) {
m_pluginBuffer = m_pluginView->lockFrontBufferForRead();
if (!m_pluginBuffer)
return;
if (!BlackBerry::Platform::Graphics::lockAndBindBufferGLTexture(m_pluginBuffer, GL_TEXTURE_2D)) {
m_pluginView->unlockFrontBuffer();
return;
}
m_layerRenderer->addLayerToReleaseTextureResourcesList(this);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glUniform1f(program.opacityLocation(), drawOpacity());
glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, m_transformedBounds.data());
glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates().data());
glDrawArrays(GL_TRIANGLE_FAN, 0, m_transformedBounds.size());
}
return;
}
#if ENABLE(VIDEO)
if (m_mediaPlayer) {
if (m_isVisible) {
IntRect paintRect;
if (m_layerRenderer->client()->shouldChildWindowsUseDocumentCoordinates()) {
float vrw2 = visibleRect.width() / 2.0;
float vrh2 = visibleRect.height() / 2.0;
FloatPoint p(m_transformedBounds[0].x() * vrw2 + vrw2 + visibleRect.x(),
-m_transformedBounds[0].y() * vrh2 + vrh2 + visibleRect.y());
paintRect = IntRect(roundedIntPoint(p), m_bounds);
} else
paintRect = m_layerRenderer->toWindowCoordinates(m_boundingBox);
m_mediaPlayer->paint(0, paintRect);
MediaPlayerPrivate* mpp = static_cast<MediaPlayerPrivate*>(m_mediaPlayer->platformMedia().media.qnxMediaPlayer);
mpp->drawBufferingAnimation(m_drawTransform, program);
}
return;
}
#endif
if (m_client)
m_client->drawTextures(this, program, scale, clipRect);
}
void LayerCompositingThread::drawSurface(const GLES2Program& program, const TransformationMatrix& drawTransform, LayerCompositingThread* mask)
{
using namespace BlackBerry::Platform::Graphics;
if (m_layerRenderer->layerAlreadyOnSurface(this)) {
LayerTexture* surfaceTexture = layerRendererSurface()->texture();
if (!surfaceTexture) {
ASSERT_NOT_REACHED();
return;
}
textureCacheCompositingThread()->textureAccessed(layerRendererSurface()->texture());
GLuint surfaceTexID = surfaceTexture->platformTexture();
if (!surfaceTexID) {
ASSERT_NOT_REACHED();
return;
}
if (mask) {
if (LayerTexture* maskTexture = mask->contentsTexture()) {
GLuint maskTexID = maskTexture->platformTexture();
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, maskTexID);
glActiveTexture(GL_TEXTURE0);
}
}
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
glBindTexture(GL_TEXTURE_2D, surfaceTexID);
FloatQuad surfaceQuad = drawTransform.mapQuad(FloatRect(-origin(), bounds()));
glUniform1f(program.opacityLocation(), layerRendererSurface()->drawOpacity());
glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, &surfaceQuad);
static float texcoords[4 * 2] = { 0, 0, 1, 0, 1, 1, 0, 1 };
glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
}
void LayerCompositingThread::releaseTextureResources()
{
if (m_pluginView && m_pluginBuffer) {
BlackBerry::Platform::Graphics::releaseBufferGLTexture(m_pluginBuffer);
m_pluginBuffer = 0;
m_pluginView->unlockFrontBuffer();
}
}
void LayerCompositingThread::setPluginView(PluginView* pluginView)
{
if (!isCompositingThread()) {
dispatchSyncCompositingMessage(BlackBerry::Platform::createMethodCallMessage(
&LayerCompositingThread::setPluginView,
this,
pluginView));
return;
}
m_pluginView = pluginView;
}
#if ENABLE(VIDEO)
void LayerCompositingThread::setMediaPlayer(MediaPlayer* mediaPlayer)
{
if (!isCompositingThread()) {
dispatchSyncCompositingMessage(BlackBerry::Platform::createMethodCallMessage(
&LayerCompositingThread::setMediaPlayer,
this,
mediaPlayer));
return;
}
m_mediaPlayer = mediaPlayer;
}
#endif
void LayerCompositingThread::removeSublayer(LayerCompositingThread* sublayer)
{
ASSERT(isCompositingThread());
int foundIndex = indexOfSublayer(sublayer);
if (foundIndex == -1)
return;
sublayer->setSuperlayer(0);
m_sublayers.remove(foundIndex);
}
int LayerCompositingThread::indexOfSublayer(const LayerCompositingThread* reference)
{
for (size_t i = 0; i < m_sublayers.size(); i++) {
if (m_sublayers[i] == reference)
return i;
}
return -1;
}
const LayerCompositingThread* LayerCompositingThread::rootLayer() const
{
const LayerCompositingThread* layer = this;
for (LayerCompositingThread* superlayer = layer->superlayer(); superlayer; layer = superlayer, superlayer = superlayer->superlayer()) { }
return layer;
}
void LayerCompositingThread::addSublayer(LayerCompositingThread* layer)
{
layer->removeFromSuperlayer();
layer->setSuperlayer(this);
m_sublayers.append(layer);
}
void LayerCompositingThread::removeFromSuperlayer()
{
if (m_superlayer)
m_superlayer->removeSublayer(this);
}
void LayerCompositingThread::setSublayers(const Vector<RefPtr<LayerCompositingThread> >& sublayers)
{
if (sublayers == m_sublayers)
return;
while (m_sublayers.size()) {
RefPtr<LayerCompositingThread> layer = m_sublayers[0].get();
ASSERT(layer->superlayer());
layer->removeFromSuperlayer();
}
m_sublayers.clear();
size_t listSize = sublayers.size();
for (size_t i = 0; i < listSize; i++) {
RefPtr<LayerCompositingThread> sublayer = sublayers[i];
sublayer->removeFromSuperlayer();
sublayer->setSuperlayer(this);
m_sublayers.insert(i, sublayer);
}
}
void LayerCompositingThread::updateTextureContentsIfNeeded()
{
if (m_client)
m_client->uploadTexturesIfNeeded(this);
}
LayerTexture* LayerCompositingThread::contentsTexture()
{
if (m_client)
return m_client->contentsTexture(this);
return 0;
}
void LayerCompositingThread::setVisible(bool visible)
{
if (visible == m_visible)
return;
m_visible = visible;
if (m_client)
m_client->layerVisibilityChanged(this, visible);
}
void LayerCompositingThread::setNeedsCommit()
{
if (m_layerRenderer)
m_layerRenderer->setNeedsCommit();
}
void LayerCompositingThread::scheduleCommit()
{
if (!m_client)
return;
if (!isWebKitThread()) {
if (m_commitScheduled)
return;
m_commitScheduled = true;
dispatchWebKitMessage(BlackBerry::Platform::createMethodCallMessage(&LayerCompositingThread::scheduleCommit, this));
return;
}
m_commitScheduled = false;
m_client->scheduleCommit();
}
void LayerCompositingThread::commitPendingTextureUploads()
{
if (m_client)
m_client->commitPendingTextureUploads(this);
}
bool LayerCompositingThread::updateAnimations(double currentTime)
{
for (size_t i = 0; i < m_suspendedAnimations.size(); ++i) {
LayerAnimation* animation = m_suspendedAnimations[i].get();
double elapsedTime = animation->timeOffset();
animation->apply(this, elapsedTime);
}
bool allAnimationsFinished = true;
for (size_t i = 0; i < m_runningAnimations.size(); ++i) {
LayerAnimation* animation = m_runningAnimations[i].get();
double elapsedTime = (m_suspendTime ? m_suspendTime : currentTime) - animation->startTime() + animation->timeOffset();
animation->apply(this, elapsedTime);
if (!animation->finished())
allAnimationsFinished = false;
}
if (m_override) {
if (m_override->isPositionSet())
m_position = m_override->position();
if (m_override->isAnchorPointSet())
m_anchorPoint = m_override->anchorPoint();
if (m_override->isBoundsSet())
m_bounds = m_override->bounds();
if (m_override->isTransformSet())
m_transform = m_override->transform();
if (m_override->isOpacitySet())
m_opacity = m_override->opacity();
for (size_t i = 0; i < m_override->animations().size(); ++i) {
LayerAnimation* animation = m_override->animations()[i].get();
double elapsedTime = (m_suspendTime ? m_suspendTime : currentTime) - animation->startTime() + animation->timeOffset();
animation->apply(this, elapsedTime);
if (!animation->finished())
allAnimationsFinished = false;
}
}
return !allAnimationsFinished;
}
bool LayerCompositingThread::hasVisibleHolePunchRect() const
{
if (m_pluginView && !m_isVisible)
return false;
#if ENABLE(VIDEO)
if (m_mediaPlayer && !m_isVisible)
return false;
#endif
return hasHolePunchRect();
}
void LayerCompositingThread::createLayerRendererSurface()
{
ASSERT(!m_layerRendererSurface);
m_layerRendererSurface = adoptPtr(new LayerRendererSurface(m_layerRenderer, this));
}
void LayerCompositingThread::removeAnimation(const String& name)
{
for (size_t i = 0; i < m_runningAnimations.size(); ++i) {
if (m_runningAnimations[i]->name() == name) {
m_runningAnimations.remove(i);
return;
}
}
}
LayerOverride* LayerCompositingThread::override()
{
if (!m_override)
m_override = LayerOverride::create();
return m_override.get();
}
void LayerCompositingThread::clearOverride()
{
m_override.clear();
}
}
#endif // USE(ACCELERATED_COMPOSITING)