OLD | NEW |
(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_fence.h" |
| 9 #include "ui/gl/gl_image.h" |
| 10 #include "ui/gl/gl_implementation.h" |
| 11 #include "ui/gl/gl_surface_egl.h" |
| 12 #include "ui/gl/scoped_binders.h" |
| 13 |
| 14 namespace gpu { |
| 15 namespace gles2 { |
| 16 |
| 17 namespace { |
| 18 |
| 19 class GLImageSync : public gfx::GLImage { |
| 20 public: |
| 21 explicit GLImageSync( |
| 22 const scoped_refptr<const NativeImageBuffer>& buffer, |
| 23 const scoped_refptr<const SharedGLFence>& fence); |
| 24 |
| 25 // Implement GLImage. |
| 26 virtual void Destroy() OVERRIDE; |
| 27 virtual gfx::Size GetSize() OVERRIDE; |
| 28 virtual bool BindTexImage(unsigned target) OVERRIDE; |
| 29 virtual void ReleaseTexImage(unsigned target) OVERRIDE; |
| 30 virtual void WillUseTexImage() OVERRIDE; |
| 31 virtual void DidUseTexImage() OVERRIDE; |
| 32 virtual void SetReleaseAfterUse() OVERRIDE; |
| 33 |
| 34 protected: |
| 35 virtual ~GLImageSync(); |
| 36 |
| 37 private: |
| 38 scoped_refptr<const NativeImageBuffer> buffer_; |
| 39 scoped_refptr<const SharedGLFence> fence_; |
| 40 |
| 41 DISALLOW_COPY_AND_ASSIGN(GLImageSync); |
| 42 }; |
| 43 |
| 44 GLImageSync::GLImageSync(const scoped_refptr<const NativeImageBuffer>& buffer, |
| 45 const scoped_refptr<const SharedGLFence>& fence) |
| 46 : buffer_(buffer), fence_(fence) {} |
| 47 |
| 48 GLImageSync::~GLImageSync() {} |
| 49 |
| 50 void GLImageSync::Destroy() {} |
| 51 |
| 52 gfx::Size GLImageSync::GetSize() { |
| 53 NOTREACHED(); |
| 54 return gfx::Size(); |
| 55 } |
| 56 |
| 57 bool GLImageSync::BindTexImage(unsigned target) { |
| 58 NOTREACHED(); |
| 59 return false; |
| 60 } |
| 61 |
| 62 void GLImageSync::ReleaseTexImage(unsigned target) { |
| 63 NOTREACHED(); |
| 64 } |
| 65 |
| 66 void GLImageSync::WillUseTexImage() { |
| 67 if (fence_.get()) { |
| 68 fence_->GpuWaitSync(); |
| 69 fence_ = NULL; |
| 70 } |
| 71 } |
| 72 |
| 73 void GLImageSync::DidUseTexImage() {} |
| 74 |
| 75 void GLImageSync::SetReleaseAfterUse() { |
| 76 NOTREACHED(); |
| 77 } |
| 78 |
| 79 class NativeImageBufferEGL : public NativeImageBuffer { |
| 80 public: |
| 81 static NativeImageBufferEGL* Create(GLuint texture_id); |
| 82 |
| 83 private: |
| 84 explicit NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image); |
| 85 virtual ~NativeImageBufferEGL(); |
| 86 virtual void BindToTexture(GLenum target) OVERRIDE; |
| 87 |
| 88 EGLDisplay egl_display_; |
| 89 EGLImageKHR egl_image_; |
| 90 |
| 91 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL); |
| 92 }; |
| 93 |
| 94 NativeImageBufferEGL* NativeImageBufferEGL::Create(GLuint texture_id) { |
| 95 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay(); |
| 96 EGLContext egl_context = eglGetCurrentContext(); |
| 97 |
| 98 if (egl_context == EGL_NO_CONTEXT || egl_display == EGL_NO_DISPLAY || |
| 99 !glIsTexture(texture_id)) { |
| 100 return NULL; |
| 101 } |
| 102 |
| 103 if (!gfx::g_driver_egl.ext.b_EGL_KHR_image_base || |
| 104 !gfx::g_driver_gl.ext.b_GL_OES_EGL_image) { |
| 105 return NULL; |
| 106 } |
| 107 |
| 108 const EGLint egl_attrib_list[] = { |
| 109 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE}; |
| 110 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id); |
| 111 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO |
| 112 |
| 113 EGLImageKHR egl_image = eglCreateImageKHR( |
| 114 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list); |
| 115 |
| 116 if (egl_image == EGL_NO_IMAGE_KHR) |
| 117 return NULL; |
| 118 |
| 119 return new NativeImageBufferEGL(egl_display, egl_image); |
| 120 } |
| 121 |
| 122 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display, |
| 123 EGLImageKHR image) |
| 124 : egl_display_(display), egl_image_(image) { |
| 125 DCHECK(egl_display_ != EGL_NO_DISPLAY); |
| 126 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR); |
| 127 } |
| 128 |
| 129 NativeImageBufferEGL::~NativeImageBufferEGL() { |
| 130 if (egl_image_ != EGL_NO_IMAGE_KHR) |
| 131 eglDestroyImageKHR(egl_display_, egl_image_); |
| 132 } |
| 133 |
| 134 void NativeImageBufferEGL::BindToTexture(GLenum target) { |
| 135 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR); |
| 136 glEGLImageTargetTexture2DOES(target, egl_image_); |
| 137 DCHECK_EQ(EGL_SUCCESS, (EGLint)eglGetError()); |
| 138 DCHECK_EQ(GL_NO_ERROR, (GLint)glGetError()); |
| 139 } |
| 140 |
| 141 } // anonymous namespace |
| 142 |
| 143 // static |
| 144 NativeImageBuffer* NativeImageBuffer::Create(GLuint texture_id) { |
| 145 switch (gfx::GetGLImplementation()) { |
| 146 case gfx::kGLImplementationEGLGLES2: |
| 147 return NativeImageBufferEGL::Create(texture_id); |
| 148 case gfx::kGLImplementationMockGL: |
| 149 default: |
| 150 NOTREACHED(); |
| 151 return NULL; |
| 152 } |
| 153 } |
| 154 |
| 155 SharedGLFence::SharedGLFence() : fence_(gfx::GLFence::Create()) {} |
| 156 |
| 157 SharedGLFence::~SharedGLFence() {} |
| 158 |
| 159 void SharedGLFence::GpuWaitSync() const { |
| 160 fence_->ServerWait(); |
| 161 } |
| 162 |
| 163 TextureDefinition::LevelInfo::LevelInfo(GLenum target, |
| 164 GLenum internal_format, |
| 165 GLsizei width, |
| 166 GLsizei height, |
| 167 GLsizei depth, |
| 168 GLint border, |
| 169 GLenum format, |
| 170 GLenum type, |
| 171 bool cleared) |
| 172 : target(target), |
| 173 internal_format(internal_format), |
| 174 width(width), |
| 175 height(height), |
| 176 depth(depth), |
| 177 border(border), |
| 178 format(format), |
| 179 type(type), |
| 180 cleared(cleared) {} |
| 181 |
| 182 TextureDefinition::LevelInfo::~LevelInfo() {} |
| 183 |
| 184 TextureDefinition::TextureDefinition(GLenum target, |
| 185 Texture* texture, |
| 186 NativeImageBuffer* image, |
| 187 const scoped_refptr<SharedGLFence>& fence) |
| 188 : target_(target), |
| 189 image_(image ? image : NativeImageBuffer::Create(texture->service_id())), |
| 190 fence_(fence), |
| 191 min_filter_(texture->min_filter()), |
| 192 mag_filter_(texture->mag_filter()), |
| 193 wrap_s_(texture->wrap_s()), |
| 194 wrap_t_(texture->wrap_t()), |
| 195 usage_(texture->usage()), |
| 196 immutable_(texture->IsImmutable()) { |
| 197 |
| 198 // TODO |
| 199 DCHECK(!texture->level_infos_.empty()); |
| 200 DCHECK(!texture->level_infos_[0].empty()); |
| 201 DCHECK(!texture->NeedsMips()); |
| 202 DCHECK(texture->level_infos_[0][0].width); |
| 203 DCHECK(texture->level_infos_[0][0].height); |
| 204 |
| 205 // TODO: If the texture is not complete, we should defer creating the image |
| 206 // until the next sync after it becomes complete. |
| 207 scoped_refptr<gfx::GLImage> gl_image(new GLImageSync(image, fence)); |
| 208 texture->SetLevelImage(NULL, target, 0, gl_image); |
| 209 |
| 210 // TODO: all levels |
| 211 level_infos_.clear(); |
| 212 const Texture::LevelInfo& level = texture->level_infos_[0][0]; |
| 213 LevelInfo info(level.target, |
| 214 level.internal_format, |
| 215 level.width, |
| 216 level.height, |
| 217 level.depth, |
| 218 level.border, |
| 219 level.format, |
| 220 level.type, |
| 221 level.cleared); |
| 222 std::vector<LevelInfo> infos; |
| 223 infos.push_back(info); |
| 224 level_infos_.push_back(infos); |
| 225 |
| 226 } |
| 227 |
| 228 TextureDefinition::~TextureDefinition() { |
| 229 } |
| 230 |
| 231 Texture* TextureDefinition::CreateTexture() const { |
| 232 if (!image_) |
| 233 return NULL; |
| 234 |
| 235 GLuint texture_id; |
| 236 glGenTextures(1, &texture_id); |
| 237 |
| 238 Texture* texture(new Texture(texture_id)); |
| 239 UpdateTexture(texture); |
| 240 |
| 241 return texture; |
| 242 } |
| 243 |
| 244 void TextureDefinition::UpdateTexture(Texture* texture) const { |
| 245 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id()); |
| 246 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_); |
| 247 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_); |
| 248 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_); |
| 249 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_); |
| 250 DCHECK(image_); |
| 251 if (image_) |
| 252 image_->BindToTexture(target_); |
| 253 glFlush(); |
| 254 |
| 255 texture->level_infos_.resize(1); |
| 256 for (size_t i = 0; i < level_infos_.size(); i++) { |
| 257 const LevelInfo& base_info = level_infos_[i][0]; |
| 258 const size_t levels_needed = TextureManager::ComputeMipMapCount( |
| 259 base_info.target, base_info.width, base_info.height, base_info.depth); |
| 260 DCHECK(level_infos_.size() <= levels_needed); |
| 261 texture->level_infos_[0].resize(levels_needed); |
| 262 for (size_t n = 0; n < level_infos_.size(); n++) { |
| 263 const LevelInfo& info = level_infos_[i][n]; |
| 264 texture->SetLevelInfo(NULL, |
| 265 info.target, |
| 266 i, |
| 267 info.internal_format, |
| 268 info.width, |
| 269 info.height, |
| 270 info.depth, |
| 271 info.border, |
| 272 info.format, |
| 273 info.type, |
| 274 info.cleared); |
| 275 } |
| 276 } |
| 277 if (image_) |
| 278 texture->SetLevelImage(NULL, target_, 0, new GLImageSync(image_, fence_)); |
| 279 |
| 280 texture->target_ = target_; |
| 281 texture->SetImmutable(immutable_); |
| 282 texture->min_filter_ = min_filter_; |
| 283 texture->mag_filter_ = mag_filter_; |
| 284 texture->wrap_s_ = wrap_s_; |
| 285 texture->wrap_t_ = wrap_t_; |
| 286 texture->usage_ = usage_; |
| 287 } |
| 288 |
| 289 } // namespace gles2 |
| 290 } // namespace gpu |
OLD | NEW |