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 support_swapbuffers_complete_callback_(true),
65 have_extension_io_surface_(false),
66 have_extension_egl_image_(false),
67 times_make_current_succeeds_(-1),
68 times_bind_texture_succeeds_(-1),
69 times_end_query_succeeds_(-1),
70 times_gen_mailbox_succeeds_(-1),
72 times_map_image_chromium_succeeds_(-1),
73 times_map_buffer_chromium_succeeds_(-1),
74 context_lost_callback_(NULL
),
75 swap_buffers_callback_(NULL
),
76 max_texture_size_(2048),
80 weak_ptr_factory_(this) {
84 TestWebGraphicsContext3D::TestWebGraphicsContext3D(
85 const WebGraphicsContext3D::Attributes
& attributes
)
86 : FakeWebGraphicsContext3D(),
87 context_id_(s_context_id
++),
88 attributes_(attributes
),
89 support_swapbuffers_complete_callback_(true),
90 have_extension_io_surface_(false),
91 have_extension_egl_image_(false),
92 times_make_current_succeeds_(-1),
93 times_bind_texture_succeeds_(-1),
94 times_end_query_succeeds_(-1),
95 times_gen_mailbox_succeeds_(-1),
97 times_map_image_chromium_succeeds_(-1),
98 times_map_buffer_chromium_succeeds_(-1),
99 context_lost_callback_(NULL
),
100 swap_buffers_callback_(NULL
),
101 max_texture_size_(2048),
105 weak_ptr_factory_(this) {
109 void TestWebGraphicsContext3D::CreateNamespace() {
110 if (attributes_
.shareResources
) {
111 base::AutoLock
lock(g_shared_namespace_lock
.Get());
112 if (shared_namespace_
) {
113 namespace_
= shared_namespace_
;
115 namespace_
= new Namespace
;
116 shared_namespace_
= namespace_
.get();
119 namespace_
= new Namespace
;
123 TestWebGraphicsContext3D::~TestWebGraphicsContext3D() {
124 for (size_t i
= 0; i
< sync_point_callbacks_
.size(); ++i
) {
125 if (sync_point_callbacks_
[i
] != NULL
)
126 delete sync_point_callbacks_
[i
];
128 base::AutoLock
lock(g_shared_namespace_lock
.Get());
132 bool TestWebGraphicsContext3D::makeContextCurrent() {
133 if (times_make_current_succeeds_
>= 0) {
134 if (!times_make_current_succeeds_
) {
135 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
136 GL_INNOCENT_CONTEXT_RESET_ARB
);
138 --times_make_current_succeeds_
;
140 return !context_lost_
;
143 int TestWebGraphicsContext3D::width() {
147 int TestWebGraphicsContext3D::height() {
151 void TestWebGraphicsContext3D::reshapeWithScaleFactor(
152 int width
, int height
, float scale_factor
) {
157 bool TestWebGraphicsContext3D::isContextLost() {
158 return context_lost_
;
161 WGC3Denum
TestWebGraphicsContext3D::getGraphicsResetStatusARB() {
162 return context_lost_
? GL_UNKNOWN_CONTEXT_RESET_ARB
: GL_NO_ERROR
;
165 WGC3Denum
TestWebGraphicsContext3D::checkFramebufferStatus(
168 return GL_FRAMEBUFFER_UNDEFINED_OES
;
169 return GL_FRAMEBUFFER_COMPLETE
;
172 WebGraphicsContext3D::Attributes
173 TestWebGraphicsContext3D::getContextAttributes() {
177 WebKit::WebString
TestWebGraphicsContext3D::getString(WGC3Denum name
) {
180 if (support_swapbuffers_complete_callback_
)
181 string
+= "GL_CHROMIUM_swapbuffers_complete_callback";
183 if (name
== GL_EXTENSIONS
) {
184 if (have_extension_io_surface_
)
185 string
+= " GL_CHROMIUM_iosurface GL_ARB_texture_rectangle";
186 if (have_extension_egl_image_
)
187 string
+= " GL_OES_EGL_image_external";
190 return WebKit::WebString::fromUTF8(string
.c_str());
193 WGC3Dint
TestWebGraphicsContext3D::getUniformLocation(
195 const WGC3Dchar
* name
) {
199 WGC3Dsizeiptr
TestWebGraphicsContext3D::getVertexAttribOffset(
205 WGC3Dboolean
TestWebGraphicsContext3D::isBuffer(
210 WGC3Dboolean
TestWebGraphicsContext3D::isEnabled(
215 WGC3Dboolean
TestWebGraphicsContext3D::isFramebuffer(
216 WebGLId framebuffer
) {
220 WGC3Dboolean
TestWebGraphicsContext3D::isProgram(
225 WGC3Dboolean
TestWebGraphicsContext3D::isRenderbuffer(
226 WebGLId renderbuffer
) {
230 WGC3Dboolean
TestWebGraphicsContext3D::isShader(
235 WGC3Dboolean
TestWebGraphicsContext3D::isTexture(
240 WebGLId
TestWebGraphicsContext3D::createBuffer() {
241 return NextBufferId();
244 void TestWebGraphicsContext3D::deleteBuffer(WebGLId id
) {
245 base::AutoLock
lock(namespace_
->lock
);
246 unsigned context_id
= id
>> 17;
247 unsigned buffer_id
= id
& 0x1ffff;
248 DCHECK(buffer_id
&& buffer_id
< namespace_
->next_buffer_id
);
249 DCHECK_EQ(context_id
, context_id_
);
252 WebGLId
TestWebGraphicsContext3D::createFramebuffer() {
253 return kFramebufferId
| context_id_
<< 16;
256 void TestWebGraphicsContext3D::deleteFramebuffer(WebGLId id
) {
257 DCHECK_EQ(kFramebufferId
| context_id_
<< 16, id
);
260 WebGLId
TestWebGraphicsContext3D::createProgram() {
261 return kProgramId
| context_id_
<< 16;
264 void TestWebGraphicsContext3D::deleteProgram(WebGLId id
) {
265 DCHECK_EQ(kProgramId
| context_id_
<< 16, id
);
268 WebGLId
TestWebGraphicsContext3D::createRenderbuffer() {
269 return kRenderbufferId
| context_id_
<< 16;
272 void TestWebGraphicsContext3D::deleteRenderbuffer(WebGLId id
) {
273 DCHECK_EQ(kRenderbufferId
| context_id_
<< 16, id
);
276 WebGLId
TestWebGraphicsContext3D::createShader(WGC3Denum
) {
277 return kShaderId
| context_id_
<< 16;
280 void TestWebGraphicsContext3D::deleteShader(WebGLId id
) {
281 DCHECK_EQ(kShaderId
| context_id_
<< 16, id
);
284 WebGLId
TestWebGraphicsContext3D::createTexture() {
285 WebGLId texture_id
= NextTextureId();
286 DCHECK_NE(texture_id
, kExternalTextureId
);
287 base::AutoLock
lock(namespace_
->lock
);
288 namespace_
->textures
.push_back(texture_id
);
292 void TestWebGraphicsContext3D::deleteTexture(WebGLId texture_id
) {
293 base::AutoLock
lock(namespace_
->lock
);
294 std::vector
<WebKit::WebGLId
>& textures
= namespace_
->textures
;
295 DCHECK(std::find(textures
.begin(), textures
.end(), texture_id
) !=
297 textures
.erase(std::find(textures
.begin(), textures
.end(), texture_id
));
300 void TestWebGraphicsContext3D::attachShader(WebGLId program
, WebGLId shader
) {
301 DCHECK_EQ(kProgramId
| context_id_
<< 16, program
);
302 DCHECK_EQ(kShaderId
| context_id_
<< 16, shader
);
305 void TestWebGraphicsContext3D::useProgram(WebGLId program
) {
308 DCHECK_EQ(kProgramId
| context_id_
<< 16, program
);
311 void TestWebGraphicsContext3D::bindFramebuffer(
312 WGC3Denum target
, WebGLId framebuffer
) {
315 DCHECK_EQ(kFramebufferId
| context_id_
<< 16, framebuffer
);
318 void TestWebGraphicsContext3D::bindRenderbuffer(
319 WGC3Denum target
, WebGLId renderbuffer
) {
322 DCHECK_EQ(kRenderbufferId
| context_id_
<< 16, renderbuffer
);
325 void TestWebGraphicsContext3D::bindTexture(
326 WGC3Denum target
, WebGLId texture_id
) {
327 if (times_bind_texture_succeeds_
>= 0) {
328 if (!times_bind_texture_succeeds_
) {
329 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
330 GL_INNOCENT_CONTEXT_RESET_ARB
);
332 --times_bind_texture_succeeds_
;
337 if (texture_id
== kExternalTextureId
)
339 base::AutoLock
lock(namespace_
->lock
);
340 std::vector
<WebKit::WebGLId
>& textures
= namespace_
->textures
;
341 DCHECK(std::find(textures
.begin(), textures
.end(), texture_id
) !=
343 used_textures_
.insert(texture_id
);
346 void TestWebGraphicsContext3D::endQueryEXT(WGC3Denum target
) {
347 if (times_end_query_succeeds_
>= 0) {
348 if (!times_end_query_succeeds_
) {
349 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
350 GL_INNOCENT_CONTEXT_RESET_ARB
);
352 --times_end_query_succeeds_
;
356 void TestWebGraphicsContext3D::getQueryObjectuivEXT(
360 // If the context is lost, behave as if result is available.
361 if (pname
== GL_QUERY_RESULT_AVAILABLE_EXT
)
365 void TestWebGraphicsContext3D::getIntegerv(
367 WebKit::WGC3Dint
* value
) {
368 if (pname
== GL_MAX_TEXTURE_SIZE
)
369 *value
= max_texture_size_
;
370 else if (pname
== GL_ACTIVE_TEXTURE
)
371 *value
= GL_TEXTURE0
;
374 void TestWebGraphicsContext3D::genMailboxCHROMIUM(WebKit::WGC3Dbyte
* mailbox
) {
375 if (times_gen_mailbox_succeeds_
>= 0) {
376 if (!times_gen_mailbox_succeeds_
) {
377 loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB
,
378 GL_INNOCENT_CONTEXT_RESET_ARB
);
380 --times_gen_mailbox_succeeds_
;
383 memset(mailbox
, 0, 64);
387 static char mailbox_name1
= '1';
388 static char mailbox_name2
= '1';
389 mailbox
[0] = mailbox_name1
;
390 mailbox
[1] = mailbox_name2
;
392 if (++mailbox_name1
== 0) {
398 void TestWebGraphicsContext3D::setContextLostCallback(
399 WebGraphicsContextLostCallback
* callback
) {
400 context_lost_callback_
= callback
;
403 void TestWebGraphicsContext3D::loseContextCHROMIUM(WGC3Denum current
,
407 context_lost_
= true;
408 if (context_lost_callback_
)
409 context_lost_callback_
->onContextLost();
411 for (size_t i
= 0; i
< shared_contexts_
.size(); ++i
)
412 shared_contexts_
[i
]->loseContextCHROMIUM(current
, other
);
413 shared_contexts_
.clear();
416 void TestWebGraphicsContext3D::signalSyncPoint(
418 WebGraphicsSyncPointCallback
* callback
) {
419 sync_point_callbacks_
.push_back(callback
);
422 void TestWebGraphicsContext3D::signalQuery(
423 WebKit::WebGLId query
,
424 WebGraphicsSyncPointCallback
* callback
) {
425 sync_point_callbacks_
.push_back(callback
);
428 void TestWebGraphicsContext3D::setSwapBuffersCompleteCallbackCHROMIUM(
429 WebGraphicsSwapBuffersCompleteCallbackCHROMIUM
* callback
) {
430 if (support_swapbuffers_complete_callback_
)
431 swap_buffers_callback_
= callback
;
434 void TestWebGraphicsContext3D::prepareTexture() {
435 if (swap_buffers_callback_
) {
436 base::MessageLoop::current()->PostTask(
437 FROM_HERE
, base::Bind(&TestWebGraphicsContext3D::SwapBuffersComplete
,
438 weak_ptr_factory_
.GetWeakPtr()));
440 CallAllSyncPointCallbacks();
443 void TestWebGraphicsContext3D::finish() {
444 CallAllSyncPointCallbacks();
447 void TestWebGraphicsContext3D::flush() {
448 CallAllSyncPointCallbacks();
451 static void CallAndDestroy(
452 WebKit::WebGraphicsContext3D::WebGraphicsSyncPointCallback
* callback
) {
455 callback
->onSyncPointReached();
459 void TestWebGraphicsContext3D::CallAllSyncPointCallbacks() {
460 for (size_t i
= 0; i
< sync_point_callbacks_
.size(); ++i
) {
461 base::MessageLoop::current()->PostTask(
463 base::Bind(&CallAndDestroy
,
464 sync_point_callbacks_
[i
]));
466 sync_point_callbacks_
.clear();
469 void TestWebGraphicsContext3D::SwapBuffersComplete() {
470 if (swap_buffers_callback_
)
471 swap_buffers_callback_
->onSwapBuffersComplete();
474 void TestWebGraphicsContext3D::bindBuffer(WebKit::WGC3Denum target
,
475 WebKit::WebGLId buffer
) {
476 bound_buffer_
= buffer
;
479 unsigned context_id
= buffer
>> 17;
480 unsigned buffer_id
= buffer
& 0x1ffff;
481 base::AutoLock
lock(namespace_
->lock
);
482 DCHECK(buffer_id
&& buffer_id
< namespace_
->next_buffer_id
);
483 DCHECK_EQ(context_id
, context_id_
);
485 ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
486 if (buffers
.count(bound_buffer_
) == 0)
487 buffers
.set(bound_buffer_
, make_scoped_ptr(new Buffer
).Pass());
489 buffers
.get(bound_buffer_
)->target
= target
;
492 void TestWebGraphicsContext3D::bufferData(WebKit::WGC3Denum target
,
493 WebKit::WGC3Dsizeiptr size
,
495 WebKit::WGC3Denum usage
) {
496 base::AutoLock
lock(namespace_
->lock
);
497 ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
498 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
499 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
501 buffers
.get(bound_buffer_
)->pixels
.reset();
504 buffers
.get(bound_buffer_
)->pixels
.reset(new uint8
[size
]);
506 memcpy(buffers
.get(bound_buffer_
)->pixels
.get(), data
, size
);
509 void* TestWebGraphicsContext3D::mapBufferCHROMIUM(WebKit::WGC3Denum target
,
510 WebKit::WGC3Denum access
) {
511 base::AutoLock
lock(namespace_
->lock
);
512 ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
513 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
514 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
515 if (times_map_buffer_chromium_succeeds_
>= 0) {
516 if (!times_map_buffer_chromium_succeeds_
) {
519 --times_map_buffer_chromium_succeeds_
;
521 return buffers
.get(bound_buffer_
)->pixels
.get();
524 WebKit::WGC3Dboolean
TestWebGraphicsContext3D::unmapBufferCHROMIUM(
525 WebKit::WGC3Denum target
) {
526 base::AutoLock
lock(namespace_
->lock
);
527 ScopedPtrHashMap
<unsigned, Buffer
>& buffers
= namespace_
->buffers
;
528 DCHECK_GT(buffers
.count(bound_buffer_
), 0u);
529 DCHECK_EQ(target
, buffers
.get(bound_buffer_
)->target
);
530 buffers
.get(bound_buffer_
)->pixels
.reset();
534 void TestWebGraphicsContext3D::bindTexImage2DCHROMIUM(
535 WebKit::WGC3Denum target
,
536 WebKit::WGC3Dint image_id
) {
537 base::AutoLock
lock(namespace_
->lock
);
538 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
541 WebKit::WGC3Duint
TestWebGraphicsContext3D::createImageCHROMIUM(
542 WebKit::WGC3Dsizei width
, WebKit::WGC3Dsizei height
,
543 WebKit::WGC3Denum internalformat
) {
544 DCHECK_EQ(GL_RGBA8_OES
, static_cast<int>(internalformat
));
545 WebKit::WGC3Duint image_id
= NextImageId();
546 base::AutoLock
lock(namespace_
->lock
);
547 ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
548 images
.set(image_id
, make_scoped_ptr(new Image
).Pass());
549 images
.get(image_id
)->pixels
.reset(new uint8
[width
* height
* 4]);
553 void TestWebGraphicsContext3D::destroyImageCHROMIUM(
554 WebKit::WGC3Duint id
) {
555 base::AutoLock
lock(namespace_
->lock
);
556 unsigned context_id
= id
>> 17;
557 unsigned image_id
= id
& 0x1ffff;
558 DCHECK(image_id
&& image_id
< namespace_
->next_image_id
);
559 DCHECK_EQ(context_id
, context_id_
);
562 void TestWebGraphicsContext3D::getImageParameterivCHROMIUM(
563 WebKit::WGC3Duint image_id
,
564 WebKit::WGC3Denum pname
,
565 WebKit::WGC3Dint
* params
) {
566 base::AutoLock
lock(namespace_
->lock
);
567 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
568 DCHECK_EQ(GL_IMAGE_ROWBYTES_CHROMIUM
, static_cast<int>(pname
));
572 void* TestWebGraphicsContext3D::mapImageCHROMIUM(WebKit::WGC3Duint image_id
,
573 WebKit::WGC3Denum access
) {
574 base::AutoLock
lock(namespace_
->lock
);
575 ScopedPtrHashMap
<unsigned, Image
>& images
= namespace_
->images
;
576 DCHECK_GT(images
.count(image_id
), 0u);
577 if (times_map_image_chromium_succeeds_
>= 0) {
578 if (!times_map_image_chromium_succeeds_
) {
581 --times_map_image_chromium_succeeds_
;
583 return images
.get(image_id
)->pixels
.get();
586 void TestWebGraphicsContext3D::unmapImageCHROMIUM(
587 WebKit::WGC3Duint image_id
) {
588 base::AutoLock
lock(namespace_
->lock
);
589 DCHECK_GT(namespace_
->images
.count(image_id
), 0u);
592 size_t TestWebGraphicsContext3D::NumTextures() const {
593 base::AutoLock
lock(namespace_
->lock
);
594 return namespace_
->textures
.size();
597 WebKit::WebGLId
TestWebGraphicsContext3D::TextureAt(int i
) const {
598 base::AutoLock
lock(namespace_
->lock
);
599 return namespace_
->textures
[i
];
602 WebGLId
TestWebGraphicsContext3D::NextTextureId() {
603 base::AutoLock
lock(namespace_
->lock
);
604 WebGLId texture_id
= namespace_
->next_texture_id
++;
605 DCHECK(texture_id
< (1 << 16));
606 texture_id
|= context_id_
<< 16;
610 WebGLId
TestWebGraphicsContext3D::NextBufferId() {
611 base::AutoLock
lock(namespace_
->lock
);
612 WebGLId buffer_id
= namespace_
->next_buffer_id
++;
613 DCHECK(buffer_id
< (1 << 17));
614 buffer_id
|= context_id_
<< 17;
618 WebKit::WGC3Duint
TestWebGraphicsContext3D::NextImageId() {
619 base::AutoLock
lock(namespace_
->lock
);
620 WGC3Duint image_id
= namespace_
->next_image_id
++;
621 DCHECK(image_id
< (1 << 17));
622 image_id
|= context_id_
<< 17;
626 TestWebGraphicsContext3D::Buffer::Buffer() : target(0) {}
628 TestWebGraphicsContext3D::Buffer::~Buffer() {}
630 TestWebGraphicsContext3D::Image::Image() {}
632 TestWebGraphicsContext3D::Image::~Image() {}