Correctly track texture cleared state for sharing
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blob7af662c400c7b29348a117ff1c42621f80a10000
1 // Copyright 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.
5 #include "gpu/command_buffer/service/texture_definition.h"
7 #include <list>
9 #include "base/memory/linked_ptr.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "base/synchronization/lock.h"
12 #include "gpu/command_buffer/service/texture_manager.h"
13 #include "ui/gl/gl_image.h"
14 #include "ui/gl/gl_implementation.h"
15 #include "ui/gl/scoped_binders.h"
17 #if !defined(OS_MACOSX)
18 #include "ui/gl/gl_surface_egl.h"
19 #endif
21 namespace gpu {
22 namespace gles2 {
24 namespace {
26 class GLImageSync : public gfx::GLImage {
27 public:
28 explicit GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
29 const gfx::Size& size);
31 // Implement GLImage.
32 void Destroy(bool have_context) override;
33 gfx::Size GetSize() override;
34 bool BindTexImage(unsigned target) override;
35 void ReleaseTexImage(unsigned target) override;
36 bool CopyTexImage(unsigned target) override;
37 void WillUseTexImage() override;
38 void WillModifyTexImage() override;
39 void DidModifyTexImage() override;
40 void DidUseTexImage() override;
41 bool ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
42 int z_order,
43 gfx::OverlayTransform transform,
44 const gfx::Rect& bounds_rect,
45 const gfx::RectF& crop_rect) override;
47 protected:
48 ~GLImageSync() override;
50 private:
51 scoped_refptr<NativeImageBuffer> buffer_;
52 gfx::Size size_;
54 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
57 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer,
58 const gfx::Size& size)
59 : buffer_(buffer), size_(size) {
60 if (buffer.get())
61 buffer->AddClient(this);
64 GLImageSync::~GLImageSync() {
65 if (buffer_.get())
66 buffer_->RemoveClient(this);
69 void GLImageSync::Destroy(bool have_context) {
72 gfx::Size GLImageSync::GetSize() {
73 return size_;
76 bool GLImageSync::BindTexImage(unsigned target) {
77 NOTREACHED();
78 return false;
81 void GLImageSync::ReleaseTexImage(unsigned target) {
82 NOTREACHED();
85 bool GLImageSync::CopyTexImage(unsigned target) {
86 return false;
89 void GLImageSync::WillUseTexImage() {
92 void GLImageSync::DidUseTexImage() {
95 void GLImageSync::WillModifyTexImage() {
98 void GLImageSync::DidModifyTexImage() {
101 bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
102 int z_order,
103 gfx::OverlayTransform transform,
104 const gfx::Rect& bounds_rect,
105 const gfx::RectF& crop_rect) {
106 NOTREACHED();
107 return false;
110 #if !defined(OS_MACOSX)
111 class NativeImageBufferEGL : public NativeImageBuffer {
112 public:
113 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
115 private:
116 NativeImageBufferEGL(EGLDisplay display, EGLImageKHR image);
117 ~NativeImageBufferEGL() override;
118 void AddClient(gfx::GLImage* client) override;
119 void RemoveClient(gfx::GLImage* client) override;
120 bool IsClient(gfx::GLImage* client) override;
121 void BindToTexture(GLenum target) override;
123 EGLDisplay egl_display_;
124 EGLImageKHR egl_image_;
126 base::Lock lock_;
128 struct ClientInfo {
129 ClientInfo(gfx::GLImage* client);
130 ~ClientInfo();
132 gfx::GLImage* client;
133 bool needs_wait_before_read;
135 std::list<ClientInfo> client_infos_;
136 gfx::GLImage* write_client_;
138 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
141 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
142 GLuint texture_id) {
143 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
144 EGLContext egl_context = eglGetCurrentContext();
146 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
147 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
148 DCHECK(glIsTexture(texture_id));
150 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
151 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
152 gfx::g_driver_gl.ext.b_GL_OES_EGL_image);
154 const EGLint egl_attrib_list[] = {
155 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
156 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
157 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
159 EGLImageKHR egl_image = eglCreateImageKHR(
160 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
162 if (egl_image == EGL_NO_IMAGE_KHR)
163 return NULL;
165 return new NativeImageBufferEGL(egl_display, egl_image);
168 NativeImageBufferEGL::ClientInfo::ClientInfo(gfx::GLImage* client)
169 : client(client), needs_wait_before_read(true) {}
171 NativeImageBufferEGL::ClientInfo::~ClientInfo() {}
173 NativeImageBufferEGL::NativeImageBufferEGL(EGLDisplay display,
174 EGLImageKHR image)
175 : NativeImageBuffer(),
176 egl_display_(display),
177 egl_image_(image),
178 write_client_(NULL) {
179 DCHECK(egl_display_ != EGL_NO_DISPLAY);
180 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
183 NativeImageBufferEGL::~NativeImageBufferEGL() {
184 DCHECK(client_infos_.empty());
185 if (egl_image_ != EGL_NO_IMAGE_KHR)
186 eglDestroyImageKHR(egl_display_, egl_image_);
189 void NativeImageBufferEGL::AddClient(gfx::GLImage* client) {
190 base::AutoLock lock(lock_);
191 client_infos_.push_back(ClientInfo(client));
194 void NativeImageBufferEGL::RemoveClient(gfx::GLImage* client) {
195 base::AutoLock lock(lock_);
196 if (write_client_ == client)
197 write_client_ = NULL;
198 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
199 it != client_infos_.end();
200 it++) {
201 if (it->client == client) {
202 client_infos_.erase(it);
203 return;
206 NOTREACHED();
209 bool NativeImageBufferEGL::IsClient(gfx::GLImage* client) {
210 base::AutoLock lock(lock_);
211 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
212 it != client_infos_.end();
213 it++) {
214 if (it->client == client)
215 return true;
217 return false;
220 void NativeImageBufferEGL::BindToTexture(GLenum target) {
221 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
222 glEGLImageTargetTexture2DOES(target, egl_image_);
223 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
224 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
227 #endif
229 class NativeImageBufferStub : public NativeImageBuffer {
230 public:
231 NativeImageBufferStub() : NativeImageBuffer() {}
233 private:
234 ~NativeImageBufferStub() override {}
235 void AddClient(gfx::GLImage* client) override {}
236 void RemoveClient(gfx::GLImage* client) override {}
237 bool IsClient(gfx::GLImage* client) override { return true; }
238 void BindToTexture(GLenum target) override {}
240 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
243 } // anonymous namespace
245 // static
246 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
247 switch (gfx::GetGLImplementation()) {
248 #if !defined(OS_MACOSX)
249 case gfx::kGLImplementationEGLGLES2:
250 return NativeImageBufferEGL::Create(texture_id);
251 #endif
252 case gfx::kGLImplementationMockGL:
253 return new NativeImageBufferStub;
254 default:
255 NOTREACHED();
256 return NULL;
260 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
261 GLenum internal_format,
262 GLsizei width,
263 GLsizei height,
264 GLsizei depth,
265 GLint border,
266 GLenum format,
267 GLenum type,
268 bool cleared)
269 : target(target),
270 internal_format(internal_format),
271 width(width),
272 height(height),
273 depth(depth),
274 border(border),
275 format(format),
276 type(type),
277 cleared(cleared) {}
279 TextureDefinition::LevelInfo::~LevelInfo() {}
281 TextureDefinition::TextureDefinition()
282 : version_(0),
283 target_(0),
284 min_filter_(0),
285 mag_filter_(0),
286 wrap_s_(0),
287 wrap_t_(0),
288 usage_(0),
289 immutable_(true) {
292 TextureDefinition::TextureDefinition(
293 Texture* texture,
294 unsigned int version,
295 const scoped_refptr<NativeImageBuffer>& image_buffer)
296 : version_(version),
297 target_(texture->target()),
298 image_buffer_(image_buffer.get()
299 ? image_buffer
300 : NativeImageBuffer::Create(texture->service_id())),
301 min_filter_(texture->min_filter()),
302 mag_filter_(texture->mag_filter()),
303 wrap_s_(texture->wrap_s()),
304 wrap_t_(texture->wrap_t()),
305 usage_(texture->usage()),
306 immutable_(texture->IsImmutable()) {
307 // TODO
308 DCHECK(!texture->face_infos_.empty());
309 DCHECK(!texture->face_infos_[0].level_infos.empty());
310 DCHECK(!texture->NeedsMips());
311 DCHECK(texture->face_infos_[0].level_infos[0].width);
312 DCHECK(texture->face_infos_[0].level_infos[0].height);
314 const Texture::FaceInfo& first_face = texture->face_infos_[0];
315 scoped_refptr<gfx::GLImage> gl_image(
316 new GLImageSync(image_buffer_,
317 gfx::Size(first_face.level_infos[0].width,
318 first_face.level_infos[0].height)));
319 texture->SetLevelImage(NULL, target_, 0, gl_image.get());
321 // TODO: all levels
322 level_infos_.clear();
323 const Texture::LevelInfo& level = first_face.level_infos[0];
324 LevelInfo info(level.target,
325 level.internal_format,
326 level.width,
327 level.height,
328 level.depth,
329 level.border,
330 level.format,
331 level.type,
332 level.cleared);
333 std::vector<LevelInfo> infos;
334 infos.push_back(info);
335 level_infos_.push_back(infos);
338 TextureDefinition::~TextureDefinition() {
341 Texture* TextureDefinition::CreateTexture() const {
342 if (!image_buffer_.get())
343 return NULL;
345 GLuint texture_id;
346 glGenTextures(1, &texture_id);
348 Texture* texture(new Texture(texture_id));
349 UpdateTexture(texture);
351 return texture;
354 void TextureDefinition::UpdateTexture(Texture* texture) const {
355 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
356 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
357 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
358 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
359 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
360 if (image_buffer_.get())
361 image_buffer_->BindToTexture(target_);
362 // We have to make sure the changes are visible to other clients in this share
363 // group. As far as the clients are concerned, the mailbox semantics only
364 // demand a single flush from the client after changes are first made,
365 // and it is not visible to them when another share group boundary is crossed.
366 // We could probably track this and be a bit smarter about when to flush
367 // though.
368 glFlush();
370 texture->face_infos_.resize(1);
371 for (size_t i = 0; i < level_infos_.size(); i++) {
372 const LevelInfo& base_info = level_infos_[i][0];
373 const size_t levels_needed = TextureManager::ComputeMipMapCount(
374 base_info.target, base_info.width, base_info.height, base_info.depth);
375 DCHECK(level_infos_.size() <= levels_needed);
376 texture->face_infos_[0].level_infos.resize(levels_needed);
377 for (size_t n = 0; n < level_infos_.size(); n++) {
378 const LevelInfo& info = level_infos_[i][n];
379 texture->SetLevelInfo(NULL,
380 info.target,
382 info.internal_format,
383 info.width,
384 info.height,
385 info.depth,
386 info.border,
387 info.format,
388 info.type,
389 info.cleared);
392 if (image_buffer_.get()) {
393 texture->SetLevelImage(
394 NULL,
395 target_,
397 new GLImageSync(
398 image_buffer_,
399 gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height)));
402 texture->target_ = target_;
403 texture->SetImmutable(immutable_);
404 texture->min_filter_ = min_filter_;
405 texture->mag_filter_ = mag_filter_;
406 texture->wrap_s_ = wrap_s_;
407 texture->wrap_t_ = wrap_t_;
408 texture->usage_ = usage_;
411 bool TextureDefinition::Matches(const Texture* texture) const {
412 DCHECK(target_ == texture->target());
413 if (texture->min_filter_ != min_filter_ ||
414 texture->mag_filter_ != mag_filter_ ||
415 texture->wrap_s_ != wrap_s_ ||
416 texture->wrap_t_ != wrap_t_ ||
417 texture->SafeToRenderFrom() != SafeToRenderFrom()) {
418 return false;
421 // All structural changes should have orphaned the texture.
422 if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
423 return false;
425 return true;
428 bool TextureDefinition::SafeToRenderFrom() const {
429 for (const std::vector<LevelInfo>& face_info : level_infos_) {
430 for (const LevelInfo& level_info : face_info) {
431 if (!level_info.cleared) {
432 return false;
436 return true;
439 } // namespace gles2
440 } // namespace gpu