GPU workaround to simulate Out of Memory errors with large textures
[chromium-blink-merge.git] / content / common / gpu / client / gpu_video_decode_accelerator_host.cc
blobcef83f6f0825e3f98d786f7e36c559fa83f99f7e
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
3 // found in the LICENSE file.
5 #include "content/common/gpu/client/gpu_video_decode_accelerator_host.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/message_loop/message_loop.h"
10 #include "content/common/gpu/client/gpu_channel_host.h"
11 #include "content/common/gpu/gpu_messages.h"
12 #include "content/common/view_messages.h"
13 #include "ipc/ipc_message_macros.h"
14 #include "ipc/ipc_message_utils.h"
16 #if defined(OS_WIN)
17 #include "content/public/common/sandbox_init.h"
18 #endif // OS_WIN
20 using media::VideoDecodeAccelerator;
21 namespace content {
23 GpuVideoDecodeAcceleratorHost::GpuVideoDecodeAcceleratorHost(
24 GpuChannelHost* channel,
25 CommandBufferProxyImpl* impl)
26 : channel_(channel),
27 decoder_route_id_(MSG_ROUTING_NONE),
28 client_(NULL),
29 impl_(impl),
30 weak_this_factory_(this) {
31 DCHECK(channel_);
32 DCHECK(impl_);
33 impl_->AddDeletionObserver(this);
36 GpuVideoDecodeAcceleratorHost::~GpuVideoDecodeAcceleratorHost() {
37 DCHECK(CalledOnValidThread());
39 if (channel_ && decoder_route_id_ != MSG_ROUTING_NONE)
40 channel_->RemoveRoute(decoder_route_id_);
41 if (impl_)
42 impl_->RemoveDeletionObserver(this);
45 bool GpuVideoDecodeAcceleratorHost::OnMessageReceived(const IPC::Message& msg) {
46 DCHECK(CalledOnValidThread());
47 bool handled = true;
48 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecodeAcceleratorHost, msg)
49 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_BitstreamBufferProcessed,
50 OnBitstreamBufferProcessed)
51 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ProvidePictureBuffers,
52 OnProvidePictureBuffer)
53 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_PictureReady,
54 OnPictureReady)
55 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_FlushDone,
56 OnFlushDone)
57 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ResetDone,
58 OnResetDone)
59 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_ErrorNotification,
60 OnNotifyError)
61 IPC_MESSAGE_HANDLER(AcceleratedVideoDecoderHostMsg_DismissPictureBuffer,
62 OnDismissPictureBuffer)
63 IPC_MESSAGE_UNHANDLED(handled = false)
64 IPC_END_MESSAGE_MAP()
65 DCHECK(handled);
66 // See OnNotifyError for why |this| mustn't be used after OnNotifyError might
67 // have been called above.
68 return handled;
71 void GpuVideoDecodeAcceleratorHost::OnChannelError() {
72 DCHECK(CalledOnValidThread());
73 if (channel_) {
74 if (decoder_route_id_ != MSG_ROUTING_NONE)
75 channel_->RemoveRoute(decoder_route_id_);
76 channel_ = NULL;
78 DLOG(ERROR) << "OnChannelError()";
79 PostNotifyError(PLATFORM_FAILURE);
82 bool GpuVideoDecodeAcceleratorHost::Initialize(media::VideoCodecProfile profile,
83 Client* client) {
84 DCHECK(CalledOnValidThread());
85 client_ = client;
87 if (!impl_)
88 return false;
90 int32 route_id = channel_->GenerateRouteID();
91 channel_->AddRoute(route_id, weak_this_factory_.GetWeakPtr());
93 bool succeeded = false;
94 Send(new GpuCommandBufferMsg_CreateVideoDecoder(
95 impl_->GetRouteID(), profile, route_id, &succeeded));
97 if (!succeeded) {
98 DLOG(ERROR) << "Send(GpuCommandBufferMsg_CreateVideoDecoder()) failed";
99 PostNotifyError(PLATFORM_FAILURE);
100 channel_->RemoveRoute(route_id);
101 return false;
103 decoder_route_id_ = route_id;
104 return true;
107 void GpuVideoDecodeAcceleratorHost::Decode(
108 const media::BitstreamBuffer& bitstream_buffer) {
109 DCHECK(CalledOnValidThread());
110 if (!channel_)
111 return;
113 base::SharedMemoryHandle handle = channel_->ShareToGpuProcess(
114 bitstream_buffer.handle());
115 if (!base::SharedMemory::IsHandleValid(handle)) {
116 NOTREACHED() << "Failed to duplicate buffer handler";
117 return;
120 Send(new AcceleratedVideoDecoderMsg_Decode(
121 decoder_route_id_, handle, bitstream_buffer.id(),
122 bitstream_buffer.size()));
125 void GpuVideoDecodeAcceleratorHost::AssignPictureBuffers(
126 const std::vector<media::PictureBuffer>& buffers) {
127 DCHECK(CalledOnValidThread());
128 if (!channel_)
129 return;
130 // Rearrange data for IPC command.
131 std::vector<int32> buffer_ids;
132 std::vector<uint32> texture_ids;
133 for (uint32 i = 0; i < buffers.size(); i++) {
134 const media::PictureBuffer& buffer = buffers[i];
135 if (buffer.size() != picture_buffer_dimensions_) {
136 DLOG(ERROR) << "buffer.size() invalid: expected "
137 << picture_buffer_dimensions_.ToString()
138 << ", got " << buffer.size().ToString();
139 PostNotifyError(INVALID_ARGUMENT);
140 return;
142 texture_ids.push_back(buffer.texture_id());
143 buffer_ids.push_back(buffer.id());
145 Send(new AcceleratedVideoDecoderMsg_AssignPictureBuffers(
146 decoder_route_id_, buffer_ids, texture_ids));
149 void GpuVideoDecodeAcceleratorHost::ReusePictureBuffer(
150 int32 picture_buffer_id) {
151 DCHECK(CalledOnValidThread());
152 if (!channel_)
153 return;
154 Send(new AcceleratedVideoDecoderMsg_ReusePictureBuffer(
155 decoder_route_id_, picture_buffer_id));
158 void GpuVideoDecodeAcceleratorHost::Flush() {
159 DCHECK(CalledOnValidThread());
160 if (!channel_)
161 return;
162 Send(new AcceleratedVideoDecoderMsg_Flush(decoder_route_id_));
165 void GpuVideoDecodeAcceleratorHost::Reset() {
166 DCHECK(CalledOnValidThread());
167 if (!channel_)
168 return;
169 Send(new AcceleratedVideoDecoderMsg_Reset(decoder_route_id_));
172 void GpuVideoDecodeAcceleratorHost::Destroy() {
173 DCHECK(CalledOnValidThread());
174 if (channel_)
175 Send(new AcceleratedVideoDecoderMsg_Destroy(decoder_route_id_));
176 client_ = NULL;
177 delete this;
180 void GpuVideoDecodeAcceleratorHost::OnWillDeleteImpl() {
181 DCHECK(CalledOnValidThread());
182 impl_ = NULL;
184 // The CommandBufferProxyImpl is going away; error out this VDA.
185 OnChannelError();
188 void GpuVideoDecodeAcceleratorHost::PostNotifyError(Error error) {
189 DCHECK(CalledOnValidThread());
190 DVLOG(2) << "PostNotifyError(): error=" << error;
191 base::MessageLoopProxy::current()->PostTask(
192 FROM_HERE,
193 base::Bind(&GpuVideoDecodeAcceleratorHost::OnNotifyError,
194 weak_this_factory_.GetWeakPtr(),
195 error));
198 void GpuVideoDecodeAcceleratorHost::Send(IPC::Message* message) {
199 DCHECK(CalledOnValidThread());
200 uint32 message_type = message->type();
201 if (!channel_->Send(message)) {
202 DLOG(ERROR) << "Send(" << message_type << ") failed";
203 PostNotifyError(PLATFORM_FAILURE);
207 void GpuVideoDecodeAcceleratorHost::OnBitstreamBufferProcessed(
208 int32 bitstream_buffer_id) {
209 DCHECK(CalledOnValidThread());
210 if (client_)
211 client_->NotifyEndOfBitstreamBuffer(bitstream_buffer_id);
214 void GpuVideoDecodeAcceleratorHost::OnProvidePictureBuffer(
215 uint32 num_requested_buffers,
216 const gfx::Size& dimensions,
217 uint32 texture_target) {
218 DCHECK(CalledOnValidThread());
219 picture_buffer_dimensions_ = dimensions;
220 if (client_) {
221 client_->ProvidePictureBuffers(
222 num_requested_buffers, dimensions, texture_target);
226 void GpuVideoDecodeAcceleratorHost::OnDismissPictureBuffer(
227 int32 picture_buffer_id) {
228 DCHECK(CalledOnValidThread());
229 if (client_)
230 client_->DismissPictureBuffer(picture_buffer_id);
233 void GpuVideoDecodeAcceleratorHost::OnPictureReady(
234 int32 picture_buffer_id,
235 int32 bitstream_buffer_id,
236 const gfx::Rect& visible_rect,
237 bool allow_overlay) {
238 DCHECK(CalledOnValidThread());
239 if (!client_)
240 return;
241 media::Picture picture(picture_buffer_id, bitstream_buffer_id, visible_rect,
242 allow_overlay);
243 client_->PictureReady(picture);
246 void GpuVideoDecodeAcceleratorHost::OnFlushDone() {
247 DCHECK(CalledOnValidThread());
248 if (client_)
249 client_->NotifyFlushDone();
252 void GpuVideoDecodeAcceleratorHost::OnResetDone() {
253 DCHECK(CalledOnValidThread());
254 if (client_)
255 client_->NotifyResetDone();
258 void GpuVideoDecodeAcceleratorHost::OnNotifyError(uint32 error) {
259 DCHECK(CalledOnValidThread());
260 if (!client_)
261 return;
262 weak_this_factory_.InvalidateWeakPtrs();
264 // Client::NotifyError() may Destroy() |this|, so calling it needs to be the
265 // last thing done on this stack!
266 media::VideoDecodeAccelerator::Client* client = NULL;
267 std::swap(client, client_);
268 client->NotifyError(static_cast<media::VideoDecodeAccelerator::Error>(error));
271 } // namespace content