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 next_program_id_(1000),
59 next_shader_id_(2000),
60 max_texture_size_(2048),
61 reshape_called_(false),
66 last_update_type_(NoUpdate
),
67 next_insert_sync_point_(1),
68 last_waited_sync_point_(0),
70 peak_transfer_buffer_memory_used_bytes_(0),
71 weak_ptr_factory_(this) {
75 TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
76 base::AutoLock
lock(g_shared_namespace_lock
.Get());
80 void TestWebGraphicsContext3D::CreateNamespace() {
81 base::AutoLock
lock(g_shared_namespace_lock
.Get());
82 if (shared_namespace_
) {
83 namespace_
= shared_namespace_
;
85 namespace_
= new Namespace
;
86 shared_namespace_
= namespace_
.get();
90 void TestWebGraphicsContext3D::reshapeWithScaleFactor(
91 int width
, int height
, float scale_factor
) {
92 reshape_called_
= true;
95 scale_factor_
= scale_factor
;
98 bool TestWebGraphicsContext3D::isContextLost() {
102 GLenum
TestWebGraphicsContext3D::checkFramebufferStatus(
105 return GL_FRAMEBUFFER_UNDEFINED_OES
;
106 return GL_FRAMEBUFFER_COMPLETE
;
109 GLint
TestWebGraphicsContext3D::getUniformLocation(
111 const GLchar
* name
) {
115 GLsizeiptr
TestWebGraphicsContext3D::getVertexAttribOffset(
121 GLboolean
TestWebGraphicsContext3D::isBuffer(
126 GLboolean
TestWebGraphicsContext3D::isEnabled(
131 GLboolean
TestWebGraphicsContext3D::isFramebuffer(
132 GLuint framebuffer
) {
136 GLboolean
TestWebGraphicsContext3D::isProgram(
141 GLboolean
TestWebGraphicsContext3D::isRenderbuffer(
142 GLuint renderbuffer
) {
146 GLboolean
TestWebGraphicsContext3D::isShader(
151 GLboolean
TestWebGraphicsContext3D::isTexture(
156 void TestWebGraphicsContext3D::genBuffers(GLsizei count
, GLuint
* ids
) {
157 for (int i
= 0; i
< count
; ++i
)
158 ids
[i
] = NextBufferId();
161 void TestWebGraphicsContext3D::genFramebuffers(
162 GLsizei count
, GLuint
* ids
) {
163 for (int i
= 0; i
< count
; ++i
)
164 ids
[i
] = kFramebufferId
| context_id_
<< 16;
167 void TestWebGraphicsContext3D::genRenderbuffers(
168 GLsizei count
, GLuint
* ids
) {
169 for (int i
= 0; i
< count
; ++i
)
170 ids
[i
] = kRenderbufferId
| context_id_
<< 16;
173 void TestWebGraphicsContext3D::genTextures(GLsizei count
, GLuint
* ids
) {
174 for (int i
= 0; i
< count
; ++i
) {
175 ids
[i
] = NextTextureId();
176 DCHECK_NE(ids
[i
], kExternalTextureId
);
178 base::AutoLock
lock(namespace_
->lock
);
179 for (int i
= 0; i
< count
; ++i
)
180 namespace_
->textures
.Append(ids
[i
], new TestTexture());
183 void TestWebGraphicsContext3D::deleteBuffers(GLsizei count
, GLuint
* ids
) {
184 for (int i
= 0; i
< count
; ++i
)
185 RetireBufferId(ids
[i
]);
188 void TestWebGraphicsContext3D::deleteFramebuffers(
189 GLsizei count
, GLuint
* ids
) {
190 for (int i
= 0; i
< count
; ++i
)
191 DCHECK_EQ(kFramebufferId
| context_id_
<< 16, ids
[i
]);
194 void TestWebGraphicsContext3D::deleteRenderbuffers(
195 GLsizei count
, GLuint
* ids
) {
196 for (int i
= 0; i
< count
; ++i
)
197 DCHECK_EQ(kRenderbufferId
| context_id_
<< 16, ids
[i
]);
200 void TestWebGraphicsContext3D::deleteTextures(GLsizei count
, GLuint
* ids
) {
201 for (int i
= 0; i
< count
; ++i
)
202 RetireTextureId(ids
[i
]);
203 base::AutoLock
lock(namespace_
->lock
);
204 for (int i
= 0; i
< count
; ++i
) {
205 namespace_
->textures
.Remove(ids
[i
]);
206 texture_targets_
.UnbindTexture(ids
[i
]);
210 GLuint
TestWebGraphicsContext3D::createBuffer() {
216 GLuint
TestWebGraphicsContext3D::createFramebuffer() {
218 genFramebuffers(1, &id
);
222 GLuint
TestWebGraphicsContext3D::createRenderbuffer() {
224 genRenderbuffers(1, &id
);
228 GLuint
TestWebGraphicsContext3D::createTexture() {
234 void TestWebGraphicsContext3D::deleteBuffer(GLuint id
) {
235 deleteBuffers(1, &id
);
238 void TestWebGraphicsContext3D::deleteFramebuffer(GLuint id
) {
239 deleteFramebuffers(1, &id
);
242 void TestWebGraphicsContext3D::deleteRenderbuffer(GLuint id
) {
243 deleteRenderbuffers(1, &id
);
246 void TestWebGraphicsContext3D::deleteTexture(GLuint id
) {
247 deleteTextures(1, &id
);
250 unsigned TestWebGraphicsContext3D::createProgram() {
251 unsigned program
= next_program_id_
++ | context_id_
<< 16;
252 program_set_
.insert(program
);
256 GLuint
TestWebGraphicsContext3D::createShader(GLenum
) {
257 unsigned shader
= next_shader_id_
++ | context_id_
<< 16;
258 shader_set_
.insert(shader
);
262 GLuint
TestWebGraphicsContext3D::createExternalTexture() {
263 base::AutoLock
lock(namespace_
->lock
);
264 namespace_
->textures
.Append(kExternalTextureId
, new TestTexture());
265 return kExternalTextureId
;
268 void TestWebGraphicsContext3D::deleteProgram(GLuint id
) {
269 if (!program_set_
.count(id
))
270 ADD_FAILURE() << "deleteProgram called on unknown program " << id
;
271 program_set_
.erase(id
);
274 void TestWebGraphicsContext3D::deleteShader(GLuint id
) {
275 if (!shader_set_
.count(id
))
276 ADD_FAILURE() << "deleteShader called on unknown shader " << id
;
277 shader_set_
.erase(id
);
280 void TestWebGraphicsContext3D::attachShader(GLuint program
, GLuint shader
) {
281 if (!program_set_
.count(program
))
282 ADD_FAILURE() << "attachShader called with unknown program " << program
;
283 if (!shader_set_
.count(shader
))
284 ADD_FAILURE() << "attachShader called with unknown shader " << shader
;
287 void TestWebGraphicsContext3D::useProgram(GLuint program
) {
290 if (!program_set_
.count(program
))
291 ADD_FAILURE() << "useProgram called on unknown program " << program
;
294 void TestWebGraphicsContext3D::bindFramebuffer(
295 GLenum target
, GLuint framebuffer
) {
298 DCHECK_EQ(kFramebufferId
| context_id_
<< 16, framebuffer
);
301 void TestWebGraphicsContext3D::bindRenderbuffer(
302 GLenum target
, GLuint renderbuffer
) {
305 DCHECK_EQ(kRenderbufferId
| context_id_
<< 16, renderbuffer
);
308 void TestWebGraphicsContext3D::bindTexture(
309 GLenum target
, GLuint texture_id
) {
310 if (times_bind_texture_succeeds_
>= 0) {
311 if (!times_bind_texture_succeeds_
) {
312 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
313 GL_INNOCENT_CONTEXT_RESET_ARB
);
315 --times_bind_texture_succeeds_
;
320 base::AutoLock
lock(namespace_
->lock
);
321 DCHECK(namespace_
->textures
.ContainsId(texture_id
));
322 texture_targets_
.BindTexture(target
, texture_id
);
323 used_textures_
.insert(texture_id
);
326 GLuint
TestWebGraphicsContext3D::BoundTextureId(
328 return texture_targets_
.BoundTexture(target
);
331 scoped_refptr
<TestTexture
> TestWebGraphicsContext3D::BoundTexture(
333 // The caller is expected to lock the namespace for texture access.
334 namespace_
->lock
.AssertAcquired();
335 return namespace_
->textures
.TextureForId(BoundTextureId(target
));
338 void TestWebGraphicsContext3D::CheckTextureIsBound(GLenum target
) {
339 DCHECK(BoundTextureId(target
));
342 GLuint
TestWebGraphicsContext3D::createQueryEXT() { return 1u; }
344 void TestWebGraphicsContext3D::endQueryEXT(GLenum target
) {
345 if (times_end_query_succeeds_
>= 0) {
346 if (!times_end_query_succeeds_
) {
347 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
348 GL_INNOCENT_CONTEXT_RESET_ARB
);
350 --times_end_query_succeeds_
;
354 void TestWebGraphicsContext3D::getQueryObjectuivEXT(
358 // If the context is lost, behave as if result is available.
359 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
363 void TestWebGraphicsContext3D::getIntegerv(
366 if (pname
== GL_MAX_TEXTURE_SIZE
)
367 *value
= max_texture_size_
;
368 else if (pname
== GL_ACTIVE_TEXTURE
)
369 *value
= GL_TEXTURE0
;
372 void TestWebGraphicsContext3D::getProgramiv(GLuint program
,
375 if (pname
== GL_LINK_STATUS
)
379 void TestWebGraphicsContext3D::getShaderiv(GLuint shader
,
382 if (pname
== GL_COMPILE_STATUS
)
386 void TestWebGraphicsContext3D::getShaderPrecisionFormat(GLenum shadertype
,
387 GLenum precisiontype
,
390 // Return the minimum precision requirements of the GLES2
392 switch (precisiontype
) {
413 case GL_MEDIUM_FLOAT
:
429 void TestWebGraphicsContext3D::genMailboxCHROMIUM(GLbyte
* mailbox
) {
430 static char mailbox_name1
= '1';
431 static char mailbox_name2
= '1';
432 mailbox
[0] = mailbox_name1
;
433 mailbox
[1] = mailbox_name2
;
435 if (++mailbox_name1
== 0) {
441 void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current
,
445 context_lost_
= true;
446 if (!context_lost_callback_
.is_null())
447 context_lost_callback_
.Run();
449 for (size_t i
= 0; i
< shared_contexts_
.size(); ++i
)
450 shared_contexts_
[i
]->loseContextCHROMIUM(current
, other
);
451 shared_contexts_
.clear();
454 void TestWebGraphicsContext3D::finish() {
455 test_support_
->CallAllSyncPointCallbacks();
458 void TestWebGraphicsContext3D::flush() {
459 test_support_
->CallAllSyncPointCallbacks();
462 GLint
TestWebGraphicsContext3D::getAttribLocation(GLuint program
,
463 const GLchar
* name
) {
467 GLenum
TestWebGraphicsContext3D::getError() { return GL_NO_ERROR
; }
469 void TestWebGraphicsContext3D::bindBuffer(GLenum target
,
471 bound_buffer_
= buffer
;
474 unsigned context_id
= buffer
>> 16;
475 unsigned buffer_id
= buffer
& 0xffff;
476 base::AutoLock
lock(namespace_
->lock
);
478 DCHECK_LT(buffer_id
, namespace_
->next_buffer_id
);
479 DCHECK_EQ(context_id
, context_id_
);
481 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
482 if (buffers
.count(bound_buffer_
) == 0)
483 buffers
.set(bound_buffer_
, make_scoped_ptr(new Buffer
).Pass());
485 buffers
.get(bound_buffer_
)->target
= target
;
488 void TestWebGraphicsContext3D::bufferData(GLenum target
,
492 base::AutoLock
lock(namespace_
->lock
);
493 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
494 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
495 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
496 Buffer
* buffer
= buffers
.get(bound_buffer_
);
498 buffer
->pixels
.reset();
502 buffer
->pixels
.reset(new uint8
[size
]);
505 memcpy(buffer
->pixels
.get(), data
, size
);
507 peak_transfer_buffer_memory_used_bytes_
=
508 std::max(peak_transfer_buffer_memory_used_bytes_
,
509 GetTransferBufferMemoryUsedBytes());
512 void* TestWebGraphicsContext3D::mapBufferCHROMIUM(GLenum target
,
514 base::AutoLock
lock(namespace_
->lock
);
515 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
516 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
517 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
518 if (times_map_buffer_chromium_succeeds_
>= 0) {
519 if (!times_map_buffer_chromium_succeeds_
) {
522 --times_map_buffer_chromium_succeeds_
;
525 peak_transfer_buffer_memory_used_bytes_
=
526 std::max(peak_transfer_buffer_memory_used_bytes_
,
527 GetTransferBufferMemoryUsedBytes());
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(
543 GLsizei width
, GLsizei height
,
544 GLenum internalformat
) {
545 DCHECK_EQ(GL_RGBA8_OES
, static_cast<int>(internalformat
));
546 GLuint image_id
= NextImageId();
547 base::AutoLock
lock(namespace_
->lock
);
548 base::ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
549 images
.set(image_id
, make_scoped_ptr(new Image
).Pass());
550 images
.get(image_id
)->pixels
.reset(new uint8
[width
* height
* 4]);
554 void TestWebGraphicsContext3D::destroyImageCHROMIUM(
559 void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
563 base::AutoLock
lock(namespace_
->lock
);
564 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
565 DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM
, static_cast<int>(pname
));
569 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 size_t TestWebGraphicsContext3D::GetTransferBufferMemoryUsedBytes() const {
660 size_t total_bytes
= 0;
661 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
662 base::ScopedPtrHashMap
<unsigned, Buffer
>::iterator it
= buffers
.begin();
663 for (; it
!= buffers
.end(); ++it
) {
664 Buffer
* buffer
= it
->second
;
665 if (buffer
->target
== GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
)
666 total_bytes
+= buffer
->size
;
671 void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes(
672 size_t max_transfer_buffer_usage_bytes
) {
673 test_capabilities_
.max_transfer_buffer_usage_bytes
=
674 max_transfer_buffer_usage_bytes
;
677 TestWebGraphicsContext3D::TextureTargets::TextureTargets() {
678 // Initialize default bindings.
679 bound_textures_
[GL_TEXTURE_2D
] = 0;
680 bound_textures_
[GL_TEXTURE_EXTERNAL_OES
] = 0;
681 bound_textures_
[GL_TEXTURE_RECTANGLE_ARB
] = 0;
684 TestWebGraphicsContext3D::TextureTargets::~TextureTargets() {}
686 void TestWebGraphicsContext3D::TextureTargets::BindTexture(
689 // Make sure this is a supported target by seeing if it was bound to before.
690 DCHECK(bound_textures_
.find(target
) != bound_textures_
.end());
691 bound_textures_
[target
] = id
;
694 void TestWebGraphicsContext3D::texParameteri(GLenum target
,
697 CheckTextureIsBound(target
);
698 base::AutoLock
lock_for_texture_access(namespace_
->lock
);
699 scoped_refptr
<TestTexture
> texture
= BoundTexture(target
);
700 DCHECK(texture
->IsValidParameter(pname
));
701 texture
->params
[pname
] = param
;
704 void TestWebGraphicsContext3D::getTexParameteriv(GLenum target
,
707 CheckTextureIsBound(target
);
708 base::AutoLock
lock_for_texture_access(namespace_
->lock
);
709 scoped_refptr
<TestTexture
> texture
= BoundTexture(target
);
710 DCHECK(texture
->IsValidParameter(pname
));
711 TestTexture::TextureParametersMap::iterator it
= texture
->params
.find(pname
);
712 if (it
!= texture
->params
.end())
716 void TestWebGraphicsContext3D::TextureTargets::UnbindTexture(
718 // Bind zero to any targets that the id is bound to.
719 for (TargetTextureMap::iterator it
= bound_textures_
.begin();
720 it
!= bound_textures_
.end();
722 if (it
->second
== id
)
727 GLuint
TestWebGraphicsContext3D::TextureTargets::BoundTexture(
729 DCHECK(bound_textures_
.find(target
) != bound_textures_
.end());
730 return bound_textures_
[target
];
733 TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {}
735 TestWebGraphicsContext3D::Buffer::~Buffer() {}
737 TestWebGraphicsContext3D::Image::Image() {}
739 TestWebGraphicsContext3D::Image::~Image() {}