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 GLuint
TestWebGraphicsContext3D::createAndConsumeTextureCHROMIUM(
444 const GLbyte
* mailbox
) {
445 return createTexture();
448 void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current
,
452 context_lost_
= true;
453 if (!context_lost_callback_
.is_null())
454 context_lost_callback_
.Run();
456 for (size_t i
= 0; i
< shared_contexts_
.size(); ++i
)
457 shared_contexts_
[i
]->loseContextCHROMIUM(current
, other
);
458 shared_contexts_
.clear();
461 void TestWebGraphicsContext3D::finish() {
462 test_support_
->CallAllSyncPointCallbacks();
465 void TestWebGraphicsContext3D::flush() {
466 test_support_
->CallAllSyncPointCallbacks();
469 GLint
TestWebGraphicsContext3D::getAttribLocation(GLuint program
,
470 const GLchar
* name
) {
474 GLenum
TestWebGraphicsContext3D::getError() { return GL_NO_ERROR
; }
476 void TestWebGraphicsContext3D::bindBuffer(GLenum target
,
478 bound_buffer_
= buffer
;
481 unsigned context_id
= buffer
>> 16;
482 unsigned buffer_id
= buffer
& 0xffff;
483 base::AutoLock
lock(namespace_
->lock
);
485 DCHECK_LT(buffer_id
, namespace_
->next_buffer_id
);
486 DCHECK_EQ(context_id
, context_id_
);
488 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
489 if (buffers
.count(bound_buffer_
) == 0)
490 buffers
.set(bound_buffer_
, make_scoped_ptr(new Buffer
).Pass());
492 buffers
.get(bound_buffer_
)->target
= target
;
495 void TestWebGraphicsContext3D::bufferData(GLenum target
,
499 base::AutoLock
lock(namespace_
->lock
);
500 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
501 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
502 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
503 Buffer
* buffer
= buffers
.get(bound_buffer_
);
505 buffer
->pixels
.reset();
509 size_t old_size
= buffer
->size
;
511 buffer
->pixels
.reset(new uint8
[size
]);
514 memcpy(buffer
->pixels
.get(), data
, size
);
515 if (buffer
->target
== GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
)
516 current_used_transfer_buffer_usage_bytes_
+= buffer
->size
- old_size
;
517 max_used_transfer_buffer_usage_bytes_
=
518 std::max(max_used_transfer_buffer_usage_bytes_
,
519 current_used_transfer_buffer_usage_bytes_
);
522 void* TestWebGraphicsContext3D::mapBufferCHROMIUM(GLenum target
,
524 base::AutoLock
lock(namespace_
->lock
);
525 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
526 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
527 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
528 if (times_map_buffer_chromium_succeeds_
>= 0) {
529 if (!times_map_buffer_chromium_succeeds_
) {
532 --times_map_buffer_chromium_succeeds_
;
535 return buffers
.get(bound_buffer_
)->pixels
.get();
538 GLboolean
TestWebGraphicsContext3D::unmapBufferCHROMIUM(
540 base::AutoLock
lock(namespace_
->lock
);
541 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
542 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
543 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
544 buffers
.get(bound_buffer_
)->pixels
.reset();
548 GLuint
TestWebGraphicsContext3D::createImageCHROMIUM(GLsizei width
,
550 GLenum internalformat
,
552 DCHECK_EQ(GL_RGBA8_OES
, static_cast<int>(internalformat
));
553 GLuint image_id
= NextImageId();
554 base::AutoLock
lock(namespace_
->lock
);
555 base::ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
556 images
.set(image_id
, make_scoped_ptr(new Image
).Pass());
557 images
.get(image_id
)->pixels
.reset(new uint8
[width
* height
* 4]);
561 void TestWebGraphicsContext3D::destroyImageCHROMIUM(
566 void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
570 base::AutoLock
lock(namespace_
->lock
);
571 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
572 DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM
, static_cast<int>(pname
));
576 void* TestWebGraphicsContext3D::mapImageCHROMIUM(GLuint image_id
) {
577 base::AutoLock
lock(namespace_
->lock
);
578 base::ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
579 DCHECK_GT(images
.count(image_id
), 0u);
580 if (times_map_image_chromium_succeeds_
>= 0) {
581 if (!times_map_image_chromium_succeeds_
) {
584 --times_map_image_chromium_succeeds_
;
586 return images
.get(image_id
)->pixels
.get();
589 void TestWebGraphicsContext3D::unmapImageCHROMIUM(
591 base::AutoLock
lock(namespace_
->lock
);
592 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
595 unsigned TestWebGraphicsContext3D::insertSyncPoint() {
596 return next_insert_sync_point_
++;
599 void TestWebGraphicsContext3D::waitSyncPoint(unsigned sync_point
) {
601 last_waited_sync_point_
= sync_point
;
604 size_t TestWebGraphicsContext3D::NumTextures() const {
605 base::AutoLock
lock(namespace_
->lock
);
606 return namespace_
->textures
.Size();
609 GLuint
TestWebGraphicsContext3D::TextureAt(int i
) const {
610 base::AutoLock
lock(namespace_
->lock
);
611 return namespace_
->textures
.IdAt(i
);
614 GLuint
TestWebGraphicsContext3D::NextTextureId() {
615 base::AutoLock
lock(namespace_
->lock
);
616 GLuint texture_id
= namespace_
->next_texture_id
++;
617 DCHECK(texture_id
< (1 << 16));
618 texture_id
|= context_id_
<< 16;
622 void TestWebGraphicsContext3D::RetireTextureId(GLuint id
) {
623 base::AutoLock
lock(namespace_
->lock
);
624 unsigned context_id
= id
>> 16;
625 unsigned texture_id
= id
& 0xffff;
627 DCHECK_LT(texture_id
, namespace_
->next_texture_id
);
628 DCHECK_EQ(context_id
, context_id_
);
631 GLuint
TestWebGraphicsContext3D::NextBufferId() {
632 base::AutoLock
lock(namespace_
->lock
);
633 GLuint buffer_id
= namespace_
->next_buffer_id
++;
634 DCHECK(buffer_id
< (1 << 16));
635 buffer_id
|= context_id_
<< 16;
639 void TestWebGraphicsContext3D::RetireBufferId(GLuint id
) {
640 base::AutoLock
lock(namespace_
->lock
);
641 unsigned context_id
= id
>> 16;
642 unsigned buffer_id
= id
& 0xffff;
644 DCHECK_LT(buffer_id
, namespace_
->next_buffer_id
);
645 DCHECK_EQ(context_id
, context_id_
);
648 GLuint
TestWebGraphicsContext3D::NextImageId() {
649 base::AutoLock
lock(namespace_
->lock
);
650 GLuint image_id
= namespace_
->next_image_id
++;
651 DCHECK(image_id
< (1 << 16));
652 image_id
|= context_id_
<< 16;
656 void TestWebGraphicsContext3D::RetireImageId(GLuint id
) {
657 base::AutoLock
lock(namespace_
->lock
);
658 unsigned context_id
= id
>> 16;
659 unsigned image_id
= id
& 0xffff;
661 DCHECK_LT(image_id
, namespace_
->next_image_id
);
662 DCHECK_EQ(context_id
, context_id_
);
665 void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes(
666 size_t max_transfer_buffer_usage_bytes
) {
667 test_capabilities_
.max_transfer_buffer_usage_bytes
=
668 max_transfer_buffer_usage_bytes
;
671 TestWebGraphicsContext3D::TextureTargets::TextureTargets() {
672 // Initialize default bindings.
673 bound_textures_
[GL_TEXTURE_2D
] = 0;
674 bound_textures_
[GL_TEXTURE_EXTERNAL_OES
] = 0;
675 bound_textures_
[GL_TEXTURE_RECTANGLE_ARB
] = 0;
678 TestWebGraphicsContext3D::TextureTargets::~TextureTargets() {}
680 void TestWebGraphicsContext3D::TextureTargets::BindTexture(
683 // Make sure this is a supported target by seeing if it was bound to before.
684 DCHECK(bound_textures_
.find(target
) != bound_textures_
.end());
685 bound_textures_
[target
] = id
;
688 void TestWebGraphicsContext3D::texParameteri(GLenum target
,
691 CheckTextureIsBound(target
);
692 base::AutoLock
lock_for_texture_access(namespace_
->lock
);
693 scoped_refptr
<TestTexture
> texture
= BoundTexture(target
);
694 DCHECK(texture
->IsValidParameter(pname
));
695 texture
->params
[pname
] = param
;
698 void TestWebGraphicsContext3D::getTexParameteriv(GLenum target
,
701 CheckTextureIsBound(target
);
702 base::AutoLock
lock_for_texture_access(namespace_
->lock
);
703 scoped_refptr
<TestTexture
> texture
= BoundTexture(target
);
704 DCHECK(texture
->IsValidParameter(pname
));
705 TestTexture::TextureParametersMap::iterator it
= texture
->params
.find(pname
);
706 if (it
!= texture
->params
.end())
710 void TestWebGraphicsContext3D::TextureTargets::UnbindTexture(
712 // Bind zero to any targets that the id is bound to.
713 for (TargetTextureMap::iterator it
= bound_textures_
.begin();
714 it
!= bound_textures_
.end();
716 if (it
->second
== id
)
721 GLuint
TestWebGraphicsContext3D::TextureTargets::BoundTexture(
723 DCHECK(bound_textures_
.find(target
) != bound_textures_
.end());
724 return bound_textures_
[target
];
727 TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {}
729 TestWebGraphicsContext3D::Buffer::~Buffer() {}
731 TestWebGraphicsContext3D::Image::Image() {}
733 TestWebGraphicsContext3D::Image::~Image() {}