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 |