| 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..37d3c6c49a01f84050978cdb37aa27fdc65f218f 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,28 +62,27 @@ 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.
|
| + // Insist that the current context is in the same share group, since we will
|
| + // only work if we're using the surface texture's client texture.
|
| + if (!IsCorrectShareGroup())
|
| + return false;
|
| +
|
| 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.
|
| @@ -123,11 +123,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 +142,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 +185,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 +198,62 @@ 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;
|
| - }
|
| +bool AVDACodecImage::GetCustomMatrix(int matrixId, float matrix[16]) {
|
| + if (matrixId != GL_CUSTOM_MATRIX_STREAM_TEXTURE_CHROMIUM)
|
| + return false;
|
|
|
| - if (texmatrix_uniform_location_ >= 0) {
|
| - glUniformMatrix4fv(texmatrix_uniform_location_, 1, false, gl_matrix_);
|
| + 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);
|
| + }
|
| }
|
| +
|
| + memcpy(matrix, gl_matrix_, sizeof(gl_matrix_));
|
| + return true;
|
| +}
|
| +
|
| +bool AVDACodecImage::IsCorrectShareGroup() const {
|
| + if (!shared_state_)
|
| + return false;
|
| +
|
| + gfx::GLContext* current_context = gfx::GLContext::GetCurrent();
|
| + if (!current_context)
|
| + return false;
|
| + return current_context->share_group() == shared_state_->share_group();
|
| +}
|
| +
|
| +bool AVDACodecImage::IsCodecBufferOutstanding() const {
|
| + return codec_buffer_index_ != kInvalidCodecBufferIndex && media_codec_;
|
| }
|
|
|
| } // namespace content
|
|
|