Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: content/common/gpu/media/rendering_helper_egl.cc

Issue 10388108: Implement media::VideoDecodeAccelerator on Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address review comments Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/common/gpu/media/rendering_helper_egl.cc
diff --git a/content/common/gpu/media/rendering_helper_egl.cc b/content/common/gpu/media/rendering_helper_egl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..17f2173467d9021a2fe96129b991cdc3513221e3
--- /dev/null
+++ b/content/common/gpu/media/rendering_helper_egl.cc
@@ -0,0 +1,388 @@
+// Copyright (c) 2012 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 "content/common/gpu/media/rendering_helper.h"
+
+#include <map>
+
+#include "base/bind.h"
+#include "base/mac/scoped_nsautorelease_pool.h"
+#include "base/message_loop.h"
+#include "base/stringize_macros.h"
+#include "base/synchronization/waitable_event.h"
+#include "third_party/angle/include/EGL/egl.h"
+
+#if defined(OS_WIN)
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#else // OS_WIN
+#include "third_party/angle/include/GLES2/gl2.h"
+#endif // OS_WIN
+
+// Helper for Shader creation.
+static void CreateShader(GLuint program,
+ GLenum type,
+ const char* source,
+ int size) {
+ GLuint shader = glCreateShader(type);
+ glShaderSource(shader, 1, &source, &size);
+ glCompileShader(shader);
+ int result = GL_FALSE;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
+ if (!result) {
+ char log[4096];
+ glGetShaderInfoLog(shader, arraysize(log), NULL, log);
+ LOG(FATAL) << log;
+ }
+ glAttachShader(program, shader);
+ glDeleteShader(shader);
+ CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
+}
+
+namespace video_test_util {
+
+class RenderingHelperEGL : public RenderingHelper {
+ public:
+ RenderingHelperEGL();
+ virtual ~RenderingHelperEGL();
+
+ // Implement RenderingHelper.
+ virtual void Initialize(bool suppress_swap_to_display,
+ int num_windows,
+ int width,
+ int height,
+ base::WaitableEvent* done) OVERRIDE;
+ virtual void UnInitialize(base::WaitableEvent* done) OVERRIDE;
+ virtual void CreateTexture(int window_id,
+ uint32* texture_id,
+ base::WaitableEvent* done) OVERRIDE;
+ virtual void RenderTexture(uint32 texture_id) OVERRIDE;
+ virtual void DeleteTexture(uint32 texture_id) OVERRIDE;
+ virtual void* GetGLContext() OVERRIDE;
+ virtual void* GetGLDisplay() OVERRIDE;
+
+ private:
+ void Clear();
+
+ // Platform specific Init/Uninit.
+ void PlatformInitialize();
+ void PlatformUnInitialize();
+
+ // Platform specific window creation.
+ EGLNativeWindowType PlatformCreateWindow(int top_left_x, int top_left_y);
+
+ // Platform specific display surface returned here.
+ EGLDisplay PlatformGetDisplay();
+
+ MessageLoop* message_loop_;
+ int width_;
+ int height_;
+ bool suppress_swap_to_display_;
+
+ EGLDisplay egl_display_;
+ EGLContext egl_context_;
+ std::vector<EGLSurface> egl_surfaces_;
+ std::map<uint32, int> texture_id_to_surface_index_;
+
+#if defined(OS_WIN)
+ std::vector<HWND> windows_;
+#else // OS_WIN
+ Display* x_display_;
+ std::vector<Window> x_windows_;
+#endif // OS_WIN
+};
+
+// static
+RenderingHelper* RenderingHelper::Create() {
+ return new RenderingHelperEGL;
+}
+
+// static
+void RenderingHelper::InitializePlatform() {
+#if defined(OS_WIN)
+ gfx::InitializeGLBindings(gfx::kGLImplementationEGLGLES2);
+ gfx::GLSurface::InitializeOneOff();
+ {
+ // Hack to ensure that EGL extension function pointers are initialized.
+ scoped_refptr<gfx::GLSurface> surface(
+ gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1)));
+ scoped_refptr<gfx::GLContext> context(
+ gfx::GLContext::CreateGLContext(NULL, surface.get(),
+ gfx::PreferIntegratedGpu));
+ context->MakeCurrent(surface.get());
+ }
+#endif // OS_WIN
+}
+
+RenderingHelperEGL::RenderingHelperEGL() {
+ Clear();
+}
+
+RenderingHelperEGL::~RenderingHelperEGL() {
+ CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor.";
+ Clear();
+}
+
+void RenderingHelperEGL::Initialize(bool suppress_swap_to_display,
+ int num_windows,
+ int width,
+ int height,
+ base::WaitableEvent* done) {
+ // Use width_ != 0 as a proxy for the class having already been
+ // Initialize()'d, and UnInitialize() before continuing.
+ if (width_) {
+ base::WaitableEvent done(false, false);
+ UnInitialize(&done);
+ done.Wait();
+ }
+
+ suppress_swap_to_display_ = suppress_swap_to_display;
+ CHECK_GT(width, 0);
+ CHECK_GT(height, 0);
+ width_ = width;
+ height_ = height;
+ message_loop_ = MessageLoop::current();
+ CHECK_GT(num_windows, 0);
+
+ PlatformInitialize();
+
+ egl_display_ = PlatformGetDisplay();
+
+ EGLint major;
+ EGLint minor;
+ CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError();
+ static EGLint rgba8888[] = {
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_NONE,
+ };
+ EGLConfig egl_config;
+ int num_configs;
+ CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs))
+ << eglGetError();
+ CHECK_GE(num_configs, 1);
+ static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+ egl_context_ = eglCreateContext(
+ egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
+ CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError();
+
+ // Per-window/surface X11 & EGL initialization.
+ for (int i = 0; i < num_windows; ++i) {
+ // Arrange X windows whimsically, with some padding.
+ int top_left_x = (width + 20) * (i % 4);
+ int top_left_y = (height + 12) * (i % 3);
+
+ EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y);
+ EGLSurface egl_surface =
+ eglCreateWindowSurface(egl_display_, egl_config, window, NULL);
+ egl_surfaces_.push_back(egl_surface);
+ CHECK_NE(egl_surface, EGL_NO_SURFACE);
+ }
+ CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0],
+ egl_surfaces_[0], egl_context_)) << eglGetError();
+
+ static const float kVertices[] =
+ { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
+ static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
+ static const char kVertexShader[] = STRINGIZE(
+ varying vec2 interp_tc;
+ attribute vec4 in_pos;
+ attribute vec2 in_tc;
+ void main() {
+ interp_tc = in_tc;
+ gl_Position = in_pos;
+ });
+ static const char kFragmentShaderEgl[] = STRINGIZE(
+ precision mediump float;
+ varying vec2 interp_tc;
+ uniform sampler2D tex;
+ void main() {
+ gl_FragColor = texture2D(tex, interp_tc);
+ });
+ GLuint program = glCreateProgram();
+ CreateShader(program, GL_VERTEX_SHADER,
+ kVertexShader, arraysize(kVertexShader));
+ CreateShader(program, GL_FRAGMENT_SHADER,
+ kFragmentShaderEgl, arraysize(kFragmentShaderEgl));
+ glLinkProgram(program);
+ int result = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &result);
+ if (!result) {
+ char log[4096];
+ glGetShaderInfoLog(program, arraysize(log), NULL, log);
+ LOG(FATAL) << log;
+ }
+ glUseProgram(program);
+ glDeleteProgram(program);
+
+ glUniform1i(glGetUniformLocation(program, "tex"), 0);
+ int pos_location = glGetAttribLocation(program, "in_pos");
+ glEnableVertexAttribArray(pos_location);
+ glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
+ int tc_location = glGetAttribLocation(program, "in_tc");
+ glEnableVertexAttribArray(tc_location);
+ glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0,
+ kTextureCoordsEgl);
+ done->Signal();
+}
+
+void RenderingHelperEGL::UnInitialize(base::WaitableEvent* done) {
+ CHECK_EQ(MessageLoop::current(), message_loop_);
+ CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
+ EGL_NO_CONTEXT)) << eglGetError();
+ CHECK(eglDestroyContext(egl_display_, egl_context_));
+ for (size_t i = 0; i < egl_surfaces_.size(); ++i)
+ CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i]));
+ CHECK(eglTerminate(egl_display_));
+ Clear();
+ done->Signal();
+}
+
+void RenderingHelperEGL::CreateTexture(int window_id,
+ uint32* texture_id,
+ base::WaitableEvent* done) {
+ if (MessageLoop::current() != message_loop_) {
+ message_loop_->PostTask(
+ FROM_HERE,
+ base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this),
+ window_id, texture_id, done));
+ return;
+ }
+ CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
+ egl_surfaces_[window_id], egl_context_))
+ << eglGetError();
+ glGenTextures(1, texture_id);
+ glBindTexture(GL_TEXTURE_2D, *texture_id);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
+ CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
+ CHECK(texture_id_to_surface_index_.insert(
+ std::make_pair(*texture_id, window_id)).second);
+ done->Signal();
+}
+
+void RenderingHelperEGL::RenderTexture(uint32 texture_id) {
+ CHECK_EQ(MessageLoop::current(), message_loop_);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
+ CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
+ if (!suppress_swap_to_display_) {
+ int window_id = texture_id_to_surface_index_[texture_id];
+ CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id],
+ egl_surfaces_[window_id], egl_context_))
+ << eglGetError();
+ eglSwapBuffers(egl_display_, egl_surfaces_[window_id]);
+ }
+ CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
+}
+
+void RenderingHelperEGL::DeleteTexture(uint32 texture_id) {
+ glDeleteTextures(1, &texture_id);
+ CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
+}
+
+void* RenderingHelperEGL::GetGLContext() {
+ return egl_context_;
+}
+
+void* RenderingHelperEGL::GetGLDisplay() {
+ return egl_display_;
+}
+
+void RenderingHelperEGL::Clear() {
+ suppress_swap_to_display_ = false;
+ width_ = 0;
+ height_ = 0;
+ texture_id_to_surface_index_.clear();
+ message_loop_ = NULL;
+ egl_display_ = EGL_NO_DISPLAY;
+ egl_context_ = EGL_NO_CONTEXT;
+ egl_surfaces_.clear();
+ PlatformUnInitialize();
+}
+
+#if defined(OS_WIN)
+void RenderingHelperEGL::PlatformInitialize() {}
+
+void RenderingHelperEGL::PlatformUnInitialize() {
+ for (size_t i = 0; i < windows_.size(); ++i) {
+ DestroyWindow(windows_[i]);
+ }
+ windows_.clear();
+}
+
+EGLNativeWindowType RenderingHelperEGL::PlatformCreateWindow(
+ int top_left_x, int top_left_y) {
+ HWND window = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest",
+ WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x,
+ top_left_y, width_, height_, NULL, NULL, NULL,
+ NULL);
+ CHECK(window != NULL);
+ windows_.push_back(window);
+ return window;
+}
+
+EGLDisplay RenderingHelperEGL::PlatformGetDisplay() {
+ return eglGetDisplay(EGL_DEFAULT_DISPLAY);
+}
+
+#else // OS_WIN
+
+void RenderingHelperEGL::PlatformInitialize() {
+ CHECK(x_display_ = base::MessagePumpForUI::GetDefaultXDisplay());
+}
+
+void RenderingHelperEGL::PlatformUnInitialize() {
+ // Destroy resources acquired in Initialize, in reverse-acquisition order.
+ for (size_t i = 0; i < x_windows_.size(); ++i) {
+ CHECK(XUnmapWindow(x_display_, x_windows_[i]));
+ CHECK(XDestroyWindow(x_display_, x_windows_[i]));
+ }
+ // Mimic newly created object.
+ x_display_ = NULL;
+ x_windows_.clear();
+}
+
+EGLDisplay RenderingHelperEGL::PlatformGetDisplay() {
+ return eglGetDisplay(x_display_);
+}
+
+EGLNativeWindowType RenderingHelperEGL::PlatformCreateWindow(int top_left_x,
+ int top_left_y) {
+ int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
+
+ XSetWindowAttributes window_attributes;
+ window_attributes.background_pixel =
+ BlackPixel(x_display_, DefaultScreen(x_display_));
+ window_attributes.override_redirect = true;
+
+ Window x_window = XCreateWindow(
+ x_display_, DefaultRootWindow(x_display_),
+ top_left_x, top_left_y, width_, height_,
+ 0 /* border width */,
+ depth, CopyFromParent /* class */, CopyFromParent /* visual */,
+ (CWBackPixel | CWOverrideRedirect), &window_attributes);
+ x_windows_.push_back(x_window);
+ XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest");
+ XSelectInput(x_display_, x_window, ExposureMask);
+ XMapWindow(x_display_, x_window);
+ return x_window;
+}
+
+#endif // OS_WIN
+
+} // namespace video_test_util

Powered by Google App Engine
This is Rietveld 408576698