Respond with QuotaExceededError when IndexedDB has no disk space on open.
[chromium-blink-merge.git] / content / common / gpu / media / rendering_helper_gl.cc
blob6fedcd158f6710b640859b50c4c6c4e8ab4fc9ce
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.
5 #include "content/common/gpu/media/rendering_helper.h"
7 #include <map>
9 #include "base/bind.h"
10 #include "base/mac/scoped_nsautorelease_pool.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/stringize_macros.h"
13 #include "base/synchronization/waitable_event.h"
14 #include "ui/gl/gl_bindings.h"
15 #include "ui/gl/gl_context.h"
16 #include "ui/gl/gl_context_stub.h"
17 #include "ui/gl/gl_implementation.h"
18 #include "ui/gl/gl_surface.h"
20 #if !defined(OS_WIN) && defined(ARCH_CPU_X86_FAMILY)
21 #define GL_VARIANT_GLX 1
22 typedef GLXWindow NativeWindowType;
23 typedef GLXContext NativeContextType;
24 struct ScopedPtrXFree {
25 void operator()(void* x) const { ::XFree(x); }
27 #else
28 #define GL_VARIANT_EGL 1
29 typedef EGLNativeWindowType NativeWindowType;
30 typedef EGLContext NativeContextType;
31 typedef EGLSurface NativeSurfaceType;
32 #endif
34 // Helper for Shader creation.
35 static void CreateShader(GLuint program,
36 GLenum type,
37 const char* source,
38 int size) {
39 GLuint shader = glCreateShader(type);
40 glShaderSource(shader, 1, &source, &size);
41 glCompileShader(shader);
42 int result = GL_FALSE;
43 glGetShaderiv(shader, GL_COMPILE_STATUS, &result);
44 if (!result) {
45 char log[4096];
46 glGetShaderInfoLog(shader, arraysize(log), NULL, log);
47 LOG(FATAL) << log;
49 glAttachShader(program, shader);
50 glDeleteShader(shader);
51 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
54 namespace {
56 // Lightweight GLContext stub implementation that returns a constructed
57 // extensions string. We use this to create a context that we can use to
58 // initialize GL extensions with, without actually creating a platform context.
59 class GLContextStubWithExtensions : public gfx::GLContextStub {
60 public:
61 GLContextStubWithExtensions() {}
62 virtual std::string GetExtensions() OVERRIDE;
64 void AddExtensionsString(const char* extensions);
66 protected:
67 virtual ~GLContextStubWithExtensions() {}
69 private:
70 std::string extensions_;
72 DISALLOW_COPY_AND_ASSIGN(GLContextStubWithExtensions);
75 void GLContextStubWithExtensions::AddExtensionsString(const char* extensions) {
76 if (extensions == NULL)
77 return;
79 if (extensions_.size() != 0)
80 extensions_ += ' ';
81 extensions_ += extensions;
84 std::string GLContextStubWithExtensions::GetExtensions() {
85 return extensions_;
88 } // anonymous
90 namespace content {
92 RenderingHelperParams::RenderingHelperParams() {}
94 RenderingHelperParams::~RenderingHelperParams() {}
96 class RenderingHelperGL : public RenderingHelper {
97 public:
98 RenderingHelperGL();
99 virtual ~RenderingHelperGL();
101 // Implement RenderingHelper.
102 virtual void Initialize(const RenderingHelperParams& params,
103 base::WaitableEvent* done) OVERRIDE;
104 virtual void UnInitialize(base::WaitableEvent* done) OVERRIDE;
105 virtual void CreateTexture(int window_id,
106 uint32 texture_target,
107 uint32* texture_id,
108 base::WaitableEvent* done) OVERRIDE;
109 virtual void RenderTexture(uint32 texture_id) OVERRIDE;
110 virtual void DeleteTexture(uint32 texture_id) OVERRIDE;
111 virtual void* GetGLContext() OVERRIDE;
112 virtual void* GetGLDisplay() OVERRIDE;
113 virtual void GetThumbnailsAsRGB(std::vector<unsigned char>* rgb,
114 bool* alpha_solid,
115 base::WaitableEvent* done) OVERRIDE;
117 static const gfx::GLImplementation kGLImplementation;
119 private:
120 void Clear();
122 // Make window_id's surface current w/ the GL context, or release the context
123 // if |window_id < 0|.
124 void MakeCurrent(int window_id);
127 base::MessageLoop* message_loop_;
128 std::vector<gfx::Size> window_dimensions_;
129 std::vector<gfx::Size> frame_dimensions_;
131 NativeContextType gl_context_;
132 std::map<uint32, int> texture_id_to_surface_index_;
134 #if defined(GL_VARIANT_EGL)
135 EGLDisplay gl_display_;
136 std::vector<NativeSurfaceType> gl_surfaces_;
137 #else
138 XVisualInfo* x_visual_;
139 #endif
141 #if defined(OS_WIN)
142 std::vector<HWND> windows_;
143 #else
144 Display* x_display_;
145 std::vector<Window> x_windows_;
146 #endif
148 bool render_as_thumbnails_;
149 int frame_count_;
150 GLuint thumbnails_fbo_id_;
151 GLuint thumbnails_texture_id_;
152 gfx::Size thumbnails_fbo_size_;
153 gfx::Size thumbnail_size_;
154 GLuint program_;
157 // static
158 const gfx::GLImplementation RenderingHelperGL::kGLImplementation =
159 #if defined(GL_VARIANT_GLX)
160 gfx::kGLImplementationDesktopGL;
161 #elif defined(GL_VARIANT_EGL)
162 gfx::kGLImplementationEGLGLES2;
163 #else
165 #error "Unknown GL implementation."
166 #endif
168 // static
169 RenderingHelper* RenderingHelper::Create() {
170 return new RenderingHelperGL;
173 RenderingHelperGL::RenderingHelperGL() {
174 Clear();
177 RenderingHelperGL::~RenderingHelperGL() {
178 CHECK_EQ(window_dimensions_.size(), 0U) <<
179 "Must call UnInitialize before dtor.";
180 Clear();
183 void RenderingHelperGL::MakeCurrent(int window_id) {
184 #if GL_VARIANT_GLX
185 if (window_id < 0) {
186 CHECK(glXMakeContextCurrent(x_display_, GLX_NONE, GLX_NONE, NULL));
187 } else {
188 CHECK(glXMakeContextCurrent(
189 x_display_, x_windows_[window_id], x_windows_[window_id], gl_context_));
191 #else // EGL
192 if (window_id < 0) {
193 CHECK(eglMakeCurrent(gl_display_, EGL_NO_SURFACE, EGL_NO_SURFACE,
194 EGL_NO_CONTEXT)) << eglGetError();
195 } else {
196 CHECK(eglMakeCurrent(gl_display_, gl_surfaces_[window_id],
197 gl_surfaces_[window_id], gl_context_))
198 << eglGetError();
200 #endif
203 void RenderingHelperGL::Initialize(const RenderingHelperParams& params,
204 base::WaitableEvent* done) {
205 // Use window_dimensions_.size() != 0 as a proxy for the class having already
206 // been Initialize()'d, and UnInitialize() before continuing.
207 if (window_dimensions_.size()) {
208 base::WaitableEvent done(false, false);
209 UnInitialize(&done);
210 done.Wait();
213 gfx::InitializeGLBindings(RenderingHelperGL::kGLImplementation);
214 scoped_refptr<GLContextStubWithExtensions> stub_context(
215 new GLContextStubWithExtensions());
217 CHECK_GT(params.window_dimensions.size(), 0U);
218 CHECK_EQ(params.frame_dimensions.size(), params.window_dimensions.size());
219 window_dimensions_ = params.window_dimensions;
220 frame_dimensions_ = params.frame_dimensions;
221 render_as_thumbnails_ = params.render_as_thumbnails;
222 message_loop_ = base::MessageLoop::current();
223 CHECK_GT(params.num_windows, 0);
225 #if GL_VARIANT_GLX
226 x_display_ = base::MessagePumpForUI::GetDefaultXDisplay();
227 CHECK(x_display_);
228 CHECK(glXQueryVersion(x_display_, NULL, NULL));
229 const int fbconfig_attr[] = {
230 GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
231 GLX_RENDER_TYPE, GLX_RGBA_BIT,
232 GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
233 GLX_BIND_TO_TEXTURE_RGB_EXT, GL_TRUE,
234 GLX_DOUBLEBUFFER, True,
235 GL_NONE,
237 int num_fbconfigs;
238 scoped_ptr_malloc<GLXFBConfig, ScopedPtrXFree> glx_fb_configs(
239 glXChooseFBConfig(x_display_, DefaultScreen(x_display_), fbconfig_attr,
240 &num_fbconfigs));
241 CHECK(glx_fb_configs.get());
242 CHECK_GT(num_fbconfigs, 0);
243 x_visual_ = glXGetVisualFromFBConfig(x_display_, glx_fb_configs.get()[0]);
244 CHECK(x_visual_);
245 gl_context_ = glXCreateContext(x_display_, x_visual_, 0, true);
246 CHECK(gl_context_);
247 stub_context->AddExtensionsString(
248 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
250 #else // EGL
251 EGLNativeDisplayType native_display;
253 #if defined(OS_WIN)
254 native_display = EGL_DEFAULT_DISPLAY;
255 #else
256 x_display_ = base::MessagePumpForUI::GetDefaultXDisplay();
257 CHECK(x_display_);
258 native_display = x_display_;
259 #endif
261 gl_display_ = eglGetDisplay(native_display);
262 CHECK(gl_display_);
263 CHECK(eglInitialize(gl_display_, NULL, NULL)) << glGetError();
265 static EGLint rgba8888[] = {
266 EGL_RED_SIZE, 8,
267 EGL_GREEN_SIZE, 8,
268 EGL_BLUE_SIZE, 8,
269 EGL_ALPHA_SIZE, 8,
270 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
271 EGL_NONE,
273 EGLConfig egl_config;
274 int num_configs;
275 CHECK(eglChooseConfig(gl_display_, rgba8888, &egl_config, 1, &num_configs))
276 << eglGetError();
277 CHECK_GE(num_configs, 1);
278 static EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
279 gl_context_ = eglCreateContext(
280 gl_display_, egl_config, EGL_NO_CONTEXT, context_attribs);
281 CHECK_NE(gl_context_, EGL_NO_CONTEXT) << eglGetError();
282 stub_context->AddExtensionsString(
283 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
284 stub_context->AddExtensionsString(
285 eglQueryString(gl_display_, EGL_EXTENSIONS));
286 #endif
288 // Per-window/surface X11 & EGL initialization.
289 for (int i = 0; i < params.num_windows; ++i) {
290 // Arrange X windows whimsically, with some padding.
291 int j = i % window_dimensions_.size();
292 int width = window_dimensions_[j].width();
293 int height = window_dimensions_[j].height();
294 CHECK_GT(width, 0);
295 CHECK_GT(height, 0);
296 int top_left_x = (width + 20) * (i % 4);
297 int top_left_y = (height + 12) * (i % 3);
299 #if defined(OS_WIN)
300 NativeWindowType window =
301 CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest",
302 WS_OVERLAPPEDWINDOW | WS_VISIBLE, top_left_x,
303 top_left_y, width, height, NULL, NULL, NULL,
304 NULL);
305 CHECK(window != NULL);
306 windows_.push_back(window);
307 #else
308 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_));
310 #if defined(GL_VARIANT_GLX)
311 CHECK_EQ(depth, x_visual_->depth);
312 #endif
314 XSetWindowAttributes window_attributes;
315 window_attributes.background_pixel =
316 BlackPixel(x_display_, DefaultScreen(x_display_));
317 window_attributes.override_redirect = true;
319 NativeWindowType window = XCreateWindow(
320 x_display_, DefaultRootWindow(x_display_),
321 top_left_x, top_left_y, width, height,
322 0 /* border width */,
323 depth, CopyFromParent /* class */, CopyFromParent /* visual */,
324 (CWBackPixel | CWOverrideRedirect), &window_attributes);
325 XStoreName(x_display_, window, "VideoDecodeAcceleratorTest");
326 XSelectInput(x_display_, window, ExposureMask);
327 XMapWindow(x_display_, window);
328 x_windows_.push_back(window);
329 #endif
331 #if GL_VARIANT_EGL
332 NativeSurfaceType egl_surface =
333 eglCreateWindowSurface(gl_display_, egl_config, window, NULL);
334 gl_surfaces_.push_back(egl_surface);
335 CHECK_NE(egl_surface, EGL_NO_SURFACE);
336 #endif
337 MakeCurrent(i);
340 // Must be done after a context is made current.
341 gfx::InitializeGLExtensionBindings(kGLImplementation, stub_context.get());
343 if (render_as_thumbnails_) {
344 CHECK_EQ(window_dimensions_.size(), 1U);
346 GLint max_texture_size;
347 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
348 CHECK_GE(max_texture_size, params.thumbnails_page_size.width());
349 CHECK_GE(max_texture_size, params.thumbnails_page_size.height());
351 thumbnails_fbo_size_ = params.thumbnails_page_size;
352 thumbnail_size_ = params.thumbnail_size;
354 glGenFramebuffersEXT(1, &thumbnails_fbo_id_);
355 glGenTextures(1, &thumbnails_texture_id_);
356 glBindTexture(GL_TEXTURE_2D, thumbnails_texture_id_);
357 glTexImage2D(GL_TEXTURE_2D,
359 GL_RGB,
360 thumbnails_fbo_size_.width(),
361 thumbnails_fbo_size_.height(),
363 GL_RGB,
364 GL_UNSIGNED_SHORT_5_6_5,
365 NULL);
366 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
367 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
371 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_);
372 glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
373 GL_COLOR_ATTACHMENT0,
374 GL_TEXTURE_2D,
375 thumbnails_texture_id_,
378 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
379 CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status;
380 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
381 glClear(GL_COLOR_BUFFER_BIT);
382 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
385 // These vertices and texture coords. map (0,0) in the texture to the
386 // bottom left of the viewport. Since we get the video frames with the
387 // the top left at (0,0) we need to flip the texture y coordinate
388 // in the vertex shader for this to be rendered the right way up.
389 // In the case of thumbnail rendering we use the same vertex shader
390 // to render the FBO the screen, where we do not want this flipping.
391 static const float kVertices[] =
392 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, };
393 static const float kTextureCoords[] = { 0, 1, 0, 0, 1, 1, 1, 0, };
394 static const char kVertexShader[] = STRINGIZE(
395 varying vec2 interp_tc;
396 attribute vec4 in_pos;
397 attribute vec2 in_tc;
398 uniform bool tex_flip;
399 void main() {
400 if (tex_flip)
401 interp_tc = vec2(in_tc.x, 1.0 - in_tc.y);
402 else
403 interp_tc = in_tc;
404 gl_Position = in_pos;
407 #if GL_VARIANT_EGL
408 static const char kFragmentShader[] = STRINGIZE(
409 precision mediump float;
410 varying vec2 interp_tc;
411 uniform sampler2D tex;
412 void main() {
413 gl_FragColor = texture2D(tex, interp_tc);
415 #else
416 static const char kFragmentShader[] = STRINGIZE(
417 varying vec2 interp_tc;
418 uniform sampler2D tex;
419 void main() {
420 gl_FragColor = texture2D(tex, interp_tc);
422 #endif
423 program_ = glCreateProgram();
424 CreateShader(
425 program_, GL_VERTEX_SHADER, kVertexShader, arraysize(kVertexShader));
426 CreateShader(program_,
427 GL_FRAGMENT_SHADER,
428 kFragmentShader,
429 arraysize(kFragmentShader));
430 glLinkProgram(program_);
431 int result = GL_FALSE;
432 glGetProgramiv(program_, GL_LINK_STATUS, &result);
433 if (!result) {
434 char log[4096];
435 glGetShaderInfoLog(program_, arraysize(log), NULL, log);
436 LOG(FATAL) << log;
438 glUseProgram(program_);
439 glDeleteProgram(program_);
441 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0);
442 glUniform1i(glGetUniformLocation(program_, "tex"), 0);
443 int pos_location = glGetAttribLocation(program_, "in_pos");
444 glEnableVertexAttribArray(pos_location);
445 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
446 int tc_location = glGetAttribLocation(program_, "in_tc");
447 glEnableVertexAttribArray(tc_location);
448 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords);
449 done->Signal();
452 void RenderingHelperGL::UnInitialize(base::WaitableEvent* done) {
453 CHECK_EQ(base::MessageLoop::current(), message_loop_);
454 if (render_as_thumbnails_) {
455 glDeleteTextures(1, &thumbnails_texture_id_);
456 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_);
458 #if GL_VARIANT_GLX
460 glXDestroyContext(x_display_, gl_context_);
461 #else // EGL
462 MakeCurrent(-1);
463 CHECK(eglDestroyContext(gl_display_, gl_context_));
464 for (size_t i = 0; i < gl_surfaces_.size(); ++i)
465 CHECK(eglDestroySurface(gl_display_, gl_surfaces_[i]));
466 CHECK(eglTerminate(gl_display_));
467 #endif
468 gfx::ClearGLBindings();
469 Clear();
470 done->Signal();
473 void RenderingHelperGL::CreateTexture(int window_id,
474 uint32 texture_target,
475 uint32* texture_id,
476 base::WaitableEvent* done) {
477 if (base::MessageLoop::current() != message_loop_) {
478 message_loop_->PostTask(
479 FROM_HERE,
480 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this),
481 window_id, texture_target, texture_id, done));
482 return;
484 CHECK_EQ(static_cast<uint32>(GL_TEXTURE_2D), texture_target);
485 MakeCurrent(window_id);
486 glGenTextures(1, texture_id);
487 glBindTexture(GL_TEXTURE_2D, *texture_id);
488 int dimensions_id = window_id % frame_dimensions_.size();
489 glTexImage2D(GL_TEXTURE_2D,
491 GL_RGBA,
492 frame_dimensions_[dimensions_id].width(),
493 frame_dimensions_[dimensions_id].height(),
495 GL_RGBA,
496 GL_UNSIGNED_BYTE,
497 NULL);
498 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
499 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
500 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures.
501 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
502 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
503 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
504 CHECK(texture_id_to_surface_index_.insert(
505 std::make_pair(*texture_id, window_id)).second);
506 done->Signal();
509 void RenderingHelperGL::RenderTexture(uint32 texture_id) {
510 CHECK_EQ(base::MessageLoop::current(), message_loop_);
511 size_t window_id = texture_id_to_surface_index_[texture_id];
512 MakeCurrent(window_id);
514 int dimensions_id = window_id % window_dimensions_.size();
515 int width = window_dimensions_[dimensions_id].width();
516 int height = window_dimensions_[dimensions_id].height();
518 if (render_as_thumbnails_) {
519 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_);
520 const int thumbnails_in_row =
521 thumbnails_fbo_size_.width() / thumbnail_size_.width();
522 const int thumbnails_in_column =
523 thumbnails_fbo_size_.height() / thumbnail_size_.height();
524 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column;
525 const int col = frame_count_ % thumbnails_in_row;
526 const int x = col * thumbnail_size_.width();
527 const int y = row * thumbnail_size_.height();
529 glViewport(x, y, thumbnail_size_.width(), thumbnail_size_.height());
530 glScissor(x, y, thumbnail_size_.width(), thumbnail_size_.height());
531 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0);
532 } else {
533 glViewport(0, 0, width, height);
534 glScissor(0, 0, width, height);
535 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
538 glActiveTexture(GL_TEXTURE0);
539 glBindTexture(GL_TEXTURE_2D, texture_id);
540 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
541 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
543 ++frame_count_;
545 if (render_as_thumbnails_) {
546 // Copy from FBO to screen
547 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
548 glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
549 glViewport(0, 0, width, height);
550 glScissor(0, 0, width, height);
551 glBindTexture(GL_TEXTURE_2D, thumbnails_texture_id_);
552 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
555 #if GL_VARIANT_GLX
556 glXSwapBuffers(x_display_, x_windows_[window_id]);
557 #else // EGL
558 eglSwapBuffers(gl_display_, gl_surfaces_[window_id]);
559 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS);
560 #endif
563 void RenderingHelperGL::DeleteTexture(uint32 texture_id) {
564 glDeleteTextures(1, &texture_id);
565 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR);
568 void* RenderingHelperGL::GetGLContext() {
569 return gl_context_;
572 void* RenderingHelperGL::GetGLDisplay() {
573 #if GL_VARIANT_GLX
574 return x_display_;
575 #else // EGL
576 return gl_display_;
577 #endif
580 void RenderingHelperGL::Clear() {
581 window_dimensions_.clear();
582 frame_dimensions_.clear();
583 texture_id_to_surface_index_.clear();
584 message_loop_ = NULL;
585 gl_context_ = NULL;
586 #if GL_VARIANT_EGL
587 gl_display_ = EGL_NO_DISPLAY;
588 gl_surfaces_.clear();
589 #endif
590 render_as_thumbnails_ = false;
591 frame_count_ = 0;
592 thumbnails_fbo_id_ = 0;
593 thumbnails_texture_id_ = 0;
595 #if defined(OS_WIN)
596 for (size_t i = 0; i < windows_.size(); ++i) {
597 DestroyWindow(windows_[i]);
599 windows_.clear();
600 #else
601 // Destroy resources acquired in Initialize, in reverse-acquisition order.
602 for (size_t i = 0; i < x_windows_.size(); ++i) {
603 CHECK(XUnmapWindow(x_display_, x_windows_[i]));
604 CHECK(XDestroyWindow(x_display_, x_windows_[i]));
606 // Mimic newly created object.
607 x_display_ = NULL;
608 x_windows_.clear();
609 #endif
612 void RenderingHelperGL::GetThumbnailsAsRGB(std::vector<unsigned char>* rgb,
613 bool* alpha_solid,
614 base::WaitableEvent* done) {
615 CHECK(render_as_thumbnails_);
617 const size_t num_pixels = thumbnails_fbo_size_.GetArea();
618 std::vector<unsigned char> rgba;
619 rgba.resize(num_pixels * 4);
620 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_);
621 glPixelStorei(GL_PACK_ALIGNMENT, 1);
622 // We can only count on GL_RGBA/GL_UNSIGNED_BYTE support.
623 glReadPixels(0,
625 thumbnails_fbo_size_.width(),
626 thumbnails_fbo_size_.height(),
627 GL_RGBA,
628 GL_UNSIGNED_BYTE,
629 &rgba[0]);
630 rgb->resize(num_pixels * 3);
631 // Drop the alpha channel, but check as we go that it is all 0xff.
632 bool solid = true;
633 unsigned char* rgb_ptr = &((*rgb)[0]);
634 unsigned char* rgba_ptr = &rgba[0];
635 for (size_t i = 0; i < num_pixels; ++i) {
636 *rgb_ptr++ = *rgba_ptr++;
637 *rgb_ptr++ = *rgba_ptr++;
638 *rgb_ptr++ = *rgba_ptr++;
639 solid = solid && (*rgba_ptr == 0xff);
640 rgba_ptr++;
642 *alpha_solid = solid;
644 done->Signal();
647 } // namespace content