VideoLayerChromium.cpp [plain text]
#include "config.h"
#if USE(ACCELERATED_COMPOSITING)
#include "VideoLayerChromium.h"
#include "Extensions3DChromium.h"
#include "GraphicsContext3D.h"
#include "LayerRendererChromium.h"
#include "NotImplemented.h"
#include "RenderLayerBacking.h"
#include "VideoFrameChromium.h"
#include "VideoFrameProvider.h"
#include "cc/CCLayerImpl.h"
#include "cc/CCVideoLayerImpl.h"
namespace WebCore {
PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(GraphicsLayerChromium* owner,
VideoFrameProvider* provider)
{
return adoptRef(new VideoLayerChromium(owner, provider));
}
VideoLayerChromium::VideoLayerChromium(GraphicsLayerChromium* owner, VideoFrameProvider* provider)
: LayerChromium(owner)
, m_skipsDraw(true)
, m_frameFormat(VideoFrameChromium::Invalid)
, m_provider(provider)
, m_currentFrame(0)
{
resetFrameParameters();
}
VideoLayerChromium::~VideoLayerChromium()
{
cleanupResources();
deleteTexturesInUse();
}
PassRefPtr<CCLayerImpl> VideoLayerChromium::createCCLayerImpl()
{
return CCVideoLayerImpl::create(this, m_layerId);
}
void VideoLayerChromium::deleteTexturesInUse()
{
if (!layerRenderer())
return;
GraphicsContext3D* context = layerRendererContext();
for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) {
Texture texture = m_textures[plane];
if (!texture.isEmpty && texture.ownedByLayerRenderer)
GLC(context, context->deleteTexture(texture.id));
}
}
void VideoLayerChromium::cleanupResources()
{
LayerChromium::cleanupResources();
if (m_currentFrame)
releaseCurrentFrame();
else
resetFrameParameters();
}
void VideoLayerChromium::updateCompositorResources()
{
if (!m_contentsDirty || !m_owner)
return;
RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_owner->client());
if (!backing || backing->paintingGoesToWindow())
return;
ASSERT(drawsContent());
m_skipsDraw = false;
VideoFrameChromium* frame = m_provider->getCurrentFrame();
if (!frame) {
m_skipsDraw = true;
m_provider->putCurrentFrame(frame);
return;
}
m_frameFormat = frame->format();
unsigned textureFormat = determineTextureFormat(frame);
if (textureFormat == GraphicsContext3D::INVALID_VALUE) {
notImplemented();
m_skipsDraw = true;
m_provider->putCurrentFrame(frame);
return;
}
if (frame->surfaceType() == VideoFrameChromium::TypeTexture) {
releaseCurrentFrame();
saveCurrentFrame(frame);
m_dirtyRect.setSize(FloatSize());
m_contentsDirty = false;
return;
}
GraphicsContext3D* context = layerRendererContext();
bool texturesAllocated = allocateTexturesIfNeeded(context, frame, textureFormat);
if (!texturesAllocated) {
m_skipsDraw = true;
m_provider->putCurrentFrame(frame);
return;
}
for (unsigned plane = 0; plane < frame->planes(); plane++) {
Texture texture = m_textures[plane];
ASSERT(frame->requiredTextureSize(plane) == texture.size);
updateTexture(context, texture.id, texture.size, textureFormat, frame->data(plane));
}
m_dirtyRect.setSize(FloatSize());
m_contentsDirty = false;
m_provider->putCurrentFrame(frame);
}
void VideoLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
{
LayerChromium::pushPropertiesTo(layer);
CCVideoLayerImpl* videoLayer = static_cast<CCVideoLayerImpl*>(layer);
videoLayer->setSkipsDraw(m_skipsDraw);
videoLayer->setFrameFormat(m_frameFormat);
for (size_t i = 0; i < 3; ++i)
videoLayer->setTexture(i, m_textures[i]);
}
unsigned VideoLayerChromium::determineTextureFormat(const VideoFrameChromium* frame)
{
switch (frame->format()) {
case VideoFrameChromium::YV12:
case VideoFrameChromium::YV16:
return GraphicsContext3D::LUMINANCE;
case VideoFrameChromium::RGBA:
return GraphicsContext3D::RGBA;
default:
break;
}
return GraphicsContext3D::INVALID_VALUE;
}
bool VideoLayerChromium::allocateTexturesIfNeeded(GraphicsContext3D* context, const VideoFrameChromium* frame, unsigned textureFormat)
{
ASSERT(context);
ASSERT(frame);
for (unsigned plane = 0; plane < frame->planes(); plane++) {
IntSize requiredTextureSize = frame->requiredTextureSize(plane);
Texture texture = m_textures[plane];
if (!layerRenderer()->checkTextureSize(requiredTextureSize))
return false;
if (texture.isEmpty) {
texture.id = layerRenderer()->createLayerTexture();
texture.ownedByLayerRenderer = true;
texture.isEmpty = false;
}
if (!requiredTextureSize.isZero() && requiredTextureSize != texture.size) {
allocateTexture(context, texture.id, requiredTextureSize, textureFormat);
texture.size = requiredTextureSize;
texture.visibleSize = computeVisibleSize(frame, plane);
}
m_textures[plane] = texture;
}
return true;
}
IntSize VideoLayerChromium::computeVisibleSize(const VideoFrameChromium* frame, unsigned plane)
{
int visibleWidth = frame->width(plane);
int visibleHeight = frame->height(plane);
if (frame->hasPaddingBytes(plane))
--visibleWidth;
if (plane == VideoFrameChromium::yPlane && frame->format() == VideoFrameChromium::YV12) {
if (frame->hasPaddingBytes(VideoFrameChromium::uPlane)) {
int originalWidth = frame->width(plane);
visibleWidth = originalWidth - 2;
}
}
return IntSize(visibleWidth, visibleHeight);
}
void VideoLayerChromium::allocateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned textureFormat) const
{
GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
GLC(context, context->texImage2DResourceSafe(GraphicsContext3D::TEXTURE_2D, 0, textureFormat, dimensions.width(), dimensions.height(), 0, textureFormat, GraphicsContext3D::UNSIGNED_BYTE));
}
void VideoLayerChromium::updateTexture(GraphicsContext3D* context, unsigned textureId, const IntSize& dimensions, unsigned format, const void* data) const
{
ASSERT(context);
GLC(context, context->bindTexture(GraphicsContext3D::TEXTURE_2D, textureId));
void* mem = static_cast<Extensions3DChromium*>(context->getExtensions())->mapTexSubImage2DCHROMIUM(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, Extensions3DChromium::WRITE_ONLY);
if (mem) {
memcpy(mem, data, dimensions.width() * dimensions.height());
GLC(context, static_cast<Extensions3DChromium*>(context->getExtensions())->unmapTexSubImage2DCHROMIUM(mem));
} else {
GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, data));
}
}
void VideoLayerChromium::releaseCurrentFrame()
{
if (!m_currentFrame)
return;
m_provider->putCurrentFrame(m_currentFrame);
m_currentFrame = 0;
resetFrameParameters();
}
void VideoLayerChromium::resetFrameParameters()
{
deleteTexturesInUse();
for (unsigned plane = 0; plane < VideoFrameChromium::maxPlanes; plane++) {
m_textures[plane].id = 0;
m_textures[plane].size = IntSize();
m_textures[plane].visibleSize = IntSize();
m_textures[plane].ownedByLayerRenderer = false;
m_textures[plane].isEmpty = true;
}
}
void VideoLayerChromium::saveCurrentFrame(VideoFrameChromium* frame)
{
ASSERT(!m_currentFrame);
deleteTexturesInUse();
m_currentFrame = frame;
for (unsigned plane = 0; plane < frame->planes(); plane++) {
m_textures[plane].id = frame->texture(plane);
m_textures[plane].size = frame->requiredTextureSize(plane);
m_textures[plane].visibleSize = computeVisibleSize(frame, plane);
m_textures[plane].ownedByLayerRenderer = false;
m_textures[plane].isEmpty = false;
}
}
}
#endif // USE(ACCELERATED_COMPOSITING)