1 // Copyright 2013 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 "cc/test/test_web_graphics_context_3d.h"
10 #include "base/bind.h"
11 #include "base/lazy_instance.h"
12 #include "base/logging.h"
13 #include "base/message_loop/message_loop.h"
14 #include "cc/test/test_context_support.h"
15 #include "gpu/GLES2/gl2extchromium.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/khronos/GLES2/gl2ext.h"
21 static const GLuint kFramebufferId = 1;
22 static const GLuint kRenderbufferId = 2;
24 static unsigned s_context_id = 1;
26 const GLuint TestWebGraphicsContext3D::kExternalTextureId = 1337;
28 static base::LazyInstance<base::Lock>::Leaky
29 g_shared_namespace_lock = LAZY_INSTANCE_INITIALIZER;
31 TestWebGraphicsContext3D::Namespace*
32 TestWebGraphicsContext3D::shared_namespace_ = NULL;
34 TestWebGraphicsContext3D::Namespace::Namespace()
40 TestWebGraphicsContext3D::Namespace::~Namespace() {
41 g_shared_namespace_lock.Get().AssertAcquired();
42 if (shared_namespace_ == this)
43 shared_namespace_ = NULL;
47 scoped_ptr<TestWebGraphicsContext3D> TestWebGraphicsContext3D::Create() {
48 return make_scoped_ptr(new TestWebGraphicsContext3D());
51 TestWebGraphicsContext3D::TestWebGraphicsContext3D()
52 : context_id_(s_context_id++),
53 times_bind_texture_succeeds_(-1),
54 times_end_query_succeeds_(-1),
56 times_map_image_chromium_succeeds_(-1),
57 times_map_buffer_chromium_succeeds_(-1),
58 current_used_transfer_buffer_usage_bytes_(0),
59 max_used_transfer_buffer_usage_bytes_(0),
60 next_program_id_(1000),
61 next_shader_id_(2000),
62 max_texture_size_(2048),
63 reshape_called_(false),
68 last_update_type_(NoUpdate),
69 next_insert_sync_point_(1),
70 last_waited_sync_point_(0),
72 weak_ptr_factory_(this) {
76 TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
77 base::AutoLock lock(g_shared_namespace_lock.Get());
81 void TestWebGraphicsContext3D::CreateNamespace() {
82 base::AutoLock lock(g_shared_namespace_lock.Get());
83 if (shared_namespace_) {
84 namespace_ = shared_namespace_;
86 namespace_ = new Namespace;
87 shared_namespace_ = namespace_.get();
91 void TestWebGraphicsContext3D::reshapeWithScaleFactor(
92 int width, int height, float scale_factor) {
93 reshape_called_ = true;
96 scale_factor_ = scale_factor;
99 bool TestWebGraphicsContext3D::isContextLost() {
100 return context_lost_;
103 GLenum TestWebGraphicsContext3D::checkFramebufferStatus(
106 return GL_FRAMEBUFFER_UNDEFINED_OES;
107 return GL_FRAMEBUFFER_COMPLETE;
110 GLint TestWebGraphicsContext3D::getUniformLocation(
112 const GLchar* name) {
116 GLsizeiptr TestWebGraphicsContext3D::getVertexAttribOffset(
122 GLboolean TestWebGraphicsContext3D::isBuffer(
127 GLboolean TestWebGraphicsContext3D::isEnabled(
132 GLboolean TestWebGraphicsContext3D::isFramebuffer(
133 GLuint framebuffer) {
137 GLboolean TestWebGraphicsContext3D::isProgram(
142 GLboolean TestWebGraphicsContext3D::isRenderbuffer(
143 GLuint renderbuffer) {
147 GLboolean TestWebGraphicsContext3D::isShader(
152 GLboolean TestWebGraphicsContext3D::isTexture(
157 void TestWebGraphicsContext3D::genBuffers(GLsizei count, GLuint* ids) {
158 for (int i = 0; i < count; ++i)
159 ids[i] = NextBufferId();
162 void TestWebGraphicsContext3D::genFramebuffers(
163 GLsizei count, GLuint* ids) {
164 for (int i = 0; i < count; ++i)
165 ids[i] = kFramebufferId | context_id_ << 16;
168 void TestWebGraphicsContext3D::genRenderbuffers(
169 GLsizei count, GLuint* ids) {
170 for (int i = 0; i < count; ++i)
171 ids[i] = kRenderbufferId | context_id_ << 16;
174 void TestWebGraphicsContext3D::genTextures(GLsizei count, GLuint* ids) {
175 for (int i = 0; i < count; ++i) {
176 ids[i] = NextTextureId();
177 DCHECK_NE(ids[i], kExternalTextureId);
179 base::AutoLock lock(namespace_->lock);
180 for (int i = 0; i < count; ++i)
181 namespace_->textures.Append(ids[i], new TestTexture());
184 void TestWebGraphicsContext3D::deleteBuffers(GLsizei count, GLuint* ids) {
185 for (int i = 0; i < count; ++i)
186 RetireBufferId(ids[i]);
189 void TestWebGraphicsContext3D::deleteFramebuffers(
190 GLsizei count, GLuint* ids) {
191 for (int i = 0; i < count; ++i)
192 DCHECK_EQ(kFramebufferId | context_id_ << 16, ids[i]);
195 void TestWebGraphicsContext3D::deleteRenderbuffers(
196 GLsizei count, GLuint* ids) {
197 for (int i = 0; i < count; ++i)
198 DCHECK_EQ(kRenderbufferId | context_id_ << 16, ids[i]);
201 void TestWebGraphicsContext3D::deleteTextures(GLsizei count, GLuint* ids) {
202 for (int i = 0; i < count; ++i)
203 RetireTextureId(ids[i]);
204 base::AutoLock lock(namespace_->lock);
205 for (int i = 0; i < count; ++i) {
206 namespace_->textures.Remove(ids[i]);
207 texture_targets_.UnbindTexture(ids[i]);
211 GLuint TestWebGraphicsContext3D::createBuffer() {
217 GLuint TestWebGraphicsContext3D::createFramebuffer() {
219 genFramebuffers(1, &id);
223 GLuint TestWebGraphicsContext3D::createRenderbuffer() {
225 genRenderbuffers(1, &id);
229 GLuint TestWebGraphicsContext3D::createTexture() {
235 void TestWebGraphicsContext3D::deleteBuffer(GLuint id) {
236 deleteBuffers(1, &id);
239 void TestWebGraphicsContext3D::deleteFramebuffer(GLuint id) {
240 deleteFramebuffers(1, &id);
243 void TestWebGraphicsContext3D::deleteRenderbuffer(GLuint id) {
244 deleteRenderbuffers(1, &id);
247 void TestWebGraphicsContext3D::deleteTexture(GLuint id) {
248 deleteTextures(1, &id);
251 unsigned TestWebGraphicsContext3D::createProgram() {
252 unsigned program = next_program_id_++ | context_id_ << 16;
253 program_set_.insert(program);
257 GLuint TestWebGraphicsContext3D::createShader(GLenum) {
258 unsigned shader = next_shader_id_++ | context_id_ << 16;
259 shader_set_.insert(shader);
263 GLuint TestWebGraphicsContext3D::createExternalTexture() {
264 base::AutoLock lock(namespace_->lock);
265 namespace_->textures.Append(kExternalTextureId, new TestTexture());
266 return kExternalTextureId;
269 void TestWebGraphicsContext3D::deleteProgram(GLuint id) {
270 if (!program_set_.count(id))
271 ADD_FAILURE() << "deleteProgram called on unknown program " << id;
272 program_set_.erase(id);
275 void TestWebGraphicsContext3D::deleteShader(GLuint id) {
276 if (!shader_set_.count(id))
277 ADD_FAILURE() << "deleteShader called on unknown shader " << id;
278 shader_set_.erase(id);
281 void TestWebGraphicsContext3D::attachShader(GLuint program, GLuint shader) {
282 if (!program_set_.count(program))
283 ADD_FAILURE() << "attachShader called with unknown program " << program;
284 if (!shader_set_.count(shader))
285 ADD_FAILURE() << "attachShader called with unknown shader " << shader;
288 void TestWebGraphicsContext3D::useProgram(GLuint program) {
291 if (!program_set_.count(program))
292 ADD_FAILURE() << "useProgram called on unknown program " << program;
295 void TestWebGraphicsContext3D::bindFramebuffer(
296 GLenum target, GLuint framebuffer) {
299 DCHECK_EQ(kFramebufferId | context_id_ << 16, framebuffer);
302 void TestWebGraphicsContext3D::bindRenderbuffer(
303 GLenum target, GLuint renderbuffer) {
306 DCHECK_EQ(kRenderbufferId | context_id_ << 16, renderbuffer);
309 void TestWebGraphicsContext3D::bindTexture(
310 GLenum target, GLuint texture_id) {
311 if (times_bind_texture_succeeds_ >= 0) {
312 if (!times_bind_texture_succeeds_) {
313 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
314 GL_INNOCENT_CONTEXT_RESET_ARB);
316 --times_bind_texture_succeeds_;
321 base::AutoLock lock(namespace_->lock);
322 DCHECK(namespace_->textures.ContainsId(texture_id));
323 texture_targets_.BindTexture(target, texture_id);
324 used_textures_.insert(texture_id);
327 GLuint TestWebGraphicsContext3D::BoundTextureId(
329 return texture_targets_.BoundTexture(target);
332 scoped_refptr<TestTexture> TestWebGraphicsContext3D::BoundTexture(
334 // The caller is expected to lock the namespace for texture access.
335 namespace_->lock.AssertAcquired();
336 return namespace_->textures.TextureForId(BoundTextureId(target));
339 void TestWebGraphicsContext3D::CheckTextureIsBound(GLenum target) {
340 DCHECK(BoundTextureId(target));
343 GLuint TestWebGraphicsContext3D::createQueryEXT() { return 1u; }
345 void TestWebGraphicsContext3D::endQueryEXT(GLenum target) {
346 if (times_end_query_succeeds_ >= 0) {
347 if (!times_end_query_succeeds_) {
348 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
349 GL_INNOCENT_CONTEXT_RESET_ARB);
351 --times_end_query_succeeds_;
355 void TestWebGraphicsContext3D::getQueryObjectuivEXT(
359 // If the context is lost, behave as if result is available.
360 if (pname == GL_QUERY_RESULT_AVAILABLE_EXT)
364 void TestWebGraphicsContext3D::getIntegerv(
367 if (pname == GL_MAX_TEXTURE_SIZE)
368 *value = max_texture_size_;
369 else if (pname == GL_ACTIVE_TEXTURE)
370 *value = GL_TEXTURE0;
373 void TestWebGraphicsContext3D::getProgramiv(GLuint program,
376 if (pname == GL_LINK_STATUS)
380 void TestWebGraphicsContext3D::getShaderiv(GLuint shader,
383 if (pname == GL_COMPILE_STATUS)
387 void TestWebGraphicsContext3D::getShaderPrecisionFormat(GLenum shadertype,
388 GLenum precisiontype,
391 // Return the minimum precision requirements of the GLES2
393 switch (precisiontype) {
414 case GL_MEDIUM_FLOAT:
430 void TestWebGraphicsContext3D::genMailboxCHROMIUM(GLbyte* mailbox) {
431 static char mailbox_name1 = '1';
432 static char mailbox_name2 = '1';
433 mailbox[0] = mailbox_name1;
434 mailbox[1] = mailbox_name2;
436 if (++mailbox_name1 == 0) {
442 void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current,
446 context_lost_ = true;
447 if (!context_lost_callback_.is_null())
448 context_lost_callback_.Run();
450 for (size_t i = 0; i < shared_contexts_.size(); ++i)
451 shared_contexts_[i]->loseContextCHROMIUM(current, other);
452 shared_contexts_.clear();
455 void TestWebGraphicsContext3D::finish() {
456 test_support_->CallAllSyncPointCallbacks();
459 void TestWebGraphicsContext3D::flush() {
460 test_support_->CallAllSyncPointCallbacks();
463 GLint TestWebGraphicsContext3D::getAttribLocation(GLuint program,
464 const GLchar* name) {
468 GLenum TestWebGraphicsContext3D::getError() { return GL_NO_ERROR; }
470 void TestWebGraphicsContext3D::bindBuffer(GLenum target,
472 bound_buffer_ = buffer;
475 unsigned context_id = buffer >> 16;
476 unsigned buffer_id = buffer & 0xffff;
477 base::AutoLock lock(namespace_->lock);
479 DCHECK_LT(buffer_id, namespace_->next_buffer_id);
480 DCHECK_EQ(context_id, context_id_);
482 base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
483 if (buffers.count(bound_buffer_) == 0)
484 buffers.set(bound_buffer_, make_scoped_ptr(new Buffer).Pass());
486 buffers.get(bound_buffer_)->target = target;
489 void TestWebGraphicsContext3D::bufferData(GLenum target,
493 base::AutoLock lock(namespace_->lock);
494 base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
495 DCHECK_GT(buffers.count(bound_buffer_), 0u);
496 DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
497 Buffer* buffer = buffers.get(bound_buffer_);
499 buffer->pixels.reset();
503 size_t old_size = buffer->size;
505 buffer->pixels.reset(new uint8[size]);
508 memcpy(buffer->pixels.get(), data, size);
509 if (buffer->target == GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM)
510 current_used_transfer_buffer_usage_bytes_ += buffer->size - old_size;
511 max_used_transfer_buffer_usage_bytes_ =
512 std::max(max_used_transfer_buffer_usage_bytes_,
513 current_used_transfer_buffer_usage_bytes_);
516 void* TestWebGraphicsContext3D::mapBufferCHROMIUM(GLenum target,
518 base::AutoLock lock(namespace_->lock);
519 base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
520 DCHECK_GT(buffers.count(bound_buffer_), 0u);
521 DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
522 if (times_map_buffer_chromium_succeeds_ >= 0) {
523 if (!times_map_buffer_chromium_succeeds_) {
526 --times_map_buffer_chromium_succeeds_;
529 return buffers.get(bound_buffer_)->pixels.get();
532 GLboolean TestWebGraphicsContext3D::unmapBufferCHROMIUM(
534 base::AutoLock lock(namespace_->lock);
535 base::ScopedPtrHashMap<unsigned, Buffer>& buffers = namespace_->buffers;
536 DCHECK_GT(buffers.count(bound_buffer_), 0u);
537 DCHECK_EQ(target, buffers.get(bound_buffer_)->target);
538 buffers.get(bound_buffer_)->pixels.reset();
542 GLuint TestWebGraphicsContext3D::createImageCHROMIUM(GLsizei width,
544 GLenum internalformat,
546 DCHECK_EQ(GL_RGBA8_OES, static_cast<int>(internalformat));
547 GLuint image_id = NextImageId();
548 base::AutoLock lock(namespace_->lock);
549 base::ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
550 images.set(image_id, make_scoped_ptr(new Image).Pass());
551 images.get(image_id)->pixels.reset(new uint8[width * height * 4]);
555 void TestWebGraphicsContext3D::destroyImageCHROMIUM(
560 void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
564 base::AutoLock lock(namespace_->lock);
565 DCHECK_GT(namespace_->images.count(image_id), 0u);
566 DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM, static_cast<int>(pname));
570 void* TestWebGraphicsContext3D::mapImageCHROMIUM(GLuint image_id) {
571 base::AutoLock lock(namespace_->lock);
572 base::ScopedPtrHashMap<unsigned, Image>& images = namespace_->images;
573 DCHECK_GT(images.count(image_id), 0u);
574 if (times_map_image_chromium_succeeds_ >= 0) {
575 if (!times_map_image_chromium_succeeds_) {
578 --times_map_image_chromium_succeeds_;
580 return images.get(image_id)->pixels.get();
583 void TestWebGraphicsContext3D::unmapImageCHROMIUM(
585 base::AutoLock lock(namespace_->lock);
586 DCHECK_GT(namespace_->images.count(image_id), 0u);
589 unsigned TestWebGraphicsContext3D::insertSyncPoint() {
590 return next_insert_sync_point_++;
593 void TestWebGraphicsContext3D::waitSyncPoint(unsigned sync_point) {
595 last_waited_sync_point_ = sync_point;
598 size_t TestWebGraphicsContext3D::NumTextures() const {
599 base::AutoLock lock(namespace_->lock);
600 return namespace_->textures.Size();
603 GLuint TestWebGraphicsContext3D::TextureAt(int i) const {
604 base::AutoLock lock(namespace_->lock);
605 return namespace_->textures.IdAt(i);
608 GLuint TestWebGraphicsContext3D::NextTextureId() {
609 base::AutoLock lock(namespace_->lock);
610 GLuint texture_id = namespace_->next_texture_id++;
611 DCHECK(texture_id < (1 << 16));
612 texture_id |= context_id_ << 16;
616 void TestWebGraphicsContext3D::RetireTextureId(GLuint id) {
617 base::AutoLock lock(namespace_->lock);
618 unsigned context_id = id >> 16;
619 unsigned texture_id = id & 0xffff;
621 DCHECK_LT(texture_id, namespace_->next_texture_id);
622 DCHECK_EQ(context_id, context_id_);
625 GLuint TestWebGraphicsContext3D::NextBufferId() {
626 base::AutoLock lock(namespace_->lock);
627 GLuint buffer_id = namespace_->next_buffer_id++;
628 DCHECK(buffer_id < (1 << 16));
629 buffer_id |= context_id_ << 16;
633 void TestWebGraphicsContext3D::RetireBufferId(GLuint id) {
634 base::AutoLock lock(namespace_->lock);
635 unsigned context_id = id >> 16;
636 unsigned buffer_id = id & 0xffff;
638 DCHECK_LT(buffer_id, namespace_->next_buffer_id);
639 DCHECK_EQ(context_id, context_id_);
642 GLuint TestWebGraphicsContext3D::NextImageId() {
643 base::AutoLock lock(namespace_->lock);
644 GLuint image_id = namespace_->next_image_id++;
645 DCHECK(image_id < (1 << 16));
646 image_id |= context_id_ << 16;
650 void TestWebGraphicsContext3D::RetireImageId(GLuint id) {
651 base::AutoLock lock(namespace_->lock);
652 unsigned context_id = id >> 16;
653 unsigned image_id = id & 0xffff;
655 DCHECK_LT(image_id, namespace_->next_image_id);
656 DCHECK_EQ(context_id, context_id_);
659 void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes(
660 size_t max_transfer_buffer_usage_bytes) {
661 test_capabilities_.max_transfer_buffer_usage_bytes =
662 max_transfer_buffer_usage_bytes;
665 TestWebGraphicsContext3D::TextureTargets::TextureTargets() {
666 // Initialize default bindings.
667 bound_textures_[GL_TEXTURE_2D] = 0;
668 bound_textures_[GL_TEXTURE_EXTERNAL_OES] = 0;
669 bound_textures_[GL_TEXTURE_RECTANGLE_ARB] = 0;
672 TestWebGraphicsContext3D::TextureTargets::~TextureTargets() {}
674 void TestWebGraphicsContext3D::TextureTargets::BindTexture(
677 // Make sure this is a supported target by seeing if it was bound to before.
678 DCHECK(bound_textures_.find(target) != bound_textures_.end());
679 bound_textures_[target] = id;
682 void TestWebGraphicsContext3D::texParameteri(GLenum target,
685 CheckTextureIsBound(target);
686 base::AutoLock lock_for_texture_access(namespace_->lock);
687 scoped_refptr<TestTexture> texture = BoundTexture(target);
688 DCHECK(texture->IsValidParameter(pname));
689 texture->params[pname] = param;
692 void TestWebGraphicsContext3D::getTexParameteriv(GLenum target,
695 CheckTextureIsBound(target);
696 base::AutoLock lock_for_texture_access(namespace_->lock);
697 scoped_refptr<TestTexture> texture = BoundTexture(target);
698 DCHECK(texture->IsValidParameter(pname));
699 TestTexture::TextureParametersMap::iterator it = texture->params.find(pname);
700 if (it != texture->params.end())
704 void TestWebGraphicsContext3D::TextureTargets::UnbindTexture(
706 // Bind zero to any targets that the id is bound to.
707 for (TargetTextureMap::iterator it = bound_textures_.begin();
708 it != bound_textures_.end();
710 if (it->second == id)
715 GLuint TestWebGraphicsContext3D::TextureTargets::BoundTexture(
717 DCHECK(bound_textures_.find(target) != bound_textures_.end());
718 return bound_textures_[target];
721 TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {}
723 TestWebGraphicsContext3D::Buffer::~Buffer() {}
725 TestWebGraphicsContext3D::Image::Image() {}
727 TestWebGraphicsContext3D::Image::~Image() {}