OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/dxva_video_decode_accelerator.h" | 5 #include "content/common/gpu/media/dxva_video_decode_accelerator.h" |
6 | 6 |
7 #if !defined(OS_WIN) | 7 #if !defined(OS_WIN) |
8 #error This file should only be built on Windows. | 8 #error This file should only be built on Windows. |
9 #endif // !defined(OS_WIN) | 9 #endif // !defined(OS_WIN) |
10 | 10 |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
65 StopOnError(error_code); \ | 65 StopOnError(error_code); \ |
66 return ret; \ | 66 return ret; \ |
67 } \ | 67 } \ |
68 } while (0) | 68 } while (0) |
69 | 69 |
70 #define RETURN_AND_NOTIFY_ON_HR_FAILURE(result, log, error_code, ret) \ | 70 #define RETURN_AND_NOTIFY_ON_HR_FAILURE(result, log, error_code, ret) \ |
71 RETURN_AND_NOTIFY_ON_FAILURE(SUCCEEDED(result), \ | 71 RETURN_AND_NOTIFY_ON_FAILURE(SUCCEEDED(result), \ |
72 log << ", HRESULT: 0x" << std::hex << result, \ | 72 log << ", HRESULT: 0x" << std::hex << result, \ |
73 error_code, ret); | 73 error_code, ret); |
74 | 74 |
| 75 // Maximum number of iterations we allow before aborting the attempt to flush |
| 76 // the batched queries to the driver and allow torn/corrupt frames to be |
| 77 // rendered. |
| 78 enum { kMaxIterationsForD3DFlush = 10 }; |
| 79 |
75 static IMFSample* CreateEmptySample() { | 80 static IMFSample* CreateEmptySample() { |
76 base::win::ScopedComPtr<IMFSample> sample; | 81 base::win::ScopedComPtr<IMFSample> sample; |
77 HRESULT hr = MFCreateSample(sample.Receive()); | 82 HRESULT hr = MFCreateSample(sample.Receive()); |
78 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); | 83 RETURN_ON_HR_FAILURE(hr, "MFCreateSample failed", NULL); |
79 return sample.Detach(); | 84 return sample.Detach(); |
80 } | 85 } |
81 | 86 |
82 // Creates a Media Foundation sample with one buffer of length |buffer_length| | 87 // Creates a Media Foundation sample with one buffer of length |buffer_length| |
83 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. | 88 // on a |align|-byte boundary. Alignment must be a perfect power of 2 or 0. |
84 static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { | 89 static IMFSample* CreateEmptySampleWithBuffer(int buffer_length, int align) { |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 | 234 |
230 HRESULT hr = DXVAVideoDecodeAccelerator::device_->CreateTexture( | 235 HRESULT hr = DXVAVideoDecodeAccelerator::device_->CreateTexture( |
231 buffer.size().width(), | 236 buffer.size().width(), |
232 buffer.size().height(), | 237 buffer.size().height(), |
233 1, | 238 1, |
234 D3DUSAGE_RENDERTARGET, | 239 D3DUSAGE_RENDERTARGET, |
235 D3DFMT_X8R8G8B8, | 240 D3DFMT_X8R8G8B8, |
236 D3DPOOL_DEFAULT, | 241 D3DPOOL_DEFAULT, |
237 picture_buffer->decoding_texture_.Receive(), | 242 picture_buffer->decoding_texture_.Receive(), |
238 &share_handle); | 243 &share_handle); |
| 244 |
239 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", | 245 RETURN_ON_HR_FAILURE(hr, "Failed to create texture", |
240 linked_ptr<DXVAPictureBuffer>(NULL)); | 246 linked_ptr<DXVAPictureBuffer>(NULL)); |
241 return picture_buffer; | 247 return picture_buffer; |
242 } | 248 } |
243 | 249 |
244 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( | 250 DXVAVideoDecodeAccelerator::DXVAPictureBuffer::DXVAPictureBuffer( |
245 const media::PictureBuffer& buffer) | 251 const media::PictureBuffer& buffer) |
246 : available_(true), | 252 : available_(true), |
247 picture_buffer_(buffer), | 253 picture_buffer_(buffer), |
248 decoding_surface_(NULL) { | 254 decoding_surface_(NULL) { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
317 d3d_surface, | 323 d3d_surface, |
318 NULL, | 324 NULL, |
319 D3DTEXF_NONE); | 325 D3DTEXF_NONE); |
320 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", | 326 RETURN_ON_HR_FAILURE(hr, "Colorspace conversion via StretchRect failed", |
321 false); | 327 false); |
322 | 328 |
323 // Ideally, this should be done immediately before the draw call that uses | 329 // Ideally, this should be done immediately before the draw call that uses |
324 // the texture. Flush it once here though. | 330 // the texture. Flush it once here though. |
325 hr = query_->Issue(D3DISSUE_END); | 331 hr = query_->Issue(D3DISSUE_END); |
326 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); | 332 RETURN_ON_HR_FAILURE(hr, "Failed to issue END", false); |
327 do { | 333 |
328 hr = query_->GetData(NULL, 0, D3DGETDATA_FLUSH); | 334 // The DXVA decoder has its own device which it uses for decoding. ANGLE |
329 if (hr == S_FALSE) | 335 // has its own device which we don't have access to. |
330 Sleep(1); // Poor-man's Yield(). | 336 // The above code attempts to copy the decoded picture into a surface |
331 } while (hr == S_FALSE); | 337 // which is owned by ANGLE. As there are multiple devices involved in |
| 338 // this, the StretchRect call above is not synchronous. |
| 339 // We attempt to flush the batched operations to ensure that the picture is |
| 340 // copied to the surface owned by ANGLE. |
| 341 // We need to do this in a loop and call flush multiple times. |
| 342 // We have seen the GetData call for flushing the command buffer fail to |
| 343 // return success occassionally on multi core machines, leading to an |
| 344 // infinite loop. |
| 345 // Workaround is to have an upper limit of 10 on the number of iterations to |
| 346 // wait for the Flush to finish. |
| 347 int iterations = 0; |
| 348 while ((query_->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) && |
| 349 ++iterations < kMaxIterationsForD3DFlush) { |
| 350 Sleep(1); // Poor-man's Yield(). |
| 351 } |
332 eglBindTexImage( | 352 eglBindTexImage( |
333 static_cast<EGLDisplay*>(eglGetDisplay(EGL_DEFAULT_DISPLAY)), | 353 static_cast<EGLDisplay*>(eglGetDisplay(EGL_DEFAULT_DISPLAY)), |
334 decoding_surface_, | 354 decoding_surface_, |
335 EGL_BACK_BUFFER); | 355 EGL_BACK_BUFFER); |
336 | |
337 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | 356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
338 glBindTexture(GL_TEXTURE_2D, current_texture); | 357 glBindTexture(GL_TEXTURE_2D, current_texture); |
339 return true; | 358 return true; |
340 } | 359 } |
341 | 360 |
342 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( | 361 DXVAVideoDecodeAccelerator::PendingSampleInfo::PendingSampleInfo( |
343 int32 buffer_id, IMFSample* sample) | 362 int32 buffer_id, IMFSample* sample) |
344 : input_buffer_id(buffer_id) { | 363 : input_buffer_id(buffer_id) { |
345 output_sample.Attach(sample); | 364 output_sample.Attach(sample); |
346 } | 365 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
408 | 427 |
409 hr = device_manager_->ResetDevice(device_, dev_manager_reset_token_); | 428 hr = device_manager_->ResetDevice(device_, dev_manager_reset_token_); |
410 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); | 429 RETURN_ON_HR_FAILURE(hr, "Failed to reset device", false); |
411 | 430 |
412 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, &query_); | 431 hr = device_->CreateQuery(D3DQUERYTYPE_EVENT, &query_); |
413 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); | 432 RETURN_ON_HR_FAILURE(hr, "Failed to create D3D device query", false); |
414 // Ensure query_ API works (to avoid an infinite loop later in | 433 // Ensure query_ API works (to avoid an infinite loop later in |
415 // CopyOutputSampleDataToPictureBuffer). | 434 // CopyOutputSampleDataToPictureBuffer). |
416 hr = query_->Issue(D3DISSUE_END); | 435 hr = query_->Issue(D3DISSUE_END); |
417 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); | 436 RETURN_ON_HR_FAILURE(hr, "Failed to issue END test query", false); |
418 | |
419 return true; | 437 return true; |
420 } | 438 } |
421 | 439 |
422 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( | 440 DXVAVideoDecodeAccelerator::DXVAVideoDecodeAccelerator( |
423 media::VideoDecodeAccelerator::Client* client, | 441 media::VideoDecodeAccelerator::Client* client, |
424 const base::Callback<bool(void)>& make_context_current) | 442 const base::Callback<bool(void)>& make_context_current) |
425 : client_(client), | 443 : client_(client), |
426 egl_config_(NULL), | 444 egl_config_(NULL), |
427 state_(kUninitialized), | 445 state_(kUninitialized), |
428 pictures_requested_(false), | 446 pictures_requested_(false), |
(...skipping 627 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1056 return; | 1074 return; |
1057 } | 1075 } |
1058 | 1076 |
1059 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 1077 MessageLoop::current()->PostTask(FROM_HERE, base::Bind( |
1060 &DXVAVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); | 1078 &DXVAVideoDecodeAccelerator::NotifyFlushDone, base::AsWeakPtr(this))); |
1061 | 1079 |
1062 state_ = kNormal; | 1080 state_ = kNormal; |
1063 } | 1081 } |
1064 | 1082 |
1065 } // namespace content | 1083 } // namespace content |
OLD | NEW |