| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "content/common/gpu/media/rendering_helper.h" |
| 6 |
| 7 #include <map> |
| 8 |
| 9 #include "base/bind.h" |
| 10 #include "base/mac/scoped_nsautorelease_pool.h" |
| 11 #include "base/message_loop.h" |
| 12 #include "base/stringize_macros.h" |
| 13 #include "base/synchronization/waitable_event.h" |
| 14 #include "third_party/angle/include/EGL/egl.h" |
| 15 |
| 16 #if defined(OS_WIN) |
| 17 #include "ui/gl/gl_bindings.h" |
| 18 #include "ui/gl/gl_context.h" |
| 19 #include "ui/gl/gl_implementation.h" |
| 20 #include "ui/gl/gl_surface.h" |
| 21 #else // OS_WIN |
| 22 #include "third_party/angle/include/GLES2/gl2.h" |
| 23 #endif // OS_WIN |
| 24 |
| 25 // Helper for Shader creation. |
| 26 static void CreateShader(GLuint program, |
| 27 GLenum type, |
| 28 const char* source, |
| 29 int size) { |
| 30 GLuint shader = glCreateShader(type); |
| 31 glShaderSource(shader, 1, &source, &size); |
| 32 glCompileShader(shader); |
| 33 int result = GL_FALSE; |
| 34 glGetShaderiv(shader, GL_COMPILE_STATUS, &result); |
| 35 if (!result) { |
| 36 char log[4096]; |
| 37 glGetShaderInfoLog(shader, arraysize(log), NULL, log); |
| 38 LOG(FATAL) << log; |
| 39 } |
| 40 glAttachShader(program, shader); |
| 41 glDeleteShader(shader); |
| 42 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 43 } |
| 44 |
| 45 namespace video_test_util { |
| 46 |
| 47 class RenderingHelperEGL : public RenderingHelper { |
| 48 public: |
| 49 RenderingHelperEGL(); |
| 50 virtual ~RenderingHelperEGL(); |
| 51 |
| 52 // Implement RenderingHelper. |
| 53 virtual void Initialize(bool suppress_swap_to_display, |
| 54 int num_windows, |
| 55 int width, |
| 56 int height, |
| 57 base::WaitableEvent* done) OVERRIDE; |
| 58 virtual void UnInitialize(base::WaitableEvent* done) OVERRIDE; |
| 59 virtual void CreateTexture(int window_id, |
| 60 uint32* texture_id, |
| 61 base::WaitableEvent* done) OVERRIDE; |
| 62 virtual void RenderTexture(uint32 texture_id) OVERRIDE; |
| 63 virtual void DeleteTexture(uint32 texture_id) OVERRIDE; |
| 64 virtual void* GetGLContext() OVERRIDE; |
| 65 virtual void* GetGLDisplay() OVERRIDE; |
| 66 |
| 67 private: |
| 68 void Clear(); |
| 69 |
| 70 // Platform specific Init/Uninit. |
| 71 void PlatformInitialize(); |
| 72 void PlatformUnInitialize(); |
| 73 |
| 74 // Platform specific window creation. |
| 75 EGLNativeWindowType PlatformCreateWindow(int top_left_x, int top_left_y); |
| 76 |
| 77 // Platform specific display surface returned here. |
| 78 EGLDisplay PlatformGetDisplay(); |
| 79 |
| 80 MessageLoop* message_loop_; |
| 81 int width_; |
| 82 int height_; |
| 83 bool suppress_swap_to_display_; |
| 84 |
| 85 EGLDisplay egl_display_; |
| 86 EGLContext egl_context_; |
| 87 std::vector<EGLSurface> egl_surfaces_; |
| 88 std::map<uint32, int> texture_id_to_surface_index_; |
| 89 |
| 90 #if defined(OS_WIN) |
| 91 std::vector<HWND> windows_; |
| 92 #else // OS_WIN |
| 93 Display* x_display_; |
| 94 std::vector<Window> x_windows_; |
| 95 #endif // OS_WIN |
| 96 }; |
| 97 |
| 98 // static |
| 99 RenderingHelper* RenderingHelper::Create() { |
| 100 return new RenderingHelperEGL; |
| 101 } |
| 102 |
| 103 // static |
| 104 void RenderingHelper::InitializePlatform() { |
| 105 #if defined(OS_WIN) |
| 106 gfx::InitializeGLBindings(gfx::kGLImplementationEGLGLES2); |
| 107 gfx::GLSurface::InitializeOneOff(); |
| 108 { |
| 109 // Hack to ensure that EGL extension function pointers are initialized. |
| 110 scoped_refptr<gfx::GLSurface> surface( |
| 111 gfx::GLSurface::CreateOffscreenGLSurface(false, gfx::Size(1, 1))); |
| 112 scoped_refptr<gfx::GLContext> context( |
| 113 gfx::GLContext::CreateGLContext(NULL, surface.get(), |
| 114 gfx::PreferIntegratedGpu)); |
| 115 context->MakeCurrent(surface.get()); |
| 116 } |
| 117 #endif // OS_WIN |
| 118 } |
| 119 |
| 120 RenderingHelperEGL::RenderingHelperEGL() { |
| 121 Clear(); |
| 122 } |
| 123 |
| 124 RenderingHelperEGL::~RenderingHelperEGL() { |
| 125 CHECK_EQ(width_, 0) << "Must call UnInitialize before dtor."; |
| 126 Clear(); |
| 127 } |
| 128 |
| 129 void RenderingHelperEGL::Initialize(bool suppress_swap_to_display, |
| 130 int num_windows, |
| 131 int width, |
| 132 int height, |
| 133 base::WaitableEvent* done) { |
| 134 // Use width_ != 0 as a proxy for the class having already been |
| 135 // Initialize()'d, and UnInitialize() before continuing. |
| 136 if (width_) { |
| 137 base::WaitableEvent done(false, false); |
| 138 UnInitialize(&done); |
| 139 done.Wait(); |
| 140 } |
| 141 |
| 142 suppress_swap_to_display_ = suppress_swap_to_display; |
| 143 CHECK_GT(width, 0); |
| 144 CHECK_GT(height, 0); |
| 145 width_ = width; |
| 146 height_ = height; |
| 147 message_loop_ = MessageLoop::current(); |
| 148 CHECK_GT(num_windows, 0); |
| 149 |
| 150 PlatformInitialize(); |
| 151 |
| 152 egl_display_ = PlatformGetDisplay(); |
| 153 |
| 154 EGLint major; |
| 155 EGLint minor; |
| 156 CHECK(eglInitialize(egl_display_, &major, &minor)) << eglGetError(); |
| 157 static EGLint rgba8888[] = { |
| 158 EGL_RED_SIZE, 8, |
| 159 EGL_GREEN_SIZE, 8, |
| 160 EGL_BLUE_SIZE, 8, |
| 161 EGL_ALPHA_SIZE, 8, |
| 162 EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| 163 EGL_NONE, |
| 164 }; |
| 165 EGLConfig egl_config; |
| 166 int num_configs; |
| 167 CHECK(eglChooseConfig(egl_display_, rgba8888, &egl_config, 1, &num_configs)) |
| 168 << eglGetError(); |
| 169 CHECK_GE(num_configs, 1); |
| 170 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; |
| 171 egl_context_ = eglCreateContext( |
| 172 egl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); |
| 173 CHECK_NE(egl_context_, EGL_NO_CONTEXT) << eglGetError(); |
| 174 |
| 175 // Per-window/surface X11 & EGL initialization. |
| 176 for (int i = 0; i < num_windows; ++i) { |
| 177 // Arrange X windows whimsically, with some padding. |
| 178 int top_left_x = (width + 20) * (i % 4); |
| 179 int top_left_y = (height + 12) * (i % 3); |
| 180 |
| 181 EGLNativeWindowType window = PlatformCreateWindow(top_left_x, top_left_y); |
| 182 EGLSurface egl_surface = |
| 183 eglCreateWindowSurface(egl_display_, egl_config, window, NULL); |
| 184 egl_surfaces_.push_back(egl_surface); |
| 185 CHECK_NE(egl_surface, EGL_NO_SURFACE); |
| 186 } |
| 187 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[0], |
| 188 egl_surfaces_[0], egl_context_)) << eglGetError(); |
| 189 |
| 190 static const float kVertices[] = |
| 191 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; |
| 192 static const float kTextureCoordsEgl[] = { 0, 1, 0, 0, 1, 1, 1, 0, }; |
| 193 static const char kVertexShader[] = STRINGIZE( |
| 194 varying vec2 interp_tc; |
| 195 attribute vec4 in_pos; |
| 196 attribute vec2 in_tc; |
| 197 void main() { |
| 198 interp_tc = in_tc; |
| 199 gl_Position = in_pos; |
| 200 }); |
| 201 static const char kFragmentShaderEgl[] = STRINGIZE( |
| 202 precision mediump float; |
| 203 varying vec2 interp_tc; |
| 204 uniform sampler2D tex; |
| 205 void main() { |
| 206 gl_FragColor = texture2D(tex, interp_tc); |
| 207 }); |
| 208 GLuint program = glCreateProgram(); |
| 209 CreateShader(program, GL_VERTEX_SHADER, |
| 210 kVertexShader, arraysize(kVertexShader)); |
| 211 CreateShader(program, GL_FRAGMENT_SHADER, |
| 212 kFragmentShaderEgl, arraysize(kFragmentShaderEgl)); |
| 213 glLinkProgram(program); |
| 214 int result = GL_FALSE; |
| 215 glGetProgramiv(program, GL_LINK_STATUS, &result); |
| 216 if (!result) { |
| 217 char log[4096]; |
| 218 glGetShaderInfoLog(program, arraysize(log), NULL, log); |
| 219 LOG(FATAL) << log; |
| 220 } |
| 221 glUseProgram(program); |
| 222 glDeleteProgram(program); |
| 223 |
| 224 glUniform1i(glGetUniformLocation(program, "tex"), 0); |
| 225 int pos_location = glGetAttribLocation(program, "in_pos"); |
| 226 glEnableVertexAttribArray(pos_location); |
| 227 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); |
| 228 int tc_location = glGetAttribLocation(program, "in_tc"); |
| 229 glEnableVertexAttribArray(tc_location); |
| 230 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, |
| 231 kTextureCoordsEgl); |
| 232 done->Signal(); |
| 233 } |
| 234 |
| 235 void RenderingHelperEGL::UnInitialize(base::WaitableEvent* done) { |
| 236 CHECK_EQ(MessageLoop::current(), message_loop_); |
| 237 CHECK(eglMakeCurrent(egl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE, |
| 238 EGL_NO_CONTEXT)) << eglGetError(); |
| 239 CHECK(eglDestroyContext(egl_display_, egl_context_)); |
| 240 for (size_t i = 0; i < egl_surfaces_.size(); ++i) |
| 241 CHECK(eglDestroySurface(egl_display_, egl_surfaces_[i])); |
| 242 CHECK(eglTerminate(egl_display_)); |
| 243 Clear(); |
| 244 done->Signal(); |
| 245 } |
| 246 |
| 247 void RenderingHelperEGL::CreateTexture(int window_id, |
| 248 uint32* texture_id, |
| 249 base::WaitableEvent* done) { |
| 250 if (MessageLoop::current() != message_loop_) { |
| 251 message_loop_->PostTask( |
| 252 FROM_HERE, |
| 253 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), |
| 254 window_id, texture_id, done)); |
| 255 return; |
| 256 } |
| 257 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], |
| 258 egl_surfaces_[window_id], egl_context_)) |
| 259 << eglGetError(); |
| 260 glGenTextures(1, texture_id); |
| 261 glBindTexture(GL_TEXTURE_2D, *texture_id); |
| 262 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height_, 0, GL_RGBA, |
| 263 GL_UNSIGNED_BYTE, NULL); |
| 264 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 265 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 266 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures. |
| 267 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 268 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 269 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 270 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
| 271 CHECK(texture_id_to_surface_index_.insert( |
| 272 std::make_pair(*texture_id, window_id)).second); |
| 273 done->Signal(); |
| 274 } |
| 275 |
| 276 void RenderingHelperEGL::RenderTexture(uint32 texture_id) { |
| 277 CHECK_EQ(MessageLoop::current(), message_loop_); |
| 278 glActiveTexture(GL_TEXTURE0); |
| 279 glBindTexture(GL_TEXTURE_2D, texture_id); |
| 280 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); |
| 281 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 282 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
| 283 if (!suppress_swap_to_display_) { |
| 284 int window_id = texture_id_to_surface_index_[texture_id]; |
| 285 CHECK(eglMakeCurrent(egl_display_, egl_surfaces_[window_id], |
| 286 egl_surfaces_[window_id], egl_context_)) |
| 287 << eglGetError(); |
| 288 eglSwapBuffers(egl_display_, egl_surfaces_[window_id]); |
| 289 } |
| 290 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
| 291 } |
| 292 |
| 293 void RenderingHelperEGL::DeleteTexture(uint32 texture_id) { |
| 294 glDeleteTextures(1, &texture_id); |
| 295 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
| 296 } |
| 297 |
| 298 void* RenderingHelperEGL::GetGLContext() { |
| 299 return egl_context_; |
| 300 } |
| 301 |
| 302 void* RenderingHelperEGL::GetGLDisplay() { |
| 303 return egl_display_; |
| 304 } |
| 305 |
| 306 void RenderingHelperEGL::Clear() { |
| 307 suppress_swap_to_display_ = false; |
| 308 width_ = 0; |
| 309 height_ = 0; |
| 310 texture_id_to_surface_index_.clear(); |
| 311 message_loop_ = NULL; |
| 312 egl_display_ = EGL_NO_DISPLAY; |
| 313 egl_context_ = EGL_NO_CONTEXT; |
| 314 egl_surfaces_.clear(); |
| 315 PlatformUnInitialize(); |
| 316 } |
| 317 |
| 318 #if defined(OS_WIN) |
| 319 void RenderingHelperEGL::PlatformInitialize() {} |
| 320 |
| 321 void RenderingHelperEGL::PlatformUnInitialize() { |
| 322 for (size_t i = 0; i < windows_.size(); ++i) { |
| 323 DestroyWindow(windows_[i]); |
| 324 } |
| 325 windows_.clear(); |
| 326 } |
| 327 |
| 328 EGLNativeWindowType RenderingHelperEGL::PlatformCreateWindow( |
| 329 int top_left_x, int top_left_y) { |
| 330 HWND window = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest", |
| 331 WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x, |
| 332 top_left_y, width_, height_, NULL, NULL, NULL, |
| 333 NULL); |
| 334 CHECK(window != NULL); |
| 335 windows_.push_back(window); |
| 336 return window; |
| 337 } |
| 338 |
| 339 EGLDisplay RenderingHelperEGL::PlatformGetDisplay() { |
| 340 return eglGetDisplay(EGL_DEFAULT_DISPLAY); |
| 341 } |
| 342 |
| 343 #else // OS_WIN |
| 344 |
| 345 void RenderingHelperEGL::PlatformInitialize() { |
| 346 CHECK(x_display_ = base::MessagePumpForUI::GetDefaultXDisplay()); |
| 347 } |
| 348 |
| 349 void RenderingHelperEGL::PlatformUnInitialize() { |
| 350 // Destroy resources acquired in Initialize, in reverse-acquisition order. |
| 351 for (size_t i = 0; i < x_windows_.size(); ++i) { |
| 352 CHECK(XUnmapWindow(x_display_, x_windows_[i])); |
| 353 CHECK(XDestroyWindow(x_display_, x_windows_[i])); |
| 354 } |
| 355 // Mimic newly created object. |
| 356 x_display_ = NULL; |
| 357 x_windows_.clear(); |
| 358 } |
| 359 |
| 360 EGLDisplay RenderingHelperEGL::PlatformGetDisplay() { |
| 361 return eglGetDisplay(x_display_); |
| 362 } |
| 363 |
| 364 EGLNativeWindowType RenderingHelperEGL::PlatformCreateWindow(int top_left_x, |
| 365 int top_left_y) { |
| 366 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_)); |
| 367 |
| 368 XSetWindowAttributes window_attributes; |
| 369 window_attributes.background_pixel = |
| 370 BlackPixel(x_display_, DefaultScreen(x_display_)); |
| 371 window_attributes.override_redirect = true; |
| 372 |
| 373 Window x_window = XCreateWindow( |
| 374 x_display_, DefaultRootWindow(x_display_), |
| 375 top_left_x, top_left_y, width_, height_, |
| 376 0 /* border width */, |
| 377 depth, CopyFromParent /* class */, CopyFromParent /* visual */, |
| 378 (CWBackPixel | CWOverrideRedirect), &window_attributes); |
| 379 x_windows_.push_back(x_window); |
| 380 XStoreName(x_display_, x_window, "VideoDecodeAcceleratorTest"); |
| 381 XSelectInput(x_display_, x_window, ExposureMask); |
| 382 XMapWindow(x_display_, x_window); |
| 383 return x_window; |
| 384 } |
| 385 |
| 386 #endif // OS_WIN |
| 387 |
| 388 } // namespace video_test_util |
| OLD | NEW |