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

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: comments 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 scoped_refptr<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 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
115 GLuint texture_id) {
116 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
117 EGLContext egl_context = eglGetCurrentContext();
118
119 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
120 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
121 DCHECK(glIsTexture(texture_id));
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(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
159 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
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 scoped_refptr<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): crbug.com/352419
283 // This is super-risky. We need to somehow find out about when the current
284 // context gets flushed, so that we will only ever wait on the write fence
285 // (esp. from another context) if it was 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.
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(
319 GLenum target,
320 Texture* texture,
321 unsigned int version,
322 const scoped_refptr<NativeImageBuffer>& image_buffer)
323 : version_(version),
324 target_(target),
325 image_buffer_(image_buffer ? image_buffer : NativeImageBuffer::Create(
326 texture->service_id())),
327 min_filter_(texture->min_filter()),
328 mag_filter_(texture->mag_filter()),
329 wrap_s_(texture->wrap_s()),
330 wrap_t_(texture->wrap_t()),
331 usage_(texture->usage()),
332 immutable_(texture->IsImmutable()) {
333
334 // TODO
335 DCHECK(!texture->level_infos_.empty());
336 DCHECK(!texture->level_infos_[0].empty());
337 DCHECK(!texture->NeedsMips());
338 DCHECK(texture->level_infos_[0][0].width);
339 DCHECK(texture->level_infos_[0][0].height);
340
341 scoped_refptr<gfx::GLImage> gl_image(new GLImageSync(image_buffer_));
342 texture->SetLevelImage(NULL, target, 0, gl_image);
343
344 // TODO: all levels
345 level_infos_.clear();
346 const Texture::LevelInfo& level = texture->level_infos_[0][0];
347 LevelInfo info(level.target,
348 level.internal_format,
349 level.width,
350 level.height,
351 level.depth,
352 level.border,
353 level.format,
354 level.type,
355 level.cleared);
356 std::vector<LevelInfo> infos;
357 infos.push_back(info);
358 level_infos_.push_back(infos);
359
360 }
361
362 TextureDefinition::~TextureDefinition() {
363 }
364
365 Texture* TextureDefinition::CreateTexture() const {
366 if (!image_buffer_)
367 return NULL;
368
369 GLuint texture_id;
370 glGenTextures(1, &texture_id);
371
372 Texture* texture(new Texture(texture_id));
373 UpdateTexture(texture);
374
375 return texture;
376 }
377
378 void TextureDefinition::UpdateTexture(Texture* texture) const {
379 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
382 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
383 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
384 if (image_buffer_)
385 image_buffer_->BindToTexture(target_);
386 // We have to make sure the changes are visible to other clients in this share
387 // group. As far as the clients are concerned, the mailbox semantics only
388 // demand a single flush from the client after changes are first made,
389 // and it is not visible to them when another share group boundary is crossed.
390 // We could probably track this and be a bit smarter about when to flush
391 // though.
392 glFlush();
393
394 texture->level_infos_.resize(1);
395 for (size_t i = 0; i < level_infos_.size(); i++) {
396 const LevelInfo& base_info = level_infos_[i][0];
397 const size_t levels_needed = TextureManager::ComputeMipMapCount(
398 base_info.target, base_info.width, base_info.height, base_info.depth);
399 DCHECK(level_infos_.size() <= levels_needed);
400 texture->level_infos_[0].resize(levels_needed);
401 for (size_t n = 0; n < level_infos_.size(); n++) {
402 const LevelInfo& info = level_infos_[i][n];
403 texture->SetLevelInfo(NULL,
404 info.target,
405 i,
406 info.internal_format,
407 info.width,
408 info.height,
409 info.depth,
410 info.border,
411 info.format,
412 info.type,
413 info.cleared);
414 }
415 }
416 if (image_buffer_)
417 texture->SetLevelImage(NULL, target_, 0, new GLImageSync(image_buffer_));
418
419 texture->target_ = target_;
420 texture->SetImmutable(immutable_);
421 texture->min_filter_ = min_filter_;
422 texture->mag_filter_ = mag_filter_;
423 texture->wrap_s_ = wrap_s_;
424 texture->wrap_t_ = wrap_t_;
425 texture->usage_ = usage_;
426 }
427
428 bool TextureDefinition::Matches(const Texture* texture) const {
429 DCHECK(target_ == texture->target());
430 if (texture->min_filter_ != min_filter_ ||
431 texture->mag_filter_ != mag_filter_ ||
432 texture->wrap_s_ != wrap_s_ ||
433 texture->wrap_t_ != wrap_t_) {
434 return false;
435 }
436
437 // All structural changes should have orphaned the texture.
438 if (image_buffer_ && !texture->GetLevelImage(texture->target(), 0))
439 return false;
440
441 return true;
442 }
443
444 } // namespace gles2
445 } // namespace gpu
OLDNEW
« no previous file with comments | « gpu/command_buffer/service/texture_definition.h ('k') | gpu/command_buffer/service/texture_manager.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698