Chromium Code Reviews| 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..28090d4804b5da2dddc7cefaf22ba9c82b64a9ba 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,16 +134,14 @@ 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); |
| + glDrawBuffers(1, kColorAttachments); |
|
ncarter (slow)
2013/04/15 23:38:19
This seems unnecessary.
miu
2013/04/16 03:51:22
It probably is. I was just playing it safe. Done
|
| glBindTexture(texture_target_, src_texture); |
| SetTextureParameters( |
| @@ -195,9 +156,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 +184,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 +192,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 +232,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 +254,46 @@ 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) { |
|
ncarter (slow)
2013/04/15 23:38:19
Might be worth TRACE_EVENTING this since it should
miu
2013/04/16 03:51:22
Done. Good call.
|
| + 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); |
| + DCHECK(glGetError() == GL_NO_ERROR); |
|
ncarter (slow)
2013/04/15 23:38:19
Why DCHECK glGetError() here specifically (is this
miu
2013/04/16 03:51:22
Done. Yep. Leftover debugging cruft. I had a pr
|
| + texture_sizes_[which] = size; |
| + } |
| +} |
| + |
| +void CompositingIOSurfaceTransformer::PrepareFramebuffer() { |
| + if (!frame_buffer_) { |
| + glGenFramebuffersEXT(1, &frame_buffer_); |
| + DCHECK_NE(frame_buffer_, 0u); |
| + } |
| +} |
| + |
| } // namespace content |