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; |
-} |