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

Side by Side Diff: gpu/command_buffer/service/texture_definition.cc

Issue 180723023: gpu: Mailbox emulation with EGLImage (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: oops Created 6 years, 9 months 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 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.
4
5 #include "gpu/command_buffer/service/texture_definition.h"
6
7 #include "gpu/command_buffer/service/texture_manager.h"
8 #include "ui/gl/gl_image.h"
9 #include "ui/gl/gl_implementation.h"
10 #include "ui/gl/scoped_binders.h"
11
12 #if !defined(OS_MACOSX)
13 #include "ui/gl/gl_surface_egl.h"
14 #endif
15
16 namespace gpu {
17 namespace gles2 {
18
19 namespace {
20
21 class GLImageSync : public gfx::GLImage {
22 public:
23 explicit GLImageSync(
24 const scoped_refptr<NativeImageBuffer>& buffer);
25
26 // Implement GLImage.
27 virtual void Destroy() OVERRIDE;
28 virtual gfx::Size GetSize() OVERRIDE;
29 virtual bool BindTexImage(unsigned target) OVERRIDE;
30 virtual void ReleaseTexImage(unsigned target) OVERRIDE;
31 virtual void WillUseTexImage() OVERRIDE;
32 virtual void WillModifyTexImage() OVERRIDE;
33 virtual void DidModifyTexImage() OVERRIDE;
34
35 virtual void DidUseTexImage() OVERRIDE;
36 virtual void SetReleaseAfterUse() OVERRIDE;
37
38 protected:
39 virtual ~GLImageSync();
40
41 private:
42 scoped_refptr<NativeImageBuffer> buffer_;
43
44 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
45 };
46
47 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer)
48 : buffer_(buffer) {
49 if (buffer)
50 buffer->AddClient(this);
51 }
52
53 GLImageSync::~GLImageSync() {
54 if (buffer_)
55 buffer_->RemoveClient(this);
56 }
57
58 void GLImageSync::Destroy() {}
59
60 gfx::Size GLImageSync::GetSize() {
61 NOTREACHED();
62 return gfx::Size();
63 }
64
65 bool GLImageSync::BindTexImage(unsigned target) {
66 NOTREACHED();
67 return false;
68 }
69
70 void GLImageSync::ReleaseTexImage(unsigned target) {
71 NOTREACHED();
72 }
73
74 void GLImageSync::WillUseTexImage() {
75 if (buffer_)
76 buffer_->WillRead(this);
77 }
78
79 void GLImageSync::DidUseTexImage() {
80 if (buffer_)
81 buffer_->DidRead(this);
82 }
83
84 void GLImageSync::WillModifyTexImage() {
85 if (buffer_)
86 buffer_->WillWrite(this);
87 }
88
89 void GLImageSync::DidModifyTexImage() {
90 if (buffer_)
91 buffer_->DidWrite(this);
92 }
93
94 void GLImageSync::SetReleaseAfterUse() {
95 NOTREACHED();
96 }
97
98 #if !defined(OS_MACOSX)
99 class NativeImageBufferEGL : public NativeImageBuffer {
100 public:
101 static NativeImageBufferEGL* Create(GLuint texture_id);
102
103 private:
104 explicit NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
105 virtual ~NativeImageBufferEGL();
106 virtual void BindToTexture(GLenum target) OVERRIDE;
107
108 EGLDisplay egl_display_;
109 EGLImageKHR egl_image_;
110
111 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
112 };
113
114 NativeImageBufferEGL* NativeImageBufferEGL::Create(GLuint texture_id) {
piman 2014/03/13 04:41:58 nit: return a scoped_refptr<NativeImageBufferEGL>
no sievers 2014/03/13 20:50:15 Done.
115 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
116 EGLContext egl_context = eglGetCurrentContext();
117
118 if (egl_context == EGL_NO_CONTEXT || egl_display == EGL_NO_DISPLAY ||
119 !glIsTexture(texture_id)) {
120 return NULL;
121 }
piman 2014/03/13 04:41:58 Can these conditions happen? Should they just be D
no sievers 2014/03/13 20:50:15 You mean no context or display, right?
piman 2014/03/13 23:29:06 Yes, thanks.
122
123 // TODO: Need to generate and check EGL_KHR_gl_texture_2D_image
124 if (!gfx::g_driver_egl.ext.b_EGL_KHR_image_base ||
125 !gfx::g_driver_gl.ext.b_GL_OES_EGL_image) {
126 return NULL;
127 }
128
129 const EGLint egl_attrib_list[] = {
130 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
131 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
132 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
133
134 EGLImageKHR egl_image = eglCreateImageKHR(
135 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
136
137 if (egl_image == EGL_NO_IMAGE_KHR)
138 return NULL;
139
140 return new NativeImageBufferEGL(egl_display, egl_image);
141 }
142
143 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
144 EGLImageKHR image)
145 : egl_display_(display), egl_image_(image) {
146 DCHECK(egl_display_ != EGL_NO_DISPLAY);
147 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
148 }
149
150 NativeImageBufferEGL::~NativeImageBufferEGL() {
151 if (egl_image_ != EGL_NO_IMAGE_KHR)
152 eglDestroyImageKHR(egl_display_, egl_image_);
153 }
154
155 void NativeImageBufferEGL::BindToTexture(GLenum target) {
156 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
157 glEGLImageTargetTexture2DOES(target, egl_image_);
158 DCHECK_EQ(EGL_SUCCESS, (EGLint)eglGetError());
159 DCHECK_EQ(GL_NO_ERROR, (GLint)glGetError());
piman 2014/03/13 04:41:58 nit: no c-style casts. Prefer static_cast or reint
no sievers 2014/03/13 20:50:15 Done.
160 }
161 #endif
162
163 class NativeImageBufferStub : public NativeImageBuffer {
164 public:
165 NativeImageBufferStub() {}
166
167 private:
168 virtual ~NativeImageBufferStub() {}
169 virtual void BindToTexture(GLenum target) OVERRIDE {}
170
171 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
172 };
173
174 } // anonymous namespace
175
176 // static
177 NativeImageBuffer* NativeImageBuffer::Create(GLuint texture_id) {
178 switch (gfx::GetGLImplementation()) {
179 #if !defined(OS_MACOSX)
180 case gfx::kGLImplementationEGLGLES2:
181 return NativeImageBufferEGL::Create(texture_id);
182 #endif
183 case gfx::kGLImplementationMockGL:
184 return new NativeImageBufferStub;
185 default:
186 NOTREACHED();
187 return NULL;
188 }
189 }
190
191 NativeImageBuffer::ClientInfo::ClientInfo(gfx::GLImage* client)
192 : client(client), needs_wait_before_read(true) {}
193
194 NativeImageBuffer::ClientInfo::~ClientInfo() {}
195
196 NativeImageBuffer::NativeImageBuffer() : write_client_(NULL) {
197 write_fence_.reset(gfx::GLFence::Create());
198 }
199
200 NativeImageBuffer::~NativeImageBuffer() {
201 DCHECK(client_infos_.empty());
202 }
203
204 void NativeImageBuffer::AddClient(gfx::GLImage* client) {
205 base::AutoLock lock(lock_);
206 client_infos_.push_back(ClientInfo(client));
207 }
208
209 void NativeImageBuffer::RemoveClient(gfx::GLImage* client) {
210 base::AutoLock lock(lock_);
211 if (write_client_ == client)
212 write_client_ = NULL;
213 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
214 it != client_infos_.end();
215 it++) {
216 if (it->client == client) {
217 client_infos_.erase(it);
218 return;
219 }
220 }
221 NOTREACHED();
222 }
223
224 bool NativeImageBuffer::IsClient(gfx::GLImage* client) {
225 base::AutoLock lock(lock_);
226 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
227 it != client_infos_.end();
228 it++) {
229 if (it->client == client)
230 return true;
231 }
232 return false;
233 }
234
235 void NativeImageBuffer::WillRead(gfx::GLImage* client) {
236 base::AutoLock lock(lock_);
237 if (!write_fence_.get() || write_client_ == client)
238 return;
239
240 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
241 it != client_infos_.end();
242 it++) {
243 if (it->client == client) {
244 if (it->needs_wait_before_read) {
245 it->needs_wait_before_read = false;
246 write_fence_->ServerWait();
247 }
248 return;
249 }
250 }
251 NOTREACHED();
252 }
253
254 void NativeImageBuffer::WillWrite(gfx::GLImage* client) {
255 base::AutoLock lock(lock_);
256 if (write_client_ != client)
257 write_fence_->ServerWait();
258
259 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
260 it != client_infos_.end();
261 it++) {
262 if (it->read_fence.get() && it->client != client)
263 it->read_fence->ServerWait();
264 }
265 }
266
267 void NativeImageBuffer::DidRead(gfx::GLImage* client) {
268 base::AutoLock lock(lock_);
269 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
270 it != client_infos_.end();
271 it++) {
272 if (it->client == client) {
273 it->read_fence = make_linked_ptr(gfx::GLFence::Create());
274 return;
275 }
276 }
277 NOTREACHED();
278 }
279
280 void NativeImageBuffer::DidWrite(gfx::GLImage* client) {
281 base::AutoLock lock(lock_);
282 // TODO(sievers): This is super-risky. We need to somehow find out
283 // about when the current context gets flushed, so that we will only
284 // ever wait on the write fence (esp. from another context) if it was
285 // flushed and is guaranteed to clear.
286 // On the other hand, proactively flushing here is not feasible in terms
287 // of perf when there are multiple draw calls per frame.
piman 2014/03/13 04:41:58 So, the risk is that if we're missing a sync point
no sievers 2014/03/13 20:50:15 Can I owe this as an immediate follow-up? I was al
piman 2014/03/13 23:29:06 Maybe file a bug and reference here... It's not so
no sievers 2014/03/13 23:51:13 Done.
288 write_fence_.reset(gfx::GLFence::CreateWithoutFlush());
289 write_client_ = client;
290 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
291 it != client_infos_.end();
292 it++) {
293 it->needs_wait_before_read = true;
294 }
295 }
296
297 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
298 GLenum internal_format,
299 GLsizei width,
300 GLsizei height,
301 GLsizei depth,
302 GLint border,
303 GLenum format,
304 GLenum type,
305 bool cleared)
306 : target(target),
307 internal_format(internal_format),
308 width(width),
309 height(height),
310 depth(depth),
311 border(border),
312 format(format),
313 type(type),
314 cleared(cleared) {}
315
316 TextureDefinition::LevelInfo::~LevelInfo() {}
317
318 TextureDefinition::TextureDefinition(GLenum target,
319 Texture* texture,
320 unsigned int version,
321 NativeImageBuffer* image)
322 : version_(version),
323 target_(target),
324 image_(image ? image : NativeImageBuffer::Create(texture->service_id())),
325 min_filter_(texture->min_filter()),
326 mag_filter_(texture->mag_filter()),
327 wrap_s_(texture->wrap_s()),
328 wrap_t_(texture->wrap_t()),
329 usage_(texture->usage()),
330 immutable_(texture->IsImmutable()) {
331
332 // TODO
333 DCHECK(!texture->level_infos_.empty());
334 DCHECK(!texture->level_infos_[0].empty());
335 DCHECK(!texture->NeedsMips());
336 DCHECK(texture->level_infos_[0][0].width);
337 DCHECK(texture->level_infos_[0][0].height);
338
339 scoped_refptr<gfx::GLImage> gl_image(new GLImageSync(image_));
340 texture->SetLevelImage(NULL, target, 0, gl_image);
341
342 // TODO: all levels
343 level_infos_.clear();
344 const Texture::LevelInfo& level = texture->level_infos_[0][0];
345 LevelInfo info(level.target,
346 level.internal_format,
347 level.width,
348 level.height,
349 level.depth,
350 level.border,
351 level.format,
352 level.type,
353 level.cleared);
354 std::vector<LevelInfo> infos;
355 infos.push_back(info);
356 level_infos_.push_back(infos);
357
358 }
359
360 TextureDefinition::~TextureDefinition() {
361 }
362
363 Texture* TextureDefinition::CreateTexture() const {
364 if (!image_)
365 return NULL;
366
367 GLuint texture_id;
368 glGenTextures(1, &texture_id);
369
370 Texture* texture(new Texture(texture_id));
371 UpdateTexture(texture);
372
373 return texture;
374 }
375
376 void TextureDefinition::UpdateTexture(Texture* texture) const {
377 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
378 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
379 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
382 DCHECK(image_);
383 if (image_)
piman 2014/03/13 04:41:58 DCHECK, or if? Chose one.
no sievers 2014/03/13 20:50:15 Done. Should eventually handle incomplete textures
384 image_->BindToTexture(target_);
385 glFlush();
piman 2014/03/13 04:41:58 DO you need this glFlush?
no sievers 2014/03/13 20:50:15 Most of the time probably not. There is one case I
piman 2014/03/13 23:29:06 I see... arguably, ctx2a needs to flush after the
no sievers 2014/03/13 23:51:13 Done. Maybe we could be smarter about when the flu
386
387 texture->level_infos_.resize(1);
388 for (size_t i = 0; i < level_infos_.size(); i++) {
389 const LevelInfo& base_info = level_infos_[i][0];
390 const size_t levels_needed = TextureManager::ComputeMipMapCount(
391 base_info.target, base_info.width, base_info.height, base_info.depth);
392 DCHECK(level_infos_.size() <= levels_needed);
393 texture->level_infos_[0].resize(levels_needed);
394 for (size_t n = 0; n < level_infos_.size(); n++) {
395 const LevelInfo& info = level_infos_[i][n];
396 texture->SetLevelInfo(NULL,
397 info.target,
398 i,
399 info.internal_format,
400 info.width,
401 info.height,
402 info.depth,
403 info.border,
404 info.format,
405 info.type,
406 info.cleared);
407 }
408 }
409 if (image_)
410 texture->SetLevelImage(NULL, target_, 0, new GLImageSync(image_));
411
412 texture->target_ = target_;
413 texture->SetImmutable(immutable_);
414 texture->min_filter_ = min_filter_;
415 texture->mag_filter_ = mag_filter_;
416 texture->wrap_s_ = wrap_s_;
417 texture->wrap_t_ = wrap_t_;
418 texture->usage_ = usage_;
419 }
420
421 bool TextureDefinition::Matches(const Texture* texture) const {
422 DCHECK(target_ == texture->target());
423 if (texture->min_filter_ != min_filter_ ||
424 texture->mag_filter_ != mag_filter_ ||
425 texture->wrap_s_ != wrap_s_ ||
426 texture->wrap_t_ != wrap_t_) {
427 return false;
428 }
429
430 // All structural changes should have orphaned the texture.
431 if (image_ && !texture->GetLevelImage(texture->target(), 0))
432 return false;
433
434 return true;
435 }
436
437 } // namespace gles2
438 } // namespace gpu
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698