[SyncFS] Build indexes from FileTracker entries on disk.
[chromium-blink-merge.git] / content / common / gpu / texture_image_transport_surface.cc
blob0ab94e3ed75bc3344a66855f4d2d8aa6ebe9c5de
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/texture_image_transport_surface.h"
7 #include <string>
8 #include <vector>
10 #include "base/command_line.h"
11 #include "content/common/gpu/gpu_channel.h"
12 #include "content/common/gpu/gpu_channel_manager.h"
13 #include "content/common/gpu/gpu_messages.h"
14 #include "content/common/gpu/sync_point_manager.h"
15 #include "content/public/common/content_switches.h"
16 #include "gpu/command_buffer/service/context_group.h"
17 #include "gpu/command_buffer/service/gpu_scheduler.h"
18 #include "gpu/command_buffer/service/mailbox_manager.h"
19 #include "ui/gl/scoped_binders.h"
21 using gpu::gles2::ContextGroup;
22 using gpu::gles2::GLES2Decoder;
23 using gpu::gles2::MailboxManager;
24 using gpu::gles2::Texture;
25 using gpu::gles2::TextureManager;
26 using gpu::gles2::TextureRef;
27 using gpu::Mailbox;
29 namespace content {
30 namespace {
32 bool IsContextValid(ImageTransportHelper* helper) {
33 return helper->stub()->decoder()->GetGLContext()->IsCurrent(NULL);
36 } // namespace
38 TextureImageTransportSurface::TextureImageTransportSurface(
39 GpuChannelManager* manager,
40 GpuCommandBufferStub* stub,
41 const gfx::GLSurfaceHandle& handle)
42 : fbo_id_(0),
43 current_size_(1, 1),
44 scale_factor_(1.f),
45 stub_destroyed_(false),
46 backbuffer_suggested_allocation_(true),
47 frontbuffer_suggested_allocation_(true),
48 handle_(handle),
49 is_swap_buffers_pending_(false),
50 did_unschedule_(false) {
51 helper_.reset(new ImageTransportHelper(this,
52 manager,
53 stub,
54 gfx::kNullPluginWindow));
57 TextureImageTransportSurface::~TextureImageTransportSurface() {
58 DCHECK(stub_destroyed_);
59 Destroy();
62 bool TextureImageTransportSurface::Initialize() {
63 mailbox_manager_ =
64 helper_->stub()->decoder()->GetContextGroup()->mailbox_manager();
66 GpuChannelManager* manager = helper_->manager();
67 surface_ = manager->GetDefaultOffscreenSurface();
68 if (!surface_.get())
69 return false;
71 if (!helper_->Initialize())
72 return false;
74 GpuChannel* parent_channel = manager->LookupChannel(handle_.parent_client_id);
75 if (parent_channel) {
76 const CommandLine* command_line = CommandLine::ForCurrentProcess();
77 if (command_line->HasSwitch(switches::kUIPrioritizeInGpuProcess))
78 helper_->SetPreemptByFlag(parent_channel->GetPreemptionFlag());
81 return true;
84 void TextureImageTransportSurface::Destroy() {
85 if (surface_.get())
86 surface_ = NULL;
88 helper_->Destroy();
91 bool TextureImageTransportSurface::DeferDraws() {
92 // The command buffer hit a draw/clear command that could clobber the
93 // texture in use by the UI compositor. If a Swap is pending, abort
94 // processing of the command by returning true and unschedule until the Swap
95 // Ack arrives.
96 DCHECK(!did_unschedule_);
97 if (is_swap_buffers_pending_) {
98 did_unschedule_ = true;
99 helper_->SetScheduled(false);
100 return true;
102 return false;
105 bool TextureImageTransportSurface::IsOffscreen() {
106 return true;
109 unsigned int TextureImageTransportSurface::GetBackingFrameBufferObject() {
110 DCHECK(IsContextValid(helper_.get()));
111 if (!fbo_id_) {
112 glGenFramebuffersEXT(1, &fbo_id_);
113 glBindFramebufferEXT(GL_FRAMEBUFFER, fbo_id_);
114 helper_->stub()->AddDestructionObserver(this);
115 CreateBackTexture();
118 return fbo_id_;
121 bool TextureImageTransportSurface::SetBackbufferAllocation(bool allocation) {
122 DCHECK(!is_swap_buffers_pending_);
123 if (backbuffer_suggested_allocation_ == allocation)
124 return true;
125 backbuffer_suggested_allocation_ = allocation;
127 if (backbuffer_suggested_allocation_) {
128 DCHECK(!backbuffer_.get());
129 CreateBackTexture();
130 } else {
131 ReleaseBackTexture();
134 return true;
137 void TextureImageTransportSurface::SetFrontbufferAllocation(bool allocation) {
138 if (frontbuffer_suggested_allocation_ == allocation)
139 return;
140 frontbuffer_suggested_allocation_ = allocation;
142 // If a swapbuffers is in flight, wait for the ack before releasing the front
143 // buffer:
144 // - we don't know yet which texture the browser will want to keep
145 // - we want to ensure we don't destroy a texture that is in flight before the
146 // browser got a reference on it.
147 if (!frontbuffer_suggested_allocation_ &&
148 !is_swap_buffers_pending_ &&
149 helper_->MakeCurrent()) {
150 ReleaseFrontTexture();
154 void* TextureImageTransportSurface::GetShareHandle() {
155 return GetHandle();
158 void* TextureImageTransportSurface::GetDisplay() {
159 return surface_.get() ? surface_->GetDisplay() : NULL;
162 void* TextureImageTransportSurface::GetConfig() {
163 return surface_.get() ? surface_->GetConfig() : NULL;
166 void TextureImageTransportSurface::OnResize(gfx::Size size,
167 float scale_factor) {
168 DCHECK_GE(size.width(), 1);
169 DCHECK_GE(size.height(), 1);
170 current_size_ = size;
171 scale_factor_ = scale_factor;
172 if (backbuffer_suggested_allocation_)
173 CreateBackTexture();
176 void TextureImageTransportSurface::OnWillDestroyStub() {
177 bool have_context = IsContextValid(helper_.get());
178 helper_->stub()->RemoveDestructionObserver(this);
180 // We are losing the stub owning us, this is our last chance to clean up the
181 // resources we allocated in the stub's context.
182 if (have_context) {
183 ReleaseBackTexture();
184 ReleaseFrontTexture();
185 } else {
186 backbuffer_ = NULL;
187 back_mailbox_ = Mailbox();
188 frontbuffer_ = NULL;
189 front_mailbox_ = Mailbox();
192 if (fbo_id_ && have_context) {
193 glDeleteFramebuffersEXT(1, &fbo_id_);
194 CHECK_GL_ERROR();
196 fbo_id_ = 0;
198 stub_destroyed_ = true;
201 void TextureImageTransportSurface::SetLatencyInfo(
202 const std::vector<ui::LatencyInfo>& latency_info) {
203 for (size_t i = 0; i < latency_info.size(); i++)
204 latency_info_.push_back(latency_info[i]);
207 void TextureImageTransportSurface::WakeUpGpu() {
208 NOTIMPLEMENTED();
211 bool TextureImageTransportSurface::SwapBuffers() {
212 DCHECK(IsContextValid(helper_.get()));
213 DCHECK(backbuffer_suggested_allocation_);
215 if (!frontbuffer_suggested_allocation_)
216 return true;
218 if (!backbuffer_.get()) {
219 LOG(ERROR) << "Swap without valid backing.";
220 return true;
223 DCHECK(backbuffer_size() == current_size_);
224 GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
225 params.size = backbuffer_size();
226 params.scale_factor = scale_factor_;
227 params.mailbox = back_mailbox_;
229 glFlush();
231 params.latency_info.swap(latency_info_);
232 helper_->SendAcceleratedSurfaceBuffersSwapped(params);
234 DCHECK(!is_swap_buffers_pending_);
235 is_swap_buffers_pending_ = true;
236 return true;
239 bool TextureImageTransportSurface::PostSubBuffer(
240 int x, int y, int width, int height) {
241 DCHECK(IsContextValid(helper_.get()));
242 DCHECK(backbuffer_suggested_allocation_);
243 if (!frontbuffer_suggested_allocation_)
244 return true;
245 const gfx::Rect new_damage_rect(x, y, width, height);
246 DCHECK(gfx::Rect(gfx::Point(), current_size_).Contains(new_damage_rect));
248 // An empty damage rect is a successful no-op.
249 if (new_damage_rect.IsEmpty())
250 return true;
252 if (!backbuffer_.get()) {
253 LOG(ERROR) << "Swap without valid backing.";
254 return true;
257 DCHECK(current_size_ == backbuffer_size());
258 GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params;
259 params.surface_size = backbuffer_size();
260 params.surface_scale_factor = scale_factor_;
261 params.x = x;
262 params.y = y;
263 params.width = width;
264 params.height = height;
265 params.mailbox = back_mailbox_;
267 glFlush();
269 params.latency_info.swap(latency_info_);
270 helper_->SendAcceleratedSurfacePostSubBuffer(params);
272 DCHECK(!is_swap_buffers_pending_);
273 is_swap_buffers_pending_ = true;
274 return true;
277 bool TextureImageTransportSurface::SupportsPostSubBuffer() {
278 return true;
281 gfx::Size TextureImageTransportSurface::GetSize() {
282 return current_size_;
285 void* TextureImageTransportSurface::GetHandle() {
286 return surface_.get() ? surface_->GetHandle() : NULL;
289 unsigned TextureImageTransportSurface::GetFormat() {
290 return surface_.get() ? surface_->GetFormat() : 0;
293 void TextureImageTransportSurface::OnBufferPresented(
294 const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
295 if (params.sync_point == 0) {
296 BufferPresentedImpl(params.mailbox);
297 } else {
298 helper_->manager()->sync_point_manager()->AddSyncPointCallback(
299 params.sync_point,
300 base::Bind(&TextureImageTransportSurface::BufferPresentedImpl,
301 this,
302 params.mailbox));
306 void TextureImageTransportSurface::BufferPresentedImpl(const Mailbox& mailbox) {
307 DCHECK(is_swap_buffers_pending_);
308 is_swap_buffers_pending_ = false;
310 // When we wait for a sync point, we may get called back after the stub is
311 // destroyed. In that case there's no need to do anything with the returned
312 // mailbox.
313 if (stub_destroyed_)
314 return;
316 // We should not have allowed the backbuffer to be discarded while the ack
317 // was pending.
318 DCHECK(backbuffer_suggested_allocation_);
319 DCHECK(backbuffer_.get());
321 bool swap = true;
322 if (!mailbox.IsZero()) {
323 if (mailbox == back_mailbox_) {
324 // The browser has skipped the frame to unblock the GPU process, waiting
325 // for one of the right size, and returned the back buffer, so don't swap.
326 swap = false;
329 if (swap) {
330 std::swap(backbuffer_, frontbuffer_);
331 std::swap(back_mailbox_, front_mailbox_);
334 // We're relying on the fact that the parent context is
335 // finished with its context when it inserts the sync point that
336 // triggers this callback.
337 if (helper_->MakeCurrent()) {
338 if (frontbuffer_.get() && !frontbuffer_suggested_allocation_)
339 ReleaseFrontTexture();
340 if (!backbuffer_.get() || backbuffer_size() != current_size_)
341 CreateBackTexture();
342 else
343 AttachBackTextureToFBO();
346 // Even if MakeCurrent fails, schedule anyway, to trigger the lost context
347 // logic.
348 if (did_unschedule_) {
349 did_unschedule_ = false;
350 helper_->SetScheduled(true);
354 void TextureImageTransportSurface::ReleaseBackTexture() {
355 DCHECK(IsContextValid(helper_.get()));
356 backbuffer_ = NULL;
357 back_mailbox_ = Mailbox();
358 glFlush();
359 CHECK_GL_ERROR();
362 void TextureImageTransportSurface::ReleaseFrontTexture() {
363 DCHECK(IsContextValid(helper_.get()));
364 frontbuffer_ = NULL;
365 front_mailbox_ = Mailbox();
366 glFlush();
367 CHECK_GL_ERROR();
368 helper_->SendAcceleratedSurfaceRelease();
371 void TextureImageTransportSurface::CreateBackTexture() {
372 DCHECK(IsContextValid(helper_.get()));
373 // If |is_swap_buffers_pending| we are waiting for our backbuffer
374 // in the mailbox, so we shouldn't be reallocating it now.
375 DCHECK(!is_swap_buffers_pending_);
377 if (backbuffer_.get() && backbuffer_size() == current_size_)
378 return;
380 VLOG(1) << "Allocating new backbuffer texture";
382 GLES2Decoder* decoder = helper_->stub()->decoder();
383 TextureManager* texture_manager =
384 decoder->GetContextGroup()->texture_manager();
385 if (!backbuffer_.get()) {
386 back_mailbox_ = gpu::Mailbox::Generate();
387 GLuint service_id;
388 glGenTextures(1, &service_id);
389 backbuffer_ = TextureRef::Create(texture_manager, 0, service_id);
390 texture_manager->SetTarget(backbuffer_.get(), GL_TEXTURE_2D);
391 Texture* texture = texture_manager->Produce(backbuffer_.get());
392 mailbox_manager_->ProduceTexture(GL_TEXTURE_2D, back_mailbox_, texture);
396 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D,
397 backbuffer_->service_id());
398 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
399 current_size_.width(), current_size_.height(), 0,
400 GL_RGBA, GL_UNSIGNED_BYTE, NULL);
401 gpu::gles2::ErrorState* error_state = decoder->GetErrorState();
402 texture_manager->SetParameteri("Backbuffer",
403 error_state,
404 backbuffer_.get(),
405 GL_TEXTURE_MIN_FILTER,
406 GL_LINEAR);
407 texture_manager->SetParameteri("Backbuffer",
408 error_state,
409 backbuffer_.get(),
410 GL_TEXTURE_MAG_FILTER,
411 GL_LINEAR);
412 texture_manager->SetParameteri("Backbuffer",
413 error_state,
414 backbuffer_.get(),
415 GL_TEXTURE_WRAP_S,
416 GL_CLAMP_TO_EDGE);
417 texture_manager->SetParameteri("Backbuffer",
418 error_state,
419 backbuffer_.get(),
420 GL_TEXTURE_WRAP_T,
421 GL_CLAMP_TO_EDGE);
422 texture_manager->SetLevelInfo(backbuffer_.get(),
423 GL_TEXTURE_2D,
425 GL_RGBA,
426 current_size_.width(),
427 current_size_.height(),
430 GL_RGBA,
431 GL_UNSIGNED_BYTE,
432 true);
433 DCHECK(texture_manager->CanRender(backbuffer_.get()));
434 CHECK_GL_ERROR();
437 AttachBackTextureToFBO();
440 void TextureImageTransportSurface::AttachBackTextureToFBO() {
441 DCHECK(IsContextValid(helper_.get()));
442 DCHECK(backbuffer_.get());
443 gfx::ScopedFrameBufferBinder fbo_binder(fbo_id_);
444 glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
445 GL_COLOR_ATTACHMENT0,
446 GL_TEXTURE_2D,
447 backbuffer_->service_id(),
449 CHECK_GL_ERROR();
451 #ifndef NDEBUG
452 GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
453 if (status != GL_FRAMEBUFFER_COMPLETE) {
454 DLOG(FATAL) << "Framebuffer incomplete: " << status;
456 #endif
459 } // namespace content