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/debug/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 "gpu/GLES2/gl2extchromium.h"
15 #include "third_party/khronos/GLES2/gl2ext.h"
17 using WebKit::WGC3Dboolean
;
18 using WebKit::WGC3Dchar
;
19 using WebKit::WGC3Denum
;
20 using WebKit::WGC3Dint
;
21 using WebKit::WGC3Dsizei
;
22 using WebKit::WGC3Dsizeiptr
;
23 using WebKit::WGC3Duint
;
24 using WebKit::WebGLId
;
25 using WebKit::WebGraphicsContext3D
;
29 static const WebGLId kFramebufferId
= 1;
30 static const WebGLId kProgramId
= 2;
31 static const WebGLId kRenderbufferId
= 3;
32 static const WebGLId kShaderId
= 4;
34 static unsigned s_context_id
= 1;
36 const WebGLId
TestWebGraphicsContext3D::kExternalTextureId
= 1337;
38 static base::LazyInstance
<base::Lock
>::Leaky
39 g_shared_namespace_lock
= LAZY_INSTANCE_INITIALIZER
;
41 TestWebGraphicsContext3D::Namespace
*
42 TestWebGraphicsContext3D::shared_namespace_
= NULL
;
44 TestWebGraphicsContext3D::Namespace::Namespace()
50 TestWebGraphicsContext3D::Namespace::~Namespace() {
51 g_shared_namespace_lock
.Get().AssertAcquired();
52 if (shared_namespace_
== this)
53 shared_namespace_
= NULL
;
57 scoped_ptr
<TestWebGraphicsContext3D
> TestWebGraphicsContext3D::Create() {
58 return make_scoped_ptr(new TestWebGraphicsContext3D());
61 TestWebGraphicsContext3D::TestWebGraphicsContext3D()
62 : FakeWebGraphicsContext3D(),
63 context_id_(s_context_id
++),
64 times_make_current_succeeds_(-1),
65 times_bind_texture_succeeds_(-1),
66 times_end_query_succeeds_(-1),
67 times_gen_mailbox_succeeds_(-1),
69 times_map_image_chromium_succeeds_(-1),
70 times_map_buffer_chromium_succeeds_(-1),
71 context_lost_callback_(NULL
),
72 swap_buffers_callback_(NULL
),
73 max_texture_size_(2048),
77 weak_ptr_factory_(this) {
79 test_capabilities_
.swapbuffers_complete_callback
= true;
82 TestWebGraphicsContext3D::TestWebGraphicsContext3D(
83 const WebGraphicsContext3D::Attributes
& attributes
)
84 : FakeWebGraphicsContext3D(),
85 context_id_(s_context_id
++),
86 attributes_(attributes
),
87 times_make_current_succeeds_(-1),
88 times_bind_texture_succeeds_(-1),
89 times_end_query_succeeds_(-1),
90 times_gen_mailbox_succeeds_(-1),
92 times_map_image_chromium_succeeds_(-1),
93 times_map_buffer_chromium_succeeds_(-1),
94 context_lost_callback_(NULL
),
95 swap_buffers_callback_(NULL
),
96 max_texture_size_(2048),
100 weak_ptr_factory_(this) {
102 test_capabilities_
.swapbuffers_complete_callback
= true;
105 void TestWebGraphicsContext3D::CreateNamespace() {
106 if (attributes_
.shareResources
) {
107 base::AutoLock
lock(g_shared_namespace_lock
.Get());
108 if (shared_namespace_
) {
109 namespace_
= shared_namespace_
;
111 namespace_
= new Namespace
;
112 shared_namespace_
= namespace_
.get();
115 namespace_
= new Namespace
;
119 TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
120 for (size_t i
= 0; i
< sync_point_callbacks_
.size(); ++i
) {
121 if (sync_point_callbacks_
[i
] != NULL
)
122 delete sync_point_callbacks_
[i
];
124 base::AutoLock
lock(g_shared_namespace_lock
.Get());
128 bool TestWebGraphicsContext3D::makeContextCurrent() {
129 if (times_make_current_succeeds_
>= 0) {
130 if (!times_make_current_succeeds_
) {
131 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
132 GL_INNOCENT_CONTEXT_RESET_ARB
);
134 --times_make_current_succeeds_
;
136 return !context_lost_
;
139 int TestWebGraphicsContext3D::width() {
143 int TestWebGraphicsContext3D::height() {
147 void TestWebGraphicsContext3D::reshapeWithScaleFactor(
148 int width
, int height
, float scale_factor
) {
153 bool TestWebGraphicsContext3D::isContextLost() {
154 return context_lost_
;
157 WGC3Denum
TestWebGraphicsContext3D::getGraphicsResetStatusARB() {
158 return context_lost_
? GL_UNKNOWN_CONTEXT_RESET_ARB
: GL_NO_ERROR
;
161 WGC3Denum
TestWebGraphicsContext3D::checkFramebufferStatus(
164 return GL_FRAMEBUFFER_UNDEFINED_OES
;
165 return GL_FRAMEBUFFER_COMPLETE
;
168 WebGraphicsContext3D::Attributes
169 TestWebGraphicsContext3D::getContextAttributes() {
173 WebKit::WebString
TestWebGraphicsContext3D::getString(WGC3Denum name
) {
174 return WebKit::WebString();
177 WGC3Dint
TestWebGraphicsContext3D::getUniformLocation(
179 const WGC3Dchar
* name
) {
183 WGC3Dsizeiptr
TestWebGraphicsContext3D::getVertexAttribOffset(
189 WGC3Dboolean
TestWebGraphicsContext3D::isBuffer(
194 WGC3Dboolean
TestWebGraphicsContext3D::isEnabled(
199 WGC3Dboolean
TestWebGraphicsContext3D::isFramebuffer(
200 WebGLId framebuffer
) {
204 WGC3Dboolean
TestWebGraphicsContext3D::isProgram(
209 WGC3Dboolean
TestWebGraphicsContext3D::isRenderbuffer(
210 WebGLId renderbuffer
) {
214 WGC3Dboolean
TestWebGraphicsContext3D::isShader(
219 WGC3Dboolean
TestWebGraphicsContext3D::isTexture(
224 WebGLId
TestWebGraphicsContext3D::createBuffer() {
225 return NextBufferId();
228 void TestWebGraphicsContext3D::deleteBuffer(WebGLId id
) {
229 base::AutoLock
lock(namespace_
->lock
);
230 unsigned context_id
= id
>> 17;
231 unsigned buffer_id
= id
& 0x1ffff;
232 DCHECK(buffer_id
&& buffer_id
< namespace_
->next_buffer_id
);
233 DCHECK_EQ(context_id
, context_id_
);
236 WebGLId
TestWebGraphicsContext3D::createFramebuffer() {
237 return kFramebufferId
| context_id_
<< 16;
240 void TestWebGraphicsContext3D::deleteFramebuffer(WebGLId id
) {
241 DCHECK_EQ(kFramebufferId
| context_id_
<< 16, id
);
244 WebGLId
TestWebGraphicsContext3D::createProgram() {
245 return kProgramId
| context_id_
<< 16;
248 void TestWebGraphicsContext3D::deleteProgram(WebGLId id
) {
249 DCHECK_EQ(kProgramId
| context_id_
<< 16, id
);
252 WebGLId
TestWebGraphicsContext3D::createRenderbuffer() {
253 return kRenderbufferId
| context_id_
<< 16;
256 void TestWebGraphicsContext3D::deleteRenderbuffer(WebGLId id
) {
257 DCHECK_EQ(kRenderbufferId
| context_id_
<< 16, id
);
260 WebGLId
TestWebGraphicsContext3D::createShader(WGC3Denum
) {
261 return kShaderId
| context_id_
<< 16;
264 void TestWebGraphicsContext3D::deleteShader(WebGLId id
) {
265 DCHECK_EQ(kShaderId
| context_id_
<< 16, id
);
268 WebGLId
TestWebGraphicsContext3D::createTexture() {
269 WebGLId texture_id
= NextTextureId();
270 DCHECK_NE(texture_id
, kExternalTextureId
);
271 base::AutoLock
lock(namespace_
->lock
);
272 namespace_
->textures
.push_back(texture_id
);
276 void TestWebGraphicsContext3D::deleteTexture(WebGLId texture_id
) {
277 base::AutoLock
lock(namespace_
->lock
);
278 std::vector
<WebKit::WebGLId
>& textures
= namespace_
->textures
;
279 DCHECK(std::find(textures
.begin(), textures
.end(), texture_id
) !=
281 textures
.erase(std::find(textures
.begin(), textures
.end(), texture_id
));
284 void TestWebGraphicsContext3D::attachShader(WebGLId program
, WebGLId shader
) {
285 DCHECK_EQ(kProgramId
| context_id_
<< 16, program
);
286 DCHECK_EQ(kShaderId
| context_id_
<< 16, shader
);
289 void TestWebGraphicsContext3D::useProgram(WebGLId program
) {
292 DCHECK_EQ(kProgramId
| context_id_
<< 16, program
);
295 void TestWebGraphicsContext3D::bindFramebuffer(
296 WGC3Denum target
, WebGLId framebuffer
) {
299 DCHECK_EQ(kFramebufferId
| context_id_
<< 16, framebuffer
);
302 void TestWebGraphicsContext3D::bindRenderbuffer(
303 WGC3Denum target
, WebGLId renderbuffer
) {
306 DCHECK_EQ(kRenderbufferId
| context_id_
<< 16, renderbuffer
);
309 void TestWebGraphicsContext3D::bindTexture(
310 WGC3Denum target
, WebGLId 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 if (texture_id
== kExternalTextureId
)
323 base::AutoLock
lock(namespace_
->lock
);
324 std::vector
<WebKit::WebGLId
>& textures
= namespace_
->textures
;
325 DCHECK(std::find(textures
.begin(), textures
.end(), texture_id
) !=
327 used_textures_
.insert(texture_id
);
330 void TestWebGraphicsContext3D::endQueryEXT(WGC3Denum target
) {
331 if (times_end_query_succeeds_
>= 0) {
332 if (!times_end_query_succeeds_
) {
333 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
334 GL_INNOCENT_CONTEXT_RESET_ARB
);
336 --times_end_query_succeeds_
;
340 void TestWebGraphicsContext3D::getQueryObjectuivEXT(
344 // If the context is lost, behave as if result is available.
345 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
349 void TestWebGraphicsContext3D::getIntegerv(
351 WebKit::WGC3Dint
* value
) {
352 if (pname
== GL_MAX_TEXTURE_SIZE
)
353 *value
= max_texture_size_
;
354 else if (pname
== GL_ACTIVE_TEXTURE
)
355 *value
= GL_TEXTURE0
;
358 void TestWebGraphicsContext3D::genMailboxCHROMIUM(WebKit::WGC3Dbyte
* mailbox
) {
359 if (times_gen_mailbox_succeeds_
>= 0) {
360 if (!times_gen_mailbox_succeeds_
) {
361 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
362 GL_INNOCENT_CONTEXT_RESET_ARB
);
364 --times_gen_mailbox_succeeds_
;
367 memset(mailbox
, 0, 64);
371 static char mailbox_name1
= '1';
372 static char mailbox_name2
= '1';
373 mailbox
[0] = mailbox_name1
;
374 mailbox
[1] = mailbox_name2
;
376 if (++mailbox_name1
== 0) {
382 void TestWebGraphicsContext3D::setContextLostCallback(
383 WebGraphicsContextLostCallback
* callback
) {
384 context_lost_callback_
= callback
;
387 void TestWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current
,
391 context_lost_
= true;
392 if (context_lost_callback_
)
393 context_lost_callback_
->onContextLost();
395 for (size_t i
= 0; i
< shared_contexts_
.size(); ++i
)
396 shared_contexts_
[i
]->loseContextCHROMIUM(current
, other
);
397 shared_contexts_
.clear();
400 void TestWebGraphicsContext3D::signalSyncPoint(
402 WebGraphicsSyncPointCallback
* callback
) {
403 sync_point_callbacks_
.push_back(callback
);
406 void TestWebGraphicsContext3D::signalQuery(
407 WebKit::WebGLId query
,
408 WebGraphicsSyncPointCallback
* callback
) {
409 sync_point_callbacks_
.push_back(callback
);
412 void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM(
413 WebGraphicsSwapBuffersCompleteCallbackCHROMIUM
* callback
) {
414 if (test_capabilities_
.swapbuffers_complete_callback
)
415 swap_buffers_callback_
= callback
;
418 void TestWebGraphicsContext3D::prepareTexture() {
419 if (swap_buffers_callback_
) {
420 base::MessageLoop::current()->PostTask(
421 FROM_HERE
, base::Bind(&TestWebGraphicsContext3D::SwapBuffersComplete
,
422 weak_ptr_factory_
.GetWeakPtr()));
424 CallAllSyncPointCallbacks();
427 void TestWebGraphicsContext3D::finish() {
428 CallAllSyncPointCallbacks();
431 void TestWebGraphicsContext3D::flush() {
432 CallAllSyncPointCallbacks();
435 static void CallAndDestroy(
436 WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback
* callback
) {
439 callback
->onSyncPointReached();
443 void TestWebGraphicsContext3D::CallAllSyncPointCallbacks() {
444 for (size_t i
= 0; i
< sync_point_callbacks_
.size(); ++i
) {
445 base::MessageLoop::current()->PostTask(
447 base::Bind(&CallAndDestroy
,
448 sync_point_callbacks_
[i
]));
450 sync_point_callbacks_
.clear();
453 void TestWebGraphicsContext3D::SwapBuffersComplete() {
454 if (swap_buffers_callback_
)
455 swap_buffers_callback_
->onSwapBuffersComplete();
458 void TestWebGraphicsContext3D::bindBuffer(WebKit::WGC3Denum target
,
459 WebKit::WebGLId buffer
) {
460 bound_buffer_
= buffer
;
463 unsigned context_id
= buffer
>> 17;
464 unsigned buffer_id
= buffer
& 0x1ffff;
465 base::AutoLock
lock(namespace_
->lock
);
466 DCHECK(buffer_id
&& buffer_id
< namespace_
->next_buffer_id
);
467 DCHECK_EQ(context_id
, context_id_
);
469 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
470 if (buffers
.count(bound_buffer_
) == 0)
471 buffers
.set(bound_buffer_
, make_scoped_ptr(new Buffer
).Pass());
473 buffers
.get(bound_buffer_
)->target
= target
;
476 void TestWebGraphicsContext3D::bufferData(WebKit::WGC3Denum target
,
477 WebKit::WGC3Dsizeiptr size
,
479 WebKit::WGC3Denum usage
) {
480 base::AutoLock
lock(namespace_
->lock
);
481 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
482 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
483 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
485 buffers
.get(bound_buffer_
)->pixels
.reset();
488 buffers
.get(bound_buffer_
)->pixels
.reset(new uint8
[size
]);
490 memcpy(buffers
.get(bound_buffer_
)->pixels
.get(), data
, size
);
493 void* TestWebGraphicsContext3D::mapBufferCHROMIUM(WebKit::WGC3Denum target
,
494 WebKit::WGC3Denum access
) {
495 base::AutoLock
lock(namespace_
->lock
);
496 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
497 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
498 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
499 if (times_map_buffer_chromium_succeeds_
>= 0) {
500 if (!times_map_buffer_chromium_succeeds_
) {
503 --times_map_buffer_chromium_succeeds_
;
505 return buffers
.get(bound_buffer_
)->pixels
.get();
508 WebKit::WGC3Dboolean
TestWebGraphicsContext3D::unmapBufferCHROMIUM(
509 WebKit::WGC3Denum target
) {
510 base::AutoLock
lock(namespace_
->lock
);
511 base::ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
512 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
513 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
514 buffers
.get(bound_buffer_
)->pixels
.reset();
518 WebKit::WGC3Duint
TestWebGraphicsContext3D::createImageCHROMIUM(
519 WebKit::WGC3Dsizei width
, WebKit::WGC3Dsizei height
,
520 WebKit::WGC3Denum internalformat
) {
521 DCHECK_EQ(GL_RGBA8_OES
, static_cast<int>(internalformat
));
522 WebKit::WGC3Duint image_id
= NextImageId();
523 base::AutoLock
lock(namespace_
->lock
);
524 base::ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
525 images
.set(image_id
, make_scoped_ptr(new Image
).Pass());
526 images
.get(image_id
)->pixels
.reset(new uint8
[width
* height
* 4]);
530 void TestWebGraphicsContext3D::destroyImageCHROMIUM(
531 WebKit::WGC3Duint id
) {
532 base::AutoLock
lock(namespace_
->lock
);
533 unsigned context_id
= id
>> 17;
534 unsigned image_id
= id
& 0x1ffff;
535 DCHECK(image_id
&& image_id
< namespace_
->next_image_id
);
536 DCHECK_EQ(context_id
, context_id_
);
539 void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
540 WebKit::WGC3Duint image_id
,
541 WebKit::WGC3Denum pname
,
542 WebKit::WGC3Dint
* params
) {
543 base::AutoLock
lock(namespace_
->lock
);
544 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
545 DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM
, static_cast<int>(pname
));
549 void* TestWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id
,
550 WebKit::WGC3Denum access
) {
551 base::AutoLock
lock(namespace_
->lock
);
552 base::ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
553 DCHECK_GT(images
.count(image_id
), 0u);
554 if (times_map_image_chromium_succeeds_
>= 0) {
555 if (!times_map_image_chromium_succeeds_
) {
558 --times_map_image_chromium_succeeds_
;
560 return images
.get(image_id
)->pixels
.get();
563 void TestWebGraphicsContext3D::unmapImageCHROMIUM(
564 WebKit::WGC3Duint image_id
) {
565 base::AutoLock
lock(namespace_
->lock
);
566 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
569 size_t TestWebGraphicsContext3D::NumTextures() const {
570 base::AutoLock
lock(namespace_
->lock
);
571 return namespace_
->textures
.size();
574 WebKit::WebGLId
TestWebGraphicsContext3D::TextureAt(int i
) const {
575 base::AutoLock
lock(namespace_
->lock
);
576 return namespace_
->textures
[i
];
579 WebGLId
TestWebGraphicsContext3D::NextTextureId() {
580 base::AutoLock
lock(namespace_
->lock
);
581 WebGLId texture_id
= namespace_
->next_texture_id
++;
582 DCHECK(texture_id
< (1 << 16));
583 texture_id
|= context_id_
<< 16;
587 WebGLId
TestWebGraphicsContext3D::NextBufferId() {
588 base::AutoLock
lock(namespace_
->lock
);
589 WebGLId buffer_id
= namespace_
->next_buffer_id
++;
590 DCHECK(buffer_id
< (1 << 17));
591 buffer_id
|= context_id_
<< 17;
595 WebKit::WGC3Duint
TestWebGraphicsContext3D::NextImageId() {
596 base::AutoLock
lock(namespace_
->lock
);
597 WGC3Duint image_id
= namespace_
->next_image_id
++;
598 DCHECK(image_id
< (1 << 17));
599 image_id
|= context_id_
<< 17;
603 TestWebGraphicsContext3D::Buffer::Buffer() : target(0) {}
605 TestWebGraphicsContext3D::Buffer::~Buffer() {}
607 TestWebGraphicsContext3D::Image::Image() {}
609 TestWebGraphicsContext3D::Image::~Image() {}