Commit 7710e0b3 authored by lionel.g.landwerlin's avatar lionel.g.landwerlin Committed by Commit bot

gpu: media: RenderingHelper: wait for the display & window to be ready

With the display configuration now asynchronous, we can't immediately read the display size. We need to wait until the hardware is probed.

Also the VSyncProvider cannot trigger the given callback until the PlatformWindow is properly setup with the display. We need to wait for it the actually be resized.

BUG=447798
TEST=run video_decode_accelerator_unittest on freon

Review URL: https://codereview.chromium.org/835653005

Cr-Commit-Position: refs/heads/master@{#313473}
parent 1cd6baf6
......@@ -13,6 +13,7 @@
#include "base/command_line.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/strings/stringize_macros.h"
#include "base/synchronization/waitable_event.h"
#include "base/time/time.h"
......@@ -70,6 +71,30 @@ namespace content {
#if defined(USE_OZONE)
class DisplayConfiguratorObserver : public ui::DisplayConfigurator::Observer {
public:
DisplayConfiguratorObserver(base::RunLoop* loop) : loop_(loop) {}
~DisplayConfiguratorObserver() override {}
private:
// ui::DisplayConfigurator::Observer overrides:
void OnDisplayModeChanged(
const ui::DisplayConfigurator::DisplayStateList& outputs) override {
if (!loop_)
return;
loop_->Quit();
loop_ = nullptr;
}
void OnDisplayModeChangeFailed(
ui::MultipleDisplayState failed_new_state) override {
LOG(FATAL) << "Could not configure display";
}
base::RunLoop* loop_;
DISALLOW_COPY_AND_ASSIGN(DisplayConfiguratorObserver);
};
class RenderingHelper::StubOzoneDelegate : public ui::PlatformWindowDelegate {
public:
StubOzoneDelegate() : accelerated_widget_(gfx::kNullAcceleratedWidget) {
......@@ -143,7 +168,7 @@ RenderingHelper::RenderedVideo::~RenderedVideo() {
}
// static
bool RenderingHelper::InitializeOneOff() {
void RenderingHelper::InitializeOneOff(base::WaitableEvent* done) {
base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
#if GL_VARIANT_GLX
cmd_line->AppendSwitchASCII(switches::kUseGL,
......@@ -151,10 +176,10 @@ bool RenderingHelper::InitializeOneOff() {
#else
cmd_line->AppendSwitchASCII(switches::kUseGL, gfx::kGLImplementationEGLName);
#endif
#if defined(USE_OZONE)
ui::OzonePlatform::InitializeForUI();
#endif
return gfx::GLSurface::InitializeOneOff();
if (!gfx::GLSurface::InitializeOneOff())
LOG(FATAL) << "Could not initialize GL";
done->Signal();
}
RenderingHelper::RenderingHelper() {
......@@ -167,26 +192,7 @@ RenderingHelper::~RenderingHelper() {
Clear();
}
void RenderingHelper::Initialize(const RenderingHelperParams& params,
base::WaitableEvent* done) {
// Use videos_.size() != 0 as a proxy for the class having already been
// Initialize()'d, and UnInitialize() before continuing.
if (videos_.size()) {
base::WaitableEvent done(false, false);
UnInitialize(&done);
done.Wait();
}
render_task_.Reset(
base::Bind(&RenderingHelper::RenderContent, base::Unretained(this)));
frame_duration_ = params.rendering_fps > 0
? base::TimeDelta::FromSeconds(1) / params.rendering_fps
: base::TimeDelta();
render_as_thumbnails_ = params.render_as_thumbnails;
message_loop_ = base::MessageLoop::current();
void RenderingHelper::Setup() {
#if defined(OS_WIN)
window_ = CreateWindowEx(0,
L"Static",
......@@ -229,21 +235,85 @@ void RenderingHelper::Initialize(const RenderingHelperParams& params,
XSelectInput(display, window_, ExposureMask);
XMapWindow(display, window_);
#elif defined(USE_OZONE)
base::MessageLoop::ScopedNestableTaskAllower nest_loop(
base::MessageLoop::current());
base::RunLoop wait_window_resize;
platform_window_delegate_.reset(new RenderingHelper::StubOzoneDelegate());
window_ = platform_window_delegate_->accelerated_widget();
#if defined(OS_CHROMEOS)
// We hold onto the main loop here to wait for the DisplayController
// to give us the size of the display so we can create a window of
// the same size.
base::RunLoop wait_display_setup;
DisplayConfiguratorObserver display_setup_observer(&wait_display_setup);
display_configurator_.reset(new ui::DisplayConfigurator());
display_configurator_->AddObserver(&display_setup_observer);
display_configurator_->Init(true);
display_configurator_->ForceInitialConfigure(0);
// Make sure all the display configuration is applied.
wait_display_setup.Run();
display_configurator_->RemoveObserver(&display_setup_observer);
platform_window_delegate_->platform_window()->SetBounds(
gfx::Rect(display_configurator_->framebuffer_size()));
#else
platform_window_delegate_->platform_window()->SetBounds(gfx::Rect(800, 600));
#endif
// On Ozone/DRI, platform windows are associated with the physical
// outputs. Association is achieved by matching the bounds of the
// window with the origin & modeset of the display output. Until a
// window is associated with a display output, we cannot get vsync
// events, because there is no hardware to get events from. Here we
// wait for the window to resized and therefore associated with
// display output to be sure that we will get such events.
wait_window_resize.RunUntilIdle();
#else
#error unknown platform
#endif
CHECK(window_ != gfx::kNullAcceleratedWidget);
}
void RenderingHelper::TearDown() {
#if defined(OS_WIN)
if (window_)
DestroyWindow(window_);
#elif defined(USE_X11)
// Destroy resources acquired in Initialize, in reverse-acquisition order.
if (window_) {
CHECK(XUnmapWindow(gfx::GetXDisplay(), window_));
CHECK(XDestroyWindow(gfx::GetXDisplay(), window_));
}
#elif defined(USE_OZONE)
platform_window_delegate_.reset();
#if defined(OS_CHROMEOS)
display_configurator_->PrepareForExit();
display_configurator_.reset();
#endif
#endif
window_ = gfx::kNullAcceleratedWidget;
}
void RenderingHelper::Initialize(const RenderingHelperParams& params,
base::WaitableEvent* done) {
// Use videos_.size() != 0 as a proxy for the class having already been
// Initialize()'d, and UnInitialize() before continuing.
if (videos_.size()) {
base::WaitableEvent done(false, false);
UnInitialize(&done);
done.Wait();
}
render_task_.Reset(
base::Bind(&RenderingHelper::RenderContent, base::Unretained(this)));
frame_duration_ = params.rendering_fps > 0
? base::TimeDelta::FromSeconds(1) / params.rendering_fps
: base::TimeDelta();
render_as_thumbnails_ = params.render_as_thumbnails;
message_loop_ = base::MessageLoop::current();
gl_surface_ = gfx::GLSurface::CreateViewGLSurface(window_);
screen_size_ = gl_surface_->GetSize();
......@@ -429,11 +499,6 @@ void RenderingHelper::WarmUpRendering(int warm_up_iterations) {
void RenderingHelper::UnInitialize(base::WaitableEvent* done) {
CHECK_EQ(base::MessageLoop::current(), message_loop_);
#if defined(USE_OZONE) && defined(OS_CHROMEOS)
display_configurator_->PrepareForExit();
display_configurator_.reset();
#endif
render_task_.Cancel();
if (render_as_thumbnails_) {
......@@ -578,20 +643,6 @@ void RenderingHelper::Clear() {
frame_count_ = 0;
thumbnails_fbo_id_ = 0;
thumbnails_texture_id_ = 0;
#if defined(OS_WIN)
if (window_)
DestroyWindow(window_);
#elif defined(USE_X11)
// Destroy resources acquired in Initialize, in reverse-acquisition order.
if (window_) {
CHECK(XUnmapWindow(gfx::GetXDisplay(), window_));
CHECK(XDestroyWindow(gfx::GetXDisplay(), window_));
}
#elif defined(USE_OZONE)
platform_window_delegate_.reset();
#endif
window_ = gfx::kNullAcceleratedWidget;
}
void RenderingHelper::GetThumbnailsAsRGB(std::vector<unsigned char>* rgb,
......
......@@ -84,13 +84,25 @@ class RenderingHelper {
RenderingHelper();
~RenderingHelper();
static bool InitializeOneOff();
// Initialize GL. This method must be called on the rendering
// thread.
static void InitializeOneOff(base::WaitableEvent* done);
// Create the render context and windows by the specified dimensions.
// Setup the platform window to display test results. This method
// must be called on the main thread.
void Setup();
// Tear down the platform window. This method must be called on the
// main thread.
void TearDown();
// Create the render context and windows by the specified
// dimensions. This method must be called on the rendering thread.
void Initialize(const RenderingHelperParams& params,
base::WaitableEvent* done);
// Undo the effects of Initialize() and signal |*done|.
// Undo the effects of Initialize() and signal |*done|. This method
// must be called on the rendering thread.
void UnInitialize(base::WaitableEvent* done);
// Return a newly-created GLES2 texture id of the specified size, and
......
......@@ -72,6 +72,10 @@
#error The VideoAccelerator tests are not supported on this platform.
#endif // OS_WIN
#if defined(USE_OZONE)
#include "ui/ozone/public/ozone_platform.h"
#endif // defined(USE_OZONE)
using media::VideoDecodeAccelerator;
namespace content {
......@@ -115,6 +119,10 @@ int g_rendering_warm_up = 0;
// special value "0" means no override.
int g_num_play_throughs = 0;
// Environment to store rendering thread.
class VideoDecodeAcceleratorTestEnvironment;
VideoDecodeAcceleratorTestEnvironment* g_env;
// Magic constants for differentiating the reasons for NotifyResetDone being
// called.
enum ResetPoint {
......@@ -203,6 +211,34 @@ enum ClientState {
CS_MAX, // Must be last entry.
};
// Initialize the GPU thread for rendering. We only need to setup once
// for all test cases.
class VideoDecodeAcceleratorTestEnvironment : public ::testing::Environment {
public:
VideoDecodeAcceleratorTestEnvironment()
: rendering_thread_("GLRenderingVDAClientThread") {}
void SetUp() override {
rendering_thread_.Start();
base::WaitableEvent done(false, false);
rendering_thread_.task_runner()->PostTask(
FROM_HERE, base::Bind(&RenderingHelper::InitializeOneOff, &done));
done.Wait();
}
void TearDown() override { rendering_thread_.Stop(); }
scoped_refptr<base::SingleThreadTaskRunner> GetRenderingTaskRunner() const {
return rendering_thread_.task_runner();
}
private:
base::Thread rendering_thread_;
DISALLOW_COPY_AND_ASSIGN(VideoDecodeAcceleratorTestEnvironment);
};
// A helper class used to manage the lifetime of a Texture.
class TextureRef : public base::RefCounted<TextureRef> {
public:
......@@ -941,52 +977,33 @@ class VideoDecodeAcceleratorTest : public ::testing::Test {
std::vector<TestVideoFile*> test_video_files_;
RenderingHelper rendering_helper_;
scoped_refptr<base::MessageLoopProxy> rendering_loop_proxy_;
private:
base::Thread rendering_thread_;
// Required for Thread to work. Not used otherwise.
base::ShadowingAtExitManager at_exit_manager_;
DISALLOW_COPY_AND_ASSIGN(VideoDecodeAcceleratorTest);
};
VideoDecodeAcceleratorTest::VideoDecodeAcceleratorTest()
: rendering_thread_("GLRenderingVDAClientThread") {}
VideoDecodeAcceleratorTest::VideoDecodeAcceleratorTest() {
}
void VideoDecodeAcceleratorTest::SetUp() {
ParseAndReadTestVideoData(g_test_video_data, &test_video_files_);
// Initialize the rendering thread.
base::Thread::Options options;
options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
#if defined(OS_WIN) || defined(USE_OZONE)
// For windows the decoding thread initializes the media foundation decoder
// which uses COM. We need the thread to be a UI thread.
// On Ozone, the backend initializes the event system using a UI
// thread.
options.message_loop_type = base::MessageLoop::TYPE_UI;
#endif // OS_WIN || USE_OZONE
rendering_thread_.StartWithOptions(options);
rendering_loop_proxy_ = rendering_thread_.message_loop_proxy();
}
void VideoDecodeAcceleratorTest::TearDown() {
rendering_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&STLDeleteElements<std::vector<TestVideoFile*> >,
&test_video_files_));
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE, base::Bind(&STLDeleteElements<std::vector<TestVideoFile*>>,
&test_video_files_));
base::WaitableEvent done(false, false);
rendering_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&RenderingHelper::UnInitialize,
base::Unretained(&rendering_helper_),
&done));
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE, base::Bind(&RenderingHelper::UnInitialize,
base::Unretained(&rendering_helper_), &done));
done.Wait();
rendering_thread_.Stop();
rendering_helper_.TearDown();
}
void VideoDecodeAcceleratorTest::ParseAndReadTestVideoData(
......@@ -1054,23 +1071,22 @@ void VideoDecodeAcceleratorTest::UpdateTestVideoFileParams(
void VideoDecodeAcceleratorTest::InitializeRenderingHelper(
const RenderingHelperParams& helper_params) {
rendering_helper_.Setup();
base::WaitableEvent done(false, false);
rendering_loop_proxy_->PostTask(
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&RenderingHelper::Initialize,
base::Unretained(&rendering_helper_),
helper_params,
&done));
base::Unretained(&rendering_helper_), helper_params, &done));
done.Wait();
}
void VideoDecodeAcceleratorTest::CreateAndStartDecoder(
GLRenderingVDAClient* client,
ClientStateNotification<ClientState>* note) {
rendering_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&GLRenderingVDAClient::CreateAndStartDecoder,
base::Unretained(client)));
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE, base::Bind(&GLRenderingVDAClient::CreateAndStartDecoder,
base::Unretained(client)));
ASSERT_EQ(note->Wait(), CS_DECODER_SET);
}
......@@ -1084,7 +1100,7 @@ void VideoDecodeAcceleratorTest::WaitUntilDecodeFinish(
void VideoDecodeAcceleratorTest::WaitUntilIdle() {
base::WaitableEvent done(false, false);
rendering_loop_proxy_->PostTask(
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
done.Wait();
......@@ -1299,11 +1315,10 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
std::vector<unsigned char> rgb;
bool alpha_solid;
base::WaitableEvent done(false, false);
rendering_loop_proxy_->PostTask(
FROM_HERE,
base::Bind(&RenderingHelper::GetThumbnailsAsRGB,
base::Unretained(&rendering_helper_),
&rgb, &alpha_solid, &done));
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE, base::Bind(&RenderingHelper::GetThumbnailsAsRGB,
base::Unretained(&rendering_helper_), &rgb,
&alpha_solid, &done));
done.Wait();
std::vector<std::string> golden_md5s;
......@@ -1349,14 +1364,14 @@ TEST_P(VideoDecodeAcceleratorParamTest, TestSimpleDecode) {
}
}
rendering_loop_proxy_->PostTask(
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&STLDeleteElements<std::vector<GLRenderingVDAClient*> >,
base::Bind(&STLDeleteElements<std::vector<GLRenderingVDAClient*>>,
&clients));
rendering_loop_proxy_->PostTask(
g_env->GetRenderingTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&STLDeleteElements<
std::vector<ClientStateNotification<ClientState>*> >,
std::vector<ClientStateNotification<ClientState>*>>,
&notes));
WaitUntilIdle();
};
......@@ -1479,8 +1494,8 @@ TEST_F(VideoDecodeAcceleratorTest, TestDecodeTimeMedian) {
if (g_output_log != NULL)
OutputLogFile(g_output_log, output_string);
rendering_loop_proxy_->DeleteSoon(FROM_HERE, client);
rendering_loop_proxy_->DeleteSoon(FROM_HERE, note);
g_env->GetRenderingTaskRunner()->DeleteSoon(FROM_HERE, client);
g_env->GetRenderingTaskRunner()->DeleteSoon(FROM_HERE, note);
WaitUntilIdle();
};
......@@ -1548,8 +1563,24 @@ int main(int argc, char **argv) {
}
base::ShadowingAtExitManager at_exit_manager;
#if defined(OS_WIN) || defined(USE_OZONE)
// For windows the decoding thread initializes the media foundation decoder
// which uses COM. We need the thread to be a UI thread.
// On Ozone, the backend initializes the event system using a UI
// thread.
base::MessageLoopForUI main_loop;
#else
base::MessageLoop main_loop;
content::RenderingHelper::InitializeOneOff();
#endif // OS_WIN || USE_OZONE
#if defined(USE_OZONE)
ui::OzonePlatform::InitializeForUI();
#endif
content::g_env =
reinterpret_cast<content::VideoDecodeAcceleratorTestEnvironment*>(
testing::AddGlobalTestEnvironment(
new content::VideoDecodeAcceleratorTestEnvironment()));
return RUN_ALL_TESTS();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment