Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(150)

Side by Side Diff: components/exo/buffer.cc

Issue 1467943002: exo: Handle lost context situations properly. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: cleanup comments Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « components/exo/buffer.h ('k') | components/exo/buffer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 "components/exo/buffer.h" 5 #include "components/exo/buffer.h"
6 6
7 #include <GLES2/gl2.h> 7 #include <GLES2/gl2.h>
8 #include <GLES2/gl2ext.h> 8 #include <GLES2/gl2ext.h>
9 #include <GLES2/gl2extchromium.h> 9 #include <GLES2/gl2extchromium.h>
10 10
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
42 GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422 42 GL_RGB_YCBCR_422_CHROMIUM, // UYVY_422
43 }; 43 };
44 static_assert(arraysize(kGLInternalFormats) == 44 static_assert(arraysize(kGLInternalFormats) ==
45 (static_cast<int>(gfx::BufferFormat::LAST) + 1), 45 (static_cast<int>(gfx::BufferFormat::LAST) + 1),
46 "BufferFormat::LAST must be last value of kGLInternalFormats"); 46 "BufferFormat::LAST must be last value of kGLInternalFormats");
47 47
48 DCHECK(format <= gfx::BufferFormat::LAST); 48 DCHECK(format <= gfx::BufferFormat::LAST);
49 return kGLInternalFormats[static_cast<int>(format)]; 49 return kGLInternalFormats[static_cast<int>(format)];
50 } 50 }
51 51
52 gpu::gles2::GLES2Interface* GetContextGL() {
53 ui::ContextFactory* context_factory =
54 aura::Env::GetInstance()->context_factory();
55 return context_factory->SharedMainThreadContextProvider()->ContextGL();
56 }
57
58 } // namespace 52 } // namespace
59 53
60 //////////////////////////////////////////////////////////////////////////////// 54 ////////////////////////////////////////////////////////////////////////////////
61 // Buffer, public: 55 // Buffer::Texture
62 56
63 Buffer::Buffer(scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer, 57 // Encapsulates the state and logic needed to bind a buffer to a GLES2 texture.
64 unsigned texture_target) 58 class Buffer::Texture {
65 : gpu_memory_buffer_(gpu_memory_buffer.Pass()), 59 public:
60 Texture(gfx::GpuMemoryBuffer* gpu_memory_buffer,
61 cc::ContextProvider* context_provider,
62 unsigned texture_target);
63 ~Texture();
64
65 // Returns true if GLES2 resources for texture have been lost.
66 bool IsLost();
67
68 // Binds the content of gpu memory buffer to the texture returned by
69 // mailbox(). Returns a sync token that can be used to when accessing texture
70 // from a different context.
71 gpu::SyncToken BindTexImage();
72
73 // Releases the content of gpu memory buffer after |sync_token| has passed.
74 void ReleaseTexImage(const gpu::SyncToken& sync_token);
75
76 // Returns the mailbox for this texture.
77 gpu::Mailbox mailbox() const { return mailbox_; }
78
79 private:
80 scoped_refptr<cc::ContextProvider> context_provider_;
81 const unsigned texture_target_;
82 const gfx::Size size_;
83 unsigned image_id_;
84 unsigned texture_id_;
85 gpu::Mailbox mailbox_;
86
87 DISALLOW_COPY_AND_ASSIGN(Texture);
88 };
89
90 Buffer::Texture::Texture(gfx::GpuMemoryBuffer* gpu_memory_buffer,
91 cc::ContextProvider* context_provider,
92 unsigned texture_target)
93 : context_provider_(context_provider),
66 texture_target_(texture_target), 94 texture_target_(texture_target),
67 texture_id_(0), 95 size_(gpu_memory_buffer->GetSize()),
68 image_id_(0) { 96 image_id_(0),
69 gpu::gles2::GLES2Interface* gles2 = GetContextGL(); 97 texture_id_(0) {
70 // Create an image for |gpu_memory_buffer_|. 98 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
71 gfx::Size size = gpu_memory_buffer_->GetSize();
72 image_id_ = gles2->CreateImageCHROMIUM( 99 image_id_ = gles2->CreateImageCHROMIUM(
73 gpu_memory_buffer_->AsClientBuffer(), size.width(), size.height(), 100 gpu_memory_buffer->AsClientBuffer(), size_.width(), size_.height(),
74 GLInternalFormat(gpu_memory_buffer_->GetFormat())); 101 GLInternalFormat(gpu_memory_buffer->GetFormat()));
75 // Create a texture with |texture_target_|. 102 gles2->GenTextures(1, &texture_id_);
76 gles2->ActiveTexture(GL_TEXTURE0); 103 gles2->ActiveTexture(GL_TEXTURE0);
77 gles2->GenTextures(1, &texture_id_);
78 gles2->BindTexture(texture_target_, texture_id_); 104 gles2->BindTexture(texture_target_, texture_id_);
79 gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 105 gles2->TexParameteri(texture_target_, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
80 gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 106 gles2->TexParameteri(texture_target_, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
81 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 107 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
82 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 108 gles2->TexParameteri(texture_target_, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
83 // Generate a crypto-secure random mailbox name. 109 // Generate a crypto-secure random mailbox name.
84 gles2->GenMailboxCHROMIUM(mailbox_.name); 110 gles2->GenMailboxCHROMIUM(mailbox_.name);
85 gles2->ProduceTextureCHROMIUM(texture_target_, mailbox_.name); 111 gles2->ProduceTextureCHROMIUM(texture_target_, mailbox_.name);
86 } 112 }
87 113
88 Buffer::~Buffer() { 114 Buffer::Texture::~Texture() {
89 gpu::gles2::GLES2Interface* gles2 = GetContextGL(); 115 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
90 if (texture_id_) 116 gles2->ActiveTexture(GL_TEXTURE0);
91 gles2->DeleteTextures(1, &texture_id_); 117 gles2->DeleteTextures(1, &texture_id_);
92 if (image_id_) 118 gles2->DestroyImageCHROMIUM(image_id_);
93 gles2->DestroyImageCHROMIUM(image_id_);
94 } 119 }
95 120
96 scoped_ptr<cc::SingleReleaseCallback> Buffer::AcquireTextureMailbox( 121 bool Buffer::Texture::IsLost() {
122 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
123 return gles2->GetGraphicsResetStatusKHR() != GL_NO_ERROR;
124 }
125
126 gpu::SyncToken Buffer::Texture::BindTexImage() {
127 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
128 gles2->ActiveTexture(GL_TEXTURE0);
129 gles2->BindTexture(texture_target_, texture_id_);
130 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id_);
131 // Create and return a sync token that can be used to ensure that the
132 // BindTexImage2DCHROMIUM call is processed before issuing any commands
133 // that will read from the texture on a different context.
134 uint64 fence_sync = gles2->InsertFenceSyncCHROMIUM();
135 gles2->OrderingBarrierCHROMIUM();
136 gpu::SyncToken sync_token;
137 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
138 return sync_token;
139 }
140
141 void Buffer::Texture::ReleaseTexImage(const gpu::SyncToken& sync_token) {
142 gpu::gles2::GLES2Interface* gles2 = context_provider_->ContextGL();
143 if (sync_token.HasData())
144 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
145 gles2->ActiveTexture(GL_TEXTURE0);
146 gles2->BindTexture(texture_target_, texture_id_);
147 gles2->ReleaseTexImage2DCHROMIUM(texture_target_, image_id_);
148 }
149
150 ////////////////////////////////////////////////////////////////////////////////
151 // Buffer, public:
152
153 Buffer::Buffer(scoped_ptr<gfx::GpuMemoryBuffer> gpu_memory_buffer,
154 unsigned texture_target)
155 : gpu_memory_buffer_(gpu_memory_buffer.Pass()),
156 texture_target_(texture_target),
157 use_count_(0) {}
158
159 Buffer::~Buffer() {}
160
161 scoped_ptr<cc::SingleReleaseCallback> Buffer::ProduceTextureMailbox(
97 cc::TextureMailbox* texture_mailbox) { 162 cc::TextureMailbox* texture_mailbox) {
98 // Buffer can only be used by one client at a time. If texture id is 0, then a 163 DLOG_IF(WARNING, use_count_)
99 // previous call to AcquireTextureMailbox() is using this buffer and it has 164 << "Producing a texture mailbox for a buffer that has not been released";
100 // not been released yet. 165
101 if (!texture_id_) { 166 // Increment the use count for this buffer.
102 DLOG(WARNING) << "Client tried to use a buffer that has not been released"; 167 ++use_count_;
168
169 // Note: This can fail if GPU acceleration has been disabled.
170 scoped_refptr<cc::ContextProvider> context_provider =
171 aura::Env::GetInstance()
172 ->context_factory()
173 ->SharedMainThreadContextProvider();
174 if (!context_provider) {
175 DLOG(WARNING) << "Failed to acquire a context provider";
176 Release(); // Decrements the use count
103 return nullptr; 177 return nullptr;
104 } 178 }
105 179
106 // Take ownerhsip of image and texture ids. 180 // Creating a new texture is relatively expensive so we reuse the last
107 unsigned texture_id = 0; 181 // texture whenever possible.
108 unsigned image_id = 0; 182 scoped_ptr<Texture> texture = last_texture_.Pass();
109 std::swap(texture_id, texture_id_);
110 DCHECK_NE(image_id_, 0u);
111 std::swap(image_id, image_id_);
112 183
113 // Bind texture to |texture_target_|. 184 // If texture is lost, destroy it to ensure that we create a new one below.
114 gpu::gles2::GLES2Interface* gles2 = GetContextGL(); 185 if (texture && texture->IsLost())
115 gles2->ActiveTexture(GL_TEXTURE0); 186 texture.reset();
piman 2015/11/23 21:04:42 I suggest doing this before getting the context_pr
reveman 2015/11/23 23:25:29 Makes sense. Done.
116 gles2->BindTexture(texture_target_, texture_id);
117 187
118 // Bind the image to texture. 188 // Create a new texture if one doesn't already exist. The contents of this
119 gles2->BindTexImage2DCHROMIUM(texture_target_, image_id); 189 // buffer can be bound to the texture using a call to BindTexImage and must
190 // be released using a matching ReleaseTexImage call before it can be reused
191 // or destroyed.
192 if (!texture) {
193 texture = make_scoped_ptr(new Texture(
194 gpu_memory_buffer_.get(), context_provider.get(), texture_target_));
195 }
120 196
121 // Create a sync token to ensure that the BindTexImage2DCHROMIUM call is 197 // This binds the latest contents of this buffer to the texture.
122 // processed before issuing any commands that will read from texture. 198 gpu::SyncToken sync_token = texture->BindTexImage();
123 uint64 fence_sync = gles2->InsertFenceSyncCHROMIUM();
124 gles2->ShallowFlushCHROMIUM();
125 gpu::SyncToken sync_token;
126 gles2->GenUnverifiedSyncTokenCHROMIUM(fence_sync, sync_token.GetData());
127 199
128 bool is_overlay_candidate = false; 200 bool is_overlay_candidate = false;
129 *texture_mailbox = 201 *texture_mailbox =
130 cc::TextureMailbox(mailbox_, sync_token, texture_target_, 202 cc::TextureMailbox(texture->mailbox(), sync_token, texture_target_,
131 gpu_memory_buffer_->GetSize(), is_overlay_candidate); 203 gpu_memory_buffer_->GetSize(), is_overlay_candidate);
132 return cc::SingleReleaseCallback::Create( 204 return cc::SingleReleaseCallback::Create(
133 base::Bind(&Buffer::Release, AsWeakPtr(), texture_target_, 205 base::Bind(&Buffer::ReleaseTexture, AsWeakPtr(), base::Passed(&texture)));
134 texture_id, image_id))
135 .Pass();
136 } 206 }
137 207
138 gfx::Size Buffer::GetSize() const { 208 gfx::Size Buffer::GetSize() const {
139 return gpu_memory_buffer_->GetSize(); 209 return gpu_memory_buffer_->GetSize();
140 } 210 }
141 211
142 scoped_refptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const { 212 scoped_refptr<base::trace_event::TracedValue> Buffer::AsTracedValue() const {
143 scoped_refptr<base::trace_event::TracedValue> value = 213 scoped_refptr<base::trace_event::TracedValue> value =
144 new base::trace_event::TracedValue; 214 new base::trace_event::TracedValue;
145 value->SetInteger("width", GetSize().width()); 215 gfx::Size size = gpu_memory_buffer_->GetSize();
146 value->SetInteger("height", GetSize().height()); 216 value->SetInteger("width", size.width());
217 value->SetInteger("height", size.height());
147 value->SetInteger("format", 218 value->SetInteger("format",
148 static_cast<int>(gpu_memory_buffer_->GetFormat())); 219 static_cast<int>(gpu_memory_buffer_->GetFormat()));
149 return value; 220 return value;
150 } 221 }
151 222
152 //////////////////////////////////////////////////////////////////////////////// 223 ////////////////////////////////////////////////////////////////////////////////
153 // Buffer, private: 224 // Buffer, private:
154 225
226 void Buffer::Release() {
227 DCHECK_GT(use_count_, 0u);
228 if (--use_count_)
229 return;
230
231 // Run release callback to notify the client that buffer has been released.
232 if (!release_callback_.is_null())
233 release_callback_.Run();
234 }
235
155 // static 236 // static
156 void Buffer::Release(base::WeakPtr<Buffer> buffer, 237 void Buffer::ReleaseTexture(base::WeakPtr<Buffer> buffer,
157 unsigned texture_target, 238 scoped_ptr<Texture> texture,
158 unsigned texture_id, 239 const gpu::SyncToken& sync_token,
159 unsigned image_id, 240 bool is_lost) {
160 const gpu::SyncToken& sync_token, 241 TRACE_EVENT1("exo", "Buffer::ReleaseTexture", "is_lost", is_lost);
161 bool is_lost) {
162 TRACE_EVENT1("exo", "Buffer::Release", "is_lost", is_lost);
163 242
164 gpu::gles2::GLES2Interface* gles2 = GetContextGL(); 243 // Release image so it can safely be reused or destroyed.
165 if (sync_token.HasData()) 244 texture->ReleaseTexImage(sync_token);
166 gles2->WaitSyncTokenCHROMIUM(sync_token.GetConstData());
167 gles2->ActiveTexture(GL_TEXTURE0);
168 gles2->BindTexture(texture_target, texture_id);
169 gles2->ReleaseTexImage2DCHROMIUM(texture_target, image_id);
170 245
171 // Delete resources and return if buffer is gone. 246 // Early out if buffer is gone. This can happen when the client destroyed the
172 if (!buffer) { 247 // buffer before receiving a release callback.
173 gles2->DeleteTextures(1, &texture_id); 248 if (!buffer)
174 gles2->DestroyImageCHROMIUM(image_id);
175 return; 249 return;
176 }
177 250
178 DCHECK_EQ(buffer->texture_id_, 0u); 251 // Allow buffer to reused texture if it's not lost.
179 buffer->texture_id_ = texture_id; 252 if (!is_lost)
180 DCHECK_EQ(buffer->image_id_, 0u); 253 buffer->last_texture_ = texture.Pass();
181 buffer->image_id_ = image_id;
182 254
183 if (!buffer->release_callback_.is_null()) 255 buffer->Release();
184 buffer->release_callback_.Run();
185 } 256 }
186 257
187 } // namespace exo 258 } // namespace exo
OLDNEW
« no previous file with comments | « components/exo/buffer.h ('k') | components/exo/buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698