Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(70)

Side by Side Diff: content/common/gpu/media/avda_codec_image.cc

Issue 1963773003: Merge to M51: Various fixes to prevent playback hang on MotoX. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@2704
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/common/gpu/media/avda_codec_image.h" 5 #include "content/common/gpu/media/avda_codec_image.h"
6 6
7 #include <string.h> 7 #include <string.h>
8 8
9 #include "base/metrics/histogram_macros.h"
10 #include "content/common/gpu/media/avda_shared_state.h" 9 #include "content/common/gpu/media/avda_shared_state.h"
11 #include "gpu/command_buffer/service/context_group.h" 10 #include "gpu/command_buffer/service/context_group.h"
12 #include "gpu/command_buffer/service/context_state.h" 11 #include "gpu/command_buffer/service/context_state.h"
13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 12 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
14 #include "gpu/command_buffer/service/texture_manager.h" 13 #include "gpu/command_buffer/service/texture_manager.h"
15 #include "ui/gl/android/surface_texture.h" 14 #include "ui/gl/android/surface_texture.h"
16 #include "ui/gl/gl_context.h" 15 #include "ui/gl/gl_context.h"
17 #include "ui/gl/scoped_make_current.h" 16 #include "ui/gl/scoped_make_current.h"
18 17
19 namespace content { 18 namespace content {
20 19
21 AVDACodecImage::AVDACodecImage( 20 AVDACodecImage::AVDACodecImage(
21 int picture_buffer_id,
22 const scoped_refptr<AVDASharedState>& shared_state, 22 const scoped_refptr<AVDASharedState>& shared_state,
23 media::VideoCodecBridge* codec, 23 media::VideoCodecBridge* codec,
24 const base::WeakPtr<gpu::gles2::GLES2Decoder>& decoder, 24 const base::WeakPtr<gpu::gles2::GLES2Decoder>& decoder,
25 const scoped_refptr<gfx::SurfaceTexture>& surface_texture) 25 const scoped_refptr<gfx::SurfaceTexture>& surface_texture)
26 : shared_state_(shared_state), 26 : shared_state_(shared_state),
27 codec_buffer_index_(kInvalidCodecBufferIndex), 27 codec_buffer_index_(kInvalidCodecBufferIndex),
28 media_codec_(codec), 28 media_codec_(codec),
29 decoder_(decoder), 29 decoder_(decoder),
30 surface_texture_(surface_texture), 30 surface_texture_(surface_texture),
31 detach_surface_texture_on_destruction_(false), 31 detach_surface_texture_on_destruction_(false),
32 texture_(0) { 32 texture_(0),
33 picture_buffer_id_(picture_buffer_id) {
33 // Default to a sane guess of "flip Y", just in case we can't get 34 // Default to a sane guess of "flip Y", just in case we can't get
34 // the matrix on the first call. 35 // the matrix on the first call.
35 memset(gl_matrix_, 0, sizeof(gl_matrix_)); 36 memset(gl_matrix_, 0, sizeof(gl_matrix_));
36 gl_matrix_[0] = gl_matrix_[10] = gl_matrix_[15] = 1.0f; 37 gl_matrix_[0] = gl_matrix_[10] = gl_matrix_[15] = 1.0f;
37 gl_matrix_[5] = -1.0f; 38 gl_matrix_[5] = -1.0f;
39 shared_state_->SetImageForPicture(picture_buffer_id_, this);
38 } 40 }
39 41
40 AVDACodecImage::~AVDACodecImage() {} 42 AVDACodecImage::~AVDACodecImage() {
43 shared_state_->SetImageForPicture(picture_buffer_id_, nullptr);
44 }
41 45
42 void AVDACodecImage::Destroy(bool have_context) {} 46 void AVDACodecImage::Destroy(bool have_context) {}
43 47
44 gfx::Size AVDACodecImage::GetSize() { 48 gfx::Size AVDACodecImage::GetSize() {
45 return size_; 49 return size_;
46 } 50 }
47 51
48 unsigned AVDACodecImage::GetInternalFormat() { 52 unsigned AVDACodecImage::GetInternalFormat() {
49 return GL_RGBA; 53 return GL_RGBA;
50 } 54 }
(...skipping 19 matching lines...) Expand all
70 return false; 74 return false;
71 75
72 // If the surface texture isn't attached yet, then attach it. Note that this 76 // If the surface texture isn't attached yet, then attach it. Note that this
73 // will be to the texture in |shared_state_|, because of the checks above. 77 // will be to the texture in |shared_state_|, because of the checks above.
74 if (!shared_state_->surface_texture_is_attached()) 78 if (!shared_state_->surface_texture_is_attached())
75 AttachSurfaceTextureToContext(); 79 AttachSurfaceTextureToContext();
76 80
77 // Make sure that we have the right image in the front buffer. Note that the 81 // Make sure that we have the right image in the front buffer. Note that the
78 // bound_service_id is guaranteed to be equal to the surface texture's client 82 // bound_service_id is guaranteed to be equal to the surface texture's client
79 // texture id, so we can skip preserving it if the right context is current. 83 // texture id, so we can skip preserving it if the right context is current.
80 UpdateSurfaceTexture(kDontRestoreBindings); 84 UpdateSurfaceInternal(UpdateMode::RENDER_TO_FRONT_BUFFER,
85 kDontRestoreBindings);
81 86
82 // By setting image state to UNBOUND instead of COPIED we ensure that 87 // By setting image state to UNBOUND instead of COPIED we ensure that
83 // CopyTexImage() is called each time the surface texture is used for drawing. 88 // CopyTexImage() is called each time the surface texture is used for drawing.
84 // It would be nice if we could do this via asking for the currently bound 89 // It would be nice if we could do this via asking for the currently bound
85 // Texture, but the active unit never seems to change. 90 // Texture, but the active unit never seems to change.
86 texture_->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this, 91 texture_->SetLevelStreamTextureImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
87 gpu::gles2::Texture::UNBOUND); 92 gpu::gles2::Texture::UNBOUND);
88 93
89 return true; 94 return true;
90 } 95 }
91 96
92 bool AVDACodecImage::CopyTexSubImage(unsigned target, 97 bool AVDACodecImage::CopyTexSubImage(unsigned target,
93 const gfx::Point& offset, 98 const gfx::Point& offset,
94 const gfx::Rect& rect) { 99 const gfx::Rect& rect) {
95 return false; 100 return false;
96 } 101 }
97 102
98 bool AVDACodecImage::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 103 bool AVDACodecImage::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
99 int z_order, 104 int z_order,
100 gfx::OverlayTransform transform, 105 gfx::OverlayTransform transform,
101 const gfx::Rect& bounds_rect, 106 const gfx::Rect& bounds_rect,
102 const gfx::RectF& crop_rect) { 107 const gfx::RectF& crop_rect) {
103 // This should only be called when we're rendering to a SurfaceView. 108 // This should only be called when we're rendering to a SurfaceView.
104 if (surface_texture_) { 109 if (surface_texture_) {
105 DVLOG(1) << "Invalid call to ScheduleOverlayPlane; this image is " 110 DVLOG(1) << "Invalid call to ScheduleOverlayPlane; this image is "
106 "SurfaceTexture backed."; 111 "SurfaceTexture backed.";
107 return false; 112 return false;
108 } 113 }
109 114
110 if (codec_buffer_index_ != kInvalidCodecBufferIndex) { 115 UpdateSurface(UpdateMode::RENDER_TO_FRONT_BUFFER);
111 media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true);
112 codec_buffer_index_ = kInvalidCodecBufferIndex;
113 }
114 return true; 116 return true;
115 } 117 }
116 118
117 void AVDACodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, 119 void AVDACodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
118 uint64_t process_tracing_id, 120 uint64_t process_tracing_id,
119 const std::string& dump_name) {} 121 const std::string& dump_name) {}
120 122
121 void AVDACodecImage::UpdateSurfaceTexture(RestoreBindingsMode mode) { 123 void AVDACodecImage::UpdateSurfaceTexture(RestoreBindingsMode mode) {
122 DCHECK(surface_texture_); 124 DCHECK(surface_texture_);
123 125 DCHECK_EQ(codec_buffer_index_, kUpdateOnly);
124 // Render via the media codec if needed. 126 codec_buffer_index_ = kRendered;
125 if (!IsCodecBufferOutstanding())
126 return;
127
128 // The decoder buffer is still pending.
129 // This must be synchronous, so wait for OnFrameAvailable.
130 media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true);
131 {
132 SCOPED_UMA_HISTOGRAM_TIMER("Media.AvdaCodecImage.WaitTimeForFrame");
133 shared_state_->WaitForFrameAvailable();
134 }
135
136 // Don't bother to check if we're rendered again.
137 codec_buffer_index_ = kInvalidCodecBufferIndex;
138 127
139 // Swap the rendered image to the front. 128 // Swap the rendered image to the front.
140 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current = MakeCurrentIfNeeded(); 129 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current = MakeCurrentIfNeeded();
141 130
142 // If we changed contexts, then we always want to restore it, since the caller 131 // If we changed contexts, then we always want to restore it, since the caller
143 // doesn't know that we're switching contexts. 132 // doesn't know that we're switching contexts.
144 if (scoped_make_current) 133 if (scoped_make_current)
145 mode = kDoRestoreBindings; 134 mode = kDoRestoreBindings;
146 135
147 // Save the current binding if requested. 136 // Save the current binding if requested.
148 GLint bound_service_id = 0; 137 GLint bound_service_id = 0;
149 if (mode == kDoRestoreBindings) 138 if (mode == kDoRestoreBindings)
150 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); 139 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
151 140
152 surface_texture_->UpdateTexImage(); 141 surface_texture_->UpdateTexImage();
153 if (mode == kDoRestoreBindings) 142 if (mode == kDoRestoreBindings)
154 glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id); 143 glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id);
155 144
156 // Helpfully, this is already column major. 145 // Helpfully, this is already column major.
157 surface_texture_->GetTransformMatrix(gl_matrix_); 146 surface_texture_->GetTransformMatrix(gl_matrix_);
158 } 147 }
159 148
160 void AVDACodecImage::SetMediaCodecBufferIndex(int buffer_index) { 149 void AVDACodecImage::UpdateSurface(UpdateMode update_mode) {
161 codec_buffer_index_ = buffer_index; 150 UpdateSurfaceInternal(update_mode, kDoRestoreBindings);
162 } 151 }
163 152
164 int AVDACodecImage::GetMediaCodecBufferIndex() const { 153 void AVDACodecImage::CodecChanged(media::MediaCodecBridge* codec) {
165 return codec_buffer_index_; 154 media_codec_ = codec;
155 codec_buffer_index_ = kInvalidCodecBufferIndex;
166 } 156 }
167 157
168 void AVDACodecImage::SetSize(const gfx::Size& size) { 158 void AVDACodecImage::UpdateSurfaceInternal(
169 size_ = size; 159 UpdateMode update_mode,
160 RestoreBindingsMode attached_bindings_mode) {
161 if (!IsCodecBufferOutstanding())
162 return;
163
164 ReleaseOutputBuffer(update_mode);
165
166 // SurfaceViews are updated implicitly, so no further steps are necessary.
167 if (!surface_texture_) {
168 DCHECK(update_mode != UpdateMode::RENDER_TO_BACK_BUFFER);
169 return;
170 }
171
172 // If front buffer rendering hasn't been requested, exit early.
173 if (update_mode != UpdateMode::RENDER_TO_FRONT_BUFFER)
174 return;
175
176 // Surface texture is already attached, so just update it.
177 if (shared_state_->surface_texture_is_attached()) {
178 UpdateSurfaceTexture(attached_bindings_mode);
179 return;
180 }
181
182 // Don't attach the surface texture permanently. Perhaps we should just
183 // attach the surface texture in avda and be done with it.
184 GLuint service_id = 0;
185 glGenTextures(1, &service_id);
186 GLint bound_service_id = 0;
187 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
188 glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id);
189 AttachSurfaceTextureToContext();
190 UpdateSurfaceTexture(kDontRestoreBindings);
191
192 // Detach the surface texture, which deletes the generated texture.
193 surface_texture_->DetachFromGLContext();
194 shared_state_->DidDetachSurfaceTexture();
195 glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id);
170 } 196 }
171 197
172 void AVDACodecImage::SetMediaCodec(media::MediaCodecBridge* codec) { 198 void AVDACodecImage::ReleaseOutputBuffer(UpdateMode update_mode) {
173 media_codec_ = codec; 199 DCHECK(IsCodecBufferOutstanding());
174 }
175 200
176 void AVDACodecImage::SetTexture(gpu::gles2::Texture* texture) { 201 // In case of discard, simply discard and clear our codec buffer index.
177 texture_ = texture; 202 if (update_mode == UpdateMode::DISCARD_CODEC_BUFFER) {
203 if (codec_buffer_index_ != kUpdateOnly)
204 media_codec_->ReleaseOutputBuffer(codec_buffer_index_, false);
205
206 // Note: No need to wait for the frame to be available in the kUpdateOnly
207 // case since it will be or has been waited on by another release call.
208 codec_buffer_index_ = kInvalidCodecBufferIndex;
209 return;
210 }
211
212 DCHECK(update_mode == UpdateMode::RENDER_TO_BACK_BUFFER ||
213 update_mode == UpdateMode::RENDER_TO_FRONT_BUFFER);
214
215 if (!surface_texture_) {
216 DCHECK(update_mode == UpdateMode::RENDER_TO_FRONT_BUFFER);
217 DCHECK_GE(codec_buffer_index_, 0);
218 media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true);
219 codec_buffer_index_ = kRendered;
220 return;
221 }
222
223 // If we've already released to the back buffer, there's nothing left to do,
224 // but wait for the previously released buffer if necessary.
225 if (codec_buffer_index_ != kUpdateOnly) {
226 DCHECK(surface_texture_);
227 DCHECK_GE(codec_buffer_index_, 0);
228 shared_state_->RenderCodecBufferToSurfaceTexture(media_codec_,
229 codec_buffer_index_);
230 codec_buffer_index_ = kUpdateOnly;
231 }
232
233 // Only wait for the SurfaceTexture update if we're rendering to the front.
234 if (update_mode == UpdateMode::RENDER_TO_FRONT_BUFFER)
235 shared_state_->WaitForFrameAvailable();
178 } 236 }
179 237
180 void AVDACodecImage::AttachSurfaceTextureToContext() { 238 void AVDACodecImage::AttachSurfaceTextureToContext() {
181 DCHECK(surface_texture_); 239 DCHECK(surface_texture_);
182 240
183 // We assume that the currently bound texture is the intended one. 241 // We assume that the currently bound texture is the intended one.
184 242
185 // Attach the surface texture to the first context we're bound on, so that 243 // Attach the surface texture to the first context we're bound on, so that
186 // no context switch is needed later. 244 // no context switch is needed later.
187 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 245 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
(...skipping 13 matching lines...) Expand all
201 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; 259 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
202 if (!shared_state_->context()->IsCurrent(NULL)) { 260 if (!shared_state_->context()->IsCurrent(NULL)) {
203 scoped_make_current.reset(new ui::ScopedMakeCurrent( 261 scoped_make_current.reset(new ui::ScopedMakeCurrent(
204 shared_state_->context(), shared_state_->surface())); 262 shared_state_->context(), shared_state_->surface()));
205 } 263 }
206 264
207 return scoped_make_current; 265 return scoped_make_current;
208 } 266 }
209 267
210 void AVDACodecImage::GetTextureMatrix(float matrix[16]) { 268 void AVDACodecImage::GetTextureMatrix(float matrix[16]) {
211 if (IsCodecBufferOutstanding() && shared_state_ && surface_texture_) { 269 // Our current matrix may be stale. Update it if possible.
212 // Our current matrix may be stale. Update it if possible. 270 if (surface_texture_)
213 if (!shared_state_->surface_texture_is_attached()) { 271 UpdateSurface(UpdateMode::RENDER_TO_FRONT_BUFFER);
214 // Don't attach the surface texture permanently. Perhaps we should
215 // just attach the surface texture in avda and be done with it.
216 GLuint service_id = 0;
217 glGenTextures(1, &service_id);
218 GLint bound_service_id = 0;
219 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id);
220 glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id);
221 AttachSurfaceTextureToContext();
222 UpdateSurfaceTexture(kDontRestoreBindings);
223 // Detach the surface texture, which deletes the generated texture.
224 surface_texture_->DetachFromGLContext();
225 shared_state_->DidDetachSurfaceTexture();
226 glBindTexture(GL_TEXTURE_EXTERNAL_OES, bound_service_id);
227 } else {
228 // Surface texture is already attached, so just update it.
229 UpdateSurfaceTexture(kDoRestoreBindings);
230 }
231 }
232
233 memcpy(matrix, gl_matrix_, sizeof(gl_matrix_)); 272 memcpy(matrix, gl_matrix_, sizeof(gl_matrix_));
234 } 273 }
235 274
236 bool AVDACodecImage::IsCodecBufferOutstanding() const { 275 bool AVDACodecImage::IsCodecBufferOutstanding() const {
237 return codec_buffer_index_ != kInvalidCodecBufferIndex && media_codec_; 276 static_assert(kUpdateOnly < 0 && kUpdateOnly > kRendered &&
277 kRendered > kInvalidCodecBufferIndex,
278 "Codec buffer index enum values are not ordered correctly.");
279 return codec_buffer_index_ > kRendered && media_codec_;
238 } 280 }
239 281
240 } // namespace content 282 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/avda_codec_image.h ('k') | content/common/gpu/media/avda_shared_state.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698