| Index: content/browser/renderer_host/compositing_iosurface_transformer_mac.cc
|
| diff --git a/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc b/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc
|
| index da2ba6aec2b5aa8911cad2e60b6e8257961ba3d5..2e0401ff476afacb2556bd5ba7571ae730469857 100644
|
| --- a/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc
|
| +++ b/content/browser/renderer_host/compositing_iosurface_transformer_mac.cc
|
| @@ -17,68 +17,11 @@ namespace content {
|
|
|
| namespace {
|
|
|
| -// Simple auto-delete scoping support for an owned Framebuffer object.
|
| -class ScopedFramebuffer {
|
| - public:
|
| - ScopedFramebuffer() {
|
| - glGenFramebuffersEXT(1, &name_);
|
| - }
|
| -
|
| - ~ScopedFramebuffer() {
|
| - if (name_ != 0u)
|
| - glDeleteFramebuffersEXT(1, &name_);
|
| - }
|
| -
|
| - bool is_valid() const { return name_ != 0u; }
|
| - GLuint name() const { return name_; }
|
| -
|
| - private:
|
| - GLuint name_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ScopedFramebuffer);
|
| +const GLenum kColorAttachments[] = {
|
| + GL_COLOR_ATTACHMENT0_EXT,
|
| + GL_COLOR_ATTACHMENT1_EXT
|
| };
|
|
|
| -// Simple auto-delete scoping support for an owned texture object.
|
| -class ScopedTexture {
|
| - public:
|
| - ScopedTexture() : name_(0u) {}
|
| - ScopedTexture(GLenum target, const gfx::Size& size);
|
| -
|
| - ~ScopedTexture() {
|
| - if (name_ != 0u)
|
| - glDeleteTextures(1, &name_);
|
| - }
|
| -
|
| - bool is_valid() const { return name_ != 0u; }
|
| - GLuint name() const { return name_; }
|
| -
|
| - void Reset(GLuint texture) {
|
| - if (name_ != 0u)
|
| - glDeleteTextures(1, &name_);
|
| - name_ = texture;
|
| - }
|
| -
|
| - GLuint Release() {
|
| - GLuint ret = name_;
|
| - name_ = 0u;
|
| - return ret;
|
| - }
|
| -
|
| - private:
|
| - GLuint name_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(ScopedTexture);
|
| -};
|
| -
|
| -ScopedTexture::ScopedTexture(GLenum target, const gfx::Size& size) {
|
| - glGenTextures(1, &name_);
|
| - glBindTexture(target, name_);
|
| - glTexImage2D(target, 0, GL_RGBA, size.width(), size.height(), 0, GL_BGRA,
|
| - GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
| - DCHECK(glGetError() == GL_NO_ERROR);
|
| - glBindTexture(target, 0u);
|
| -}
|
| -
|
| // Set viewport and model/projection matrices for drawing to a framebuffer of
|
| // size dst_size, with coordinates starting at (0, 0).
|
| void SetTransformationsForOffScreenRendering(const gfx::Size& dst_size) {
|
| @@ -146,11 +89,14 @@ CompositingIOSurfaceTransformer::CompositingIOSurfaceTransformer(
|
| CompositingIOSurfaceShaderPrograms* shader_program_cache)
|
| : texture_target_(texture_target),
|
| src_texture_needs_y_flip_(src_texture_needs_y_flip),
|
| - shader_program_cache_(shader_program_cache) {
|
| + shader_program_cache_(shader_program_cache),
|
| + frame_buffer_(0) {
|
| DCHECK(texture_target_ == GL_TEXTURE_RECTANGLE_ARB)
|
| << "Fragment shaders currently only support RECTANGLE textures.";
|
| DCHECK(shader_program_cache_);
|
|
|
| + memset(textures_, 0, sizeof(textures_));
|
| +
|
| // The RGB-to-YV12 transform requires that the driver/hardware supports
|
| // multiple draw buffers.
|
| GLint max_draw_buffers = 1;
|
| @@ -159,6 +105,23 @@ CompositingIOSurfaceTransformer::CompositingIOSurfaceTransformer(
|
| }
|
|
|
| CompositingIOSurfaceTransformer::~CompositingIOSurfaceTransformer() {
|
| + for (int i = 0; i < NUM_CACHED_TEXTURES; ++i)
|
| + DCHECK_EQ(textures_[i], 0u) << "Failed to call ReleaseCachedGLObjects().";
|
| + DCHECK_EQ(frame_buffer_, 0u) << "Failed to call ReleaseCachedGLObjects().";
|
| +}
|
| +
|
| +void CompositingIOSurfaceTransformer::ReleaseCachedGLObjects() {
|
| + for (int i = 0; i < NUM_CACHED_TEXTURES; ++i) {
|
| + if (textures_[i]) {
|
| + glDeleteTextures(1, &textures_[i]);
|
| + textures_[i] = 0;
|
| + texture_sizes_[i] = gfx::Size();
|
| + }
|
| + }
|
| + if (frame_buffer_) {
|
| + glDeleteFramebuffersEXT(1, &frame_buffer_);
|
| + frame_buffer_ = 0;
|
| + }
|
| }
|
|
|
| bool CompositingIOSurfaceTransformer::ResizeBilinear(
|
| @@ -171,14 +134,11 @@ bool CompositingIOSurfaceTransformer::ResizeBilinear(
|
| glDisable(GL_DEPTH_TEST);
|
| glDisable(GL_BLEND);
|
|
|
| - ScopedTexture dst_texture(texture_target_, dst_size);
|
| - if (!dst_texture.is_valid())
|
| - return false;
|
| -
|
| - ScopedFramebuffer temp_frame_buffer;
|
| - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, temp_frame_buffer.name());
|
| + PrepareTexture(RGBA_OUTPUT, dst_size);
|
| + PrepareFramebuffer();
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame_buffer_);
|
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
| - texture_target_, dst_texture.name(), 0);
|
| + texture_target_, textures_[RGBA_OUTPUT], 0);
|
| DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
|
| GL_FRAMEBUFFER_COMPLETE_EXT);
|
|
|
| @@ -195,9 +155,11 @@ bool CompositingIOSurfaceTransformer::ResizeBilinear(
|
| src_texture_needs_y_flip_,
|
| dst_size.width(), dst_size.height());
|
| glUseProgram(0);
|
| - glBindTexture(texture_target_, 0u);
|
|
|
| - *texture = dst_texture.Release();
|
| + glBindTexture(texture_target_, 0);
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
| +
|
| + *texture = textures_[RGBA_OUTPUT];
|
| return true;
|
| }
|
|
|
| @@ -221,7 +183,7 @@ bool CompositingIOSurfaceTransformer::TransformRGBToYV12(
|
| glDisable(GL_DEPTH_TEST);
|
| glDisable(GL_BLEND);
|
|
|
| - // Allocate output textures for each plane, and the temporary one for the UUVV
|
| + // Resize output textures for each plane, and for the intermediate UUVV one
|
| // that becomes an input into pass #2. |packed_y_size| is the size of the Y
|
| // output texture, where its width is 1/4 the number of Y pixels because 4 Y
|
| // pixels are packed into a single quad. |packed_uv_size| is half the size of
|
| @@ -229,36 +191,22 @@ bool CompositingIOSurfaceTransformer::TransformRGBToYV12(
|
| *packed_y_size = gfx::Size((dst_size.width() + 3) / 4, dst_size.height());
|
| *packed_uv_size = gfx::Size((packed_y_size->width() + 1) / 2,
|
| (packed_y_size->height() + 1) / 2);
|
| - ScopedTexture temp_texture_y(texture_target_, *packed_y_size);
|
| - if (!temp_texture_y.is_valid())
|
| - return false;
|
| - ScopedTexture temp_texture_u(texture_target_, *packed_uv_size);
|
| - if (!temp_texture_u.is_valid())
|
| - return false;
|
| - ScopedTexture temp_texture_v(texture_target_, *packed_uv_size);
|
| - if (!temp_texture_v.is_valid())
|
| - return false;
|
| -
|
| - // Create a temporary texture for the UUVV that becomes an input into pass #2.
|
| - ScopedTexture temp_texture_uuvv(texture_target_, *packed_y_size);
|
| - if (!temp_texture_uuvv.is_valid())
|
| - return false;
|
| -
|
| - // Create a temporary FBO for writing to the textures off-screen.
|
| - ScopedFramebuffer temp_frame_buffer;
|
| - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, temp_frame_buffer.name());
|
| + PrepareTexture(Y_PLANE_OUTPUT, *packed_y_size);
|
| + PrepareTexture(UUVV_INTERMEDIATE, *packed_y_size);
|
| + PrepareTexture(U_PLANE_OUTPUT, *packed_uv_size);
|
| + PrepareTexture(V_PLANE_OUTPUT, *packed_uv_size);
|
|
|
| /////////////////////////////////////////
|
| // Pass 1: RGB --(scaled)--> YYYY + UUVV
|
| + PrepareFramebuffer();
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, frame_buffer_);
|
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
| - texture_target_, temp_texture_y.name(), 0);
|
| + texture_target_, textures_[Y_PLANE_OUTPUT], 0);
|
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
|
| - texture_target_, temp_texture_uuvv.name(), 0);
|
| + texture_target_, textures_[UUVV_INTERMEDIATE], 0);
|
| DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
|
| GL_FRAMEBUFFER_COMPLETE_EXT);
|
| - static const GLenum kAttachments[] =
|
| - { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
|
| - glDrawBuffers(2, kAttachments);
|
| + glDrawBuffers(2, kColorAttachments);
|
|
|
| // Read from |src_texture|. Enable bilinear filtering only if scaling is
|
| // required. The filtering will take place entirely in the first pass.
|
| @@ -283,15 +231,15 @@ bool CompositingIOSurfaceTransformer::TransformRGBToYV12(
|
| /////////////////////////////////////////
|
| // Pass 2: UUVV -> UUUU + VVVV
|
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
| - texture_target_, temp_texture_u.name(), 0);
|
| + texture_target_, textures_[U_PLANE_OUTPUT], 0);
|
| glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT,
|
| - texture_target_, temp_texture_v.name(), 0);
|
| + texture_target_, textures_[V_PLANE_OUTPUT], 0);
|
| DCHECK(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) ==
|
| GL_FRAMEBUFFER_COMPLETE_EXT);
|
|
|
| - // Read from texture_uuvv. The second pass uses bilinear minification to
|
| - // achieve vertical scaling, so enable it always.
|
| - glBindTexture(texture_target_, temp_texture_uuvv.name());
|
| + // Read from the intermediate UUVV texture. The second pass uses bilinear
|
| + // minification to achieve vertical scaling, so enable it always.
|
| + glBindTexture(texture_target_, textures_[UUVV_INTERMEDIATE]);
|
| SetTextureParameters(texture_target_, GL_LINEAR, GL_CLAMP_TO_EDGE);
|
|
|
| // Use the second-pass shader program and draw the scene.
|
| @@ -305,15 +253,48 @@ bool CompositingIOSurfaceTransformer::TransformRGBToYV12(
|
| false,
|
| packed_uv_size->width(), packed_uv_size->height());
|
| glUseProgram(0);
|
| - glBindTexture(texture_target_, 0);
|
|
|
| // Before leaving, put back to drawing to a single rendering output.
|
| - glDrawBuffers(1, kAttachments);
|
| + glDrawBuffers(1, kColorAttachments);
|
|
|
| - *texture_y = temp_texture_y.Release();
|
| - *texture_u = temp_texture_u.Release();
|
| - *texture_v = temp_texture_v.Release();
|
| + glBindTexture(texture_target_, 0);
|
| + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
|
| +
|
| + *texture_y = textures_[Y_PLANE_OUTPUT];
|
| + *texture_u = textures_[U_PLANE_OUTPUT];
|
| + *texture_v = textures_[V_PLANE_OUTPUT];
|
| return true;
|
| }
|
|
|
| +void CompositingIOSurfaceTransformer::PrepareTexture(
|
| + CachedTexture which, const gfx::Size& size) {
|
| + DCHECK_GE(which, 0);
|
| + DCHECK_LT(which, NUM_CACHED_TEXTURES);
|
| + DCHECK(!size.IsEmpty());
|
| +
|
| + if (!textures_[which]) {
|
| + glGenTextures(1, &textures_[which]);
|
| + DCHECK_NE(textures_[which], 0u);
|
| + texture_sizes_[which] = gfx::Size();
|
| + }
|
| +
|
| + // Re-allocate the texture if its size has changed since last use.
|
| + if (texture_sizes_[which] != size) {
|
| + TRACE_EVENT2("gpu", "Resize Texture",
|
| + "which", which,
|
| + "new_size", size.ToString());
|
| + glBindTexture(texture_target_, textures_[which]);
|
| + glTexImage2D(texture_target_, 0, GL_RGBA, size.width(), size.height(), 0,
|
| + GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
|
| + texture_sizes_[which] = size;
|
| + }
|
| +}
|
| +
|
| +void CompositingIOSurfaceTransformer::PrepareFramebuffer() {
|
| + if (!frame_buffer_) {
|
| + glGenFramebuffersEXT(1, &frame_buffer_);
|
| + DCHECK_NE(frame_buffer_, 0u);
|
| + }
|
| +}
|
| +
|
| } // namespace content
|
|
|