Performance histograms for extension content verification
[chromium-blink-merge.git] / gpu / command_buffer / service / texture_definition.cc
blob24382f0da39734390ccedd940d6aac2d8551afa3
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 "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"
12 #if !defined(OS_MACOSX)
13 #include "ui/gl/gl_surface_egl.h"
14 #endif
16 namespace gpu {
17 namespace gles2 {
19 namespace {
21 class GLImageSync : public gfx::GLImage {
22 public:
23 explicit GLImageSync(
24 const scoped_refptr<NativeImageBuffer>& buffer);
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;
35 virtual void DidUseTexImage() OVERRIDE;
36 virtual void SetReleaseAfterUse() OVERRIDE;
38 protected:
39 virtual ~GLImageSync();
41 private:
42 scoped_refptr<NativeImageBuffer> buffer_;
44 DISALLOW_COPY_AND_ASSIGN(GLImageSync);
47 GLImageSync::GLImageSync(const scoped_refptr<NativeImageBuffer>& buffer)
48 : buffer_(buffer) {
49 if (buffer)
50 buffer->AddClient(this);
53 GLImageSync::~GLImageSync() {
54 if (buffer_)
55 buffer_->RemoveClient(this);
58 void GLImageSync::Destroy() {}
60 gfx::Size GLImageSync::GetSize() {
61 NOTREACHED();
62 return gfx::Size();
65 bool GLImageSync::BindTexImage(unsigned target) {
66 NOTREACHED();
67 return false;
70 void GLImageSync::ReleaseTexImage(unsigned target) {
71 NOTREACHED();
74 void GLImageSync::WillUseTexImage() {
75 if (buffer_)
76 buffer_->WillRead(this);
79 void GLImageSync::DidUseTexImage() {
80 if (buffer_)
81 buffer_->DidRead(this);
84 void GLImageSync::WillModifyTexImage() {
85 if (buffer_)
86 buffer_->WillWrite(this);
89 void GLImageSync::DidModifyTexImage() {
90 if (buffer_)
91 buffer_->DidWrite(this);
94 void GLImageSync::SetReleaseAfterUse() {
95 NOTREACHED();
98 #if !defined(OS_MACOSX)
99 class NativeImageBufferEGL : public NativeImageBuffer {
100 public:
101 static scoped_refptr<NativeImageBufferEGL> Create(GLuint texture_id);
103 private:
104 NativeImageBufferEGL(scoped_ptr<gfx::GLFence> write_fence,
105 EGLDisplay display,
106 EGLImageKHR image);
107 virtual ~NativeImageBufferEGL();
108 virtual void BindToTexture(GLenum target) OVERRIDE;
110 EGLDisplay egl_display_;
111 EGLImageKHR egl_image_;
113 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
116 scoped_refptr<NativeImageBufferEGL> NativeImageBufferEGL::Create(
117 GLuint texture_id) {
118 EGLDisplay egl_display = gfx::GLSurfaceEGL::GetHardwareDisplay();
119 EGLContext egl_context = eglGetCurrentContext();
121 DCHECK_NE(EGL_NO_CONTEXT, egl_context);
122 DCHECK_NE(EGL_NO_DISPLAY, egl_display);
123 DCHECK(glIsTexture(texture_id));
125 DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
126 gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
127 gfx::g_driver_gl.ext.b_GL_OES_EGL_image &&
128 gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync);
130 const EGLint egl_attrib_list[] = {
131 EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
132 EGLClientBuffer egl_buffer = reinterpret_cast<EGLClientBuffer>(texture_id);
133 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR; // TODO
135 EGLImageKHR egl_image = eglCreateImageKHR(
136 egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
138 if (egl_image == EGL_NO_IMAGE_KHR)
139 return NULL;
141 return new NativeImageBufferEGL(
142 make_scoped_ptr(gfx::GLFence::Create()), egl_display, egl_image);
145 NativeImageBufferEGL::NativeImageBufferEGL(scoped_ptr<gfx::GLFence> write_fence,
146 EGLDisplay display,
147 EGLImageKHR image)
148 : NativeImageBuffer(write_fence.Pass()),
149 egl_display_(display),
150 egl_image_(image) {
151 DCHECK(egl_display_ != EGL_NO_DISPLAY);
152 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
155 NativeImageBufferEGL::~NativeImageBufferEGL() {
156 if (egl_image_ != EGL_NO_IMAGE_KHR)
157 eglDestroyImageKHR(egl_display_, egl_image_);
160 void NativeImageBufferEGL::BindToTexture(GLenum target) {
161 DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
162 glEGLImageTargetTexture2DOES(target, egl_image_);
163 DCHECK_EQ(static_cast<EGLint>(EGL_SUCCESS), eglGetError());
164 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
166 #endif
168 class NativeImageBufferStub : public NativeImageBuffer {
169 public:
170 NativeImageBufferStub() : NativeImageBuffer(scoped_ptr<gfx::GLFence>()) {}
172 private:
173 virtual ~NativeImageBufferStub() {}
174 virtual void BindToTexture(GLenum target) OVERRIDE {}
176 DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
179 } // anonymous namespace
181 // static
182 scoped_refptr<NativeImageBuffer> NativeImageBuffer::Create(GLuint texture_id) {
183 switch (gfx::GetGLImplementation()) {
184 #if !defined(OS_MACOSX)
185 case gfx::kGLImplementationEGLGLES2:
186 return NativeImageBufferEGL::Create(texture_id);
187 #endif
188 case gfx::kGLImplementationMockGL:
189 return new NativeImageBufferStub;
190 default:
191 NOTREACHED();
192 return NULL;
196 NativeImageBuffer::ClientInfo::ClientInfo(gfx::GLImage* client)
197 : client(client), needs_wait_before_read(true) {}
199 NativeImageBuffer::ClientInfo::~ClientInfo() {}
201 NativeImageBuffer::NativeImageBuffer(scoped_ptr<gfx::GLFence> write_fence)
202 : write_fence_(write_fence.Pass()), write_client_(NULL) {
205 NativeImageBuffer::~NativeImageBuffer() {
206 DCHECK(client_infos_.empty());
209 void NativeImageBuffer::AddClient(gfx::GLImage* client) {
210 base::AutoLock lock(lock_);
211 client_infos_.push_back(ClientInfo(client));
214 void NativeImageBuffer::RemoveClient(gfx::GLImage* client) {
215 base::AutoLock lock(lock_);
216 if (write_client_ == client)
217 write_client_ = NULL;
218 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
219 it != client_infos_.end();
220 it++) {
221 if (it->client == client) {
222 client_infos_.erase(it);
223 return;
226 NOTREACHED();
229 bool NativeImageBuffer::IsClient(gfx::GLImage* client) {
230 base::AutoLock lock(lock_);
231 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
232 it != client_infos_.end();
233 it++) {
234 if (it->client == client)
235 return true;
237 return false;
240 void NativeImageBuffer::WillRead(gfx::GLImage* client) {
241 base::AutoLock lock(lock_);
242 if (!write_fence_.get() || write_client_ == client)
243 return;
245 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
246 it != client_infos_.end();
247 it++) {
248 if (it->client == client) {
249 if (it->needs_wait_before_read) {
250 it->needs_wait_before_read = false;
251 write_fence_->ServerWait();
253 return;
256 NOTREACHED();
259 void NativeImageBuffer::WillWrite(gfx::GLImage* client) {
260 base::AutoLock lock(lock_);
261 if (write_client_ != client)
262 write_fence_->ServerWait();
264 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
265 it != client_infos_.end();
266 it++) {
267 if (it->read_fence.get() && it->client != client)
268 it->read_fence->ServerWait();
272 void NativeImageBuffer::DidRead(gfx::GLImage* client) {
273 base::AutoLock lock(lock_);
274 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
275 it != client_infos_.end();
276 it++) {
277 if (it->client == client) {
278 it->read_fence = make_linked_ptr(gfx::GLFence::Create());
279 return;
282 NOTREACHED();
285 void NativeImageBuffer::DidWrite(gfx::GLImage* client) {
286 base::AutoLock lock(lock_);
287 // Sharing semantics require the client to flush in order to make changes
288 // visible to other clients.
289 write_fence_.reset(gfx::GLFence::CreateWithoutFlush());
290 write_client_ = client;
291 for (std::list<ClientInfo>::iterator it = client_infos_.begin();
292 it != client_infos_.end();
293 it++) {
294 it->needs_wait_before_read = true;
298 TextureDefinition::LevelInfo::LevelInfo(GLenum target,
299 GLenum internal_format,
300 GLsizei width,
301 GLsizei height,
302 GLsizei depth,
303 GLint border,
304 GLenum format,
305 GLenum type,
306 bool cleared)
307 : target(target),
308 internal_format(internal_format),
309 width(width),
310 height(height),
311 depth(depth),
312 border(border),
313 format(format),
314 type(type),
315 cleared(cleared) {}
317 TextureDefinition::LevelInfo::~LevelInfo() {}
319 TextureDefinition::TextureDefinition(
320 GLenum target,
321 Texture* texture,
322 unsigned int version,
323 const scoped_refptr<NativeImageBuffer>& image_buffer)
324 : version_(version),
325 target_(target),
326 image_buffer_(image_buffer ? image_buffer : NativeImageBuffer::Create(
327 texture->service_id())),
328 min_filter_(texture->min_filter()),
329 mag_filter_(texture->mag_filter()),
330 wrap_s_(texture->wrap_s()),
331 wrap_t_(texture->wrap_t()),
332 usage_(texture->usage()),
333 immutable_(texture->IsImmutable()) {
335 // TODO
336 DCHECK(!texture->level_infos_.empty());
337 DCHECK(!texture->level_infos_[0].empty());
338 DCHECK(!texture->NeedsMips());
339 DCHECK(texture->level_infos_[0][0].width);
340 DCHECK(texture->level_infos_[0][0].height);
342 scoped_refptr<gfx::GLImage> gl_image(new GLImageSync(image_buffer_));
343 texture->SetLevelImage(NULL, target, 0, gl_image);
345 // TODO: all levels
346 level_infos_.clear();
347 const Texture::LevelInfo& level = texture->level_infos_[0][0];
348 LevelInfo info(level.target,
349 level.internal_format,
350 level.width,
351 level.height,
352 level.depth,
353 level.border,
354 level.format,
355 level.type,
356 level.cleared);
357 std::vector<LevelInfo> infos;
358 infos.push_back(info);
359 level_infos_.push_back(infos);
363 TextureDefinition::~TextureDefinition() {
366 Texture* TextureDefinition::CreateTexture() const {
367 if (!image_buffer_)
368 return NULL;
370 GLuint texture_id;
371 glGenTextures(1, &texture_id);
373 Texture* texture(new Texture(texture_id));
374 UpdateTexture(texture);
376 return texture;
379 void TextureDefinition::UpdateTexture(Texture* texture) const {
380 gfx::ScopedTextureBinder texture_binder(target_, texture->service_id());
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter_);
382 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter_);
383 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s_);
384 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t_);
385 if (image_buffer_)
386 image_buffer_->BindToTexture(target_);
387 // We have to make sure the changes are visible to other clients in this share
388 // group. As far as the clients are concerned, the mailbox semantics only
389 // demand a single flush from the client after changes are first made,
390 // and it is not visible to them when another share group boundary is crossed.
391 // We could probably track this and be a bit smarter about when to flush
392 // though.
393 glFlush();
395 texture->level_infos_.resize(1);
396 for (size_t i = 0; i < level_infos_.size(); i++) {
397 const LevelInfo& base_info = level_infos_[i][0];
398 const size_t levels_needed = TextureManager::ComputeMipMapCount(
399 base_info.target, base_info.width, base_info.height, base_info.depth);
400 DCHECK(level_infos_.size() <= levels_needed);
401 texture->level_infos_[0].resize(levels_needed);
402 for (size_t n = 0; n < level_infos_.size(); n++) {
403 const LevelInfo& info = level_infos_[i][n];
404 texture->SetLevelInfo(NULL,
405 info.target,
407 info.internal_format,
408 info.width,
409 info.height,
410 info.depth,
411 info.border,
412 info.format,
413 info.type,
414 info.cleared);
417 if (image_buffer_)
418 texture->SetLevelImage(NULL, target_, 0, new GLImageSync(image_buffer_));
420 texture->target_ = target_;
421 texture->SetImmutable(immutable_);
422 texture->min_filter_ = min_filter_;
423 texture->mag_filter_ = mag_filter_;
424 texture->wrap_s_ = wrap_s_;
425 texture->wrap_t_ = wrap_t_;
426 texture->usage_ = usage_;
429 bool TextureDefinition::Matches(const Texture* texture) const {
430 DCHECK(target_ == texture->target());
431 if (texture->min_filter_ != min_filter_ ||
432 texture->mag_filter_ != mag_filter_ ||
433 texture->wrap_s_ != wrap_s_ ||
434 texture->wrap_t_ != wrap_t_) {
435 return false;
438 // All structural changes should have orphaned the texture.
439 if (image_buffer_ && !texture->GetLevelImage(texture->target(), 0))
440 return false;
442 return true;
445 } // namespace gles2
446 } // namespace gpu