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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: gpu/command_buffer/service/texture_definition.cc
diff --git a/gpu/command_buffer/service/texture_definition.cc b/gpu/command_buffer/service/texture_definition.cc
new file mode 100644
index 0000000000000000000000000000000000000000..69ca8eba74b23fcc451b490adea0909400444b8f
--- /dev/null
+++ b/gpu/command_buffer/service/texture_definition.cc
@@ -0,0 +1,445 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/texture_definition.h"
+
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/scoped_binders.h"
+
+#if !defined(OS_MACOSX)
+#include "ui/gl/gl_surface_egl.h"
+#endif
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+class GLImageSync : public gfx::GLImage {
+ public:
+ explicit GLImageSync(
+ const scoped_refptr<NativeImageBuffer>& buffer);
+
+ // Implement GLImage.
+ virtual void Destroy() OVERRIDE;
+ virtual gfx::Size GetSize() OVERRIDE;
+ virtual bool BindTexImage(unsigned target) OVERRIDE;
+ virtual void ReleaseTexImage(unsigned target) OVERRIDE;
+ virtual void WillUseTexImage() OVERRIDE;
+ virtual void WillModifyTexImage() OVERRIDE;
+ virtual void DidModifyTexImage() OVERRIDE;
+
+ virtual void DidUseTexImage() OVERRIDE;
+ virtual void SetReleaseAfterUse() OVERRIDE;
+
+ protected:
+ virtual ~GLImageSync();
+
+ private:
+ scoped_refptr<NativeImageBuffer> buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLImageSync);
+};
+
+GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer)
+ : buffer_(buffer) {
+ if (buffer)
+ buffer->AddClient(this);
+}
+
+GLImageSync::~GLImageSync() {
+ if (buffer_)
+ buffer_->RemoveClient(this);
+}
+
+void GLImageSync::Destroy() {}
+
+gfx::Size GLImageSync::GetSize() {
+ NOTREACHED();
+ return gfx::Size();
+}
+
+bool GLImageSync::BindTexImage(unsigned target) {
+ NOTREACHED();
+ return false;
+}
+
+void GLImageSync::ReleaseTexImage(unsigned target) {
+ NOTREACHED();
+}
+
+void GLImageSync::WillUseTexImage() {
+ if (buffer_)
+ buffer_->WillRead(this);
+}
+
+void GLImageSync::DidUseTexImage() {
+ if (buffer_)
+ buffer_->DidRead(this);
+}
+
+void GLImageSync::WillModifyTexImage() {
+ if (buffer_)
+ buffer_->WillWrite(this);
+}
+
+void GLImageSync::DidModifyTexImage() {
+ if (buffer_)
+ buffer_->DidWrite(this);
+}
+
+void GLImageSync::SetReleaseAfterUse() {
+ NOTREACHED();
+}
+
+#if !defined(OS_MACOSX)
+class NativeImageBufferEGL : public NativeImageBuffer {
+ public:
+ static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
+
+ private:
+ explicit NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
+ virtual ~NativeImageBufferEGL();
+ virtual void BindToTexture(GLenum target) OVERRIDE;
+
+ EGLDisplay egl_display_;
+ EGLImageKHR egl_image_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
+};
+
+scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
+ GLuint texture_id) {
+ EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
+ EGLContext egl_context = eglGetCurrentContext();
+
+ DCHECK_NE(EGL_NO_CONTEXT, egl_context);
+ DCHECK_NE(EGL_NO_DISPLAY, egl_display);
+ DCHECK(glIsTexture(texture_id));
+
+ // TODO: Need to generate and check EGL_KHR_gl_texture_2D_image
+ if (!gfx::g_driver_egl.ext.b_EGL_KHR_image_base ||
+ !gfx::g_driver_gl.ext.b_GL_OES_EGL_image) {
+ return NULL;
+ }
+
+ const EGLint egl_attrib_list[] = {
+ EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
+ EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
+
+ EGLImageKHR egl_image = eglCreateImageKHR(
+ egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
+
+ if (egl_image == EGL_NO_IMAGE_KHR)
+ return NULL;
+
+ return new NativeImageBufferEGL(egl_display, egl_image);
+}
+
+NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
+ EGLImageKHR image)
+ : egl_display_(display), egl_image_(image) {
+ DCHECK(egl_display_ != EGL_NO_DISPLAY);
+ DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
+}
+
+NativeImageBufferEGL::~NativeImageBufferEGL() {
+ if (egl_image_ != EGL_NO_IMAGE_KHR)
+ eglDestroyImageKHR(egl_display_, egl_image_);
+}
+
+void NativeImageBufferEGL::BindToTexture(GLenum target) {
+ DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
+ glEGLImageTargetTexture2DOES(target, egl_image_);
+ DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+}
+#endif
+
+class NativeImageBufferStub : public NativeImageBuffer {
+ public:
+ NativeImageBufferStub() {}
+
+ private:
+ virtual ~NativeImageBufferStub() {}
+ virtual void BindToTexture(GLenum target) OVERRIDE {}
+
+ DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
+};
+
+} // anonymous namespace
+
+// static
+scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
+ switch (gfx::GetGLImplementation()) {
+#if !defined(OS_MACOSX)
+ case gfx::kGLImplementationEGLGLES2:
+ return NativeImageBufferEGL::Create(texture_id);
+#endif
+ case gfx::kGLImplementationMockGL:
+ return new NativeImageBufferStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+NativeImageBuffer::ClientInfo::ClientInfo(gfx::GLImage* client)
+ : client(client), needs_wait_before_read(true) {}
+
+NativeImageBuffer::ClientInfo::~ClientInfo() {}
+
+NativeImageBuffer::NativeImageBuffer() : write_client_(NULL) {
+ write_fence_.reset(gfx::GLFence::Create());
+}
+
+NativeImageBuffer::~NativeImageBuffer() {
+ DCHECK(client_infos_.empty());
+}
+
+void NativeImageBuffer::AddClient(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ client_infos_.push_back(ClientInfo(client));
+}
+
+void NativeImageBuffer::RemoveClient(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ if (write_client_ == client)
+ write_client_ = NULL;
+ for (std::list<ClientInfo>::iterator it = client_infos_.begin();
+ it != client_infos_.end();
+ it++) {
+ if (it->client == client) {
+ client_infos_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+bool NativeImageBuffer::IsClient(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ for (std::list<ClientInfo>::iterator it = client_infos_.begin();
+ it != client_infos_.end();
+ it++) {
+ if (it->client == client)
+ return true;
+ }
+ return false;
+}
+
+void NativeImageBuffer::WillRead(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ if (!write_fence_.get() || write_client_ == client)
+ return;
+
+ for (std::list<ClientInfo>::iterator it = client_infos_.begin();
+ it != client_infos_.end();
+ it++) {
+ if (it->client == client) {
+ if (it->needs_wait_before_read) {
+ it->needs_wait_before_read = false;
+ write_fence_->ServerWait();
+ }
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+void NativeImageBuffer::WillWrite(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ if (write_client_ != client)
+ write_fence_->ServerWait();
+
+ for (std::list<ClientInfo>::iterator it = client_infos_.begin();
+ it != client_infos_.end();
+ it++) {
+ if (it->read_fence.get() && it->client != client)
+ it->read_fence->ServerWait();
+ }
+}
+
+void NativeImageBuffer::DidRead(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ for (std::list<ClientInfo>::iterator it = client_infos_.begin();
+ it != client_infos_.end();
+ it++) {
+ if (it->client == client) {
+ it->read_fence = make_linked_ptr(gfx::GLFence::Create());
+ return;
+ }
+ }
+ NOTREACHED();
+}
+
+void NativeImageBuffer::DidWrite(gfx::GLImage* client) {
+ base::AutoLock lock(lock_);
+ // TODO(sievers): crbug.com/352419
+ // This is super-risky. We need to somehow find out about when the current
+ // context gets flushed, so that we will only ever wait on the write fence
+ // (esp. from another context) if it was flushed and is guaranteed to clear.
+ // On the other hand, proactively flushing here is not feasible in terms
+ // of perf when there are multiple draw calls per frame.
+ write_fence_.reset(gfx::GLFence::CreateWithoutFlush());
+ write_client_ = client;
+ for (std::list<ClientInfo>::iterator it = client_infos_.begin();
+ it != client_infos_.end();
+ it++) {
+ it->needs_wait_before_read = true;
+ }
+}
+
+TextureDefinition::LevelInfo::LevelInfo(GLenum target,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ bool cleared)
+ : target(target),
+ internal_format(internal_format),
+ width(width),
+ height(height),
+ depth(depth),
+ border(border),
+ format(format),
+ type(type),
+ cleared(cleared) {}
+
+TextureDefinition::LevelInfo::~LevelInfo() {}
+
+TextureDefinition::TextureDefinition(
+ GLenum target,
+ Texture* texture,
+ unsigned int version,
+ const scoped_refptr<NativeImageBuffer>& image_buffer)
+ : version_(version),
+ target_(target),
+ image_buffer_(image_buffer ? image_buffer : NativeImageBuffer::Create(
+ texture->service_id())),
+ min_filter_(texture->min_filter()),
+ mag_filter_(texture->mag_filter()),
+ wrap_s_(texture->wrap_s()),
+ wrap_t_(texture->wrap_t()),
+ usage_(texture->usage()),
+ immutable_(texture->IsImmutable()) {
+
+ // TODO
+ DCHECK(!texture->level_infos_.empty());
+ DCHECK(!texture->level_infos_[0].empty());
+ DCHECK(!texture->NeedsMips());
+ DCHECK(texture->level_infos_[0][0].width);
+ DCHECK(texture->level_infos_[0][0].height);
+
+ scoped_refptr<gfx::GLImage> gl_image(new GLImageSync(image_buffer_));
+ texture->SetLevelImage(NULL, target, 0, gl_image);
+
+ // TODO: all levels
+ level_infos_.clear();
+ const Texture::LevelInfo& level = texture->level_infos_[0][0];
+ LevelInfo info(level.target,
+ level.internal_format,
+ level.width,
+ level.height,
+ level.depth,
+ level.border,
+ level.format,
+ level.type,
+ level.cleared);
+ std::vector<LevelInfo> infos;
+ infos.push_back(info);
+ level_infos_.push_back(infos);
+
+}
+
+TextureDefinition::~TextureDefinition() {
+}
+
+Texture* TextureDefinition::CreateTexture() const {
+ if (!image_buffer_)
+ return NULL;
+
+ GLuint texture_id;
+ glGenTextures(1, &texture_id);
+
+ Texture* texture(new Texture(texture_id));
+ UpdateTexture(texture);
+
+ return texture;
+}
+
+void TextureDefinition::UpdateTexture(Texture* texture) const {
+ gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
+ if (image_buffer_)
+ image_buffer_->BindToTexture(target_);
+ // We have to make sure the changes are visible to other clients in this share
+ // group. As far as the clients are concerned, the mailbox semantics only
+ // demand a single flush from the client after changes are first made,
+ // and it is not visible to them when another share group boundary is crossed.
+ // We could probably track this and be a bit smarter about when to flush
+ // though.
+ glFlush();
+
+ texture->level_infos_.resize(1);
+ for (size_t i = 0; i < level_infos_.size(); i++) {
+ const LevelInfo& base_info = level_infos_[i][0];
+ const size_t levels_needed = TextureManager::ComputeMipMapCount(
+ base_info.target, base_info.width, base_info.height, base_info.depth);
+ DCHECK(level_infos_.size() <= levels_needed);
+ texture->level_infos_[0].resize(levels_needed);
+ for (size_t n = 0; n < level_infos_.size(); n++) {
+ const LevelInfo& info = level_infos_[i][n];
+ texture->SetLevelInfo(NULL,
+ info.target,
+ i,
+ info.internal_format,
+ info.width,
+ info.height,
+ info.depth,
+ info.border,
+ info.format,
+ info.type,
+ info.cleared);
+ }
+ }
+ if (image_buffer_)
+ texture->SetLevelImage(NULL, target_, 0, new GLImageSync(image_buffer_));
+
+ texture->target_ = target_;
+ texture->SetImmutable(immutable_);
+ texture->min_filter_ = min_filter_;
+ texture->mag_filter_ = mag_filter_;
+ texture->wrap_s_ = wrap_s_;
+ texture->wrap_t_ = wrap_t_;
+ texture->usage_ = usage_;
+}
+
+bool TextureDefinition::Matches(const Texture* texture) const {
+ DCHECK(target_ == texture->target());
+ if (texture->min_filter_ != min_filter_ ||
+ texture->mag_filter_ != mag_filter_ ||
+ texture->wrap_s_ != wrap_s_ ||
+ texture->wrap_t_ != wrap_t_) {
+ return false;
+ }
+
+ // All structural changes should have orphaned the texture.
+ if (image_buffer_ && !texture->GetLevelImage(texture->target(), 0))
+ return false;
+
+ return true;
+}
+
+} // namespace gles2
+} // namespace gpu
« 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