Index: content/common/gpu/media/avda_codec_image.cc |
diff --git a/content/common/gpu/media/avda_codec_image.cc b/content/common/gpu/media/avda_codec_image.cc |
index 6b0fa8a62658424e3b74e0e61262afb817112a5c..e0a0cb59c55a39ae0d3e8b5aae13098469fd3190 100644 |
--- a/content/common/gpu/media/avda_codec_image.cc |
+++ b/content/common/gpu/media/avda_codec_image.cc |
@@ -29,11 +29,12 @@ AVDACodecImage::AVDACodecImage( |
decoder_(decoder), |
surface_texture_(surface_texture), |
detach_surface_texture_on_destruction_(false), |
- texture_(0), |
- need_shader_info_(true), |
- texmatrix_uniform_location_(-1) { |
+ texture_(0) { |
+ // Default to a sane guess of "flip Y", just in case we can't get |
+ // the matrix on the first call. |
memset(gl_matrix_, 0, sizeof(gl_matrix_)); |
- gl_matrix_[0] = gl_matrix_[5] = gl_matrix_[10] = gl_matrix_[15] = 1.0f; |
+ gl_matrix_[0] = gl_matrix_[10] = gl_matrix_[15] = 1.0f; |
+ gl_matrix_[5] = -1.0f; |
} |
AVDACodecImage::~AVDACodecImage() {} |
@@ -61,35 +62,29 @@ bool AVDACodecImage::CopyTexImage(unsigned target) { |
if (target != GL_TEXTURE_EXTERNAL_OES) |
return false; |
- // Verify that the currently bound texture is the right one. If we're not |
- // copying to a Texture that shares our service_id, then we can't do much. |
- // This will force a copy. |
- // TODO(liberato): Fall back to a copy that uses the texture matrix. |
GLint bound_service_id = 0; |
glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); |
+ // We insist that the currently bound texture is the right one. We could |
+ // make a new glimage from a 2D image. |
if (bound_service_id != shared_state_->surface_texture_service_id()) |
return false; |
- // Attach the surface texture to our GL context if needed. |
+ // If the surface texture isn't attached yet, then attach it. Note that this |
+ // will be to the texture in |shared_state_|, because of the checks above. |
if (!shared_state_->surface_texture_is_attached()) |
AttachSurfaceTextureToContext(); |
- // Make sure that we have the right image in the front buffer. |
- UpdateSurfaceTexture(); |
- |
- InstallTextureMatrix(); |
- |
- // TODO(liberato): Handle the texture matrix properly. |
- // Either we can update the shader with it or we can move all of the logic |
- // to updateTexImage() to the right place in the cc to send it to the shader. |
- // For now, we just skip it. crbug.com/530681 |
+ // Make sure that we have the right image in the front buffer. Note that the |
+ // bound_service_id is guaranteed to be equal to the surface texture's client |
+ // texture id, so we can skip preserving it if the right context is current. |
+ UpdateSurfaceTexture(kDontRestoreBindings); |
// By setting image state to UNBOUND instead of COPIED we ensure that |
// CopyTexImage() is called each time the surface texture is used for drawing. |
// It would be nice if we could do this via asking for the currently bound |
// Texture, but the active unit never seems to change. |
- texture_->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this, |
- gpu::gles2::Texture::UNBOUND); |
+ texture_->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this, |
+ gpu::gles2::Texture::UNBOUND); |
return true; |
} |
@@ -123,11 +118,11 @@ void AVDACodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, |
uint64_t process_tracing_id, |
const std::string& dump_name) {} |
-void AVDACodecImage::UpdateSurfaceTexture() { |
+void AVDACodecImage::UpdateSurfaceTexture(RestoreBindingsMode mode) { |
DCHECK(surface_texture_); |
// Render via the media codec if needed. |
- if (codec_buffer_index_ == kInvalidCodecBufferIndex || !media_codec_) |
+ if (!IsCodecBufferOutstanding()) |
return; |
// The decoder buffer is still pending. |
@@ -142,12 +137,21 @@ void AVDACodecImage::UpdateSurfaceTexture() { |
codec_buffer_index_ = kInvalidCodecBufferIndex; |
// Swap the rendered image to the front. |
- scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; |
- if (!shared_state_->context()->IsCurrent(NULL)) { |
- scoped_make_current.reset(new ui::ScopedMakeCurrent( |
- shared_state_->context(), shared_state_->surface())); |
- } |
+ scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current = MakeCurrentIfNeeded(); |
+ |
+ // If we changed contexts, then we always want to restore it, since the caller |
+ // doesn't know that we're switching contexts. |
+ if (scoped_make_current) |
+ mode = kDoRestoreBindings; |
+ |
+ // Save the current binding if requested. |
+ GLint bound_service_id = 0; |
+ if (mode == kDoRestoreBindings) |
+ glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); |
+ |
surface_texture_->UpdateTexImage(); |
+ if (mode == kDoRestoreBindings) |
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id); |
// Helpfully, this is already column major. |
surface_texture_->GetTransformMatrix(gl_matrix_); |
@@ -176,6 +180,8 @@ void AVDACodecImage::SetTexture(gpu::gles2::Texture* texture) { |
void AVDACodecImage::AttachSurfaceTextureToContext() { |
DCHECK(surface_texture_); |
+ // We assume that the currently bound texture is the intended one. |
+ |
// Attach the surface texture to the first context we're bound on, so that |
// no context switch is needed later. |
glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
@@ -187,38 +193,48 @@ void AVDACodecImage::AttachSurfaceTextureToContext() { |
// We could do this earlier, but SurfaceTexture has context affinity, and we |
// don't want to require a context switch. |
surface_texture_->AttachToGLContext(); |
- shared_state_->did_attach_surface_texture(); |
+ shared_state_->DidAttachSurfaceTexture(); |
} |
-void AVDACodecImage::InstallTextureMatrix() { |
- DCHECK(surface_texture_); |
+scoped_ptr<ui::ScopedMakeCurrent> AVDACodecImage::MakeCurrentIfNeeded() { |
+ DCHECK(shared_state_->context()); |
+ scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; |
+ if (!shared_state_->context()->IsCurrent(NULL)) { |
+ scoped_make_current.reset(new ui::ScopedMakeCurrent( |
+ shared_state_->context(), shared_state_->surface())); |
+ } |
- // glUseProgram() has been run already -- just modify the uniform. |
- // Updating this via VideoFrameProvider::Client::DidUpdateMatrix() would |
- // be a better solution, except that we'd definitely miss a frame at this |
- // point in drawing. |
- // Our current method assumes that we'll end up being a stream resource, |
- // and that the program has a texMatrix uniform that does what we want. |
- if (need_shader_info_) { |
- GLint program_id = -1; |
- glGetIntegerv(GL_CURRENT_PROGRAM, &program_id); |
- |
- if (program_id >= 0) { |
- // This is memorized from cc/output/shader.cc . |
- const char* uniformName = "texMatrix"; |
- |
- // Within unittests this value may be -1. |
- texmatrix_uniform_location_ = |
- glGetUniformLocation(program_id, uniformName); |
- } |
+ return scoped_make_current; |
+} |
- // Only try once. |
- need_shader_info_ = false; |
+void AVDACodecImage::GetTextureMatrix(float matrix[16]) { |
+ if (IsCodecBufferOutstanding() && shared_state_ && surface_texture_) { |
+ // Our current matrix may be stale. Update it if possible. |
+ if (!shared_state_->surface_texture_is_attached()) { |
+ // Don't attach the surface texture permanently. Perhaps we should |
+ // just attach the surface texture in avda and be done with it. |
+ GLuint service_id = 0; |
+ glGenTextures(1, &service_id); |
+ GLint bound_service_id = 0; |
+ glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); |
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id); |
+ AttachSurfaceTextureToContext(); |
+ UpdateSurfaceTexture(kDontRestoreBindings); |
+ // Detach the surface texture, which deletes the generated texture. |
+ surface_texture_->DetachFromGLContext(); |
+ shared_state_->DidDetachSurfaceTexture(); |
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id); |
+ } else { |
+ // Surface texture is already attached, so just update it. |
+ UpdateSurfaceTexture(kDoRestoreBindings); |
+ } |
} |
- if (texmatrix_uniform_location_ >= 0) { |
- glUniformMatrix4fv(texmatrix_uniform_location_, 1, false, gl_matrix_); |
- } |
+ memcpy(matrix, gl_matrix_, sizeof(gl_matrix_)); |
+} |
+ |
+bool AVDACodecImage::IsCodecBufferOutstanding() const { |
+ return codec_buffer_index_ != kInvalidCodecBufferIndex && media_codec_; |
} |
} // namespace content |