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_buffer_chromium_succeeds_(-1),
57 current_used_transfer_buffer_usage_bytes_(0),
58 max_used_transfer_buffer_usage_bytes_(0),
59 next_program_id_(1000),
60 next_shader_id_(2000),
61 max_texture_size_(2048),
62 reshape_called_(false),
67 last_update_type_(NoUpdate
),
68 next_insert_sync_point_(1),
69 last_waited_sync_point_(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 GLuint
TestWebGraphicsContext3D::createAndConsumeTextureCHROMIUM(
443 const GLbyte
* mailbox
) {
444 return createTexture();
447 void TestWebGraphicsContext3D::loseContextCHROMIUM(GLenum current
,
451 context_lost_
= true;
452 if (!context_lost_callback_
.is_null())
453 context_lost_callback_
.Run();
455 for (size_t i
= 0; i
< shared_contexts_
.size(); ++i
)
456 shared_contexts_
[i
]->loseContextCHROMIUM(current
, other
);
457 shared_contexts_
.clear();
460 void TestWebGraphicsContext3D::finish() {
461 test_support_
->CallAllSyncPointCallbacks();
464 void TestWebGraphicsContext3D::flush() {
465 test_support_
->CallAllSyncPointCallbacks();
468 GLint
TestWebGraphicsContext3D::getAttribLocation(GLuint program
,
469 const GLchar
* name
) {
473 GLenum
TestWebGraphicsContext3D::getError() { return GL_NO_ERROR
; }
475 void TestWebGraphicsContext3D::bindBuffer(GLenum target
,
477 bound_buffer_
= buffer
;
480 unsigned context_id
= buffer
>> 16;
481 unsigned buffer_id
= buffer
& 0xffff;
482 base::AutoLock
lock(namespace_
->lock
);
484 DCHECK_LT(buffer_id
, namespace_
->next_buffer_id
);
485 DCHECK_EQ(context_id
, context_id_
);
487 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
488 if (buffers
.count(bound_buffer_
) == 0)
489 buffers
.set(bound_buffer_
, make_scoped_ptr(new Buffer
).Pass());
491 buffers
.get(bound_buffer_
)->target
= target
;
494 void TestWebGraphicsContext3D::bufferData(GLenum target
,
498 base::AutoLock
lock(namespace_
->lock
);
499 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
500 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
501 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
502 Buffer
* buffer
= buffers
.get(bound_buffer_
);
504 buffer
->pixels
= nullptr;
508 size_t old_size
= buffer
->size
;
510 buffer
->pixels
.reset(new uint8
[size
]);
513 memcpy(buffer
->pixels
.get(), data
, size
);
514 if (buffer
->target
== GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
)
515 current_used_transfer_buffer_usage_bytes_
+= buffer
->size
- old_size
;
516 max_used_transfer_buffer_usage_bytes_
=
517 std::max(max_used_transfer_buffer_usage_bytes_
,
518 current_used_transfer_buffer_usage_bytes_
);
521 void* TestWebGraphicsContext3D::mapBufferCHROMIUM(GLenum target
,
523 base::AutoLock
lock(namespace_
->lock
);
524 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
525 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
526 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
527 if (times_map_buffer_chromium_succeeds_
>= 0) {
528 if (!times_map_buffer_chromium_succeeds_
) {
531 --times_map_buffer_chromium_succeeds_
;
534 return buffers
.get(bound_buffer_
)->pixels
.get();
537 GLboolean
TestWebGraphicsContext3D::unmapBufferCHROMIUM(
539 base::AutoLock
lock(namespace_
->lock
);
540 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
541 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
542 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
543 buffers
.get(bound_buffer_
)->pixels
= nullptr;
547 GLuint
TestWebGraphicsContext3D::createImageCHROMIUM(ClientBuffer buffer
,
550 GLenum internalformat
) {
551 DCHECK_EQ(GL_RGBA
, static_cast<int>(internalformat
));
552 GLuint image_id
= NextImageId();
553 base::AutoLock
lock(namespace_
->lock
);
554 base::hash_set
<unsigned>& images
= namespace_
->images
;
555 images
.insert(image_id
);
559 void TestWebGraphicsContext3D::destroyImageCHROMIUM(
562 base::AutoLock
lock(namespace_
->lock
);
563 base::hash_set
<unsigned>& images
= namespace_
->images
;
564 if (!images
.count(id
))
565 ADD_FAILURE() << "destroyImageCHROMIUM called on unknown image " << id
;
569 GLuint
TestWebGraphicsContext3D::createGpuMemoryBufferImageCHROMIUM(
572 GLenum internalformat
,
574 DCHECK_EQ(GL_RGBA
, static_cast<int>(internalformat
));
575 GLuint image_id
= NextImageId();
576 base::AutoLock
lock(namespace_
->lock
);
577 base::hash_set
<unsigned>& images
= namespace_
->images
;
578 images
.insert(image_id
);
582 unsigned TestWebGraphicsContext3D::insertSyncPoint() {
583 return next_insert_sync_point_
++;
586 void TestWebGraphicsContext3D::waitSyncPoint(unsigned sync_point
) {
588 last_waited_sync_point_
= sync_point
;
591 size_t TestWebGraphicsContext3D::NumTextures() const {
592 base::AutoLock
lock(namespace_
->lock
);
593 return namespace_
->textures
.Size();
596 GLuint
TestWebGraphicsContext3D::TextureAt(int i
) const {
597 base::AutoLock
lock(namespace_
->lock
);
598 return namespace_
->textures
.IdAt(i
);
601 GLuint
TestWebGraphicsContext3D::NextTextureId() {
602 base::AutoLock
lock(namespace_
->lock
);
603 GLuint texture_id
= namespace_
->next_texture_id
++;
604 DCHECK(texture_id
< (1 << 16));
605 texture_id
|= context_id_
<< 16;
609 void TestWebGraphicsContext3D::RetireTextureId(GLuint id
) {
610 base::AutoLock
lock(namespace_
->lock
);
611 unsigned context_id
= id
>> 16;
612 unsigned texture_id
= id
& 0xffff;
614 DCHECK_LT(texture_id
, namespace_
->next_texture_id
);
615 DCHECK_EQ(context_id
, context_id_
);
618 GLuint
TestWebGraphicsContext3D::NextBufferId() {
619 base::AutoLock
lock(namespace_
->lock
);
620 GLuint buffer_id
= namespace_
->next_buffer_id
++;
621 DCHECK(buffer_id
< (1 << 16));
622 buffer_id
|= context_id_
<< 16;
626 void TestWebGraphicsContext3D::RetireBufferId(GLuint id
) {
627 base::AutoLock
lock(namespace_
->lock
);
628 unsigned context_id
= id
>> 16;
629 unsigned buffer_id
= id
& 0xffff;
631 DCHECK_LT(buffer_id
, namespace_
->next_buffer_id
);
632 DCHECK_EQ(context_id
, context_id_
);
635 GLuint
TestWebGraphicsContext3D::NextImageId() {
636 base::AutoLock
lock(namespace_
->lock
);
637 GLuint image_id
= namespace_
->next_image_id
++;
638 DCHECK(image_id
< (1 << 16));
639 image_id
|= context_id_
<< 16;
643 void TestWebGraphicsContext3D::RetireImageId(GLuint id
) {
644 base::AutoLock
lock(namespace_
->lock
);
645 unsigned context_id
= id
>> 16;
646 unsigned image_id
= id
& 0xffff;
648 DCHECK_LT(image_id
, namespace_
->next_image_id
);
649 DCHECK_EQ(context_id
, context_id_
);
652 void TestWebGraphicsContext3D::SetMaxTransferBufferUsageBytes(
653 size_t max_transfer_buffer_usage_bytes
) {
654 test_capabilities_
.max_transfer_buffer_usage_bytes
=
655 max_transfer_buffer_usage_bytes
;
658 TestWebGraphicsContext3D::TextureTargets::TextureTargets() {
659 // Initialize default bindings.
660 bound_textures_
[GL_TEXTURE_2D
] = 0;
661 bound_textures_
[GL_TEXTURE_EXTERNAL_OES
] = 0;
662 bound_textures_
[GL_TEXTURE_RECTANGLE_ARB
] = 0;
665 TestWebGraphicsContext3D::TextureTargets::~TextureTargets() {}
667 void TestWebGraphicsContext3D::TextureTargets::BindTexture(
670 // Make sure this is a supported target by seeing if it was bound to before.
671 DCHECK(bound_textures_
.find(target
) != bound_textures_
.end());
672 bound_textures_
[target
] = id
;
675 void TestWebGraphicsContext3D::texParameteri(GLenum target
,
678 CheckTextureIsBound(target
);
679 base::AutoLock
lock_for_texture_access(namespace_
->lock
);
680 scoped_refptr
<TestTexture
> texture
= BoundTexture(target
);
681 DCHECK(texture
->IsValidParameter(pname
));
682 texture
->params
[pname
] = param
;
685 void TestWebGraphicsContext3D::getTexParameteriv(GLenum target
,
688 CheckTextureIsBound(target
);
689 base::AutoLock
lock_for_texture_access(namespace_
->lock
);
690 scoped_refptr
<TestTexture
> texture
= BoundTexture(target
);
691 DCHECK(texture
->IsValidParameter(pname
));
692 TestTexture::TextureParametersMap::iterator it
= texture
->params
.find(pname
);
693 if (it
!= texture
->params
.end())
697 void TestWebGraphicsContext3D::TextureTargets::UnbindTexture(
699 // Bind zero to any targets that the id is bound to.
700 for (TargetTextureMap::iterator it
= bound_textures_
.begin();
701 it
!= bound_textures_
.end();
703 if (it
->second
== id
)
708 GLuint
TestWebGraphicsContext3D::TextureTargets::BoundTexture(
710 DCHECK(bound_textures_
.find(target
) != bound_textures_
.end());
711 return bound_textures_
[target
];
714 TestWebGraphicsContext3D::Buffer::Buffer() : target(0), size(0) {}
716 TestWebGraphicsContext3D::Buffer::~Buffer() {}
718 TestWebGraphicsContext3D::Image::Image() {}
720 TestWebGraphicsContext3D::Image::~Image() {}