1 // Copyright 2014 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 "gpu/command_buffer/service/mailbox_synchronizer.h"
8 #include "gpu/command_buffer/service/mailbox_manager.h"
9 #include "gpu/command_buffer/service/texture_manager.h"
10 #include "ui/gl/gl_implementation.h"
17 MailboxSynchronizer
* g_instance
= NULL
;
19 } // anonymous namespace
22 bool MailboxSynchronizer::Initialize() {
24 DCHECK(gfx::GetGLImplementation() != gfx::kGLImplementationNone
)
25 << "GL bindings not initialized";
26 switch (gfx::GetGLImplementation()) {
27 case gfx::kGLImplementationMockGL
:
29 case gfx::kGLImplementationEGLGLES2
:
30 #if !defined(OS_MACOSX)
32 if (!gfx::g_driver_egl
.ext
.b_EGL_KHR_image_base
||
33 !gfx::g_driver_egl
.ext
.b_EGL_KHR_gl_texture_2D_image
||
34 !gfx::g_driver_gl
.ext
.b_GL_OES_EGL_image
||
35 !gfx::g_driver_egl
.ext
.b_EGL_KHR_fence_sync
) {
36 LOG(WARNING
) << "MailboxSync not supported due to missing EGL "
37 "image/fence support";
47 g_instance
= new MailboxSynchronizer
;
52 void MailboxSynchronizer::Terminate() {
59 MailboxSynchronizer
* MailboxSynchronizer::GetInstance() {
63 MailboxSynchronizer::TargetName::TargetName(unsigned target
,
64 const Mailbox
& mailbox
)
65 : target(target
), mailbox(mailbox
) {}
67 MailboxSynchronizer::TextureGroup::TextureGroup(
68 const TextureDefinition
& definition
)
69 : definition(definition
) {}
71 MailboxSynchronizer::TextureGroup::~TextureGroup() {}
73 MailboxSynchronizer::TextureVersion::TextureVersion(
74 linked_ptr
<TextureGroup
> group
)
75 : version(group
->definition
.version()), group(group
) {}
77 MailboxSynchronizer::TextureVersion::~TextureVersion() {}
79 MailboxSynchronizer::MailboxSynchronizer() {}
81 MailboxSynchronizer::~MailboxSynchronizer() {
82 DCHECK_EQ(0U, textures_
.size());
85 void MailboxSynchronizer::ReassociateMailboxLocked(
86 const TargetName
& target_name
,
87 TextureGroup
* group
) {
88 lock_
.AssertAcquired();
89 for (TextureMap::iterator it
= textures_
.begin(); it
!= textures_
.end();
91 std::set
<TargetName
>::iterator mb_it
=
92 it
->second
.group
->mailboxes
.find(target_name
);
93 if (it
->second
.group
!= group
&&
94 mb_it
!= it
->second
.group
->mailboxes
.end()) {
95 it
->second
.group
->mailboxes
.erase(mb_it
);
98 group
->mailboxes
.insert(target_name
);
101 linked_ptr
<MailboxSynchronizer::TextureGroup
>
102 MailboxSynchronizer::GetGroupForMailboxLocked(const TargetName
& target_name
) {
103 lock_
.AssertAcquired();
104 for (TextureMap::iterator it
= textures_
.begin(); it
!= textures_
.end();
106 std::set
<TargetName
>::const_iterator mb_it
=
107 it
->second
.group
->mailboxes
.find(target_name
);
108 if (mb_it
!= it
->second
.group
->mailboxes
.end())
109 return it
->second
.group
;
111 return make_linked_ptr
<MailboxSynchronizer::TextureGroup
>(NULL
);
114 Texture
* MailboxSynchronizer::CreateTextureFromMailbox(unsigned target
,
115 const Mailbox
& mailbox
) {
116 base::AutoLock
lock(lock_
);
117 TargetName
target_name(target
, mailbox
);
118 linked_ptr
<TextureGroup
> group
= GetGroupForMailboxLocked(target_name
);
120 Texture
* new_texture
= group
->definition
.CreateTexture();
122 textures_
.insert(std::make_pair(new_texture
, TextureVersion(group
)));
129 void MailboxSynchronizer::TextureDeleted(Texture
* texture
) {
130 base::AutoLock
lock(lock_
);
131 TextureMap::iterator it
= textures_
.find(texture
);
132 if (it
!= textures_
.end()) {
133 // TODO: We could avoid the update if this was the last ref.
134 UpdateTextureLocked(it
->first
, it
->second
);
139 void MailboxSynchronizer::PushTextureUpdates(MailboxManager
* manager
) {
140 base::AutoLock
lock(lock_
);
141 for (MailboxManager::MailboxToTextureMap::const_iterator texture_it
=
142 manager
->mailbox_to_textures_
.begin();
143 texture_it
!= manager
->mailbox_to_textures_
.end();
145 TargetName
target_name(texture_it
->first
.target
, texture_it
->first
.mailbox
);
146 Texture
* texture
= texture_it
->second
->first
;
147 // TODO(sievers): crbug.com/352274
148 // Should probably only fail if it already *has* mipmaps, while allowing
149 // incomplete textures here. Also reconsider how to fail otherwise.
150 bool needs_mips
= texture
->min_filter() != GL_NEAREST
&&
151 texture
->min_filter() != GL_LINEAR
;
152 if (target_name
.target
!= GL_TEXTURE_2D
|| needs_mips
)
155 TextureMap::iterator it
= textures_
.find(texture
);
156 if (it
!= textures_
.end()) {
157 TextureVersion
& texture_version
= it
->second
;
158 TextureGroup
* group
= texture_version
.group
.get();
159 std::set
<TargetName
>::const_iterator mb_it
=
160 group
->mailboxes
.find(target_name
);
161 if (mb_it
== group
->mailboxes
.end()) {
162 // We previously did not associate this texture with the given mailbox.
163 // Unlink other texture groups from the mailbox.
164 ReassociateMailboxLocked(target_name
, group
);
166 UpdateTextureLocked(texture
, texture_version
);
169 // Skip compositor resources/tile textures.
170 // TODO: Remove this, see crbug.com/399226.
171 if (texture
->pool() == GL_TEXTURE_POOL_MANAGED_CHROMIUM
)
174 linked_ptr
<TextureGroup
> group
= make_linked_ptr(new TextureGroup(
175 TextureDefinition(target_name
.target
, texture
, 1, NULL
)));
177 // Unlink other textures from this mailbox in case the name is not new.
178 ReassociateMailboxLocked(target_name
, group
.get());
179 textures_
.insert(std::make_pair(texture
, TextureVersion(group
)));
184 void MailboxSynchronizer::UpdateTextureLocked(Texture
* texture
,
185 TextureVersion
& texture_version
) {
186 lock_
.AssertAcquired();
187 gfx::GLImage
* gl_image
= texture
->GetLevelImage(texture
->target(), 0);
188 TextureGroup
* group
= texture_version
.group
.get();
189 scoped_refptr
<NativeImageBuffer
> image_buffer
= group
->definition
.image();
191 // Make sure we don't clobber with an older version
192 if (!group
->definition
.IsOlderThan(texture_version
.version
))
195 // Also don't push redundant updates. Note that it would break the
197 if (group
->definition
.Matches(texture
))
200 if (gl_image
&& !image_buffer
->IsClient(gl_image
)) {
201 LOG(ERROR
) << "MailboxSync: Incompatible attachment";
205 group
->definition
= TextureDefinition(texture
->target(),
207 ++texture_version
.version
,
208 gl_image
? image_buffer
: NULL
);
211 void MailboxSynchronizer::PullTextureUpdates(MailboxManager
* manager
) {
212 base::AutoLock
lock(lock_
);
213 for (MailboxManager::MailboxToTextureMap::const_iterator texture_it
=
214 manager
->mailbox_to_textures_
.begin();
215 texture_it
!= manager
->mailbox_to_textures_
.end();
217 Texture
* texture
= texture_it
->second
->first
;
218 TextureMap::iterator it
= textures_
.find(texture
);
219 if (it
!= textures_
.end()) {
220 TextureDefinition
& definition
= it
->second
.group
->definition
;
221 if (it
->second
.version
== definition
.version() ||
222 definition
.IsOlderThan(it
->second
.version
))
224 it
->second
.version
= definition
.version();
225 definition
.UpdateTexture(texture
);