| Index: chrome/gpu/gpu_video_layer_glx.cc
|
| ===================================================================
|
| --- chrome/gpu/gpu_video_layer_glx.cc (revision 65168)
|
| +++ chrome/gpu/gpu_video_layer_glx.cc (working copy)
|
| @@ -1,332 +0,0 @@
|
| -// Copyright (c) 2010 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/gpu/gpu_video_layer_glx.h"
|
| -
|
| -#include "app/gfx/gl/gl_bindings.h"
|
| -#include "chrome/common/gpu_messages.h"
|
| -#include "chrome/gpu/gpu_thread.h"
|
| -#include "chrome/gpu/gpu_view_x.h"
|
| -
|
| -// Handy constants for addressing YV12 data.
|
| -static const int kYUVPlanes = 3;
|
| -static const int kYPlane = 0;
|
| -static const int kUPlane = 1;
|
| -static const int kVPlane = 2;
|
| -
|
| -// Buffer size for shader compile errors.
|
| -static const unsigned int kErrorSize = 4096;
|
| -
|
| -// Matrix used for the YUV to RGB conversion.
|
| -static const float kYUV2RGB[9] = {
|
| - 1.f, 0.f, 1.403f,
|
| - 1.f, -.344f, -.714f,
|
| - 1.f, 1.772f, 0.f,
|
| -};
|
| -
|
| -// Texture coordinates mapping the entire texture.
|
| -static const float kTextureCoords[8] = {
|
| - 0, 0,
|
| - 0, 1,
|
| - 1, 0,
|
| - 1, 1,
|
| -};
|
| -
|
| -#define I915_WORKAROUND
|
| -
|
| -// Pass-through vertex shader.
|
| -static const char kVertexShader[] =
|
| - "varying vec2 interp_tc;\n"
|
| - "\n"
|
| - "attribute vec4 in_pos;\n"
|
| - "attribute vec2 in_tc;\n"
|
| - "\n"
|
| - "void main() {\n"
|
| -#if defined(I915_WORKAROUND)
|
| - " gl_TexCoord[0].st = in_tc;\n"
|
| -#else
|
| - " interp_tc = in_tc;\n"
|
| -#endif
|
| - " gl_Position = in_pos;\n"
|
| - "}\n";
|
| -
|
| -// YUV to RGB pixel shader. Loads a pixel from each plane and pass through the
|
| -// matrix.
|
| -static const char kFragmentShader[] =
|
| - "varying vec2 interp_tc;\n"
|
| - "\n"
|
| - "uniform sampler2D y_tex;\n"
|
| - "uniform sampler2D u_tex;\n"
|
| - "uniform sampler2D v_tex;\n"
|
| - "uniform mat3 yuv2rgb;\n"
|
| - "\n"
|
| - "void main() {\n"
|
| -#if defined(I915_WORKAROUND)
|
| - " float y = texture2D(y_tex, gl_TexCoord[0].st).x;\n"
|
| - " float u = texture2D(u_tex, gl_TexCoord[0].st).r - .5;\n"
|
| - " float v = texture2D(v_tex, gl_TexCoord[0].st).r - .5;\n"
|
| - " float r = y + v * 1.403;\n"
|
| - " float g = y - u * 0.344 - v * 0.714;\n"
|
| - " float b = y + u * 1.772;\n"
|
| - " gl_FragColor = vec4(r, g, b, 1);\n"
|
| -#else
|
| - " float y = texture2D(y_tex, interp_tc).x;\n"
|
| - " float u = texture2D(u_tex, interp_tc).r - .5;\n"
|
| - " float v = texture2D(v_tex, interp_tc).r - .5;\n"
|
| - " vec3 rgb = yuv2rgb * vec3(y, u, v);\n"
|
| - " gl_FragColor = vec4(rgb, 1);\n"
|
| -#endif
|
| - "}\n";
|
| -
|
| -
|
| -// Assume that somewhere along the line, someone will do width * height * 4
|
| -// with signed numbers. If the maximum value is 2**31, then 2**31 / 4 =
|
| -// 2**29 and floor(sqrt(2**29)) = 23170.
|
| -
|
| -// Max height and width for layers
|
| -static const int kMaxVideoLayerSize = 23170;
|
| -
|
| -GpuVideoLayerGLX::GpuVideoLayerGLX(GpuViewX* view,
|
| - GpuThread* gpu_thread,
|
| - int32 routing_id,
|
| - const gfx::Size& size)
|
| - : view_(view),
|
| - gpu_thread_(gpu_thread),
|
| - routing_id_(routing_id),
|
| - native_size_(size),
|
| - program_(0) {
|
| - memset(textures_, 0, sizeof(textures_));
|
| -
|
| - // Load identity vertices.
|
| - gfx::Rect identity(0, 0, 1, 1);
|
| - CalculateVertices(identity.size(), identity, target_vertices_);
|
| -
|
| - gpu_thread_->AddRoute(routing_id_, this);
|
| -
|
| - view_->BindContext(); // Must do this before issuing OpenGl.
|
| -
|
| - // TODO(apatrick): These functions are not available in GLES2.
|
| - // glMatrixMode(GL_MODELVIEW);
|
| -
|
| - // Create 3 textures, one for each plane, and bind them to different
|
| - // texture units.
|
| - glGenTextures(kYUVPlanes, textures_);
|
| -
|
| - glBindTexture(GL_TEXTURE_2D, textures_[kYPlane]);
|
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
| -
|
| - glBindTexture(GL_TEXTURE_2D, textures_[kUPlane]);
|
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
| -
|
| - glBindTexture(GL_TEXTURE_2D, textures_[kVPlane]);
|
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
| -
|
| - // Create our YUV->RGB shader.
|
| - program_ = glCreateProgram();
|
| - GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
|
| - const char* vs_source = kVertexShader;
|
| - int vs_size = sizeof(kVertexShader);
|
| - glShaderSource(vertex_shader, 1, &vs_source, &vs_size);
|
| - glCompileShader(vertex_shader);
|
| - int result = GL_FALSE;
|
| - glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &result);
|
| - if (!result) {
|
| - char log[kErrorSize];
|
| - int len;
|
| - glGetShaderInfoLog(vertex_shader, kErrorSize - 1, &len, log);
|
| - log[kErrorSize - 1] = 0;
|
| - LOG(FATAL) << log;
|
| - }
|
| - glAttachShader(program_, vertex_shader);
|
| - glDeleteShader(vertex_shader);
|
| -
|
| - GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
|
| - const char* ps_source = kFragmentShader;
|
| - int ps_size = sizeof(kFragmentShader);
|
| - glShaderSource(fragment_shader, 1, &ps_source, &ps_size);
|
| - glCompileShader(fragment_shader);
|
| - result = GL_FALSE;
|
| - glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &result);
|
| - if (!result) {
|
| - char log[kErrorSize];
|
| - int len;
|
| - glGetShaderInfoLog(fragment_shader, kErrorSize - 1, &len, log);
|
| - log[kErrorSize - 1] = 0;
|
| - LOG(FATAL) << log;
|
| - }
|
| - glAttachShader(program_, fragment_shader);
|
| - glDeleteShader(fragment_shader);
|
| -
|
| - glLinkProgram(program_);
|
| - result = GL_FALSE;
|
| - glGetProgramiv(program_, GL_LINK_STATUS, &result);
|
| - if (!result) {
|
| - char log[kErrorSize];
|
| - int len;
|
| - glGetProgramInfoLog(program_, kErrorSize - 1, &len, log);
|
| - log[kErrorSize - 1] = 0;
|
| - LOG(FATAL) << log;
|
| - }
|
| -}
|
| -
|
| -GpuVideoLayerGLX::~GpuVideoLayerGLX() {
|
| - // TODO(scherkus): this seems like a bad idea.. we might be better off with
|
| - // separate Initialize()/Teardown() calls instead.
|
| - view_->BindContext();
|
| - if (program_) {
|
| - glDeleteProgram(program_);
|
| - }
|
| -
|
| - gpu_thread_->RemoveRoute(routing_id_);
|
| -}
|
| -
|
| -void GpuVideoLayerGLX::Render(const gfx::Size& viewport_size) {
|
| - // Nothing to do if we're not visible or have no YUV data.
|
| - if (target_rect_.IsEmpty()) {
|
| - return;
|
| - }
|
| -
|
| - // Calculate the position of our quad.
|
| - CalculateVertices(viewport_size, target_rect_, target_vertices_);
|
| -
|
| - // Bind Y, U and V textures to texture units.
|
| - glActiveTexture(GL_TEXTURE0);
|
| - glBindTexture(GL_TEXTURE_2D, textures_[kYPlane]);
|
| - glActiveTexture(GL_TEXTURE1);
|
| - glBindTexture(GL_TEXTURE_2D, textures_[kUPlane]);
|
| - glActiveTexture(GL_TEXTURE2);
|
| - glBindTexture(GL_TEXTURE_2D, textures_[kVPlane]);
|
| -
|
| - // Bind vertex/fragment shader program.
|
| - glUseProgram(program_);
|
| -
|
| - // Bind parameters.
|
| - glUniform1i(glGetUniformLocation(program_, "y_tex"), 0);
|
| - glUniform1i(glGetUniformLocation(program_, "u_tex"), 1);
|
| - glUniform1i(glGetUniformLocation(program_, "v_tex"), 2);
|
| -
|
| -#if !defined(I915_WORKAROUND)
|
| - int yuv2rgb_location = glGetUniformLocation(program_, "yuv2rgb");
|
| - glUniformMatrix3fv(yuv2rgb_location, 1, GL_TRUE, kYUV2RGB);
|
| -#endif
|
| -
|
| - // TODO(scherkus): instead of calculating and loading a geometry each time,
|
| - // we should store a constant geometry in a VBO and use a vertex shader.
|
| - int pos_location = glGetAttribLocation(program_, "in_pos");
|
| - glEnableVertexAttribArray(pos_location);
|
| - glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0,
|
| - target_vertices_);
|
| -
|
| - int tc_location = glGetAttribLocation(program_, "in_tc");
|
| - glEnableVertexAttribArray(tc_location);
|
| - glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
|
| - kTextureCoords);
|
| -
|
| - // Render!
|
| - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
| -
|
| - // Reset back to original state.
|
| - glDisableVertexAttribArray(pos_location);
|
| - glDisableVertexAttribArray(tc_location);
|
| - glActiveTexture(GL_TEXTURE0);
|
| - glUseProgram(0);
|
| -}
|
| -
|
| -void GpuVideoLayerGLX::OnMessageReceived(const IPC::Message& msg) {
|
| - IPC_BEGIN_MESSAGE_MAP(GpuVideoLayerGLX, msg)
|
| - IPC_MESSAGE_HANDLER(GpuMsg_PaintToVideoLayer, OnPaintToVideoLayer)
|
| - IPC_END_MESSAGE_MAP_EX()
|
| -}
|
| -
|
| -void GpuVideoLayerGLX::OnChannelConnected(int32 peer_pid) {
|
| -}
|
| -
|
| -void GpuVideoLayerGLX::OnChannelError() {
|
| - // FIXME(brettw) does this mean we aren't getting any more messages and we
|
| - // should delete outselves?
|
| - NOTIMPLEMENTED();
|
| -}
|
| -
|
| -void GpuVideoLayerGLX::OnPaintToVideoLayer(base::ProcessId source_process_id,
|
| - TransportDIB::Id id,
|
| - const gfx::Rect& bitmap_rect) {
|
| - // TODO(scherkus): |native_size_| is set in constructor, so perhaps this check
|
| - // should be a DCHECK().
|
| - const int width = native_size_.width();
|
| - const int height = native_size_.height();
|
| - const int stride = width;
|
| -
|
| - if (width <= 0 || width > kMaxVideoLayerSize ||
|
| - height <= 0 || height > kMaxVideoLayerSize)
|
| - return;
|
| -
|
| - TransportDIB* dib = TransportDIB::Map(id);
|
| - if (!dib)
|
| - return;
|
| -
|
| - // Everything looks good, update our target position and size.
|
| - target_rect_ = bitmap_rect;
|
| -
|
| - // Perform colour space conversion.
|
| - uint8* planes[kYUVPlanes];
|
| - planes[kYPlane] = reinterpret_cast<uint8*>(dib->memory());
|
| - planes[kUPlane] = planes[kYPlane] + width * height;
|
| - planes[kVPlane] = planes[kUPlane] + ((width * height) >> 2);
|
| -
|
| - view_->BindContext(); // Must do this before issuing OpenGl.
|
| -
|
| - // Assume YV12 format.
|
| - for (int i = 0; i < kYUVPlanes; ++i) {
|
| - int plane_width = (i == kYPlane ? width : width / 2);
|
| - int plane_height = (i == kYPlane ? height : height / 2);
|
| - int plane_stride = (i == kYPlane ? stride : stride / 2);
|
| -
|
| - // Ensure that we will not read outside the shared mem region.
|
| - if (planes[i] >= planes[kYPlane] &&
|
| - (dib->size() - (planes[kYPlane] - planes[i])) >=
|
| - static_cast<unsigned int>(plane_width * plane_height)) {
|
| - glActiveTexture(GL_TEXTURE0 + i);
|
| - glBindTexture(GL_TEXTURE_2D, textures_[i]);
|
| - glPixelStorei(GL_UNPACK_ROW_LENGTH, plane_stride);
|
| - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, plane_width, plane_height, 0,
|
| - GL_LUMINANCE, GL_UNSIGNED_BYTE, planes[i]);
|
| - }
|
| - }
|
| -
|
| - // Reset back to original state.
|
| - glActiveTexture(GL_TEXTURE0);
|
| - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
| - glFlush();
|
| -
|
| - // TODO(scherkus): we may not need to ACK video layer updates at all.
|
| - gpu_thread_->Send(new GpuHostMsg_PaintToVideoLayer_ACK(routing_id_));
|
| -}
|
| -
|
| -// static
|
| -void GpuVideoLayerGLX::CalculateVertices(const gfx::Size& world,
|
| - const gfx::Rect& object,
|
| - float* vertices) {
|
| - // Don't forget GL has a flipped Y-axis!
|
| - float width = world.width();
|
| - float height = world.height();
|
| -
|
| - // Top left.
|
| - vertices[0] = 2.0f * (object.x() / width) - 1.0f;
|
| - vertices[1] = -2.0f * (object.y() / height) + 1.0f;
|
| -
|
| - // Bottom left.
|
| - vertices[2] = 2.0f * (object.x() / width) - 1.0f;
|
| - vertices[3] = -2.0f * (object.bottom() / height) + 1.0f;
|
| -
|
| - // Top right.
|
| - vertices[4] = 2.0f * (object.right() / width) - 1.0f;
|
| - vertices[5] = -2.0f * (object.y() / height) + 1.0f;
|
| -
|
| - // Bottom right.
|
| - vertices[6] = 2.0f * (object.right() / width) - 1.0f;
|
| - vertices[7] = -2.0f * (object.bottom() / height) + 1.0f;
|
| -}
|
|
|