initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / chromium / VideoLayerChromium.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #if USE(ACCELERATED_COMPOSITING)
34 #include "VideoLayerChromium.h"
35
36 #include "Extensions3DChromium.h"
37 #include "GraphicsContext3D.h"
38 #include "LayerRendererChromium.h"
39 #include "NotImplemented.h"
40 #include "VideoFrameChromium.h"
41 #include "VideoFrameProvider.h"
42 #include "cc/CCLayerImpl.h"
43 #include "cc/CCVideoLayerImpl.h"
44
45 namespace WebCore {
46
47 PassRefPtr<VideoLayerChromium> VideoLayerChromium::create(CCLayerDelegate* delegate,
48                                                           VideoFrameProvider* provider)
49 {
50     return adoptRef(new VideoLayerChromium(delegate, provider));
51 }
52
53 VideoLayerChromium::VideoLayerChromium(CCLayerDelegate* delegate, VideoFrameProvider* provider)
54     : LayerChromium(delegate)
55     , m_skipsDraw(true)
56     , m_frameFormat(VideoFrameChromium::Invalid)
57     , m_provider(provider)
58     , m_currentFrame(0)
59 {
60 }
61
62 VideoLayerChromium::~VideoLayerChromium()
63 {
64     cleanupResources();
65 }
66
67 PassRefPtr<CCLayerImpl> VideoLayerChromium::createCCLayerImpl()
68 {
69     return CCVideoLayerImpl::create(m_layerId);
70 }
71
72 void VideoLayerChromium::cleanupResources()
73 {
74     LayerChromium::cleanupResources();
75     for (size_t i = 0; i < 3; ++i)
76         m_textures[i].m_texture.clear();
77     releaseCurrentFrame();
78 }
79
80 void VideoLayerChromium::updateCompositorResources(GraphicsContext3D* context)
81 {
82     if (!m_contentsDirty || !m_delegate)
83         return;
84
85     ASSERT(drawsContent());
86
87     m_skipsDraw = false;
88     VideoFrameChromium* frame = m_provider->getCurrentFrame();
89     if (!frame) {
90         m_skipsDraw = true;
91         m_provider->putCurrentFrame(frame);
92         return;
93     }
94
95     m_frameFormat = frame->format();
96     GC3Denum textureFormat = determineTextureFormat(frame);
97     if (textureFormat == GraphicsContext3D::INVALID_VALUE) {
98         // FIXME: Implement other paths.
99         notImplemented();
100         m_skipsDraw = true;
101         m_provider->putCurrentFrame(frame);
102         return;
103     }
104
105     // Allocate textures for planes if they are not allocated already, or
106     // reallocate textures that are the wrong size for the frame.
107     bool texturesReserved = reserveTextures(frame, textureFormat);
108     if (!texturesReserved) {
109         m_skipsDraw = true;
110         m_provider->putCurrentFrame(frame);
111         return;
112     }
113
114     // Update texture planes.
115     for (unsigned plane = 0; plane < frame->planes(); plane++) {
116         Texture& texture = m_textures[plane];
117         ASSERT(texture.m_texture);
118         ASSERT(frame->requiredTextureSize(plane) == texture.m_texture->size());
119         updateTexture(context, texture, frame->data(plane));
120     }
121
122     m_dirtyRect.setSize(FloatSize());
123     m_contentsDirty = false;
124
125     m_provider->putCurrentFrame(frame);
126 }
127
128 void VideoLayerChromium::pushPropertiesTo(CCLayerImpl* layer)
129 {
130     LayerChromium::pushPropertiesTo(layer);
131
132     CCVideoLayerImpl* videoLayer = static_cast<CCVideoLayerImpl*>(layer);
133     videoLayer->setSkipsDraw(m_skipsDraw);
134     videoLayer->setFrameFormat(m_frameFormat);
135     for (size_t i = 0; i < 3; ++i) {
136         if (!m_textures[i].m_texture) {
137             videoLayer->setSkipsDraw(true);
138             break;
139         }
140         videoLayer->setTexture(i, m_textures[i].m_texture->textureId(), m_textures[i].m_texture->size(), m_textures[i].m_visibleSize);
141     }
142 }
143
144 void VideoLayerChromium::setLayerTreeHost(CCLayerTreeHost* host)
145 {
146     if (host && layerTreeHost() != host) {
147         for (size_t i = 0; i < 3; ++i) {
148             m_textures[i].m_visibleSize = IntSize();
149             m_textures[i].m_texture = ManagedTexture::create(host->contentsTextureManager());
150         }
151     }
152
153     LayerChromium::setLayerTreeHost(host);
154 }
155
156 GC3Denum VideoLayerChromium::determineTextureFormat(const VideoFrameChromium* frame)
157 {
158     switch (frame->format()) {
159     case VideoFrameChromium::YV12:
160     case VideoFrameChromium::YV16:
161         return GraphicsContext3D::LUMINANCE;
162     case VideoFrameChromium::RGBA:
163         return GraphicsContext3D::RGBA;
164     default:
165         break;
166     }
167     return GraphicsContext3D::INVALID_VALUE;
168 }
169
170 bool VideoLayerChromium::reserveTextures(const VideoFrameChromium* frame, GC3Denum textureFormat)
171 {
172     ASSERT(layerTreeHost());
173     ASSERT(frame);
174     ASSERT(textureFormat != GraphicsContext3D::INVALID_VALUE);
175
176     int maxTextureSize = layerTreeHost()->layerRendererCapabilities().maxTextureSize;
177
178     for (unsigned plane = 0; plane < frame->planes(); plane++) {
179         IntSize requiredTextureSize = frame->requiredTextureSize(plane);
180
181         // If the renderer cannot handle this large of a texture, return false.
182         // FIXME: Remove this test when tiled layers are implemented.
183         if (requiredTextureSize.isZero() || requiredTextureSize.width() > maxTextureSize || requiredTextureSize.height() > maxTextureSize)
184             return false;
185
186         if (!m_textures[plane].m_texture)
187             return false;
188
189         if (m_textures[plane].m_texture->size() != requiredTextureSize)
190             m_textures[plane].m_visibleSize = computeVisibleSize(frame, plane);
191
192         m_textures[plane].m_texture->reserve(requiredTextureSize, textureFormat);
193     }
194
195     return true;
196 }
197
198 IntSize VideoLayerChromium::computeVisibleSize(const VideoFrameChromium* frame, unsigned plane)
199 {
200     int visibleWidth = frame->width(plane);
201     int visibleHeight = frame->height(plane);
202     // When there are dead pixels at the edge of the texture, decrease
203     // the frame width by 1 to prevent the rightmost pixels from
204     // interpolating with the dead pixels.
205     if (frame->hasPaddingBytes(plane))
206         --visibleWidth;
207
208     // In YV12, every 2x2 square of Y values corresponds to one U and
209     // one V value. If we decrease the width of the UV plane, we must decrease the
210     // width of the Y texture by 2 for proper alignment. This must happen
211     // always, even if Y's texture does not have padding bytes.
212     if (plane == VideoFrameChromium::yPlane && frame->format() == VideoFrameChromium::YV12) {
213         if (frame->hasPaddingBytes(VideoFrameChromium::uPlane)) {
214             int originalWidth = frame->width(plane);
215             visibleWidth = originalWidth - 2;
216         }
217     }
218
219     return IntSize(visibleWidth, visibleHeight);
220 }
221
222 void VideoLayerChromium::updateTexture(GraphicsContext3D* context, Texture& texture, const void* data) const
223 {
224     ASSERT(context);
225     ASSERT(texture.m_texture);
226
227     texture.m_texture->bindTexture(context);
228
229     GC3Denum format = texture.m_texture->format();
230     IntSize dimensions = texture.m_texture->size();
231
232     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);
233     if (mem) {
234         memcpy(mem, data, dimensions.width() * dimensions.height());
235         GLC(context, static_cast<Extensions3DChromium*>(context->getExtensions())->unmapTexSubImage2DCHROMIUM(mem));
236     } else {
237         // If mapTexSubImage2DCHROMIUM fails, then do the slower texSubImage2D
238         // upload. This does twice the copies as mapTexSubImage2DCHROMIUM, one
239         // in the command buffer and another to the texture.
240         GLC(context, context->texSubImage2D(GraphicsContext3D::TEXTURE_2D, 0, 0, 0, dimensions.width(), dimensions.height(), format, GraphicsContext3D::UNSIGNED_BYTE, data));
241     }
242 }
243
244 void VideoLayerChromium::releaseCurrentFrame()
245 {
246     if (!m_currentFrame)
247         return;
248
249     m_provider->putCurrentFrame(m_currentFrame);
250     m_currentFrame = 0;
251 }
252
253 } // namespace WebCore
254
255 #endif // USE(ACCELERATED_COMPOSITING)