summaryrefslogtreecommitdiff
path: root/chromium/gpu
diff options
context:
space:
mode:
authorZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
committerZeno Albisser <zeno.albisser@digia.com>2013-08-15 21:46:11 +0200
commit679147eead574d186ebf3069647b4c23e8ccace6 (patch)
treefc247a0ac8ff119f7c8550879ebb6d3dd8d1ff69 /chromium/gpu
downloadqtwebengine-chromium-679147eead574d186ebf3069647b4c23e8ccace6.tar.gz
Initial import.
Diffstat (limited to 'chromium/gpu')
-rw-r--r--chromium/gpu/DEPS12
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt131
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt86
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_depth_texture.txt38
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_enable_feature.txt67
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_flipy.txt118
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt109
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_lose_context.txt55
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_image.txt107
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_sub.txt148
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_request_extension.txt66
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt73
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt3.txt47
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt5.txt47
-rw-r--r--chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_mailbox.txt120
-rw-r--r--chromium/gpu/GLES2/gl2chromium.h25
-rw-r--r--chromium/gpu/GLES2/gl2chromium_autogen.h240
-rw-r--r--chromium/gpu/GLES2/gl2extchromium.h623
-rw-r--r--chromium/gpu/OWNERS2
-rwxr-xr-xchromium/gpu/command_buffer/build_gles2_cmd_buffer.py7814
-rw-r--r--chromium/gpu/command_buffer/client/atomicops.cc99
-rw-r--r--chromium/gpu/command_buffer/client/atomicops.h51
-rw-r--r--chromium/gpu/command_buffer/client/buffer_tracker.cc68
-rw-r--r--chromium/gpu/command_buffer/client/buffer_tracker.h113
-rw-r--r--chromium/gpu/command_buffer/client/buffer_tracker_unittest.cc129
-rw-r--r--chromium/gpu/command_buffer/client/client_context_state.cc25
-rw-r--r--chromium/gpu/command_buffer/client/client_context_state.h39
-rw-r--r--chromium/gpu/command_buffer/client/client_context_state_autogen.h27
-rw-r--r--chromium/gpu/command_buffer/client/client_context_state_impl_autogen.h123
-rw-r--r--chromium/gpu/command_buffer/client/client_test_helper.cc156
-rw-r--r--chromium/gpu/command_buffer/client/client_test_helper.h87
-rw-r--r--chromium/gpu/command_buffer/client/cmd_buffer_helper.cc276
-rw-r--r--chromium/gpu/command_buffer/client/cmd_buffer_helper.h271
-rw-r--r--chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc333
-rw-r--r--chromium/gpu/command_buffer/client/fenced_allocator.cc235
-rw-r--r--chromium/gpu/command_buffer/client/fenced_allocator.h254
-rw-r--r--chromium/gpu/command_buffer/client/fenced_allocator_test.cc578
-rw-r--r--chromium/gpu/command_buffer/client/gl_in_process_context.cc431
-rw-r--r--chromium/gpu/command_buffer/client/gl_in_process_context.h85
-rw-r--r--chromium/gpu/command_buffer/client/gles2_c_lib.cc24
-rw-r--r--chromium/gpu/command_buffer/client/gles2_c_lib_autogen.h1122
-rw-r--r--chromium/gpu/command_buffer/client/gles2_c_lib_export.h29
-rw-r--r--chromium/gpu/command_buffer/client/gles2_cmd_helper.cc21
-rw-r--r--chromium/gpu/command_buffer/client/gles2_cmd_helper.h112
-rw-r--r--chromium/gpu/command_buffer/client/gles2_cmd_helper_autogen.h2114
-rw-r--r--chromium/gpu/command_buffer/client/gles2_impl_export.h29
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation.cc3831
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation.h712
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation_autogen.h555
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation_impl_autogen.h1738
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc2876
-rw-r--r--chromium/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h1853
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface.cc19
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface.h29
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface_autogen.h323
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface_stub.cc24
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface_stub.h29
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface_stub_autogen.h354
-rw-r--r--chromium/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h665
-rw-r--r--chromium/gpu/command_buffer/client/gles2_lib.cc55
-rw-r--r--chromium/gpu/command_buffer/client/gles2_lib.h38
-rw-r--r--chromium/gpu/command_buffer/client/gles2_trace_implementation.cc25
-rw-r--r--chromium/gpu/command_buffer/client/gles2_trace_implementation.h34
-rw-r--r--chromium/gpu/command_buffer/client/gles2_trace_implementation_autogen.h354
-rw-r--r--chromium/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h1233
-rw-r--r--chromium/gpu/command_buffer/client/gpu_memory_buffer_factory.h29
-rw-r--r--chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc60
-rw-r--r--chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.h45
-rw-r--r--chromium/gpu/command_buffer/client/hash_tables.h24
-rw-r--r--chromium/gpu/command_buffer/client/image_factory.h35
-rw-r--r--chromium/gpu/command_buffer/client/mapped_memory.cc110
-rw-r--r--chromium/gpu/command_buffer/client/mapped_memory.h167
-rw-r--r--chromium/gpu/command_buffer/client/mapped_memory_unittest.cc309
-rw-r--r--chromium/gpu/command_buffer/client/program_info_manager.cc523
-rw-r--r--chromium/gpu/command_buffer/client/program_info_manager.h53
-rw-r--r--chromium/gpu/command_buffer/client/program_info_manager_unittest.cc32
-rw-r--r--chromium/gpu/command_buffer/client/query_tracker.cc265
-rw-r--r--chromium/gpu/command_buffer/client/query_tracker.h177
-rw-r--r--chromium/gpu/command_buffer/client/query_tracker_unittest.cc208
-rw-r--r--chromium/gpu/command_buffer/client/ref_counted.h13
-rw-r--r--chromium/gpu/command_buffer/client/ring_buffer.cc121
-rw-r--r--chromium/gpu/command_buffer/client/ring_buffer.h198
-rw-r--r--chromium/gpu/command_buffer/client/ring_buffer_test.cc301
-rw-r--r--chromium/gpu/command_buffer/client/share_group.cc216
-rw-r--r--chromium/gpu/command_buffer/client/share_group.h82
-rw-r--r--chromium/gpu/command_buffer/client/transfer_buffer.cc227
-rw-r--r--chromium/gpu/command_buffer/client/transfer_buffer.h233
-rw-r--r--chromium/gpu/command_buffer/client/transfer_buffer_unittest.cc469
-rw-r--r--chromium/gpu/command_buffer/client/vertex_array_object_manager.cc640
-rw-r--r--chromium/gpu/command_buffer/client/vertex_array_object_manager.h125
-rw-r--r--chromium/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc262
-rw-r--r--chromium/gpu/command_buffer/cmd_buffer_functions.txt222
-rw-r--r--chromium/gpu/command_buffer/command_buffer.gyp29
-rw-r--r--chromium/gpu/command_buffer/command_buffer.gypi37
-rw-r--r--chromium/gpu/command_buffer/command_buffer_untrusted.gyp36
-rw-r--r--chromium/gpu/command_buffer/common/bitfield_helpers.h40
-rw-r--r--chromium/gpu/command_buffer/common/bitfield_helpers_test.cc38
-rw-r--r--chromium/gpu/command_buffer/common/buffer.h31
-rw-r--r--chromium/gpu/command_buffer/common/cmd_buffer_common.cc44
-rw-r--r--chromium/gpu/command_buffer/common/cmd_buffer_common.h529
-rw-r--r--chromium/gpu/command_buffer/common/command_buffer.h150
-rw-r--r--chromium/gpu/command_buffer/common/command_buffer_mock.cc16
-rw-r--r--chromium/gpu/command_buffer/common/command_buffer_mock.h47
-rw-r--r--chromium/gpu/command_buffer/common/command_buffer_shared.h63
-rw-r--r--chromium/gpu/command_buffer/common/command_buffer_shared_test.cc96
-rw-r--r--chromium/gpu/command_buffer/common/compiler_specific.h22
-rw-r--r--chromium/gpu/command_buffer/common/constants.h58
-rw-r--r--chromium/gpu/command_buffer/common/debug_marker_manager.cc51
-rw-r--r--chromium/gpu/command_buffer/common/debug_marker_manager.h62
-rw-r--r--chromium/gpu/command_buffer/common/debug_marker_manager_unittest.cc63
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_format.cc31
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_format.h557
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_format_autogen.h11102
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_format_test.cc58
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h4533
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_ids.h23
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_ids_autogen.h267
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_utils.cc813
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_utils.h200
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_utils_autogen.h69
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h1408
-rw-r--r--chromium/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc293
-rw-r--r--chromium/gpu/command_buffer/common/gles2_utils_export.h29
-rw-r--r--chromium/gpu/command_buffer/common/id_allocator.cc121
-rw-r--r--chromium/gpu/command_buffer/common/id_allocator.h98
-rw-r--r--chromium/gpu/command_buffer/common/id_allocator_test.cc128
-rw-r--r--chromium/gpu/command_buffer/common/logging.cc24
-rw-r--r--chromium/gpu/command_buffer/common/logging.h221
-rw-r--r--chromium/gpu/command_buffer/common/logging_android.cc33
-rw-r--r--chromium/gpu/command_buffer/common/mailbox.cc34
-rw-r--r--chromium/gpu/command_buffer/common/mailbox.h24
-rw-r--r--chromium/gpu/command_buffer/common/thread_local.h59
-rw-r--r--chromium/gpu/command_buffer/common/time.h32
-rw-r--r--chromium/gpu/command_buffer/common/trace_event.h10
-rw-r--r--chromium/gpu/command_buffer/common/types.h186
-rw-r--r--chromium/gpu/command_buffer/common/unittest_main.cc22
-rw-r--r--chromium/gpu/command_buffer/docs/gles2_cmd_format_docs.txt2262
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.cc70
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.h112
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc17
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h39
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager.cc76
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager.h119
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_android.cc66
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc769
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.h57
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc338
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.h63
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_linux.cc40
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mac.cc30
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.cc15
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.h38
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc579
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h59
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.cc88
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.h38
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.cc138
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.h49
-rw-r--r--chromium/gpu/command_buffer/service/async_pixel_transfer_manager_win.cc30
-rw-r--r--chromium/gpu/command_buffer/service/buffer_manager.cc407
-rw-r--r--chromium/gpu/command_buffer/service/buffer_manager.h286
-rw-r--r--chromium/gpu/command_buffer/service/buffer_manager_unittest.cc426
-rw-r--r--chromium/gpu/command_buffer/service/cmd_buffer_engine.h47
-rw-r--r--chromium/gpu/command_buffer/service/cmd_parser.cc107
-rw-r--r--chromium/gpu/command_buffer/service/cmd_parser.h101
-rw-r--r--chromium/gpu/command_buffer/service/cmd_parser_test.cc319
-rw-r--r--chromium/gpu/command_buffer/service/command_buffer_service.cc210
-rw-r--r--chromium/gpu/command_buffer/service/command_buffer_service.h92
-rw-r--r--chromium/gpu/command_buffer/service/command_buffer_service_unittest.cc156
-rw-r--r--chromium/gpu/command_buffer/service/common_decoder.cc292
-rw-r--r--chromium/gpu/command_buffer/service/common_decoder.h175
-rw-r--r--chromium/gpu/command_buffer/service/common_decoder_unittest.cc512
-rw-r--r--chromium/gpu/command_buffer/service/context_group.cc387
-rw-r--r--chromium/gpu/command_buffer/service/context_group.h235
-rw-r--r--chromium/gpu/command_buffer/service/context_group_unittest.cc142
-rw-r--r--chromium/gpu/command_buffer/service/context_state.cc174
-rw-r--r--chromium/gpu/command_buffer/service/context_state.h170
-rw-r--r--chromium/gpu/command_buffer/service/context_state_autogen.h85
-rw-r--r--chromium/gpu/command_buffer/service/context_state_impl_autogen.h814
-rw-r--r--chromium/gpu/command_buffer/service/disk_cache_proto.proto23
-rw-r--r--chromium/gpu/command_buffer/service/error_state.cc183
-rw-r--r--chromium/gpu/command_buffer/service/error_state.h107
-rw-r--r--chromium/gpu/command_buffer/service/error_state_mock.cc17
-rw-r--r--chromium/gpu/command_buffer/service/error_state_mock.h48
-rw-r--r--chromium/gpu/command_buffer/service/feature_info.cc683
-rw-r--r--chromium/gpu/command_buffer/service/feature_info.h128
-rw-r--r--chromium/gpu/command_buffer/service/feature_info_unittest.cc908
-rw-r--r--chromium/gpu/command_buffer/service/framebuffer_manager.cc618
-rw-r--r--chromium/gpu/command_buffer/service/framebuffer_manager.h259
-rw-r--r--chromium/gpu/command_buffer/service/framebuffer_manager_unittest.cc829
-rw-r--r--chromium/gpu/command_buffer/service/gl_context_virtual.cc117
-rw-r--r--chromium/gpu/command_buffer/service/gl_context_virtual.h65
-rw-r--r--chromium/gpu/command_buffer/service/gl_state_restorer_impl.cc39
-rw-r--r--chromium/gpu/command_buffer/service/gl_state_restorer_impl.h39
-rw-r--r--chromium/gpu/command_buffer/service/gl_surface_mock.cc14
-rw-r--r--chromium/gpu/command_buffer/service/gl_surface_mock.h44
-rw-r--r--chromium/gpu/command_buffer/service/gl_utils.h25
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc436
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h64
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc10261
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder.h253
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h3368
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc21
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.h121
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc8670
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h108
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc274
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h1869
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc402
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h1767
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc70
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h81
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc1434
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h558
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_validation.cc21
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_validation.h58
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_validation_autogen.h74
-rw-r--r--chromium/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h675
-rw-r--r--chromium/gpu/command_buffer/service/gpu_scheduler.cc310
-rw-r--r--chromium/gpu/command_buffer/service/gpu_scheduler.h168
-rw-r--r--chromium/gpu/command_buffer/service/gpu_scheduler_mock.h28
-rw-r--r--chromium/gpu/command_buffer/service/gpu_scheduler_unittest.cc218
-rw-r--r--chromium/gpu/command_buffer/service/gpu_switches.cc92
-rw-r--r--chromium/gpu/command_buffer/service/gpu_switches.h39
-rw-r--r--chromium/gpu/command_buffer/service/gpu_tracer.cc347
-rw-r--r--chromium/gpu/command_buffer/service/gpu_tracer.h42
-rw-r--r--chromium/gpu/command_buffer/service/id_manager.cc57
-rw-r--r--chromium/gpu/command_buffer/service/id_manager.h51
-rw-r--r--chromium/gpu/command_buffer/service/id_manager_unittest.cc76
-rw-r--r--chromium/gpu/command_buffer/service/image_manager.cc35
-rw-r--r--chromium/gpu/command_buffer/service/image_manager.h43
-rw-r--r--chromium/gpu/command_buffer/service/in_process_command_buffer.cc756
-rw-r--r--chromium/gpu/command_buffer/service/in_process_command_buffer.h171
-rw-r--r--chromium/gpu/command_buffer/service/logger.cc64
-rw-r--r--chromium/gpu/command_buffer/service/logger.h58
-rw-r--r--chromium/gpu/command_buffer/service/mailbox_manager.cc116
-rw-r--r--chromium/gpu/command_buffer/service/mailbox_manager.h101
-rw-r--r--chromium/gpu/command_buffer/service/mailbox_manager_unittest.cc146
-rw-r--r--chromium/gpu/command_buffer/service/memory_program_cache.cc336
-rw-r--r--chromium/gpu/command_buffer/service/memory_program_cache.h136
-rw-r--r--chromium/gpu/command_buffer/service/memory_program_cache_unittest.cc626
-rw-r--r--chromium/gpu/command_buffer/service/memory_tracking.h112
-rw-r--r--chromium/gpu/command_buffer/service/mocks.cc45
-rw-r--r--chromium/gpu/command_buffer/service/mocks.h143
-rw-r--r--chromium/gpu/command_buffer/service/program_cache.cc136
-rw-r--r--chromium/gpu/command_buffer/service/program_cache.h118
-rw-r--r--chromium/gpu/command_buffer/service/program_cache_unittest.cc201
-rw-r--r--chromium/gpu/command_buffer/service/program_manager.cc1187
-rw-r--r--chromium/gpu/command_buffer/service/program_manager.h398
-rw-r--r--chromium/gpu/command_buffer/service/program_manager_unittest.cc1379
-rw-r--r--chromium/gpu/command_buffer/service/query_manager.cc679
-rw-r--r--chromium/gpu/command_buffer/service/query_manager.h244
-rw-r--r--chromium/gpu/command_buffer/service/query_manager_unittest.cc574
-rw-r--r--chromium/gpu/command_buffer/service/renderbuffer_manager.cc191
-rw-r--r--chromium/gpu/command_buffer/service/renderbuffer_manager.h199
-rw-r--r--chromium/gpu/command_buffer/service/renderbuffer_manager_unittest.cc297
-rw-r--r--chromium/gpu/command_buffer/service/safe_shared_memory_pool.cc149
-rw-r--r--chromium/gpu/command_buffer/service/safe_shared_memory_pool.h82
-rw-r--r--chromium/gpu/command_buffer/service/shader_manager.cc187
-rw-r--r--chromium/gpu/command_buffer/service/shader_manager.h209
-rw-r--r--chromium/gpu/command_buffer/service/shader_manager_unittest.cc252
-rw-r--r--chromium/gpu/command_buffer/service/shader_translator.cc318
-rw-r--r--chromium/gpu/command_buffer/service/shader_translator.h164
-rw-r--r--chromium/gpu/command_buffer/service/shader_translator_cache.cc62
-rw-r--r--chromium/gpu/command_buffer/service/shader_translator_cache.h95
-rw-r--r--chromium/gpu/command_buffer/service/shader_translator_unittest.cc263
-rw-r--r--chromium/gpu/command_buffer/service/stream_texture.h32
-rw-r--r--chromium/gpu/command_buffer/service/stream_texture_manager.h38
-rw-r--r--chromium/gpu/command_buffer/service/stream_texture_manager_mock.cc15
-rw-r--r--chromium/gpu/command_buffer/service/stream_texture_manager_mock.h32
-rw-r--r--chromium/gpu/command_buffer/service/stream_texture_mock.cc15
-rw-r--r--chromium/gpu/command_buffer/service/stream_texture_mock.h28
-rw-r--r--chromium/gpu/command_buffer/service/test_helper.cc553
-rw-r--r--chromium/gpu/command_buffer/service/test_helper.h127
-rw-r--r--chromium/gpu/command_buffer/service/texture_manager.cc1474
-rw-r--r--chromium/gpu/command_buffer/service/texture_manager.h817
-rw-r--r--chromium/gpu/command_buffer/service/texture_manager_unittest.cc2353
-rw-r--r--chromium/gpu/command_buffer/service/transfer_buffer_manager.cc115
-rw-r--r--chromium/gpu/command_buffer/service/transfer_buffer_manager.h55
-rw-r--r--chromium/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc115
-rw-r--r--chromium/gpu/command_buffer/service/vertex_array_manager.cc83
-rw-r--r--chromium/gpu/command_buffer/service/vertex_array_manager.h67
-rw-r--r--chromium/gpu/command_buffer/service/vertex_array_manager_unittest.cc103
-rw-r--r--chromium/gpu/command_buffer/service/vertex_attrib_manager.cc274
-rw-r--r--chromium/gpu/command_buffer/service/vertex_attrib_manager.h296
-rw-r--r--chromium/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc233
-rw-r--r--chromium/gpu/command_buffer_client.gypi32
-rw-r--r--chromium/gpu/command_buffer_common.gypi32
-rw-r--r--chromium/gpu/command_buffer_service.gypi143
-rw-r--r--chromium/gpu/config/DEPS4
-rw-r--r--chromium/gpu/config/OWNERS4
-rw-r--r--chromium/gpu/config/dx_diag_node.cc17
-rw-r--r--chromium/gpu/config/dx_diag_node.h31
-rw-r--r--chromium/gpu/config/gpu_blacklist.cc51
-rw-r--r--chromium/gpu/config/gpu_blacklist.h28
-rw-r--r--chromium/gpu/config/gpu_blacklist_unittest.cc143
-rw-r--r--chromium/gpu/config/gpu_control_list.cc1450
-rw-r--r--chromium/gpu/config/gpu_control_list.h503
-rw-r--r--chromium/gpu/config/gpu_control_list_entry_unittest.cc745
-rw-r--r--chromium/gpu/config/gpu_control_list_jsons.h19
-rw-r--r--chromium/gpu/config/gpu_control_list_machine_model_info_unittest.cc57
-rw-r--r--chromium/gpu/config/gpu_control_list_number_info_unittest.cc210
-rw-r--r--chromium/gpu/config/gpu_control_list_os_info_unittest.cc111
-rw-r--r--chromium/gpu/config/gpu_control_list_string_info_unittest.cc98
-rw-r--r--chromium/gpu/config/gpu_control_list_unittest.cc497
-rw-r--r--chromium/gpu/config/gpu_control_list_version_info_unittest.cc258
-rw-r--r--chromium/gpu/config/gpu_driver_bug_list.cc59
-rw-r--r--chromium/gpu/config/gpu_driver_bug_list.h30
-rw-r--r--chromium/gpu/config/gpu_driver_bug_list_json.cc434
-rw-r--r--chromium/gpu/config/gpu_driver_bug_list_unittest.cc81
-rw-r--r--chromium/gpu/config/gpu_driver_bug_workaround_type.h81
-rw-r--r--chromium/gpu/config/gpu_dx_diagnostics_win.cc135
-rw-r--r--chromium/gpu/config/gpu_feature_type.h32
-rw-r--r--chromium/gpu/config/gpu_info.cc30
-rw-r--r--chromium/gpu/config/gpu_info.h147
-rw-r--r--chromium/gpu/config/gpu_info_collector.cc161
-rw-r--r--chromium/gpu/config/gpu_info_collector.h67
-rw-r--r--chromium/gpu/config/gpu_info_collector_android.cc80
-rw-r--r--chromium/gpu/config/gpu_info_collector_mac.mm220
-rw-r--r--chromium/gpu/config/gpu_info_collector_ozone.cc37
-rw-r--r--chromium/gpu/config/gpu_info_collector_unittest.cc186
-rw-r--r--chromium/gpu/config/gpu_info_collector_win.cc653
-rw-r--r--chromium/gpu/config/gpu_info_collector_x11.cc274
-rw-r--r--chromium/gpu/config/gpu_info_unittest.cc35
-rw-r--r--chromium/gpu/config/gpu_performance_stats.h23
-rw-r--r--chromium/gpu/config/gpu_switching_list.cc29
-rw-r--r--chromium/gpu/config/gpu_switching_list.h29
-rw-r--r--chromium/gpu/config/gpu_switching_list_json.cc125
-rw-r--r--chromium/gpu/config/gpu_switching_list_unittest.cc109
-rw-r--r--chromium/gpu/config/gpu_switching_option.h22
-rw-r--r--chromium/gpu/config/gpu_test_config.cc272
-rw-r--r--chromium/gpu/config/gpu_test_config.h124
-rw-r--r--chromium/gpu/config/gpu_test_config_unittest.cc255
-rw-r--r--chromium/gpu/config/gpu_test_expectations_parser.cc503
-rw-r--r--chromium/gpu/config/gpu_test_expectations_parser.h88
-rw-r--r--chromium/gpu/config/gpu_test_expectations_parser_unittest.cc245
-rw-r--r--chromium/gpu/config/gpu_util.cc82
-rw-r--r--chromium/gpu/config/gpu_util.h38
-rw-r--r--chromium/gpu/config/gpu_util_unittest.cc78
-rw-r--r--chromium/gpu/config/software_rendering_list_json.cc1170
-rw-r--r--chromium/gpu/gles2_cmd_helper.gypi12
-rw-r--r--chromium/gpu/gles2_conform_support/DEPS3
-rw-r--r--chromium/gpu/gles2_conform_support/egl/config.cc152
-rw-r--r--chromium/gpu/gles2_conform_support/egl/config.h92
-rw-r--r--chromium/gpu/gles2_conform_support/egl/display.cc265
-rw-r--r--chromium/gpu/gles2_conform_support/egl/display.h101
-rw-r--r--chromium/gpu/gles2_conform_support/egl/egl.cc404
-rw-r--r--chromium/gpu/gles2_conform_support/egl/surface.cc15
-rw-r--r--chromium/gpu/gles2_conform_support/egl/surface.h29
-rw-r--r--chromium/gpu/gles2_conform_support/gles2_conform_support.c23
-rw-r--r--chromium/gpu/gles2_conform_support/gles2_conform_support.gyp140
-rw-r--r--chromium/gpu/gles2_conform_support/gtf/gtf_stubs.h23
-rw-r--r--chromium/gpu/gles2_conform_support/native/egl_native.cc42
-rw-r--r--chromium/gpu/gles2_conform_support/native/egl_native_aura.cc42
-rw-r--r--chromium/gpu/gles2_conform_support/native/egl_native_gtk.cc63
-rw-r--r--chromium/gpu/gles2_conform_support/native/egl_native_win.cc117
-rw-r--r--chromium/gpu/gles2_conform_support/native/egl_native_windowless.cc45
-rw-r--r--chromium/gpu/gles2_conform_support/native/egl_native_x11.cc74
-rw-r--r--chromium/gpu/gles2_conform_support/native/main.cc41
-rw-r--r--chromium/gpu/gpu.gyp551
-rw-r--r--chromium/gpu/gpu_common.gypi73
-rw-r--r--chromium/gpu/gpu_config.gypi77
-rw-r--r--chromium/gpu/gpu_export.h29
-rw-r--r--chromium/gpu/gpu_ipc.gypi35
-rw-r--r--chromium/gpu/gpu_untrusted.gyp121
-rw-r--r--chromium/gpu/ipc/DEPS4
-rw-r--r--chromium/gpu/ipc/command_buffer_proxy.cc5
-rw-r--r--chromium/gpu/ipc/command_buffer_proxy.h42
-rw-r--r--chromium/gpu/ipc/gpu_command_buffer_traits.cc63
-rw-r--r--chromium/gpu/ipc/gpu_command_buffer_traits.h36
-rw-r--r--chromium/gpu/tools/compositor_model_bench/compositor_model_bench.cc404
-rw-r--r--chromium/gpu/tools/compositor_model_bench/forward_render_model.cc70
-rw-r--r--chromium/gpu/tools/compositor_model_bench/forward_render_model.h34
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT10.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT11.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT12.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT13.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT4.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT5.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT6.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT7.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT8.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT9.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special10.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special11.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special12.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special4.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special5.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special6.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special7.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special8.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special9.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/abra0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/abra1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/abra2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/abra3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/abra4.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/abra5.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_0.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_1.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_2.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_3.txt.json1
-rw-r--r--chromium/gpu/tools/compositor_model_bench/render_model_utils.cc174
-rw-r--r--chromium/gpu/tools/compositor_model_bench/render_model_utils.h62
-rw-r--r--chromium/gpu/tools/compositor_model_bench/render_models.cc41
-rw-r--r--chromium/gpu/tools/compositor_model_bench/render_models.h42
-rw-r--r--chromium/gpu/tools/compositor_model_bench/render_tree.cc483
-rw-r--r--chromium/gpu/tools/compositor_model_bench/render_tree.h211
-rw-r--r--chromium/gpu/tools/compositor_model_bench/shaders.cc450
-rw-r--r--chromium/gpu/tools/compositor_model_bench/shaders.h52
-rw-r--r--chromium/gpu/tools/tools.gyp37
435 files changed, 137123 insertions, 0 deletions
diff --git a/chromium/gpu/DEPS b/chromium/gpu/DEPS
new file mode 100644
index 00000000000..42f86cdd4ea
--- /dev/null
+++ b/chromium/gpu/DEPS
@@ -0,0 +1,12 @@
+include_rules = [
+ "+native_client/src/include",
+ "+third_party/angle_dx11",
+ "+third_party/amd",
+ "+third_party/re2",
+ "+third_party/smhasher",
+ "+third_party/protbuf",
+ "+crypto",
+ "+ui/gfx",
+ "+ui/gl",
+ "+ui/surface",
+]
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt
new file mode 100644
index 00000000000..c6619bb5462
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt
@@ -0,0 +1,131 @@
+Name
+
+ CHROMIUM_bind_uniform_location
+
+Name Strings
+
+ GL_CHROMIUM_bind_uniform_location
+
+Version
+
+ Last Modifed Date: June 20, 2012
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension is simlar to glBindAttribLocation but instead
+ lets you choose a location for a uniform. This allows you
+ to not have to query the locations of uniforms.
+
+ This allows the client program to know the locations of uniforms
+ without having to wait for shaders to compile or GLSL programs to
+ link to query the locations and therefore have no blocking calls
+ when initializing programs.
+
+Issues
+
+ If a uniform is an array you can only call glBindUniformLocation
+ for the location of the first element. Other elements' locations
+ must be queried if you need them. Often this is not an issue
+ because you can set all the elements with a single gl call from
+ the first location.
+
+ Good Example:
+
+ --shader--
+ uniform float u_someArray[4];
+
+ --C--
+ GLint location = 123;
+ glBindUniformLocation(program, location, "u_someArray");
+ glLinkProgram(program);
+ glUseProgram(program);
+
+ // set all 4 floats in u_someArray
+ float values[] = { 0.1f, 0.2f, 0.3f, 0.4f, };
+ glUniform1fv(location, 4, values);
+
+ Bad example 1:
+
+ GLint location = 123;
+ glBindUniformLocation(program, location, "u_someArray");
+ glLinkProgram(program);
+ glUseProgram(program);
+
+ // set floats in u_someArray one at a time
+ glUniform1f(location, 0.1f);
+ glUniform1f(location + 1, 0.2f); // ERROR! math not allowed on locations
+
+ Bad example 2:
+
+ GLint location0 = 123;
+ GLint location1 = 124;
+ glBindUniformLocation(program, location0, "u_someArray[0]");
+ glBindUniformLocation(program, location1, "u_someArray[1]"); // ERROR!
+ // not allowed to assign locations to array elements
+
+ If you need to set individual elements of a uniform array you must query the
+ location of the each element you wish to set.
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ void BindUniformLocationCHROMIUM (GLuint program, GLint location,
+ const GLhchar* name);
+
+ specifes that the uniform variable named <name> in program <program>
+ should be bound to uniform location <location> when the program is next
+ linked. If <name> was bound previously, its assigned binding is replaced
+ with <location>. <name> must be a null terminated string. The error
+ INVALID_VALUE is generated if <location> is equal or greater than
+
+ (MAX_VERTEX_UNIFORM_VECTORS + MAX_FRAGMENT_UNIFORM_VECTORS) * 4
+
+ or less than 0. BindUniformLocation has no effect until the program is
+ linked. In particular, it doesn't modify the bindings of active uniforms
+ variables in a program that has already been linked.
+
+ The error INVALID_OPERATION is generated if name starts with the reserved
+ "gl_" prefix. The error INVALID_VALUE is generated if name ends with
+ an array element expression other than "[0]".
+
+ When a program is linked, any active uniforms without a binding specified
+ through BindUniformLocation will be automatically be bound to locations by
+ the GL. Such bindings can be queried using the command
+ GetUniformLocation.
+
+ BindUniformLocation may be issued before any shader objects are attached
+ to a program object. Hence it is allowed to bind any name (except a name
+ starting with "gl_") to an index, including a name that is never used as a
+ uniform in any shader object. Assigned bindings for uniform variables
+ that do not exist or are not active are ignored.
+
+ It is possible for an application to bind more than one uniform name to
+ the same location. This is referred to as aliasing. This will only work
+ if only one of the aliased uniforms is active in the executable program,
+ or if no path through the shader consumes more than one uniform of a set
+ of uniforms aliased to the same location. A link error can occur if the
+ linker determines that every path through the shader consumes multiple
+ aliased uniforms, but implementations are not required to generate an
+ error in this case. The compiler and linker are allowed to assume that no
+ aliasing is done, and may employ optimizations that work only in the
+ absence of aliasing.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 7/20/2012 Documented the extension
+
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
new file mode 100644
index 00000000000..4cd179fad6e
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_copy_texture.txt
@@ -0,0 +1,86 @@
+Name
+
+ CHROMIUM_copy_texture
+
+Name Strings
+
+ GL_CHROMIUM_copy_texture
+
+Version
+
+ Last Modifed Date: April 1, 2013
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+ CHROMIUM_flipy affects the definition of this extension.
+ EXT_texture_format_BGRA8888 affects the definition of this extension.
+
+Overview
+
+ This extension expands on the functionality provided by the
+ glCopyTexImage2D command. A new function is exported,
+ glCopyTextureCHROMIUM, that performs the same copy operation as
+ glCopyTexImage2D, while respecting the pixel-storage modifiers
+ UNPACK_FLIP_Y_CHROMIUM, GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM and
+ GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM.
+
+ If GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM and
+ GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM are enabled. Then no alpha
+ processing occurs. This is the equivalent of having neither flag set.
+
+ The extension also supports copying BGRA textures and copying
+ EXTERNAL_OES texture to BGRA texture, which is not explicitly
+ granted by EXT_texture_format_BGRA8888.
+
+New Procedures and Functions
+
+ void glCopyTextureCHROMIUM (GLenum target, GLenum source_id,
+ GLenum dest_id, GLint level,
+ GLint internal_format, GLenum dest_type)
+
+ Copies the contents of texture referred to by <source_id> to texture
+ <dest_id>.
+
+ Texture level 0 is copied from the source image to level <level> of the
+ destination texture. The level parameter must be 0 at present.
+
+ The internal format of the destination texture is converted to that
+ specified by <internal_format>.
+
+ The format type of the destination texture is converted to that specified
+ by <dest_type>.
+
+ <target> uses the same parameters as TexImage2D.
+
+ INVALID_VALUE is generated if <target> is not GL_TEXTURE_2D.
+
+ INVALID_VALUE is generated if <source_id> or <dest_id> are not valid texture
+ objects.
+
+ INVALID_VALUE is generated if textures corresponding to <dest_id> have not
+ been bound as GL_TEXTURE_2D object.
+
+ INVALID_VALUE is generated if textures corresponding to <source_id> have not
+ been bound as GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES objects.
+
+ INVALID_VALUE is generated if <level> is not a valid level of the
+ destination texture, or if level 0 of the source texture is not defined.
+
+Errors
+
+ None.
+
+New Tokens
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 8/1/2011 Documented the extension
+ 7/4/2013 Add a new parameter dest_type to glCopyTextureCHROMIUM()
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_depth_texture.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_depth_texture.txt
new file mode 100644
index 00000000000..b7cc380215f
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_depth_texture.txt
@@ -0,0 +1,38 @@
+Name
+
+ CHROMIUM_depth_texture
+
+Name Strings
+
+ GL_CHROMIUM_depth_texture
+
+Status
+
+ DRAFT.
+
+Version
+
+ Last Modifed Date: June 4, 2012
+ Revision: #1
+
+Number
+
+ TBD
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+ This extension is written against the OpenGL ES 2.0.25 specification
+
+ ANGLE_depth_texture.
+
+Overview
+
+ This extension is the same as ANGLE_depth_texture except it does
+ not add support for TexStorageEXT.
+
+New Procedures and Functions
+
+ None
+
+
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_enable_feature.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_enable_feature.txt
new file mode 100644
index 00000000000..100cf0c541d
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_enable_feature.txt
@@ -0,0 +1,67 @@
+Name
+
+ CHROMIUM_enable_feature
+
+Name Strings
+
+ GL_CHROMIUM_enable_feature
+
+Version
+
+ Last Modifed Date: August 11, 2011
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension allows certain optional features to be turned on in
+ the Chromium OpenGL ES 2.0 implementation.
+
+Issues
+
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ CommandBufferEnableCHROMIUM(const GLchar *feature)
+
+ <feature> is a null terminated string of the feature you wish to enable.
+ The requestable feature strings are as follows:
+
+ Note: If used this function MUST be called before any other GL commands
+ except GetString. Calling any other functions first will result in
+ undefined behavior.
+
+ pepper3d_allow_buffers_on_mulitple_targets
+
+ OpenGL ES 2.0 allows a single buffer to be bound to both the ARRAY_BUFFER
+ and ELEMENT_ARRAY_BUFFER bind points. By default Chromium does not allow
+ this.
+
+ This feature is only provided for full OpenGL ES 2.0 compatibility. It is
+ expensive to use and should generally be avoided.
+
+ pepper3d_support_fixed_attribs
+
+ Turns on support for the type GL_FIXED. By default this feature is off in
+ Chromium.
+
+ This feature is only provided for full OpenGL ES 2.0 compatibility. It is
+ expensive to use and should generally be avoided.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 8/11/2011 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_flipy.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_flipy.txt
new file mode 100644
index 00000000000..7511fc432a3
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_flipy.txt
@@ -0,0 +1,118 @@
+Name
+
+ CHROMIUM_flipy
+
+Name Strings
+
+ GL_CHROMIUM_flipy
+
+Version
+
+ Last Modifed Date: April 9, 2012
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension adds the ability to vertically flip texture image data when
+ calling TexImage2D and TexSubImage2D.
+
+Issues
+
+
+New Tokens
+
+ Accepted by the <param> parameter of PixelStorei:
+
+ UNPACK_FLIP_Y_CHROMIUM 0x9240
+
+Additions to the OpenGL ES 2.0 Specification
+
+ Modifications to Table 3.1 (PixelStore Parameters)
+
+ Add the following entry:
+
+ Parameter Name Type Initial Value Valid Range
+ ============== ==== ============= ===========
+ UNPACK_FLIP_Y_CHROMIUM boolean FALSE {TRUE, FALSE}
+
+ Modifications to 3.6.2 Transfer of Pixel Rectangles, in the Unpacking
+ section:
+
+ Change
+ "If p indicates the location in memory of the first element of the first
+ row, then the first element of the Nth row is indicated by
+ p + Nk (3.9)"
+ to
+ "If p indicates the location in memory of the first element of the first
+ row, then the first element of the Nth row is indicated by
+ p + Nk (3.9)
+ if UNPACK_FLIP_Y is FALSE. Otherwise, the first element of the Nth row
+ is indicated by
+ p - Nk (3.10)
+
+ After the sentence
+
+ "If the number of bits per element is not 1, 2, 4, or 8 times the number
+ of bits in a GL ubyte, then k = nl for all values of a."
+
+ insert:
+
+ "If UNPACK_FLIP_Y_CHROMIUM is FALSE then p is equal to pixels. Otherwise
+ p is pixels + (height - 1)k."
+
+Interactions with GL_EXT_unpack_subimage
+
+ Do not add the sentence "If UNPACK_FLIP_Y_CHROMIUM is FALSE ..." described
+ in this extension. Instead do the following after applying
+ GL_EXT_unpack_subimage:
+
+ Change
+
+ "There is a mechanism for selecting a sub-rectangle of groups
+ from a larger containing rectangle. This mechanism relies on
+ three integer parameters: UNPACK_ROW_LENGTH, UNPACK_SKIP_ROWS,
+ and UNPACK_SKIP_PIXELS. Before obtaining the first group from
+ memory, the pointer supplied to TexImage2D is effectively
+ advanced by (UNPACK_SKIP_PIXELS)n + (UNPACK_SKIP_ROWS)k
+ elements. Then <width> groups are obtained from contiguous
+ elements in memory (without advancing the pointer), after
+ which the pointer is advanced by k elements. <height> sets of
+ <width> groups of values are obtained this way. See figure
+ 3.6."
+
+ to
+
+ "There is a mechanism for selecting a sub-rectangle of groups
+ from a larger containing rectangle. This mechanism relies on
+ three integer parameters: UNPACK_ROW_LENGTH, UNPACK_SKIP_ROWS,
+ and UNPACK_SKIP_PIXELS. IF UNPACK_FLIP_Y_CHROMIUM is FALSE then
+ p, the location of the first element of the first
+ group, is pixels + (UNPACK_SKIP_PIXELS)n + (UNPACK_SKIP_ROWS)k.
+ When UNPACK_FLIP_Y_CHROMIUM is TRUE then p is pixels +
+ (UNPACK_SKIP_PIXELS)n + (UNPACK_SKIP_ROWS + height - 1)k. After
+ p is determined <width> groups are obtained from contiguous
+ elements in memory (without advancing the pointer), after which
+ the pointer is advanced by +/-k elements depending on the value
+ of UNPACK_CHROMIUM_FLIP_Y. <height> sets of <width> groups of
+ values are obtained this way. See figure 3.6."
+
+New Procedures and Functions
+
+ None.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 7/22/2011 Documented the extension
+ 4/09/2012 Added more documentation and described interactions with
+ GL_EXT_unpack_subimage
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
new file mode 100644
index 00000000000..0a357007e8b
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
@@ -0,0 +1,109 @@
+Name
+
+ CHROMIUM_get_multiple
+
+Name Strings
+
+ GL_CHROMIUM_get_multiple
+
+Version
+
+ Last Modifed Date: July 22, 2011
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension adds the ability to query multiple state and program
+ information in a single call.
+
+Issues
+
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ void GetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count,
+ GLint* results, GLsizeiptr size)
+
+ <pnames> points to an array of state enums that would normally be queried by
+ GetIntegerv. <count> is the number of pnames. <results> points memory large
+ enough to contain all the state being queried. <size> is the size of the
+ buffer pointed to be <results>
+
+ Example: <pnames> points to an array with VIEWPORT and MAX_TEXTURE_SIZE.
+ VIEWPORT returns 4 values, MAX_TEXTURE_SIZE returns 1 value. Therefore
+ results must point to a buffer of size 5 * sizeof(GLint) and size must be at
+ least 5 * sizeof(GLint)
+
+ INVALID_ENUM is generated if any of the pnames are not valid for GetIntegerv
+
+ INVALID_VALUE is generated if <size> does not equal the size needed for the
+ query
+
+ INVALID_VALUE is generated if the memory pointed to be <results> has not
+ been zeroed out.
+
+ void GetProgrmaInfoCHROMIUM (GLuint program, GLsizei bufsize,
+ GLsizei* size, void* info)
+
+ <program> is the program to query. <bufsize> is the size of the buffer to
+ hold the results. <size> is a pointer to a GLsizei to store the size needed
+ to hold the results. <info> is a pointer to memory to store the result.
+
+ To query the space needed for the results set <info> to NULL.
+
+ The format of the data that will be stored in the memory pointed to by
+ <info> is as follows.
+
+ struct ProgramInfoHeader {
+ uint32 link_status; // same as GetProgramiv called with LINK_STATUS
+ uint32 num_attribs; // the number of active attributes
+ uint32 num_uniforms; // the number of active uniforms
+ ProgramInput inputs[num_attribs + num_uniforms];
+ }
+
+ // The data for one attrib or uniform from GetProgramInfoCHROMIUM.
+ struct ProgramInput {
+ uint32 type; // The type (GL_VEC3, GL_SAMPLER_2D, etc.
+ int32 size; // The size (size of array for uniforms)
+ uint32 location_offset; // offset from ProgramInfoHeader to 'size'
+ // locations for uniforms, 1 for attribs.
+ uint32 name_offset; // offset from ProgrmaInfoHeader to start of
+ // name.
+ uint32 name_length; // length of the name.
+ };
+
+ It is important to note that for attribs, size is the size of the attrib and
+ location_offset points to a single location. For uniforms, size is the
+ number of array elements and location_offset points to an array of size
+ locations, one of each element of the array.
+
+ INVALID_VALUE is generated if <bufsize> is less than 0
+
+ INVALID_VALUE is generated if <size> is NULL
+
+ INVALID_OPERATION is returned if <size> is less than the size needed to hold
+ all the results.
+
+
+ NOTE: This function is not intended to be used directly. Chromium uses it
+ internally to cache data.
+
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 7/22/2011 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_lose_context.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_lose_context.txt
new file mode 100644
index 00000000000..a7ff30ceb6d
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_lose_context.txt
@@ -0,0 +1,55 @@
+Name
+
+ CHROMIUM_lose_context
+
+Name Strings
+
+ GL_CHROMIUM_lose_context
+
+Version
+
+ Last Modifed Date: December 17, 2012
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension allows an application to force a lost context event.
+ This is useful for debugging that an app can correctly handle the context
+ becoming lost.
+
+Issues
+
+ None
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ void LoseContextCHROMIUM (GLenum current, GLenum other)
+
+ Causes the current context and all other contexts in the same share group
+ to become lost. <current> and <other> can each be one of:
+
+ GL_GUILTY_CONTEXT_RESET_EXT
+ GL_INNOCENT_CONTEXT_RESET_EXT
+ GL_UNKNOWN_CONTEXT_RESET_EXT
+
+ INVALID_ENUM is generated if <current> or <other> is not one of the values
+ mentioned above.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 12/17/2012 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_image.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_image.txt
new file mode 100644
index 00000000000..6304fdace0f
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_image.txt
@@ -0,0 +1,107 @@
+Name
+
+ CHROMIUM_map_image
+
+Name Strings
+
+ GL_CHROMIUM_map_image
+
+Version
+
+ Last Modifed Date: May 9, 2013
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension allows for more efficient uploading of texture data through
+ Chromium's OpenGL ES 2.0 implementation.
+
+ For security reasons Chromium accesses the GPU from a separate process. User
+ processes are not allowed to access the GPU directly. This multi-process
+ architechure has the advantage that GPU operations can be secured and
+ pipelined but it has the disadvantage that all data that is going to be
+ passed to GPU must first be made available to the separate GPU process.
+
+ This extension helps the application directly allocate and access texture
+ memory.
+
+Issues
+
+ None
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ GLuint CreateImageCHROMIUM (GLsizei width, GLsizei height,
+ GLenum internalformat)
+
+ Allocate an image with width equal to <width> and height equal
+ to <height> stored in format <internalformat>.
+
+ Returns a unique identifier for the allocated image that could be used
+ in subsequent operations.
+
+ INVALID_VALUE is generated if <width> or <height> is nonpositive.
+
+ void DestroyImageCHROMIUM (GLuint image_id)
+
+ Frees the image previously allocated by a call to CreateImageCHROMIUM.
+
+ INVALID_OPERATION is generated if <image_id> is not a valid image id.
+
+ void* MapImageCHROMIUM (GLuint image_id, GLenum access)
+
+ Returns a pointer to in the user memory for the application to modify
+ the image. <access> parameter defines if the user will read or write the
+ pixels.
+
+ INVALID_OPERATION is generated if <image_id> is not a valid image id.
+
+ INVALID_OPERATION is generated if the image was already mapped by a previous
+ call to this method.
+
+ INVALID_ENUM is generated if <access> is not one of WRITE_ONLY, READ_ONLY
+ and READ_WRITE.
+
+ void UnmapImageCHROMIUM (GLuint image_id)
+
+ Removes the mapping created by a call to MapImageCHROMIUM.
+
+ Note that after calling UnmapImageCHROMIUM the application should assume
+ that the memory returned by MapImageCHROMIUM is off limits and is no longer
+ accessible by the application. Accessing it after calling
+ UnmapImageCHROMIUM will produce undefined results.
+
+ INVALID_OPERATION is generated if <image_id> is not a valid image id.
+
+ INVALID_OPERATION is generated if the image was not already mapped by a
+ previous call to MapImageCHROMIUM.
+
+ void GetImageParameterivCHROMIUM(GLuint image_id, GLenum pname,
+ GLint* params)
+
+ Sets <params> to the integer value of the parameter specified by <pname>
+ for the image specified by <image_id>. <params> is expected to be
+ properly allocated before calling this method.
+
+ INVALID_OPERATION is generated if <image_id> is not a valid image id.
+
+ INVALID_ENUM is generated if <pname> is not IMAGE_ROWBYTES_CHROMIUM.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 5/9/2013 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_sub.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_sub.txt
new file mode 100644
index 00000000000..5638f3016ae
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_map_sub.txt
@@ -0,0 +1,148 @@
+Name
+
+ CHROMIUM_map_sub
+
+Name Strings
+
+ GL_CHROMIUM_map_sub
+
+Version
+
+ Last Modifed Date: July 22, 2011
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension allows for more efficiently uploading of buffer or texture
+ data through Chromium's OpenGL ES 2.0 implementation.
+
+ For security reasons Chromium accesses the GPU from a separate process. User
+ processes are not allowed to access the GPU directly. This multi-process
+ architechure has the advantage that GPU operations can be secured and
+ pipelined but it has the disadvantage that all data that is going to be
+ passed to GPU must first be made available to the separate GPU process.
+
+ Chromium's OpenGL ES 2.0 implementation hides this issue when using the
+ standard OpenGL functions BufferData, BufferSubData, TexImage2D, and
+ TexSubImage2D by first copying the user's data to shared memory and then
+ telling the GPU process to use that shared memory to upload the data.
+
+ This extension helps avoid that extra copy from user memory to shared memory
+ in a safe and secure manner.
+
+Issues
+
+ This extension was designed for only 2 common use cases.
+
+ #1) Dynamic textures. A good example would be a video player that needs to
+ upload video into a texture.
+
+ #2) CPU based skinning.
+
+ The common feature of these 2 use cases is the size of the texture in the
+ first case and the size of the buffer in the second case do not change
+ often. The implemenation of this extension is currently designed to never
+ free shared memory and re-use previously allocated shared memory that is no
+ longer in use.
+
+ This design fits the 2 use cases above but it does not fit uploading lots of
+ arbitrarily sized pieces of data and so, at least in it's current
+ implemenation it should really be only used for cases similar to those
+ described above.
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ void* MapBufferSubDataCHROMIUM (GLuint target, GLintptr offset,
+ GLsizeiptr size, GLenum access)
+
+ Returns a pointer to shared memory of the requested <size> or NULL if the
+ request can not be honoured.
+
+ <target>, <offset> and <size> use the exact same parameters as
+ BufferSubData. <access> must be WRITE_ONLY.
+
+ INVALID_ENUM is generated if <access> is not WRITE_ONLY
+
+ INVALID_VALUE is generated if <offset> or <size> is negative
+
+ void UnmapBufferSubDataCHROMIUM (const void* mem)
+
+ Calling this function effectively calls BufferSubData with the parameters
+ that were specified when originally calling MapBufferSubData. Note that
+ after calling UnmapBufferSubDataCHROMIUM the application should assume that
+ the memory pointed do by <mem> is off limits and is no longer writable by
+ the application. Writing to it after calling UnmapBufferSubDataCHROMIUM will
+ produce undefined results. No security issues exist because of this but
+ which data makes it to the GPU will be unknown from the point of view of
+ the user program.
+
+ <mem> is a pointer previously returned by calling MapBufferSubData and not
+ yet unmapped.
+
+ INVALID_VALUE is generated if <mem> is not a value previously returned by
+ MapBufferSubData or if it has already been passed to
+ UnmapBufferSubDataCHROMIUM.
+
+ Other errors are the same errors that would be returned by BufferSubData.
+
+ void* MapTexSubImage2DCHROMIUM (GLenum target, GLint level,
+ GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height,
+ GLenum format, GLenum type, GLenum access)
+
+ Returns a pointer to shared memory that matches the image rectangle
+ described by <width>, <height>, <format>, <type> and the current PixelStorei
+ UNPACK_ALIGNMENT setting or NULL if the request can not be honoured.
+
+ So for example, a width 3, height 4, format RGB, type UNSIGNED_BYTE,
+ UNPACK_ALIGNMENT 4 would return a pointer to a piece of memory 45 bytes
+ in size. Width 3 at RGB is 9 bytes. Padded to an UNPACK_ALIGNMENT of 4 means
+ 12 bytes per row. The last row is not padded.
+
+ <target>, <level>, <xoffset>, <yoffset>, <width>, <height>, <format>, and
+ <type> use the exact same parameters as TexSubImage2D. <access> must be
+ WRITE_ONLY.
+
+ INVALID_ENUM is generated if <access> is not WRITE_ONLY
+
+ INVALID_VALUE is generated if <xoffset>, <yoffset>, <width>, <height> or
+ <level> is negative
+
+ void UnmapTexSubImage2DCHROMIUM (const void* mem)
+
+ Calling this function effectively calls TexSubImage2D with the parameters
+ that were specified when originally calling MapTexSubImage2D. Note that
+ after calling UnmapTexSubImage2DCHROMIUM the application should assume that
+ the memory pointed do by <mem> is off limits and is no longer writable by
+ the application. Writing to it after calling UnmapTexSubImage2DCHROMIUM will
+ produce undefined results. No security issues exist because of this but
+ which data makes it to the GPU will be unknown from the point of view of the
+ user program.
+
+ <mem> is a pointer previously returned by calling MapTexSubImage2D and not
+ yet unmapped.
+
+ INVALID_VALUE is generated if <mem> is not a value previously returned by
+ MapTexSubImage2D or if it has already been passed to
+ UnmapTexSubImage2DCHROMIUM.
+
+ Other errors are the same errors that would be returned by TexSubImage2D.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 7/22/2011 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_request_extension.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_request_extension.txt
new file mode 100644
index 00000000000..cbc2aa4ebf5
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_request_extension.txt
@@ -0,0 +1,66 @@
+Name
+
+ CHROMIUM_request_extension
+
+Name Strings
+
+ GL_CHROMIUM_request_extension
+
+Version
+
+ Last Modifed Date: July 22, 2011
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension is for WebGL only. In some implemenations of OpenGL ES 2.0,
+ in particular the Chromium implementation, it is possible to create an
+ OpenGL context and request that most extensions be disabled. From that
+ point, this extension allows extensions to then be selectively enabled.
+
+ WebGL requires the base OpenGL ES 2.0 with NO extensions. So for example,
+ if an OpenGL ES 2.0 implemention exposed the extension OES_texture_npot, the
+ WebGL implementation would have to make it appear as though that extension
+ does not exist. For Chromium WebGL OpenGL contexts, Chromium requests a
+ context with no extensions. It then queries which extensions exist. If
+ OES_texture_npot does NOT exist then WebGL can decide to not do the extra
+ work required to emulate it not existing.
+
+ Subsequently, if the user calls
+ WebGLRenderingContext.getExtension("WEBGL_texture_npot"), assuming such an
+ extension exists, the WebGL implementation can call this extension to turn
+ on OES_texture_npot. After calling RequestExtensionCHROMIUM you must call
+ GetString(GL_EXTENSIONS) in order to find out if the extension was actually
+ enabled.
+
+ Note: This extension really has no meaning outside of WebGL. By default, all
+ supported extensions are enabled.
+
+Issues
+
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ RequestExtensionCHROMIUM(const GLchar *extension)
+
+ <extension> is a null terminated string of the extension you wish to enable.
+ For example "OES_texture_npot".
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 7/22/2011 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt
new file mode 100644
index 00000000000..bc8665a3064
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_point.txt
@@ -0,0 +1,73 @@
+Name
+
+ CHROMIUM_sync_point
+
+Name Strings
+
+ GL_CHROMIUM_sync_point
+
+Version
+
+ Last Modifed Date: February 25, 2013
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension allows a client to order operations between contexts.
+
+ This extension implements a small subset of ARB_sync, with weaker
+ guarantees. In particular it doesn't ensure commands are actually executed
+ by the server, it only guarantees submission order.
+
+ It does however guarantee operation order with respect to
+ ConsumeTextureCHROMIUM and ProduceTextureCHROMIUM from
+ CHROMIUM_texture_mailbox, if present.
+
+Issues
+
+ None
+
+New Tokens
+
+ None
+
+New Procedures and Functions
+
+ The command
+
+ uint InsertSyncPointCHROMIUM()
+
+ creates a sync point and inserts it into the stream of commands for the
+ current context. The sync point acts as a fence, which is signaled when
+ previous commands have been submitted to the server, or when the context is
+ destroyed, whichever happens first. The sync point name is returned. The
+ sync point is implicitly deleted when it becomes signaled. The sync point
+ namespace is shared between all contexts on the same server, including other
+ context groups.
+
+
+ The command
+
+ void WaitSyncPointCHROMIUM(uint sync_point)
+
+ causes the current context to stop submitting commands until the specified
+ sync point becomes signaled. This is implemented as a server-side wait.
+ <sync_point> is the name of the sync point to wait for. If <sync_point>
+ isn't a valid sync point returned by InsertSyncPointCHROMIUM, or if the sync
+ point has already been deleted, the command is equivalent to a no-op and no
+ error is generated.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 2/25/2013 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt3.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt3.txt
new file mode 100644
index 00000000000..377b064eea4
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt3.txt
@@ -0,0 +1,47 @@
+Name
+
+ CHROMIUM_texture_compression_dxt3
+
+Name Strings
+
+ GL_CHROMIUM_texture_compression_dxt3
+
+Version
+
+ Last Modifed Date: August 1, 2011
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extensions is pretty much the same as EXT_texture_compression_dxt1
+ except it supports dxt3.
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted by the <internalformat> parameter of CompressedTexImage2D
+ and the <format> parameter of CompressedTexSubImage2D:
+
+ COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+
+New Procedures and Functions
+
+ None.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 8/1/2011 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt5.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt5.txt
new file mode 100644
index 00000000000..b89423540dd
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_compression_dxt5.txt
@@ -0,0 +1,47 @@
+Name
+
+ CHROMIUM_texture_compression_dxt5
+
+Name Strings
+
+ GL_CHROMIUM_texture_compression_dxt5
+
+Version
+
+ Last Modifed Date: August 1, 2011
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extensions is pretty much the same as EXT_texture_compression_dxt1
+ except it supports dxt5.
+
+New Procedures and Functions
+
+ None
+
+New Tokens
+
+ Accepted by the <internalformat> parameter of CompressedTexImage2D
+ and the <format> parameter of CompressedTexSubImage2D:
+
+ COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+
+New Procedures and Functions
+
+ None.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 8/1/2011 Documented the extension
diff --git a/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_mailbox.txt b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_mailbox.txt
new file mode 100644
index 00000000000..f3c476bdc5a
--- /dev/null
+++ b/chromium/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_texture_mailbox.txt
@@ -0,0 +1,120 @@
+Name
+
+ CHROMIUM_texture_mailbox
+
+Name Strings
+
+ GL_CHROMIUM_texture_mailbox
+
+Version
+
+ Last Modifed Date: April 25, 2012
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ This extension defines a way of sharing texture image data between texture
+ objects in different contexts where the contexts would not normally share
+ texture resources. Three new functions are exported. glGenMailboxCHROMIUM
+ generates a name that can be used to identify texture image data outside
+ the scope of a context group. glProduceMailboxCHROMIUM associates a texture
+ object with a global mailbox name. glConsumeMailboxCHROMIUM associates the
+ texture object referenced by a mailbox name to a texture name.
+
+New Procedures and Functions
+
+ void glGenMailboxCHROMIUM (GLbyte *mailbox)
+
+ Generates a unique name identifying a mailbox. The name is generated using
+ a cryptographic random number generator and is intended to be difficult to
+ guess. The scope of the name is implementation specific, for example it
+ might not span multiple displays.
+
+ <mailbox> returns a GL_MAILBOX_SIZE_CHROMIUM byte sized name
+
+
+ void glProduceTextureCHROMIUM (GLenum target, const GLbyte *mailbox)
+
+ Associates the currently bound texture object with the mailbox name. A
+ given texture object can be associated with several mailbox names. If a
+ mailbox name was previously associated with a texture object, that
+ previous association is broken. The currently bound texture object is not
+ modified by the operation.
+
+ If glProduceTextureCHROMIUM generates an error, the mailbox name keeps its
+ current association, if any.
+
+ The mailbox does not keep a reference to the texture object. When the
+ texture object is destroyed (deleted from all context groups, and unbound
+ from all texture units and framebuffer attachments), the mailbox is
+ disassociated from the texture object.
+
+ <target> uses the same parameters as TexImage2D.
+
+ <mailbox> identifies a GL_MAILBOX_SIZE_CHROMIUM byte sized name returned by
+ glGenMailboxCHROMIUM.
+
+ INVALID_OPERATION is generated if <target> is not a valid target.
+
+ INVALID_OPERATION is generated if <mailbox> is invalid.
+
+
+ void glConsumeTextureCHROMIUM (GLenum target, const GLbyte *mailbox)
+
+ <target> uses the same parameters as TexImage2D.
+
+ <mailbox> identifies a GL_MAILBOX_SIZE_CHROMIUM byte sized name returned by
+ glGenMailboxCHROMIUM.
+
+ Deletes the currently bound texture object, and redefines its texture name
+ to point to the texture object associated with the mailbox name. All the
+ contexts that have consumed the texture object, as well as produced it share
+ the texture object, as if the contexts were part of the share group. The
+ texture object is deleted once all contexts have deleted the texture name
+ associated with the texture object, and detached it from all framebuffer
+ objects as well as texture unit bindings. See Appendix C of the OpenGL ES
+ 2.0 specification for details relative to visibility in one context of
+ changes to the shared texture object in another context.
+
+ If glConsumeTextureCHROMIUM generates an error, the currently bound texture
+ object is preserved.
+
+ INVALID_OPERATION is generated if <target> is not a valid target.
+
+ INVALID_OPERATION is generated if <mailbox> is invalid.
+
+ INVALID_OPERATION is generated if <mailbox> is not associated with a texture
+ object.
+
+ INVALID_OPERATION is generated if the texture object associated with
+ <mailbox> has a different target than <target>.
+
+ INVALID_OPERATION is generated if the currently bound texture was previously
+ deleted (for example in another context), hence doesn't have a name.
+
+New Tokens
+
+ The size of a mailbox name in bytes.
+
+ GL_MAILBOX_SIZE_CHROMIUM 64
+
+Errors
+
+ None.
+
+New Tokens
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 4/25/2011 Documented the extension
+ 5/23/2013 Major revision in Produce/Consume semantics, introducing
+ sharing.
diff --git a/chromium/gpu/GLES2/gl2chromium.h b/chromium/gpu/GLES2/gl2chromium.h
new file mode 100644
index 00000000000..3b429049c2d
--- /dev/null
+++ b/chromium/gpu/GLES2/gl2chromium.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains Chromium-specific GLES2 declarations.
+
+#ifndef GPU_GLES2_GL2CHROMIUM_H_
+#define GPU_GLES2_GL2CHROMIUM_H_
+
+#include <GLES2/gl2platform.h>
+
+#define GL_CONTEXT_LOST 0x300E
+
+// Because we are using both the real system GL and our own
+// emulated GL we need to use different names to avoid conflicts.
+#if defined(GLES2_USE_CPP_BINDINGS)
+#define GLES2_GET_FUN(name) gles2::GetGLContext()->name
+#else
+#define GLES2_GET_FUN(name) GLES2 ## name
+#endif
+
+#include <GLES2/gl2chromium_autogen.h>
+
+#endif // GPU_GLES2_GL2CHROMIUM_H_
+
diff --git a/chromium/gpu/GLES2/gl2chromium_autogen.h b/chromium/gpu/GLES2/gl2chromium_autogen.h
new file mode 100644
index 00000000000..e2e1c1f1822
--- /dev/null
+++ b/chromium/gpu/GLES2/gl2chromium_autogen.h
@@ -0,0 +1,240 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file contains Chromium-specific GLES2 declarations.
+
+#ifndef GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
+#define GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
+
+#define glActiveTexture GLES2_GET_FUN(ActiveTexture)
+#define glAttachShader GLES2_GET_FUN(AttachShader)
+#define glBindAttribLocation GLES2_GET_FUN(BindAttribLocation)
+#define glBindBuffer GLES2_GET_FUN(BindBuffer)
+#define glBindFramebuffer GLES2_GET_FUN(BindFramebuffer)
+#define glBindRenderbuffer GLES2_GET_FUN(BindRenderbuffer)
+#define glBindTexture GLES2_GET_FUN(BindTexture)
+#define glBlendColor GLES2_GET_FUN(BlendColor)
+#define glBlendEquation GLES2_GET_FUN(BlendEquation)
+#define glBlendEquationSeparate GLES2_GET_FUN(BlendEquationSeparate)
+#define glBlendFunc GLES2_GET_FUN(BlendFunc)
+#define glBlendFuncSeparate GLES2_GET_FUN(BlendFuncSeparate)
+#define glBufferData GLES2_GET_FUN(BufferData)
+#define glBufferSubData GLES2_GET_FUN(BufferSubData)
+#define glCheckFramebufferStatus GLES2_GET_FUN(CheckFramebufferStatus)
+#define glClear GLES2_GET_FUN(Clear)
+#define glClearColor GLES2_GET_FUN(ClearColor)
+#define glClearDepthf GLES2_GET_FUN(ClearDepthf)
+#define glClearStencil GLES2_GET_FUN(ClearStencil)
+#define glColorMask GLES2_GET_FUN(ColorMask)
+#define glCompileShader GLES2_GET_FUN(CompileShader)
+#define glCompressedTexImage2D GLES2_GET_FUN(CompressedTexImage2D)
+#define glCompressedTexSubImage2D GLES2_GET_FUN(CompressedTexSubImage2D)
+#define glCopyTexImage2D GLES2_GET_FUN(CopyTexImage2D)
+#define glCopyTexSubImage2D GLES2_GET_FUN(CopyTexSubImage2D)
+#define glCreateProgram GLES2_GET_FUN(CreateProgram)
+#define glCreateShader GLES2_GET_FUN(CreateShader)
+#define glCullFace GLES2_GET_FUN(CullFace)
+#define glDeleteBuffers GLES2_GET_FUN(DeleteBuffers)
+#define glDeleteFramebuffers GLES2_GET_FUN(DeleteFramebuffers)
+#define glDeleteProgram GLES2_GET_FUN(DeleteProgram)
+#define glDeleteRenderbuffers GLES2_GET_FUN(DeleteRenderbuffers)
+#define glDeleteShader GLES2_GET_FUN(DeleteShader)
+#define glDeleteTextures GLES2_GET_FUN(DeleteTextures)
+#define glDepthFunc GLES2_GET_FUN(DepthFunc)
+#define glDepthMask GLES2_GET_FUN(DepthMask)
+#define glDepthRangef GLES2_GET_FUN(DepthRangef)
+#define glDetachShader GLES2_GET_FUN(DetachShader)
+#define glDisable GLES2_GET_FUN(Disable)
+#define glDisableVertexAttribArray GLES2_GET_FUN(DisableVertexAttribArray)
+#define glDrawArrays GLES2_GET_FUN(DrawArrays)
+#define glDrawElements GLES2_GET_FUN(DrawElements)
+#define glEnable GLES2_GET_FUN(Enable)
+#define glEnableVertexAttribArray GLES2_GET_FUN(EnableVertexAttribArray)
+#define glFinish GLES2_GET_FUN(Finish)
+#define glFlush GLES2_GET_FUN(Flush)
+#define glFramebufferRenderbuffer GLES2_GET_FUN(FramebufferRenderbuffer)
+#define glFramebufferTexture2D GLES2_GET_FUN(FramebufferTexture2D)
+#define glFrontFace GLES2_GET_FUN(FrontFace)
+#define glGenBuffers GLES2_GET_FUN(GenBuffers)
+#define glGenerateMipmap GLES2_GET_FUN(GenerateMipmap)
+#define glGenFramebuffers GLES2_GET_FUN(GenFramebuffers)
+#define glGenRenderbuffers GLES2_GET_FUN(GenRenderbuffers)
+#define glGenTextures GLES2_GET_FUN(GenTextures)
+#define glGetActiveAttrib GLES2_GET_FUN(GetActiveAttrib)
+#define glGetActiveUniform GLES2_GET_FUN(GetActiveUniform)
+#define glGetAttachedShaders GLES2_GET_FUN(GetAttachedShaders)
+#define glGetAttribLocation GLES2_GET_FUN(GetAttribLocation)
+#define glGetBooleanv GLES2_GET_FUN(GetBooleanv)
+#define glGetBufferParameteriv GLES2_GET_FUN(GetBufferParameteriv)
+#define glGetError GLES2_GET_FUN(GetError)
+#define glGetFloatv GLES2_GET_FUN(GetFloatv)
+#define glGetFramebufferAttachmentParameteriv GLES2_GET_FUN( \
+ GetFramebufferAttachmentParameteriv)
+#define glGetIntegerv GLES2_GET_FUN(GetIntegerv)
+#define glGetProgramiv GLES2_GET_FUN(GetProgramiv)
+#define glGetProgramInfoLog GLES2_GET_FUN(GetProgramInfoLog)
+#define glGetRenderbufferParameteriv GLES2_GET_FUN(GetRenderbufferParameteriv)
+#define glGetShaderiv GLES2_GET_FUN(GetShaderiv)
+#define glGetShaderInfoLog GLES2_GET_FUN(GetShaderInfoLog)
+#define glGetShaderPrecisionFormat GLES2_GET_FUN(GetShaderPrecisionFormat)
+#define glGetShaderSource GLES2_GET_FUN(GetShaderSource)
+#define glGetString GLES2_GET_FUN(GetString)
+#define glGetTexParameterfv GLES2_GET_FUN(GetTexParameterfv)
+#define glGetTexParameteriv GLES2_GET_FUN(GetTexParameteriv)
+#define glGetUniformfv GLES2_GET_FUN(GetUniformfv)
+#define glGetUniformiv GLES2_GET_FUN(GetUniformiv)
+#define glGetUniformLocation GLES2_GET_FUN(GetUniformLocation)
+#define glGetVertexAttribfv GLES2_GET_FUN(GetVertexAttribfv)
+#define glGetVertexAttribiv GLES2_GET_FUN(GetVertexAttribiv)
+#define glGetVertexAttribPointerv GLES2_GET_FUN(GetVertexAttribPointerv)
+#define glHint GLES2_GET_FUN(Hint)
+#define glIsBuffer GLES2_GET_FUN(IsBuffer)
+#define glIsEnabled GLES2_GET_FUN(IsEnabled)
+#define glIsFramebuffer GLES2_GET_FUN(IsFramebuffer)
+#define glIsProgram GLES2_GET_FUN(IsProgram)
+#define glIsRenderbuffer GLES2_GET_FUN(IsRenderbuffer)
+#define glIsShader GLES2_GET_FUN(IsShader)
+#define glIsTexture GLES2_GET_FUN(IsTexture)
+#define glLineWidth GLES2_GET_FUN(LineWidth)
+#define glLinkProgram GLES2_GET_FUN(LinkProgram)
+#define glPixelStorei GLES2_GET_FUN(PixelStorei)
+#define glPolygonOffset GLES2_GET_FUN(PolygonOffset)
+#define glReadPixels GLES2_GET_FUN(ReadPixels)
+#define glReleaseShaderCompiler GLES2_GET_FUN(ReleaseShaderCompiler)
+#define glRenderbufferStorage GLES2_GET_FUN(RenderbufferStorage)
+#define glSampleCoverage GLES2_GET_FUN(SampleCoverage)
+#define glScissor GLES2_GET_FUN(Scissor)
+#define glShaderBinary GLES2_GET_FUN(ShaderBinary)
+#define glShaderSource GLES2_GET_FUN(ShaderSource)
+#define glShallowFinishCHROMIUM GLES2_GET_FUN(ShallowFinishCHROMIUM)
+#define glShallowFlushCHROMIUM GLES2_GET_FUN(ShallowFlushCHROMIUM)
+#define glStencilFunc GLES2_GET_FUN(StencilFunc)
+#define glStencilFuncSeparate GLES2_GET_FUN(StencilFuncSeparate)
+#define glStencilMask GLES2_GET_FUN(StencilMask)
+#define glStencilMaskSeparate GLES2_GET_FUN(StencilMaskSeparate)
+#define glStencilOp GLES2_GET_FUN(StencilOp)
+#define glStencilOpSeparate GLES2_GET_FUN(StencilOpSeparate)
+#define glTexImage2D GLES2_GET_FUN(TexImage2D)
+#define glTexParameterf GLES2_GET_FUN(TexParameterf)
+#define glTexParameterfv GLES2_GET_FUN(TexParameterfv)
+#define glTexParameteri GLES2_GET_FUN(TexParameteri)
+#define glTexParameteriv GLES2_GET_FUN(TexParameteriv)
+#define glTexSubImage2D GLES2_GET_FUN(TexSubImage2D)
+#define glUniform1f GLES2_GET_FUN(Uniform1f)
+#define glUniform1fv GLES2_GET_FUN(Uniform1fv)
+#define glUniform1i GLES2_GET_FUN(Uniform1i)
+#define glUniform1iv GLES2_GET_FUN(Uniform1iv)
+#define glUniform2f GLES2_GET_FUN(Uniform2f)
+#define glUniform2fv GLES2_GET_FUN(Uniform2fv)
+#define glUniform2i GLES2_GET_FUN(Uniform2i)
+#define glUniform2iv GLES2_GET_FUN(Uniform2iv)
+#define glUniform3f GLES2_GET_FUN(Uniform3f)
+#define glUniform3fv GLES2_GET_FUN(Uniform3fv)
+#define glUniform3i GLES2_GET_FUN(Uniform3i)
+#define glUniform3iv GLES2_GET_FUN(Uniform3iv)
+#define glUniform4f GLES2_GET_FUN(Uniform4f)
+#define glUniform4fv GLES2_GET_FUN(Uniform4fv)
+#define glUniform4i GLES2_GET_FUN(Uniform4i)
+#define glUniform4iv GLES2_GET_FUN(Uniform4iv)
+#define glUniformMatrix2fv GLES2_GET_FUN(UniformMatrix2fv)
+#define glUniformMatrix3fv GLES2_GET_FUN(UniformMatrix3fv)
+#define glUniformMatrix4fv GLES2_GET_FUN(UniformMatrix4fv)
+#define glUseProgram GLES2_GET_FUN(UseProgram)
+#define glValidateProgram GLES2_GET_FUN(ValidateProgram)
+#define glVertexAttrib1f GLES2_GET_FUN(VertexAttrib1f)
+#define glVertexAttrib1fv GLES2_GET_FUN(VertexAttrib1fv)
+#define glVertexAttrib2f GLES2_GET_FUN(VertexAttrib2f)
+#define glVertexAttrib2fv GLES2_GET_FUN(VertexAttrib2fv)
+#define glVertexAttrib3f GLES2_GET_FUN(VertexAttrib3f)
+#define glVertexAttrib3fv GLES2_GET_FUN(VertexAttrib3fv)
+#define glVertexAttrib4f GLES2_GET_FUN(VertexAttrib4f)
+#define glVertexAttrib4fv GLES2_GET_FUN(VertexAttrib4fv)
+#define glVertexAttribPointer GLES2_GET_FUN(VertexAttribPointer)
+#define glViewport GLES2_GET_FUN(Viewport)
+#define glBlitFramebufferEXT GLES2_GET_FUN(BlitFramebufferEXT)
+#define glRenderbufferStorageMultisampleEXT GLES2_GET_FUN( \
+ RenderbufferStorageMultisampleEXT)
+#define glFramebufferTexture2DMultisampleEXT GLES2_GET_FUN( \
+ FramebufferTexture2DMultisampleEXT)
+#define glTexStorage2DEXT GLES2_GET_FUN(TexStorage2DEXT)
+#define glGenQueriesEXT GLES2_GET_FUN(GenQueriesEXT)
+#define glDeleteQueriesEXT GLES2_GET_FUN(DeleteQueriesEXT)
+#define glIsQueryEXT GLES2_GET_FUN(IsQueryEXT)
+#define glBeginQueryEXT GLES2_GET_FUN(BeginQueryEXT)
+#define glEndQueryEXT GLES2_GET_FUN(EndQueryEXT)
+#define glGetQueryivEXT GLES2_GET_FUN(GetQueryivEXT)
+#define glGetQueryObjectuivEXT GLES2_GET_FUN(GetQueryObjectuivEXT)
+#define glInsertEventMarkerEXT GLES2_GET_FUN(InsertEventMarkerEXT)
+#define glPushGroupMarkerEXT GLES2_GET_FUN(PushGroupMarkerEXT)
+#define glPopGroupMarkerEXT GLES2_GET_FUN(PopGroupMarkerEXT)
+#define glGenVertexArraysOES GLES2_GET_FUN(GenVertexArraysOES)
+#define glDeleteVertexArraysOES GLES2_GET_FUN(DeleteVertexArraysOES)
+#define glIsVertexArrayOES GLES2_GET_FUN(IsVertexArrayOES)
+#define glBindVertexArrayOES GLES2_GET_FUN(BindVertexArrayOES)
+#define glSwapBuffers GLES2_GET_FUN(SwapBuffers)
+#define glGetMaxValueInBufferCHROMIUM GLES2_GET_FUN( \
+ GetMaxValueInBufferCHROMIUM)
+#define glGenSharedIdsCHROMIUM GLES2_GET_FUN(GenSharedIdsCHROMIUM)
+#define glDeleteSharedIdsCHROMIUM GLES2_GET_FUN(DeleteSharedIdsCHROMIUM)
+#define glRegisterSharedIdsCHROMIUM GLES2_GET_FUN(RegisterSharedIdsCHROMIUM)
+#define glEnableFeatureCHROMIUM GLES2_GET_FUN(EnableFeatureCHROMIUM)
+#define glMapBufferCHROMIUM GLES2_GET_FUN(MapBufferCHROMIUM)
+#define glUnmapBufferCHROMIUM GLES2_GET_FUN(UnmapBufferCHROMIUM)
+#define glMapImageCHROMIUM GLES2_GET_FUN(MapImageCHROMIUM)
+#define glUnmapImageCHROMIUM GLES2_GET_FUN(UnmapImageCHROMIUM)
+#define glMapBufferSubDataCHROMIUM GLES2_GET_FUN(MapBufferSubDataCHROMIUM)
+#define glUnmapBufferSubDataCHROMIUM GLES2_GET_FUN(UnmapBufferSubDataCHROMIUM)
+#define glMapTexSubImage2DCHROMIUM GLES2_GET_FUN(MapTexSubImage2DCHROMIUM)
+#define glUnmapTexSubImage2DCHROMIUM GLES2_GET_FUN(UnmapTexSubImage2DCHROMIUM)
+#define glResizeCHROMIUM GLES2_GET_FUN(ResizeCHROMIUM)
+#define glGetRequestableExtensionsCHROMIUM GLES2_GET_FUN( \
+ GetRequestableExtensionsCHROMIUM)
+#define glRequestExtensionCHROMIUM GLES2_GET_FUN(RequestExtensionCHROMIUM)
+#define glRateLimitOffscreenContextCHROMIUM GLES2_GET_FUN( \
+ RateLimitOffscreenContextCHROMIUM)
+#define glGetMultipleIntegervCHROMIUM GLES2_GET_FUN( \
+ GetMultipleIntegervCHROMIUM)
+#define glGetProgramInfoCHROMIUM GLES2_GET_FUN(GetProgramInfoCHROMIUM)
+#define glCreateStreamTextureCHROMIUM GLES2_GET_FUN( \
+ CreateStreamTextureCHROMIUM)
+#define glDestroyStreamTextureCHROMIUM GLES2_GET_FUN( \
+ DestroyStreamTextureCHROMIUM)
+#define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM)
+#define glDestroyImageCHROMIUM GLES2_GET_FUN(DestroyImageCHROMIUM)
+#define glGetImageParameterivCHROMIUM GLES2_GET_FUN( \
+ GetImageParameterivCHROMIUM)
+#define glGetTranslatedShaderSourceANGLE GLES2_GET_FUN( \
+ GetTranslatedShaderSourceANGLE)
+#define glPostSubBufferCHROMIUM GLES2_GET_FUN(PostSubBufferCHROMIUM)
+#define glTexImageIOSurface2DCHROMIUM GLES2_GET_FUN( \
+ TexImageIOSurface2DCHROMIUM)
+#define glCopyTextureCHROMIUM GLES2_GET_FUN(CopyTextureCHROMIUM)
+#define glDrawArraysInstancedANGLE GLES2_GET_FUN(DrawArraysInstancedANGLE)
+#define glDrawElementsInstancedANGLE GLES2_GET_FUN(DrawElementsInstancedANGLE)
+#define glVertexAttribDivisorANGLE GLES2_GET_FUN(VertexAttribDivisorANGLE)
+#define glGenMailboxCHROMIUM GLES2_GET_FUN(GenMailboxCHROMIUM)
+#define glProduceTextureCHROMIUM GLES2_GET_FUN(ProduceTextureCHROMIUM)
+#define glConsumeTextureCHROMIUM GLES2_GET_FUN(ConsumeTextureCHROMIUM)
+#define glBindUniformLocationCHROMIUM GLES2_GET_FUN( \
+ BindUniformLocationCHROMIUM)
+#define glBindTexImage2DCHROMIUM GLES2_GET_FUN(BindTexImage2DCHROMIUM)
+#define glReleaseTexImage2DCHROMIUM GLES2_GET_FUN(ReleaseTexImage2DCHROMIUM)
+#define glTraceBeginCHROMIUM GLES2_GET_FUN(TraceBeginCHROMIUM)
+#define glTraceEndCHROMIUM GLES2_GET_FUN(TraceEndCHROMIUM)
+#define glAsyncTexSubImage2DCHROMIUM GLES2_GET_FUN(AsyncTexSubImage2DCHROMIUM)
+#define glAsyncTexImage2DCHROMIUM GLES2_GET_FUN(AsyncTexImage2DCHROMIUM)
+#define glWaitAsyncTexImage2DCHROMIUM GLES2_GET_FUN( \
+ WaitAsyncTexImage2DCHROMIUM)
+#define glDiscardFramebufferEXT GLES2_GET_FUN(DiscardFramebufferEXT)
+#define glLoseContextCHROMIUM GLES2_GET_FUN(LoseContextCHROMIUM)
+#define glInsertSyncPointCHROMIUM GLES2_GET_FUN(InsertSyncPointCHROMIUM)
+#define glWaitSyncPointCHROMIUM GLES2_GET_FUN(WaitSyncPointCHROMIUM)
+#define glDrawBuffersEXT GLES2_GET_FUN(DrawBuffersEXT)
+
+#endif // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_
+
diff --git a/chromium/gpu/GLES2/gl2extchromium.h b/chromium/gpu/GLES2/gl2extchromium.h
new file mode 100644
index 00000000000..433242c66fd
--- /dev/null
+++ b/chromium/gpu/GLES2/gl2extchromium.h
@@ -0,0 +1,623 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains Chromium-specific GLES2 extensions declarations.
+
+#ifndef GPU_GLES2_GL2EXTCHROMIUM_H_
+#define GPU_GLES2_GL2EXTCHROMIUM_H_
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* GL_CHROMIUM_iosurface */
+#ifndef GL_CHROMIUM_iosurface
+#define GL_CHROMIUM_iosurface 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGEIOSURFACE2DCHROMIUMPROC) (
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane);
+#endif /* GL_CHROMIUM_iosurface */
+
+/* GL_CHROMIUM_gpu_memory_manager */
+#ifndef GL_CHROMIUM_gpu_memory_manager
+#define GL_CHROMIUM_gpu_memory_manager 1
+
+#ifndef GL_TEXTURE_POOL_UNMANAGED_CHROMIUM
+#define GL_TEXTURE_POOL_UNMANAGED_CHROMIUM 0x6002
+#endif
+
+#ifndef GL_TEXTURE_POOL_CHROMIUM
+#define GL_TEXTURE_POOL_CHROMIUM 0x6000
+#endif
+
+#ifndef GL_TEXTURE_POOL_MANAGED_CHROMIUM
+#define GL_TEXTURE_POOL_MANAGED_CHROMIUM 0x6001
+#endif
+#endif /* GL_CHROMIUM_gpu_memory_manager */
+
+/* GL_CHROMIUM_texture_mailbox */
+#ifndef GL_CHROMIUM_texture_mailbox
+#define GL_CHROMIUM_texture_mailbox 1
+
+#ifndef GL_MAILBOX_SIZE_CHROMIUM
+#define GL_MAILBOX_SIZE_CHROMIUM 64
+#endif
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenMailboxCHROMIUM(GLbyte* mailbox);
+GL_APICALL void GL_APIENTRY glProduceTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox);
+GL_APICALL void GL_APIENTRY glConsumeTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENMAILBOXCHROMIUMPROC) (GLbyte* mailbox);
+typedef void (GL_APIENTRYP PFNGLPRODUCETEXTURECHROMIUMPROC) (
+ GLenum target, const GLbyte* mailbox);
+typedef void (GL_APIENTRYP PFNGLCONSUMETEXTURECHROMIUMPROC) (
+ GLenum target, const GLbyte* mailbox);
+#endif /* GL_CHROMIUM_texture_mailbox */
+
+/* GL_CHROMIUM_pixel_transfer_buffer_object */
+#ifndef GL_CHROMIUM_pixel_transfer_buffer_object
+#define GL_CHROMIUM_pixel_transfer_buffer_object 1
+
+#ifndef GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM
+// TODO(reveman): Get official numbers for this constants.
+#define GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM 0x78EC
+#define GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM 0x78ED
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferCHROMIUM(GLuint target,GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferCHROMIUM(GLuint target);
+#endif
+typedef void* (GL_APIENTRY PFNGLMAPBUFFERCHROMIUM) (
+ GLuint target,GLenum access);
+typedef GLboolean (GL_APIENTRY PFNGLUNMAPBUFFERCHROMIUM) (GLuint target);
+#endif /* GL_CHROMIUM_pixel_transfer_buffer_object */
+
+#ifndef GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM
+// TODO(reveman): Get official numbers for this constants.
+#define GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM 0x78EF
+#define GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM 0x78EE
+#endif
+
+#ifndef GL_STREAM_READ
+#define GL_STREAM_READ 0x88E1
+#endif
+#endif /* GL_CHROMIUM_pixel_transfer_buffer_object */
+
+/* GL_CHROMIUM_map_image */
+#ifndef GL_CHROMIUM_map_image
+#define GL_CHROMIUM_map_image 1
+
+#ifndef GL_IMAGE_ROWBYTES_CHROMIUM
+#define GL_IMAGE_ROWBYTES_CHROMIUM 0x78F0
+#endif
+
+#ifndef GL_READ_WRITE
+#define GL_READ_WRITE 0x88BA
+#endif
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLuint GL_APIENTRY glCreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat);
+GL_APICALL void GL_APIENTRY glDestroyImageCHROMIUM(GLuint image_id);
+GL_APICALL void GL_APIENTRY glGetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params);
+GL_APICALL void* GL_APIENTRY glMapImageCHROMIUM(GLuint image_id, GLenum access);
+GL_APICALL void GL_APIENTRY glUnmapImageCHROMIUM(GLuint image_id);
+#endif
+typedef GLuint (GL_APIENTRYP PFNGLCREATEIMAGECHROMIUMPROC) (
+ GLsizei width, GLsizei height, GLenum internalformat);
+typedef void (
+ GL_APIENTRYP PFNGLDESTROYIMAGECHROMIUMPROC) (GLuint image_id);
+typedef void (
+ GL_APIENTRYP PFNGLGETIMAGEPARAMETERIVCHROMIUMPROC) (
+ GLuint image_id, GLenum pname, GLint* params);
+typedef void* (GL_APIENTRYP PFNGLMAPIMAGECHROMIUMPROC) (
+ GLuint image_id, GLenum access);
+typedef void (GL_APIENTRYP PFNGLUNMAPIMAGECHROMIUMPROC) (GLuint image_id);
+#endif /* GL_CHROMIUM_map_image */
+
+/* GL_CHROMIUM_map_sub */
+#ifndef GL_CHROMIUM_map_sub
+#define GL_CHROMIUM_map_sub 1
+
+#ifndef GL_READ_ONLY
+#define GL_READ_ONLY 0x88B8
+#endif
+
+#ifndef GL_WRITE_ONLY
+#define GL_WRITE_ONLY 0x88B9
+#endif
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access);
+GL_APICALL void GL_APIENTRY glUnmapBufferSubDataCHROMIUM(const void* mem);
+GL_APICALL void* GL_APIENTRY glMapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access);
+GL_APICALL void GL_APIENTRY glUnmapTexSubImage2DCHROMIUM(const void* mem);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFERSUBDATACHROMIUMPROC) (
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access);
+typedef void (
+ GL_APIENTRYP PFNGLUNMAPBUFFERSUBDATACHROMIUMPROC) (const void* mem);
+typedef void* (GL_APIENTRYP PFNGLMAPTEXSUBIMAGE2DCHROMIUMPROC) (
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access);
+typedef void (
+ GL_APIENTRYP PFNGLUNMAPTEXSUBIMAGE2DCHROMIUMPROC) (const void* mem);
+#endif /* GL_CHROMIUM_map_sub */
+
+/* GL_CHROMIUM_request_extension */
+#ifndef GL_CHROMIUM_request_extension
+#define GL_CHROMIUM_request_extension 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL const GLchar* GL_APIENTRY glGetRequestableExtensionsCHROMIUM();
+GL_APICALL void GL_APIENTRY glRequestExtensionCHROMIUM(const char* extension);
+#endif
+typedef const GLchar* (GL_APIENTRYP PFNGLGETREQUESTABLEEXTENSIONSCHROMIUMPROC) (
+ );
+typedef void (GL_APIENTRYP PFNGLREQUESTEXTENSIONCHROMIUMPROC) (
+ const char* extension);
+#endif /* GL_CHROMIUM_request_extension */
+
+/* GL_CHROMIUM_get_error_query */
+#ifndef GL_CHROMIUM_get_error_query
+#define GL_CHROMIUM_get_error_query 1
+
+#ifndef GL_GET_ERROR_QUERY_CHROMIUM
+// TODO(gman): Get official numbers for this constants.
+#define GL_GET_ERROR_QUERY_CHROMIUM 0x84F3
+#endif
+#endif /* GL_CHROMIUM_get_error_query */
+
+/* GL_CHROMIUM_texture_from_image */
+#ifndef GL_CHROMIUM_texture_from_image
+#define GL_CHROMIUM_texture_from_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindTexImage2DCHROMIUM(
+ GLenum target, GLint imageId);
+GL_APICALL void GL_APIENTRY glReleaseTexImage2DCHROMIUM(
+ GLenum target, GLint imageId);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDTEXIMAGE2DCHROMIUMPROC) (
+ GLenum target, GLint imageId);
+typedef void (GL_APIENTRYP PFNGLRELEASETEXIMAGE2DCHROMIUMPROC) (
+ GLenum target, GLint imageId);
+#endif /* GL_CHROMIUM_texture_from_image */
+
+/* GL_CHROMIUM_rate_limit_offscreen_context */
+#ifndef GL_CHROMIUM_rate_limit_offscreen_context
+#define GL_CHROMIUM_rate_limit_offscreen_context 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRateLimitOffscreenContextCHROMIUM();
+#endif
+typedef void (GL_APIENTRYP PFNGLRATELIMITOFFSCREENCONTEXTCHROMIUMPROC) ();
+#endif /* GL_CHROMIUM_rate_limit_offscreen_context */
+
+/* GL_CHROMIUM_post_sub_buffer */
+#ifndef GL_CHROMIUM_post_sub_buffer
+#define GL_CHROMIUM_post_sub_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glPostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height);
+#endif
+typedef void (GL_APIENTRYP PFNGLPOSTSUBBUFFERCHROMIUMPROC) (
+ GLint x, GLint y, GLint width, GLint height);
+#endif /* GL_CHROMIUM_post_sub_buffer */
+
+/* GL_CHROMIUM_bind_uniform_location */
+#ifndef GL_CHROMIUM_bind_uniform_location
+#define GL_CHROMIUM_bind_uniform_location 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDUNIFORMLOCATIONCHROMIUMPROC) (
+ GLuint program, GLint location, const char* name);
+#endif /* GL_CHROMIUM_bind_uniform_location */
+
+/* GL_CHROMIUM_command_buffer_query */
+#ifndef GL_CHROMIUM_command_buffer_query
+#define GL_CHROMIUM_command_buffer_query 1
+
+#ifndef GL_COMMANDS_ISSUED_CHROMIUM
+// TODO(gman): Get official numbers for this constants.
+#define GL_COMMANDS_ISSUED_CHROMIUM 0x84F2
+#endif
+#endif /* GL_CHROMIUM_command_buffer_query */
+
+/* GL_EXT_framebuffer_multisample */
+#ifndef GL_EXT_framebuffer_multisample
+#define GL_EXT_framebuffer_multisample 1
+
+#ifndef GL_FRAMEBUFFER_BINDING_EXT
+#define GL_FRAMEBUFFER_BINDING_EXT GL_FRAMEBUFFER_BINDING
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER_BINDING_EXT
+#define GL_DRAW_FRAMEBUFFER_BINDING_EXT GL_DRAW_FRAMEBUFFER_BINDING
+#endif
+
+#ifndef GL_RENDERBUFFER_BINDING_EXT
+#define GL_RENDERBUFFER_BINDING_EXT GL_RENDERBUFFER_BINDING
+#endif
+
+#ifndef GL_RENDERBUFFER_SAMPLES
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#endif
+
+#ifndef GL_READ_FRAMEBUFFER_EXT
+#define GL_READ_FRAMEBUFFER_EXT GL_READ_FRAMEBUFFER
+#endif
+
+#ifndef GL_RENDERBUFFER_SAMPLES_EXT
+#define GL_RENDERBUFFER_SAMPLES_EXT GL_RENDERBUFFER_SAMPLES
+#endif
+
+#ifndef GL_RENDERBUFFER_BINDING
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#endif
+
+#ifndef GL_READ_FRAMEBUFFER_BINDING
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#endif
+
+#ifndef GL_MAX_SAMPLES
+#define GL_MAX_SAMPLES 0x8D57
+#endif
+
+#ifndef GL_READ_FRAMEBUFFER_BINDING_EXT
+#define GL_READ_FRAMEBUFFER_BINDING_EXT GL_READ_FRAMEBUFFER_BINDING
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER_BINDING
+#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6
+#endif
+
+#ifndef GL_MAX_SAMPLES_EXT
+#define GL_MAX_SAMPLES_EXT GL_MAX_SAMPLES
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#endif
+
+#ifndef GL_READ_FRAMEBUFFER
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#endif
+
+#ifndef GL_DRAW_FRAMEBUFFER_EXT
+#define GL_DRAW_FRAMEBUFFER_EXT GL_DRAW_FRAMEBUFFER
+#endif
+
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#endif
+
+#ifndef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE // NOLINT
+#endif
+
+#ifndef GL_FRAMEBUFFER_BINDING
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#endif
+#endif /* GL_EXT_framebuffer_multisample */
+
+/* GL_CHROMIUM_texture_compression_dxt3 */
+#ifndef GL_CHROMIUM_texture_compression_dxt3
+#define GL_CHROMIUM_texture_compression_dxt3 1
+
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT3_EXT
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#endif
+#endif /* GL_CHROMIUM_texture_compression_dxt3 */
+
+/* GL_CHROMIUM_texture_compression_dxt5 */
+#ifndef GL_CHROMIUM_texture_compression_dxt5
+#define GL_CHROMIUM_texture_compression_dxt5 1
+
+#ifndef GL_COMPRESSED_RGBA_S3TC_DXT5_EXT
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+#endif
+#endif /* GL_CHROMIUM_texture_compression_dxt5 */
+
+/* GL_CHROMIUM_async_pixel_transfers */
+#ifndef GL_CHROMIUM_async_pixel_transfers
+#define GL_CHROMIUM_async_pixel_transfers 1
+
+#ifndef GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM
+#define GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM 0x84F5
+#endif
+#ifndef GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM
+#define GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM 0x84F6
+#endif
+#endif /* GL_CHROMIUM_async_pixel_transfers */
+
+/* GL_CHROMIUM_copy_texture */
+#ifndef GL_CHROMIUM_copy_texture
+#define GL_CHROMIUM_copy_texture 1
+
+#ifndef GL_UNPACK_COLORSPACE_CONVERSION_CHROMIUM
+#define GL_UNPACK_COLORSPACE_CONVERSION_CHROMIUM 0x9243
+#endif
+
+#ifndef GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM
+#define GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM 0x9242
+#endif
+
+#ifndef GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM
+#define GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM 0x9241
+#endif
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOPYTEXTURECHROMIUMPROC) (
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type);
+#endif /* GL_CHROMIUM_copy_texture */
+
+/* GL_CHROMIUM_lose_context */
+#ifndef GL_CHROMIUM_lose_context
+#define GL_CHROMIUM_lose_context 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLoseContextCHROMIUM(GLenum current, GLenum other);
+#endif
+typedef void (GL_APIENTRYP PFNGLLOSECONTEXTCHROMIUMPROC) (
+ GLenum current, GLenum other);
+#endif /* GL_CHROMIUM_lose_context */
+
+/* GL_CHROMIUM_flipy */
+#ifndef GL_CHROMIUM_flipy
+#define GL_CHROMIUM_flipy 1
+
+#ifndef GL_UNPACK_FLIP_Y_CHROMIUM
+#define GL_UNPACK_FLIP_Y_CHROMIUM 0x9240
+#endif
+#endif /* GL_CHROMIUM_flipy */
+
+/* GL_ARB_texture_rectangle */
+#ifndef GL_ARB_texture_rectangle
+#define GL_ARB_texture_rectangle 1
+
+#ifndef GL_SAMPLER_2D_RECT_ARB
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#endif
+
+#ifndef GL_TEXTURE_BINDING_RECTANGLE_ARB
+#define GL_TEXTURE_BINDING_RECTANGLE_ARB 0x84F6
+#endif
+
+#ifndef GL_TEXTURE_RECTANGLE_ARB
+#define GL_TEXTURE_RECTANGLE_ARB 0x84F5
+#endif
+#endif /* GL_ARB_texture_rectangle */
+
+/* GL_CHROMIUM_enable_feature */
+#ifndef GL_CHROMIUM_enable_feature
+#define GL_CHROMIUM_enable_feature 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLboolean GL_APIENTRY glEnableFeatureCHROMIUM(const char* feature);
+#endif
+typedef GLboolean (GL_APIENTRYP PFNGLENABLEFEATURECHROMIUMPROC) (
+ const char* feature);
+#endif /* GL_CHROMIUM_enable_feature */
+
+/* GL_CHROMIUM_command_buffer_latency_query */
+#ifndef GL_CHROMIUM_command_buffer_latency_query
+#define GL_CHROMIUM_command_buffer_latency_query 1
+
+#ifndef GL_LATENCY_QUERY_CHROMIUM
+// TODO(gman): Get official numbers for these constants.
+#define GL_LATENCY_QUERY_CHROMIUM 0x84F4
+#endif
+#endif /* GL_CHROMIUM_command_buffer_latency_query */
+
+/* GL_ARB_robustness */
+#ifndef GL_ARB_robustness
+#define GL_ARB_robustness 1
+
+#ifndef GL_GUILTY_CONTEXT_RESET_ARB
+#define GL_GUILTY_CONTEXT_RESET_ARB 0x8253
+#endif
+
+#ifndef GL_UNKNOWN_CONTEXT_RESET_ARB
+#define GL_UNKNOWN_CONTEXT_RESET_ARB 0x8255
+#endif
+
+#ifndef GL_INNOCENT_CONTEXT_RESET_ARB
+#define GL_INNOCENT_CONTEXT_RESET_ARB 0x8254
+#endif
+#endif /* GL_ARB_robustness */
+
+/* GL_EXT_framebuffer_blit */
+#ifndef GL_EXT_framebuffer_blit
+#define GL_EXT_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFEREXTPROC) (
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif /* GL_EXT_framebuffer_blit */
+
+/* GL_EXT_draw_buffers */
+#ifndef GL_EXT_draw_buffers
+#define GL_EXT_draw_buffers 1
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersEXT(
+ GLsizei n, const GLenum* bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSEXTPROC) (
+ GLsizei n, const GLenum* bufs);
+
+#ifndef GL_COLOR_ATTACHMENT0_EXT
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#endif
+#ifndef GL_COLOR_ATTACHMENT1_EXT
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#endif
+#ifndef GL_COLOR_ATTACHMENT2_EXT
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#endif
+#ifndef GL_COLOR_ATTACHMENT3_EXT
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#endif
+#ifndef GL_COLOR_ATTACHMENT4_EXT
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#endif
+#ifndef GL_COLOR_ATTACHMENT5_EXT
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#endif
+#ifndef GL_COLOR_ATTACHMENT6_EXT
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#endif
+#ifndef GL_COLOR_ATTACHMENT7_EXT
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#endif
+#ifndef GL_COLOR_ATTACHMENT8_EXT
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#endif
+#ifndef GL_COLOR_ATTACHMENT9_EXT
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#endif
+#ifndef GL_COLOR_ATTACHMENT10_EXT
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#endif
+#ifndef GL_COLOR_ATTACHMENT11_EXT
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#endif
+#ifndef GL_COLOR_ATTACHMENT12_EXT
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#endif
+#ifndef GL_COLOR_ATTACHMENT13_EXT
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#endif
+#ifndef GL_COLOR_ATTACHMENT14_EXT
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#endif
+#ifndef GL_COLOR_ATTACHMENT15_EXT
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#endif
+
+#ifndef GL_DRAW_BUFFER0_EXT
+#define GL_DRAW_BUFFER0_EXT 0x8825
+#endif
+#ifndef GL_DRAW_BUFFER1_EXT
+#define GL_DRAW_BUFFER1_EXT 0x8826
+#endif
+#ifndef GL_DRAW_BUFFER2_EXT
+#define GL_DRAW_BUFFER2_EXT 0x8827
+#endif
+#ifndef GL_DRAW_BUFFER3_EXT
+#define GL_DRAW_BUFFER3_EXT 0x8828
+#endif
+#ifndef GL_DRAW_BUFFER4_EXT
+#define GL_DRAW_BUFFER4_EXT 0x8829
+#endif
+#ifndef GL_DRAW_BUFFER5_EXT
+#define GL_DRAW_BUFFER5_EXT 0x882A
+#endif
+#ifndef GL_DRAW_BUFFER6_EXT
+#define GL_DRAW_BUFFER6_EXT 0x882B
+#endif
+#ifndef GL_DRAW_BUFFER7_EXT
+#define GL_DRAW_BUFFER7_EXT 0x882C
+#endif
+#ifndef GL_DRAW_BUFFER8_EXT
+#define GL_DRAW_BUFFER8_EXT 0x882D
+#endif
+#ifndef GL_DRAW_BUFFER9_EXT
+#define GL_DRAW_BUFFER9_EXT 0x882E
+#endif
+#ifndef GL_DRAW_BUFFER10_EXT
+#define GL_DRAW_BUFFER10_EXT 0x882F
+#endif
+#ifndef GL_DRAW_BUFFER11_EXT
+#define GL_DRAW_BUFFER11_EXT 0x8830
+#endif
+#ifndef GL_DRAW_BUFFER12_EXT
+#define GL_DRAW_BUFFER12_EXT 0x8831
+#endif
+#ifndef GL_DRAW_BUFFER13_EXT
+#define GL_DRAW_BUFFER13_EXT 0x8832
+#endif
+#ifndef GL_DRAW_BUFFER14_EXT
+#define GL_DRAW_BUFFER14_EXT 0x8833
+#endif
+#ifndef GL_DRAW_BUFFER15_EXT
+#define GL_DRAW_BUFFER15_EXT 0x8834
+#endif
+
+#ifndef GL_MAX_COLOR_ATTACHMENTS_EXT
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#endif
+
+#ifndef GL_MAX_DRAW_BUFFERS_EXT
+#define GL_MAX_DRAW_BUFFERS_EXT 0x8824
+#endif
+
+#endif /* GL_EXT_draw_buffers */
+
+/* GL_CHROMIUM_resize */
+#ifndef GL_CHROMIUM_resize
+#define GL_CHROMIUM_resize 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glResizeCHROMIUM(
+ GLuint width, GLuint height, GLfloat scale_factor);
+#endif
+typedef void (GL_APIENTRYP PFNGLRESIZECHROMIUMPROC) (
+ GLuint width, GLuint height);
+#endif /* GL_CHROMIUM_resize */
+
+/* GL_CHROMIUM_get_multiple */
+#ifndef GL_CHROMIUM_get_multiple
+#define GL_CHROMIUM_get_multiple 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
+GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETMULTIPLEINTEGERVCHROMIUMPROC) (
+ const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOCHROMIUMPROC) (
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info);
+#endif /* GL_CHROMIUM_get_multiple */
+
+/* GL_CHROMIUM_front_buffer_cached */
+#ifndef GL_CHROMIUM_front_buffer_cached
+#define GL_CHROMIUM_front_buffer_cached 1
+#endif /* GL_CHROMIUM_front_buffer_cached */
+
+/* GL_CHROMIUM_sync_point */
+#ifndef GL_CHROMIUM_sync_point
+#define GL_CHROMIUM_sync_point 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLuint GL_APIENTRY glInsertSyncPointCHROMIUM();
+GL_APICALL void GL_APIENTRY glWaitSyncPointCHROMIUM(GLuint sync_point);
+#endif
+typedef GLuint (GL_APIENTRYP PFNGLINSERTSYNCPOINTCHROMIUMPROC) ();
+typedef void (GL_APIENTRYP PFNGLWAITSYNCPOINTCHROMIUMPROC) (GLuint sync_point);
+#endif /* GL_CHROMIUM_sync_point */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // GPU_GLES2_GL2EXTCHROMIUM_H_
diff --git a/chromium/gpu/OWNERS b/chromium/gpu/OWNERS
new file mode 100644
index 00000000000..0c5f595fb6a
--- /dev/null
+++ b/chromium/gpu/OWNERS
@@ -0,0 +1,2 @@
+piman@chromium.org
+apatrick@chromium.org
diff --git a/chromium/gpu/command_buffer/build_gles2_cmd_buffer.py b/chromium/gpu/command_buffer/build_gles2_cmd_buffer.py
new file mode 100755
index 00000000000..a6f13c15a5c
--- /dev/null
+++ b/chromium/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -0,0 +1,7814 @@
+#!/usr/bin/env python
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""code generator for GLES2 command buffers."""
+
+import itertools
+import os
+import os.path
+import sys
+import re
+from optparse import OptionParser
+
+_SIZE_OF_UINT32 = 4
+_SIZE_OF_COMMAND_HEADER = 4
+_FIRST_SPECIFIC_COMMAND_ID = 256
+
+_LICENSE = """// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+"""
+
+_DO_NOT_EDIT_WARNING = """// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+"""
+
+# This string is copied directly out of the gl2.h file from GLES2.0
+#
+# Edits:
+#
+# *) Any argument that is a resourceID has been changed to GLid<Type>.
+# (not pointer arguments) and if it's allowed to be zero it's GLidZero<Type>
+# If it's allowed to not exist it's GLidBind<Type>
+#
+# *) All GLenums have been changed to GLenumTypeOfEnum
+#
+_GL_TYPES = {
+ 'GLenum': 'unsigned int',
+ 'GLboolean': 'unsigned char',
+ 'GLbitfield': 'unsigned int',
+ 'GLbyte': 'signed char',
+ 'GLshort': 'short',
+ 'GLint': 'int',
+ 'GLsizei': 'int',
+ 'GLubyte': 'unsigned char',
+ 'GLushort': 'unsigned short',
+ 'GLuint': 'unsigned int',
+ 'GLfloat': 'float',
+ 'GLclampf': 'float',
+ 'GLvoid': 'void',
+ 'GLfixed': 'int',
+ 'GLclampx': 'int',
+ 'GLintptr': 'long int',
+ 'GLsizeiptr': 'long int',
+}
+
+# Capabilites selected with glEnable
+_CAPABILITY_FLAGS = [
+ {'name': 'blend'},
+ {'name': 'cull_face'},
+ {'name': 'depth_test', 'state_flag': 'framebuffer_state_.clear_state_dirty'},
+ {'name': 'dither', 'default': True},
+ {'name': 'polygon_offset_fill'},
+ {'name': 'sample_alpha_to_coverage'},
+ {'name': 'sample_coverage'},
+ {'name': 'scissor_test',
+ 'state_flag': 'framebuffer_state_.clear_state_dirty'},
+ {'name': 'stencil_test',
+ 'state_flag': 'framebuffer_state_.clear_state_dirty'},
+]
+
+_STATES = {
+ 'ClearColor': {
+ 'type': 'Normal',
+ 'func': 'ClearColor',
+ 'enum': 'GL_COLOR_CLEAR_VALUE',
+ 'states': [
+ {'name': 'color_clear_red', 'type': 'GLfloat', 'default': '0.0f'},
+ {'name': 'color_clear_green', 'type': 'GLfloat', 'default': '0.0f'},
+ {'name': 'color_clear_blue', 'type': 'GLfloat', 'default': '0.0f'},
+ {'name': 'color_clear_alpha', 'type': 'GLfloat', 'default': '0.0f'},
+ ],
+ },
+ 'ClearDepthf': {
+ 'type': 'Normal',
+ 'func': 'ClearDepth',
+ 'enum': 'GL_DEPTH_CLEAR_VALUE',
+ 'states': [
+ {'name': 'depth_clear', 'type': 'GLclampf', 'default': '1.0f'},
+ ],
+ },
+ 'ColorMask': {
+ 'type': 'Normal',
+ 'func': 'ColorMask',
+ 'enum': 'GL_COLOR_WRITEMASK',
+ 'states': [
+ {'name': 'color_mask_red', 'type': 'GLboolean', 'default': 'true'},
+ {'name': 'color_mask_green', 'type': 'GLboolean', 'default': 'true'},
+ {'name': 'color_mask_blue', 'type': 'GLboolean', 'default': 'true'},
+ {'name': 'color_mask_alpha', 'type': 'GLboolean', 'default': 'true'},
+ ],
+ 'state_flag': 'framebuffer_state_.clear_state_dirty',
+ },
+ 'ClearStencil': {
+ 'type': 'Normal',
+ 'func': 'ClearStencil',
+ 'enum': 'GL_STENCIL_CLEAR_VALUE',
+ 'states': [
+ {'name': 'stencil_clear', 'type': 'GLint', 'default': '0'},
+ ],
+ },
+ 'BlendColor': {
+ 'type': 'Normal',
+ 'func': 'BlendColor',
+ 'enum': 'GL_BLEND_COLOR',
+ 'states': [
+ {'name': 'blend_color_red', 'type': 'GLfloat', 'default': '0.0f'},
+ {'name': 'blend_color_green', 'type': 'GLfloat', 'default': '0.0f'},
+ {'name': 'blend_color_blue', 'type': 'GLfloat', 'default': '0.0f'},
+ {'name': 'blend_color_alpha', 'type': 'GLfloat', 'default': '0.0f'},
+ ],
+ },
+ 'BlendEquation': {
+ 'type': 'SrcDst',
+ 'func': 'BlendEquationSeparate',
+ 'states': [
+ {
+ 'name': 'blend_equation_rgb',
+ 'type': 'GLenum',
+ 'enum': 'GL_BLEND_EQUATION_RGB',
+ 'default': 'GL_FUNC_ADD',
+ },
+ {
+ 'name': 'blend_equation_alpha',
+ 'type': 'GLenum',
+ 'enum': 'GL_BLEND_EQUATION_ALPHA',
+ 'default': 'GL_FUNC_ADD',
+ },
+ ],
+ },
+ 'BlendFunc': {
+ 'type': 'SrcDst',
+ 'func': 'BlendFuncSeparate',
+ 'states': [
+ {
+ 'name': 'blend_source_rgb',
+ 'type': 'GLenum',
+ 'enum': 'GL_BLEND_SRC_RGB',
+ 'default': 'GL_ONE',
+ },
+ {
+ 'name': 'blend_dest_rgb',
+ 'type': 'GLenum',
+ 'enum': 'GL_BLEND_DST_RGB',
+ 'default': 'GL_ZERO',
+ },
+ {
+ 'name': 'blend_source_alpha',
+ 'type': 'GLenum',
+ 'enum': 'GL_BLEND_SRC_ALPHA',
+ 'default': 'GL_ONE',
+ },
+ {
+ 'name': 'blend_dest_alpha',
+ 'type': 'GLenum',
+ 'enum': 'GL_BLEND_DST_ALPHA',
+ 'default': 'GL_ZERO',
+ },
+ ],
+ },
+ 'PolygonOffset': {
+ 'type': 'Normal',
+ 'func': 'PolygonOffset',
+ 'states': [
+ {
+ 'name': 'polygon_offset_factor',
+ 'type': 'GLfloat',
+ 'enum': 'GL_POLYGON_OFFSET_FACTOR',
+ 'default': '0.0f',
+ },
+ {
+ 'name': 'polygon_offset_units',
+ 'type': 'GLfloat',
+ 'enum': 'GL_POLYGON_OFFSET_UNITS',
+ 'default': '0.0f',
+ },
+ ],
+ },
+ 'CullFace': {
+ 'type': 'Normal',
+ 'func': 'CullFace',
+ 'enum': 'GL_CULL_FACE_MODE',
+ 'states': [
+ {
+ 'name': 'cull_mode',
+ 'type': 'GLenum',
+ 'default': 'GL_BACK',
+ },
+ ],
+ },
+ 'FrontFace': {
+ 'type': 'Normal',
+ 'func': 'FrontFace',
+ 'enum': 'GL_FRONT_FACE',
+ 'states': [{'name': 'front_face', 'type': 'GLenum', 'default': 'GL_CCW'}],
+ },
+ 'DepthFunc': {
+ 'type': 'Normal',
+ 'func': 'DepthFunc',
+ 'enum': 'GL_DEPTH_FUNC',
+ 'states': [{'name': 'depth_func', 'type': 'GLenum', 'default': 'GL_LESS'}],
+ },
+ 'DepthRange': {
+ 'type': 'Normal',
+ 'func': 'DepthRange',
+ 'enum': 'GL_DEPTH_RANGE',
+ 'states': [
+ {'name': 'z_near', 'type': 'GLclampf', 'default': '0.0f'},
+ {'name': 'z_far', 'type': 'GLclampf', 'default': '1.0f'},
+ ],
+ },
+ 'SampleCoverage': {
+ 'type': 'Normal',
+ 'func': 'SampleCoverage',
+ 'states': [
+ {
+ 'name': 'sample_coverage_value',
+ 'type': 'GLclampf',
+ 'enum': 'GL_SAMPLE_COVERAGE_VALUE',
+ 'default': '1.0f',
+ },
+ {
+ 'name': 'sample_coverage_invert',
+ 'type': 'GLboolean',
+ 'enum': 'GL_SAMPLE_COVERAGE_INVERT',
+ 'default': 'false',
+ },
+ ],
+ },
+ 'StencilMask': {
+ 'type': 'FrontBack',
+ 'func': 'StencilMaskSeparate',
+ 'state_flag': 'framebuffer_state_.clear_state_dirty',
+ 'states': [
+ {
+ 'name': 'stencil_front_writemask',
+ 'type': 'GLuint',
+ 'enum': 'GL_STENCIL_WRITEMASK',
+ 'default': '0xFFFFFFFFU',
+ },
+ {
+ 'name': 'stencil_back_writemask',
+ 'type': 'GLuint',
+ 'enum': 'GL_STENCIL_BACK_WRITEMASK',
+ 'default': '0xFFFFFFFFU',
+ },
+ ],
+ },
+ 'StencilOp': {
+ 'type': 'FrontBack',
+ 'func': 'StencilOpSeparate',
+ 'states': [
+ {
+ 'name': 'stencil_front_fail_op',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_FAIL',
+ 'default': 'GL_KEEP',
+ },
+ {
+ 'name': 'stencil_front_z_fail_op',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_PASS_DEPTH_FAIL',
+ 'default': 'GL_KEEP',
+ },
+ {
+ 'name': 'stencil_front_z_pass_op',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_PASS_DEPTH_PASS',
+ 'default': 'GL_KEEP',
+ },
+ {
+ 'name': 'stencil_back_fail_op',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_BACK_FAIL',
+ 'default': 'GL_KEEP',
+ },
+ {
+ 'name': 'stencil_back_z_fail_op',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_BACK_PASS_DEPTH_FAIL',
+ 'default': 'GL_KEEP',
+ },
+ {
+ 'name': 'stencil_back_z_pass_op',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_BACK_PASS_DEPTH_PASS',
+ 'default': 'GL_KEEP',
+ },
+ ],
+ },
+ 'StencilFunc': {
+ 'type': 'FrontBack',
+ 'func': 'StencilFuncSeparate',
+ 'states': [
+ {
+ 'name': 'stencil_front_func',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_FUNC',
+ 'default': 'GL_ALWAYS',
+ },
+ {
+ 'name': 'stencil_front_ref',
+ 'type': 'GLint',
+ 'enum': 'GL_STENCIL_REF',
+ 'default': '0',
+ },
+ {
+ 'name': 'stencil_front_mask',
+ 'type': 'GLuint',
+ 'enum': 'GL_STENCIL_VALUE_MASK',
+ 'default': '0xFFFFFFFFU',
+ },
+ {
+ 'name': 'stencil_back_func',
+ 'type': 'GLenum',
+ 'enum': 'GL_STENCIL_BACK_FUNC',
+ 'default': 'GL_ALWAYS',
+ },
+ {
+ 'name': 'stencil_back_ref',
+ 'type': 'GLint',
+ 'enum': 'GL_STENCIL_BACK_REF',
+ 'default': '0',
+ },
+ {
+ 'name': 'stencil_back_mask',
+ 'type': 'GLuint',
+ 'enum': 'GL_STENCIL_BACK_VALUE_MASK',
+ 'default': '0xFFFFFFFFU',
+ },
+ ],
+ },
+ 'Hint': {
+ 'type': 'NamedParameter',
+ 'func': 'Hint',
+ 'states': [
+ {
+ 'name': 'hint_generate_mipmap',
+ 'type': 'GLenum',
+ 'enum': 'GL_GENERATE_MIPMAP_HINT',
+ 'default': 'GL_DONT_CARE'
+ },
+ {
+ 'name': 'hint_fragment_shader_derivative',
+ 'type': 'GLenum',
+ 'enum': 'GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES',
+ 'default': 'GL_DONT_CARE',
+ 'extension_flag': 'oes_standard_derivatives'
+ }
+ ],
+ },
+ 'PixelStore': {
+ 'type': 'NamedParameter',
+ 'func': 'PixelStorei',
+ 'states': [
+ {
+ 'name': 'pack_alignment',
+ 'type': 'GLint',
+ 'enum': 'GL_PACK_ALIGNMENT',
+ 'default': '4'
+ },
+ {
+ 'name': 'unpack_alignment',
+ 'type': 'GLint',
+ 'enum': 'GL_UNPACK_ALIGNMENT',
+ 'default': '4'
+ }
+ ],
+ },
+ # TODO: Consider implemenenting these states
+ # GL_ACTIVE_TEXTURE
+ 'LineWidth': {
+ 'type': 'Normal',
+ 'func': 'LineWidth',
+ 'enum': 'GL_LINE_WIDTH',
+ 'states': [
+ {
+ 'name': 'line_width',
+ 'type': 'GLfloat',
+ 'default': '1.0f',
+ 'range_checks': [{'check': "<= 0.0f", 'test_value': "0.0f"}],
+ }],
+ },
+ 'DepthMask': {
+ 'type': 'Normal',
+ 'func': 'DepthMask',
+ 'enum': 'GL_DEPTH_WRITEMASK',
+ 'states': [
+ {'name': 'depth_mask', 'type': 'GLboolean', 'default': 'true'},
+ ],
+ 'state_flag': 'framebuffer_state_.clear_state_dirty',
+ },
+ 'Scissor': {
+ 'type': 'Normal',
+ 'func': 'Scissor',
+ 'enum': 'GL_SCISSOR_BOX',
+ 'states': [
+ # NOTE: These defaults reset at GLES2DecoderImpl::Initialization.
+ {
+ 'name': 'scissor_x',
+ 'type': 'GLint',
+ 'default': '0',
+ 'expected': 'kViewportX',
+ },
+ {
+ 'name': 'scissor_y',
+ 'type': 'GLint',
+ 'default': '0',
+ 'expected': 'kViewportY',
+ },
+ {
+ 'name': 'scissor_width',
+ 'type': 'GLsizei',
+ 'default': '1',
+ 'expected': 'kViewportWidth',
+ },
+ {
+ 'name': 'scissor_height',
+ 'type': 'GLsizei',
+ 'default': '1',
+ 'expected': 'kViewportHeight',
+ },
+ ],
+ },
+ 'Viewport': {
+ 'type': 'Normal',
+ 'func': 'Viewport',
+ 'enum': 'GL_VIEWPORT',
+ 'states': [
+ # NOTE: These defaults reset at GLES2DecoderImpl::Initialization.
+ {
+ 'name': 'viewport_x',
+ 'type': 'GLint',
+ 'default': '0',
+ 'expected': 'kViewportX',
+ },
+ {
+ 'name': 'viewport_y',
+ 'type': 'GLint',
+ 'default': '0',
+ 'expected': 'kViewportY',
+ },
+ {
+ 'name': 'viewport_width',
+ 'type': 'GLsizei',
+ 'default': '1',
+ 'expected': 'kViewportWidth',
+ },
+ {
+ 'name': 'viewport_height',
+ 'type': 'GLsizei',
+ 'default': '1',
+ 'expected': 'kViewportHeight',
+ },
+ ],
+ },
+}
+
+# This is a list of enum names and their valid values. It is used to map
+# GLenum arguments to a specific set of valid values.
+_ENUM_LISTS = {
+ 'BlitFilter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_NEAREST',
+ 'GL_LINEAR',
+ ],
+ 'invalid': [
+ 'GL_LINEAR_MIPMAP_LINEAR',
+ ],
+ },
+ 'FrameBufferTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_FRAMEBUFFER',
+ ],
+ 'invalid': [
+ 'GL_DRAW_FRAMEBUFFER' ,
+ 'GL_READ_FRAMEBUFFER' ,
+ ],
+ },
+ 'RenderBufferTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_RENDERBUFFER',
+ ],
+ 'invalid': [
+ 'GL_FRAMEBUFFER',
+ ],
+ },
+ 'BufferTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ARRAY_BUFFER',
+ 'GL_ELEMENT_ARRAY_BUFFER',
+ ],
+ 'invalid': [
+ 'GL_RENDERBUFFER',
+ ],
+ },
+ 'BufferUsage': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_STREAM_DRAW',
+ 'GL_STATIC_DRAW',
+ 'GL_DYNAMIC_DRAW',
+ ],
+ 'invalid': [
+ 'GL_STATIC_READ',
+ ],
+ },
+ 'CompressedTextureFormat': {
+ 'type': 'GLenum',
+ 'valid': [
+ ],
+ },
+ 'GLState': {
+ 'type': 'GLenum',
+ 'valid': [
+ # NOTE: State an Capability entries added later.
+ 'GL_ACTIVE_TEXTURE',
+ 'GL_ALIASED_LINE_WIDTH_RANGE',
+ 'GL_ALIASED_POINT_SIZE_RANGE',
+ 'GL_ALPHA_BITS',
+ 'GL_ARRAY_BUFFER_BINDING',
+ 'GL_BLUE_BITS',
+ 'GL_COMPRESSED_TEXTURE_FORMATS',
+ 'GL_CURRENT_PROGRAM',
+ 'GL_DEPTH_BITS',
+ 'GL_DEPTH_RANGE',
+ 'GL_ELEMENT_ARRAY_BUFFER_BINDING',
+ 'GL_FRAMEBUFFER_BINDING',
+ 'GL_GENERATE_MIPMAP_HINT',
+ 'GL_GREEN_BITS',
+ 'GL_IMPLEMENTATION_COLOR_READ_FORMAT',
+ 'GL_IMPLEMENTATION_COLOR_READ_TYPE',
+ 'GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS',
+ 'GL_MAX_CUBE_MAP_TEXTURE_SIZE',
+ 'GL_MAX_FRAGMENT_UNIFORM_VECTORS',
+ 'GL_MAX_RENDERBUFFER_SIZE',
+ 'GL_MAX_TEXTURE_IMAGE_UNITS',
+ 'GL_MAX_TEXTURE_SIZE',
+ 'GL_MAX_VARYING_VECTORS',
+ 'GL_MAX_VERTEX_ATTRIBS',
+ 'GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS',
+ 'GL_MAX_VERTEX_UNIFORM_VECTORS',
+ 'GL_MAX_VIEWPORT_DIMS',
+ 'GL_NUM_COMPRESSED_TEXTURE_FORMATS',
+ 'GL_NUM_SHADER_BINARY_FORMATS',
+ 'GL_PACK_ALIGNMENT',
+ 'GL_RED_BITS',
+ 'GL_RENDERBUFFER_BINDING',
+ 'GL_SAMPLE_BUFFERS',
+ 'GL_SAMPLE_COVERAGE_INVERT',
+ 'GL_SAMPLE_COVERAGE_VALUE',
+ 'GL_SAMPLES',
+ 'GL_SCISSOR_BOX',
+ 'GL_SHADER_BINARY_FORMATS',
+ 'GL_SHADER_COMPILER',
+ 'GL_SUBPIXEL_BITS',
+ 'GL_STENCIL_BITS',
+ 'GL_TEXTURE_BINDING_2D',
+ 'GL_TEXTURE_BINDING_CUBE_MAP',
+ 'GL_UNPACK_ALIGNMENT',
+ 'GL_UNPACK_FLIP_Y_CHROMIUM',
+ 'GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM',
+ 'GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM',
+ # we can add this because we emulate it if the driver does not support it.
+ 'GL_VERTEX_ARRAY_BINDING_OES',
+ 'GL_VIEWPORT',
+ ],
+ 'invalid': [
+ 'GL_FOG_HINT',
+ ],
+ },
+ 'GetTexParamTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_TEXTURE_2D',
+ 'GL_TEXTURE_CUBE_MAP',
+ ],
+ 'invalid': [
+ 'GL_PROXY_TEXTURE_CUBE_MAP',
+ ]
+ },
+ 'TextureTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_TEXTURE_2D',
+ 'GL_TEXTURE_CUBE_MAP_POSITIVE_X',
+ 'GL_TEXTURE_CUBE_MAP_NEGATIVE_X',
+ 'GL_TEXTURE_CUBE_MAP_POSITIVE_Y',
+ 'GL_TEXTURE_CUBE_MAP_NEGATIVE_Y',
+ 'GL_TEXTURE_CUBE_MAP_POSITIVE_Z',
+ 'GL_TEXTURE_CUBE_MAP_NEGATIVE_Z',
+ ],
+ 'invalid': [
+ 'GL_PROXY_TEXTURE_CUBE_MAP',
+ ]
+ },
+ 'TextureBindTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_TEXTURE_2D',
+ 'GL_TEXTURE_CUBE_MAP',
+ ],
+ 'invalid': [
+ 'GL_TEXTURE_1D',
+ 'GL_TEXTURE_3D',
+ ],
+ },
+ 'ShaderType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_VERTEX_SHADER',
+ 'GL_FRAGMENT_SHADER',
+ ],
+ 'invalid': [
+ 'GL_GEOMETRY_SHADER',
+ ],
+ },
+ 'FaceType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_FRONT',
+ 'GL_BACK',
+ 'GL_FRONT_AND_BACK',
+ ],
+ },
+ 'FaceMode': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_CW',
+ 'GL_CCW',
+ ],
+ },
+ 'CmpFunction': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_NEVER',
+ 'GL_LESS',
+ 'GL_EQUAL',
+ 'GL_LEQUAL',
+ 'GL_GREATER',
+ 'GL_NOTEQUAL',
+ 'GL_GEQUAL',
+ 'GL_ALWAYS',
+ ],
+ },
+ 'Equation': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_FUNC_ADD',
+ 'GL_FUNC_SUBTRACT',
+ 'GL_FUNC_REVERSE_SUBTRACT',
+ ],
+ 'invalid': [
+ 'GL_MIN',
+ 'GL_MAX',
+ ],
+ },
+ 'SrcBlendFactor': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ZERO',
+ 'GL_ONE',
+ 'GL_SRC_COLOR',
+ 'GL_ONE_MINUS_SRC_COLOR',
+ 'GL_DST_COLOR',
+ 'GL_ONE_MINUS_DST_COLOR',
+ 'GL_SRC_ALPHA',
+ 'GL_ONE_MINUS_SRC_ALPHA',
+ 'GL_DST_ALPHA',
+ 'GL_ONE_MINUS_DST_ALPHA',
+ 'GL_CONSTANT_COLOR',
+ 'GL_ONE_MINUS_CONSTANT_COLOR',
+ 'GL_CONSTANT_ALPHA',
+ 'GL_ONE_MINUS_CONSTANT_ALPHA',
+ 'GL_SRC_ALPHA_SATURATE',
+ ],
+ },
+ 'DstBlendFactor': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ZERO',
+ 'GL_ONE',
+ 'GL_SRC_COLOR',
+ 'GL_ONE_MINUS_SRC_COLOR',
+ 'GL_DST_COLOR',
+ 'GL_ONE_MINUS_DST_COLOR',
+ 'GL_SRC_ALPHA',
+ 'GL_ONE_MINUS_SRC_ALPHA',
+ 'GL_DST_ALPHA',
+ 'GL_ONE_MINUS_DST_ALPHA',
+ 'GL_CONSTANT_COLOR',
+ 'GL_ONE_MINUS_CONSTANT_COLOR',
+ 'GL_CONSTANT_ALPHA',
+ 'GL_ONE_MINUS_CONSTANT_ALPHA',
+ ],
+ },
+ 'Capability': {
+ 'type': 'GLenum',
+ 'valid': ["GL_%s" % cap['name'].upper() for cap in _CAPABILITY_FLAGS],
+ 'invalid': [
+ 'GL_CLIP_PLANE0',
+ 'GL_POINT_SPRITE',
+ ],
+ },
+ 'DrawMode': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_POINTS',
+ 'GL_LINE_STRIP',
+ 'GL_LINE_LOOP',
+ 'GL_LINES',
+ 'GL_TRIANGLE_STRIP',
+ 'GL_TRIANGLE_FAN',
+ 'GL_TRIANGLES',
+ ],
+ 'invalid': [
+ 'GL_QUADS',
+ 'GL_POLYGON',
+ ],
+ },
+ 'IndexType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_UNSIGNED_BYTE',
+ 'GL_UNSIGNED_SHORT',
+ ],
+ 'invalid': [
+ 'GL_UNSIGNED_INT',
+ 'GL_INT',
+ ],
+ },
+ 'GetMaxIndexType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_UNSIGNED_BYTE',
+ 'GL_UNSIGNED_SHORT',
+ 'GL_UNSIGNED_INT',
+ ],
+ 'invalid': [
+ 'GL_INT',
+ ],
+ },
+ 'Attachment': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_COLOR_ATTACHMENT0',
+ 'GL_DEPTH_ATTACHMENT',
+ 'GL_STENCIL_ATTACHMENT',
+ ],
+ },
+ 'BackbufferAttachment': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_COLOR_EXT',
+ 'GL_DEPTH_EXT',
+ 'GL_STENCIL_EXT',
+ ],
+ },
+ 'BufferParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_BUFFER_SIZE',
+ 'GL_BUFFER_USAGE',
+ ],
+ 'invalid': [
+ 'GL_PIXEL_PACK_BUFFER',
+ ],
+ },
+ 'FrameBufferParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE',
+ 'GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME',
+ 'GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL',
+ 'GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE',
+ ],
+ },
+ 'ProgramParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_DELETE_STATUS',
+ 'GL_LINK_STATUS',
+ 'GL_VALIDATE_STATUS',
+ 'GL_INFO_LOG_LENGTH',
+ 'GL_ATTACHED_SHADERS',
+ 'GL_ACTIVE_ATTRIBUTES',
+ 'GL_ACTIVE_ATTRIBUTE_MAX_LENGTH',
+ 'GL_ACTIVE_UNIFORMS',
+ 'GL_ACTIVE_UNIFORM_MAX_LENGTH',
+ ],
+ },
+ 'QueryObjectParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_QUERY_RESULT_EXT',
+ 'GL_QUERY_RESULT_AVAILABLE_EXT',
+ ],
+ },
+ 'QueryParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_CURRENT_QUERY_EXT',
+ ],
+ },
+ 'QueryTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ANY_SAMPLES_PASSED_EXT',
+ 'GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT',
+ 'GL_COMMANDS_ISSUED_CHROMIUM',
+ 'GL_LATENCY_QUERY_CHROMIUM',
+ 'GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM',
+ 'GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM',
+ ],
+ },
+ 'RenderBufferParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_RENDERBUFFER_RED_SIZE',
+ 'GL_RENDERBUFFER_GREEN_SIZE',
+ 'GL_RENDERBUFFER_BLUE_SIZE',
+ 'GL_RENDERBUFFER_ALPHA_SIZE',
+ 'GL_RENDERBUFFER_DEPTH_SIZE',
+ 'GL_RENDERBUFFER_STENCIL_SIZE',
+ 'GL_RENDERBUFFER_WIDTH',
+ 'GL_RENDERBUFFER_HEIGHT',
+ 'GL_RENDERBUFFER_INTERNAL_FORMAT',
+ ],
+ },
+ 'ShaderParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_SHADER_TYPE',
+ 'GL_DELETE_STATUS',
+ 'GL_COMPILE_STATUS',
+ 'GL_INFO_LOG_LENGTH',
+ 'GL_SHADER_SOURCE_LENGTH',
+ 'GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE',
+ ],
+ },
+ 'ShaderPrecision': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_LOW_FLOAT',
+ 'GL_MEDIUM_FLOAT',
+ 'GL_HIGH_FLOAT',
+ 'GL_LOW_INT',
+ 'GL_MEDIUM_INT',
+ 'GL_HIGH_INT',
+ ],
+ },
+ 'StringType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_VENDOR',
+ 'GL_RENDERER',
+ 'GL_VERSION',
+ 'GL_SHADING_LANGUAGE_VERSION',
+ 'GL_EXTENSIONS',
+ ],
+ },
+ 'TextureParameter': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_TEXTURE_MAG_FILTER',
+ 'GL_TEXTURE_MIN_FILTER',
+ 'GL_TEXTURE_POOL_CHROMIUM',
+ 'GL_TEXTURE_WRAP_S',
+ 'GL_TEXTURE_WRAP_T',
+ ],
+ 'invalid': [
+ 'GL_GENERATE_MIPMAP',
+ ],
+ },
+ 'TexturePool': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_TEXTURE_POOL_MANAGED_CHROMIUM',
+ 'GL_TEXTURE_POOL_UNMANAGED_CHROMIUM',
+ ],
+ },
+ 'TextureWrapMode': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_CLAMP_TO_EDGE',
+ 'GL_MIRRORED_REPEAT',
+ 'GL_REPEAT',
+ ],
+ },
+ 'TextureMinFilterMode': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_NEAREST',
+ 'GL_LINEAR',
+ 'GL_NEAREST_MIPMAP_NEAREST',
+ 'GL_LINEAR_MIPMAP_NEAREST',
+ 'GL_NEAREST_MIPMAP_LINEAR',
+ 'GL_LINEAR_MIPMAP_LINEAR',
+ ],
+ },
+ 'TextureMagFilterMode': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_NEAREST',
+ 'GL_LINEAR',
+ ],
+ },
+ 'TextureUsage': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_NONE',
+ 'GL_FRAMEBUFFER_ATTACHMENT_ANGLE',
+ ],
+ },
+ 'VertexAttribute': {
+ 'type': 'GLenum',
+ 'valid': [
+ # some enum that the decoder actually passes through to GL needs
+ # to be the first listed here since it's used in unit tests.
+ 'GL_VERTEX_ATTRIB_ARRAY_NORMALIZED',
+ 'GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING',
+ 'GL_VERTEX_ATTRIB_ARRAY_ENABLED',
+ 'GL_VERTEX_ATTRIB_ARRAY_SIZE',
+ 'GL_VERTEX_ATTRIB_ARRAY_STRIDE',
+ 'GL_VERTEX_ATTRIB_ARRAY_TYPE',
+ 'GL_CURRENT_VERTEX_ATTRIB',
+ ],
+ },
+ 'VertexPointer': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_VERTEX_ATTRIB_ARRAY_POINTER',
+ ],
+ },
+ 'HintTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_GENERATE_MIPMAP_HINT',
+ ],
+ 'invalid': [
+ 'GL_PERSPECTIVE_CORRECTION_HINT',
+ ],
+ },
+ 'HintMode': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_FASTEST',
+ 'GL_NICEST',
+ 'GL_DONT_CARE',
+ ],
+ },
+ 'PixelStore': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_PACK_ALIGNMENT',
+ 'GL_UNPACK_ALIGNMENT',
+ 'GL_UNPACK_FLIP_Y_CHROMIUM',
+ 'GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM',
+ 'GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM',
+ ],
+ 'invalid': [
+ 'GL_PACK_SWAP_BYTES',
+ 'GL_UNPACK_SWAP_BYTES',
+ ],
+ },
+ 'PixelStoreAlignment': {
+ 'type': 'GLint',
+ 'valid': [
+ '1',
+ '2',
+ '4',
+ '8',
+ ],
+ 'invalid': [
+ '3',
+ '9',
+ ],
+ },
+ 'ReadPixelFormat': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ALPHA',
+ 'GL_RGB',
+ 'GL_RGBA',
+ ],
+ },
+ 'PixelType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_UNSIGNED_BYTE',
+ 'GL_UNSIGNED_SHORT_5_6_5',
+ 'GL_UNSIGNED_SHORT_4_4_4_4',
+ 'GL_UNSIGNED_SHORT_5_5_5_1',
+ ],
+ 'invalid': [
+ 'GL_SHORT',
+ 'GL_INT',
+ ],
+ },
+ 'ReadPixelType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_UNSIGNED_BYTE',
+ 'GL_UNSIGNED_SHORT_5_6_5',
+ 'GL_UNSIGNED_SHORT_4_4_4_4',
+ 'GL_UNSIGNED_SHORT_5_5_5_1',
+ ],
+ 'invalid': [
+ 'GL_SHORT',
+ 'GL_INT',
+ ],
+ },
+ 'RenderBufferFormat': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_RGBA4',
+ 'GL_RGB565',
+ 'GL_RGB5_A1',
+ 'GL_DEPTH_COMPONENT16',
+ 'GL_STENCIL_INDEX8',
+ ],
+ },
+ 'ShaderBinaryFormat': {
+ 'type': 'GLenum',
+ 'valid': [
+ ],
+ },
+ 'StencilOp': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_KEEP',
+ 'GL_ZERO',
+ 'GL_REPLACE',
+ 'GL_INCR',
+ 'GL_INCR_WRAP',
+ 'GL_DECR',
+ 'GL_DECR_WRAP',
+ 'GL_INVERT',
+ ],
+ },
+ 'TextureFormat': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ALPHA',
+ 'GL_LUMINANCE',
+ 'GL_LUMINANCE_ALPHA',
+ 'GL_RGB',
+ 'GL_RGBA',
+ ],
+ 'invalid': [
+ 'GL_BGRA',
+ 'GL_BGR',
+ ],
+ },
+ 'TextureInternalFormat': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_ALPHA',
+ 'GL_LUMINANCE',
+ 'GL_LUMINANCE_ALPHA',
+ 'GL_RGB',
+ 'GL_RGBA',
+ ],
+ 'invalid': [
+ 'GL_BGRA',
+ 'GL_BGR',
+ ],
+ },
+ 'TextureInternalFormatStorage': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_RGB565',
+ 'GL_RGBA4',
+ 'GL_RGB5_A1',
+ 'GL_ALPHA8_EXT',
+ 'GL_LUMINANCE8_EXT',
+ 'GL_LUMINANCE8_ALPHA8_EXT',
+ 'GL_RGB8_OES',
+ 'GL_RGBA8_OES',
+ ],
+ },
+ 'VertexAttribType': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_BYTE',
+ 'GL_UNSIGNED_BYTE',
+ 'GL_SHORT',
+ 'GL_UNSIGNED_SHORT',
+ # 'GL_FIXED', // This is not available on Desktop GL.
+ 'GL_FLOAT',
+ ],
+ 'invalid': [
+ 'GL_DOUBLE',
+ ],
+ },
+ 'TextureBorder': {
+ 'type': 'GLint',
+ 'valid': [
+ '0',
+ ],
+ 'invalid': [
+ '1',
+ ],
+ },
+ 'VertexAttribSize': {
+ 'type': 'GLint',
+ 'valid': [
+ '1',
+ '2',
+ '3',
+ '4',
+ ],
+ 'invalid': [
+ '0',
+ '5',
+ ],
+ },
+ 'ZeroOnly': {
+ 'type': 'GLint',
+ 'valid': [
+ '0',
+ ],
+ 'invalid': [
+ '1',
+ ],
+ },
+ 'FalseOnly': {
+ 'type': 'GLboolean',
+ 'valid': [
+ 'false',
+ ],
+ 'invalid': [
+ 'true',
+ ],
+ },
+ 'ResetStatus': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_GUILTY_CONTEXT_RESET_ARB',
+ 'GL_INNOCENT_CONTEXT_RESET_ARB',
+ 'GL_UNKNOWN_CONTEXT_RESET_ARB',
+ ],
+ },
+}
+
+# This table specifies the different pepper interfaces that are supported for
+# GL commands. 'dev' is true if it's a dev interface.
+_PEPPER_INTERFACES = [
+ {'name': '', 'dev': False},
+ {'name': 'InstancedArrays', 'dev': False},
+ {'name': 'FramebufferBlit', 'dev': False},
+ {'name': 'FramebufferMultisample', 'dev': False},
+ {'name': 'ChromiumEnableFeature', 'dev': False},
+ {'name': 'ChromiumMapSub', 'dev': False},
+ {'name': 'Query', 'dev': False},
+]
+
+# This table specifies types and other special data for the commands that
+# will be generated.
+#
+# Must match function names specified in "cmd_buffer_functions.txt".
+#
+# cmd_comment: A comment added to the cmd format.
+# type: defines which handler will be used to generate code.
+# decoder_func: defines which function to call in the decoder to execute the
+# corresponding GL command. If not specified the GL command will
+# be called directly.
+# gl_test_func: GL function that is expected to be called when testing.
+# cmd_args: The arguments to use for the command. This overrides generating
+# them based on the GL function arguments.
+# a NonImmediate type is a type that stays a pointer even in
+# and immediate version of acommand.
+# gen_cmd: Whether or not this function geneates a command. Default = True.
+# immediate: Whether or not to generate an immediate command for the GL
+# function. The default is if there is exactly 1 pointer argument
+# in the GL function an immediate command is generated.
+# bucket: True to generate a bucket version of the command.
+# impl_func: Whether or not to generate the GLES2Implementation part of this
+# command.
+# impl_decl: Whether or not to generate the GLES2Implementation declaration
+# for this command.
+# needs_size: If true a data_size field is added to the command.
+# data_type: The type of data the command uses. For PUTn or PUT types.
+# count: The number of units per element. For PUTn or PUT types.
+# unit_test: If False no service side unit test will be generated.
+# client_test: If False no client side unit test will be generated.
+# expectation: If False the unit test will have no expected calls.
+# gen_func: Name of function that generates GL resource for corresponding
+# bind function.
+# states: array of states that get set by this function corresponding to
+# the given arguments
+# state_flag: name of flag that is set to true when function is called.
+# no_gl: no GL function is called.
+# valid_args: A dictionary of argument indices to args to use in unit tests
+# when they can not be automatically determined.
+# pepper_interface: The pepper interface that is used for this extension
+# invalid_test: False if no invalid test needed.
+# shadowed: True = the value is shadowed so no glGetXXX call will be made.
+# first_element_only: For PUT types, True if only the first element of an
+# array is used and we end up calling the single value
+# corresponding function. eg. TexParameteriv -> TexParameteri
+
+_FUNCTION_INFO = {
+ 'ActiveTexture': {
+ 'decoder_func': 'DoActiveTexture',
+ 'unit_test': False,
+ 'impl_func': False,
+ 'client_test': False,
+ },
+ 'AttachShader': {'decoder_func': 'DoAttachShader'},
+ 'BindAttribLocation': {'type': 'GLchar', 'bucket': True, 'needs_size': True},
+ 'BindBuffer': {
+ 'type': 'Bind',
+ 'decoder_func': 'DoBindBuffer',
+ 'gen_func': 'GenBuffersARB',
+ },
+ 'BindFramebuffer': {
+ 'type': 'Bind',
+ 'decoder_func': 'DoBindFramebuffer',
+ 'gl_test_func': 'glBindFramebufferEXT',
+ 'gen_func': 'GenFramebuffersEXT',
+ },
+ 'BindRenderbuffer': {
+ 'type': 'Bind',
+ 'decoder_func': 'DoBindRenderbuffer',
+ 'gl_test_func': 'glBindRenderbufferEXT',
+ 'gen_func': 'GenRenderbuffersEXT',
+ },
+ 'BindTexture': {
+ 'type': 'Bind',
+ 'decoder_func': 'DoBindTexture',
+ 'gen_func': 'GenTextures',
+ # TODO(gman): remove this once client side caching works.
+ 'client_test': False,
+ },
+ 'BlitFramebufferEXT': {
+ 'decoder_func': 'DoBlitFramebufferEXT',
+ 'unit_test': False,
+ 'extension': True,
+ 'pepper_interface': 'FramebufferBlit',
+ 'defer_reads': True,
+ 'defer_draws': True,
+ },
+ 'BufferData': {
+ 'type': 'Manual',
+ 'immediate': True,
+ 'client_test': False,
+ },
+ 'BufferSubData': {
+ 'type': 'Data',
+ 'client_test': False,
+ 'decoder_func': 'DoBufferSubData',
+ },
+ 'CheckFramebufferStatus': {
+ 'type': 'Is',
+ 'decoder_func': 'DoCheckFramebufferStatus',
+ 'gl_test_func': 'glCheckFramebufferStatusEXT',
+ 'error_value': 'GL_FRAMEBUFFER_UNSUPPORTED',
+ 'result': ['GLenum'],
+ },
+ 'Clear': {
+ 'decoder_func': 'DoClear',
+ 'defer_draws': True,
+ },
+ 'ClearColor': {
+ 'type': 'StateSet',
+ 'state': 'ClearColor',
+ },
+ 'ClearDepthf': {
+ 'type': 'StateSet',
+ 'state': 'ClearDepthf',
+ 'decoder_func': 'glClearDepth',
+ 'gl_test_func': 'glClearDepth',
+ 'valid_args': {
+ '0': '0.5f'
+ },
+ },
+ 'ColorMask': {
+ 'type': 'StateSet',
+ 'state': 'ColorMask',
+ 'no_gl': True,
+ 'expectation': False,
+ },
+ 'ConsumeTextureCHROMIUM': {
+ 'decoder_func': 'DoConsumeTextureCHROMIUM',
+ 'type': 'PUT',
+ 'data_type': 'GLbyte',
+ 'count': 64,
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'ClearStencil': {
+ 'type': 'StateSet',
+ 'state': 'ClearStencil',
+ },
+ 'EnableFeatureCHROMIUM': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'decoder_func': 'DoEnableFeatureCHROMIUM',
+ 'expectation': False,
+ 'cmd_args': 'GLuint bucket_id, GLint* result',
+ 'result': ['GLint'],
+ 'extension': True,
+ 'chromium': True,
+ 'pepper_interface': 'ChromiumEnableFeature',
+ },
+ 'CompileShader': {'decoder_func': 'DoCompileShader', 'unit_test': False},
+ 'CompressedTexImage2D': {
+ 'type': 'Manual',
+ 'immediate': True,
+ 'bucket': True,
+ },
+ 'CompressedTexSubImage2D': {
+ 'type': 'Data',
+ 'bucket': True,
+ 'decoder_func': 'DoCompressedTexSubImage2D',
+ },
+ 'CopyTexImage2D': {
+ 'decoder_func': 'DoCopyTexImage2D',
+ 'unit_test': False,
+ 'defer_reads': True,
+ },
+ 'CopyTexSubImage2D': {
+ 'decoder_func': 'DoCopyTexSubImage2D',
+ 'defer_reads': True,
+ },
+ 'CreateImageCHROMIUM': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLsizei width, GLsizei height, GLenum internalformat',
+ 'result': ['GLuint'],
+ 'client_test': False,
+ 'gen_cmd': False,
+ 'expectation': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'DestroyImageCHROMIUM': {
+ 'type': 'Manual',
+ 'immediate': True,
+ 'client_test': False,
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'GetImageParameterivCHROMIUM': {
+ 'type': 'Manual',
+ 'client_test': False,
+ 'gen_cmd': False,
+ 'expectation': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'CreateProgram': {
+ 'type': 'Create',
+ 'client_test': False,
+ },
+ 'CreateShader': {
+ 'type': 'Create',
+ 'client_test': False,
+ },
+ 'BlendColor': {
+ 'type': 'StateSet',
+ 'state': 'BlendColor',
+ },
+ 'BlendEquation': {
+ 'type': 'StateSetRGBAlpha',
+ 'state': 'BlendEquation',
+ 'valid_args': {
+ '0': 'GL_FUNC_SUBTRACT'
+ },
+ },
+ 'BlendEquationSeparate': {
+ 'type': 'StateSet',
+ 'state': 'BlendEquation',
+ 'valid_args': {
+ '0': 'GL_FUNC_SUBTRACT'
+ },
+ },
+ 'BlendFunc': {
+ 'type': 'StateSetRGBAlpha',
+ 'state': 'BlendFunc',
+ },
+ 'BlendFuncSeparate': {
+ 'type': 'StateSet',
+ 'state': 'BlendFunc',
+ },
+ 'SampleCoverage': {'decoder_func': 'DoSampleCoverage'},
+ 'StencilFunc': {
+ 'type': 'StateSetFrontBack',
+ 'state': 'StencilFunc',
+ },
+ 'StencilFuncSeparate': {
+ 'type': 'StateSetFrontBackSeparate',
+ 'state': 'StencilFunc',
+ },
+ 'StencilOp': {
+ 'type': 'StateSetFrontBack',
+ 'state': 'StencilOp',
+ 'valid_args': {
+ '1': 'GL_INCR'
+ },
+ },
+ 'StencilOpSeparate': {
+ 'type': 'StateSetFrontBackSeparate',
+ 'state': 'StencilOp',
+ 'valid_args': {
+ '1': 'GL_INCR'
+ },
+ },
+ 'Hint': {
+ 'type': 'StateSetNamedParameter',
+ 'state': 'Hint',
+ },
+ 'CullFace': {'type': 'StateSet', 'state': 'CullFace'},
+ 'FrontFace': {'type': 'StateSet', 'state': 'FrontFace'},
+ 'DepthFunc': {'type': 'StateSet', 'state': 'DepthFunc'},
+ 'LineWidth': {
+ 'type': 'StateSet',
+ 'state': 'LineWidth',
+ 'valid_args': {
+ '0': '0.5f'
+ },
+ },
+ 'PolygonOffset': {
+ 'type': 'StateSet',
+ 'state': 'PolygonOffset',
+ },
+ 'DeleteBuffers': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteBuffersARB',
+ 'resource_type': 'Buffer',
+ 'resource_types': 'Buffers',
+ },
+ 'DeleteFramebuffers': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteFramebuffersEXT',
+ 'resource_type': 'Framebuffer',
+ 'resource_types': 'Framebuffers',
+ },
+ 'DeleteProgram': {'type': 'Delete', 'decoder_func': 'DoDeleteProgram'},
+ 'DeleteRenderbuffers': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteRenderbuffersEXT',
+ 'resource_type': 'Renderbuffer',
+ 'resource_types': 'Renderbuffers',
+ },
+ 'DeleteShader': {'type': 'Delete', 'decoder_func': 'DoDeleteShader'},
+ 'DeleteSharedIdsCHROMIUM': {
+ 'type': 'Custom',
+ 'decoder_func': 'DoDeleteSharedIdsCHROMIUM',
+ 'impl_func': False,
+ 'expectation': False,
+ 'immediate': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'DeleteTextures': {
+ 'type': 'DELn',
+ 'resource_type': 'Texture',
+ 'resource_types': 'Textures',
+ },
+ 'DepthRangef': {
+ 'decoder_func': 'DoDepthRangef',
+ 'gl_test_func': 'glDepthRange',
+ },
+ 'DepthMask': {
+ 'type': 'StateSet',
+ 'state': 'DepthMask',
+ 'no_gl': True,
+ 'expectation': False,
+ },
+ 'DetachShader': {'decoder_func': 'DoDetachShader'},
+ 'Disable': {
+ 'decoder_func': 'DoDisable',
+ 'impl_func': False,
+ 'client_test': False,
+ },
+ 'DisableVertexAttribArray': {
+ 'decoder_func': 'DoDisableVertexAttribArray',
+ 'impl_decl': False,
+ },
+ 'DrawArrays': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumDrawMode mode, GLint first, GLsizei count',
+ 'defer_draws': True,
+ },
+ 'DrawElements': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumDrawMode mode, GLsizei count, '
+ 'GLenumIndexType type, GLuint index_offset',
+ 'client_test': False,
+ 'defer_draws': True,
+ },
+ 'Enable': {
+ 'decoder_func': 'DoEnable',
+ 'impl_func': False,
+ 'client_test': False,
+ },
+ 'EnableVertexAttribArray': {
+ 'decoder_func': 'DoEnableVertexAttribArray',
+ 'impl_decl': False,
+ },
+ 'Finish': {
+ 'impl_func': False,
+ 'client_test': False,
+ 'decoder_func': 'DoFinish',
+ 'defer_reads': True,
+ },
+ 'Flush': {
+ 'impl_func': False,
+ 'decoder_func': 'DoFlush',
+ },
+ 'FramebufferRenderbuffer': {
+ 'decoder_func': 'DoFramebufferRenderbuffer',
+ 'gl_test_func': 'glFramebufferRenderbufferEXT',
+ },
+ 'FramebufferTexture2D': {
+ 'decoder_func': 'DoFramebufferTexture2D',
+ 'gl_test_func': 'glFramebufferTexture2DEXT',
+ },
+ 'FramebufferTexture2DMultisampleEXT': {
+ 'decoder_func': 'DoFramebufferTexture2DMultisample',
+ 'gl_test_func': 'glFramebufferTexture2DMultisampleEXT',
+ 'expectation': False,
+ 'unit_test': False,
+ 'extension': True,
+ },
+ 'GenerateMipmap': {
+ 'decoder_func': 'DoGenerateMipmap',
+ 'gl_test_func': 'glGenerateMipmapEXT',
+ },
+ 'GenBuffers': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenBuffersARB',
+ 'resource_type': 'Buffer',
+ 'resource_types': 'Buffers',
+ },
+ 'GenMailboxCHROMIUM': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLuint bucket_id',
+ 'result': ['SizedResult<GLint>'],
+ 'client_test': False,
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'GenFramebuffers': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenFramebuffersEXT',
+ 'resource_type': 'Framebuffer',
+ 'resource_types': 'Framebuffers',
+ },
+ 'GenRenderbuffers': {
+ 'type': 'GENn', 'gl_test_func': 'glGenRenderbuffersEXT',
+ 'resource_type': 'Renderbuffer',
+ 'resource_types': 'Renderbuffers',
+ },
+ 'GenTextures': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenTextures',
+ 'resource_type': 'Texture',
+ 'resource_types': 'Textures',
+ },
+ 'GenSharedIdsCHROMIUM': {
+ 'type': 'Custom',
+ 'decoder_func': 'DoGenSharedIdsCHROMIUM',
+ 'impl_func': False,
+ 'expectation': False,
+ 'immediate': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'GetActiveAttrib': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'cmd_args':
+ 'GLidProgram program, GLuint index, uint32 name_bucket_id, '
+ 'void* result',
+ 'result': [
+ 'int32 success',
+ 'int32 size',
+ 'uint32 type',
+ ],
+ },
+ 'GetActiveUniform': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'cmd_args':
+ 'GLidProgram program, GLuint index, uint32 name_bucket_id, '
+ 'void* result',
+ 'result': [
+ 'int32 success',
+ 'int32 size',
+ 'uint32 type',
+ ],
+ },
+ 'GetAttachedShaders': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'cmd_args': 'GLidProgram program, void* result, uint32 result_size',
+ 'result': ['SizedResult<GLuint>'],
+ },
+ 'GetAttribLocation': {
+ 'type': 'HandWritten',
+ 'immediate': True,
+ 'bucket': True,
+ 'needs_size': True,
+ 'cmd_args':
+ 'GLidProgram program, const char* name, NonImmediate GLint* location',
+ 'result': ['GLint'],
+ },
+ 'GetBooleanv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLboolean>'],
+ 'decoder_func': 'DoGetBooleanv',
+ 'gl_test_func': 'glGetBooleanv',
+ },
+ 'GetBufferParameteriv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLint>'],
+ 'decoder_func': 'DoGetBufferParameteriv',
+ 'expectation': False,
+ 'shadowed': True,
+ },
+ 'GetError': {
+ 'type': 'Is',
+ 'decoder_func': 'GetErrorState()->GetGLError',
+ 'impl_func': False,
+ 'result': ['GLenum'],
+ 'client_test': False,
+ },
+ 'GetFloatv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLfloat>'],
+ 'decoder_func': 'DoGetFloatv',
+ 'gl_test_func': 'glGetFloatv',
+ },
+ 'GetFramebufferAttachmentParameteriv': {
+ 'type': 'GETn',
+ 'decoder_func': 'DoGetFramebufferAttachmentParameteriv',
+ 'gl_test_func': 'glGetFramebufferAttachmentParameterivEXT',
+ 'result': ['SizedResult<GLint>'],
+ },
+ 'GetIntegerv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLint>'],
+ 'decoder_func': 'DoGetIntegerv',
+ 'client_test': False,
+ },
+ 'GetMaxValueInBufferCHROMIUM': {
+ 'type': 'Is',
+ 'decoder_func': 'DoGetMaxValueInBufferCHROMIUM',
+ 'result': ['GLuint'],
+ 'unit_test': False,
+ 'client_test': False,
+ 'extension': True,
+ 'chromium': True,
+ 'impl_func': False,
+ },
+ 'GetMultipleIntegervCHROMIUM': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'expectation': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'GetProgramiv': {
+ 'type': 'GETn',
+ 'decoder_func': 'DoGetProgramiv',
+ 'result': ['SizedResult<GLint>'],
+ 'expectation': False,
+ },
+ 'GetProgramInfoCHROMIUM': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'expectation': False,
+ 'impl_func': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ 'cmd_args': 'GLidProgram program, uint32 bucket_id',
+ 'result': [
+ 'uint32 link_status',
+ 'uint32 num_attribs',
+ 'uint32 num_uniforms',
+ ],
+ },
+ 'GetProgramInfoLog': {
+ 'type': 'STRn',
+ 'expectation': False,
+ },
+ 'GetRenderbufferParameteriv': {
+ 'type': 'GETn',
+ 'decoder_func': 'DoGetRenderbufferParameteriv',
+ 'gl_test_func': 'glGetRenderbufferParameterivEXT',
+ 'result': ['SizedResult<GLint>'],
+ },
+ 'GetShaderiv': {
+ 'type': 'GETn',
+ 'decoder_func': 'DoGetShaderiv',
+ 'result': ['SizedResult<GLint>'],
+ },
+ 'GetShaderInfoLog': {
+ 'type': 'STRn',
+ 'get_len_func': 'glGetShaderiv',
+ 'get_len_enum': 'GL_INFO_LOG_LENGTH',
+ 'unit_test': False,
+ },
+ 'GetShaderPrecisionFormat': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'cmd_args':
+ 'GLenumShaderType shadertype, GLenumShaderPrecision precisiontype, '
+ 'void* result',
+ 'result': [
+ 'int32 success',
+ 'int32 min_range',
+ 'int32 max_range',
+ 'int32 precision',
+ ],
+ },
+ 'GetShaderSource': {
+ 'type': 'STRn',
+ 'get_len_func': 'DoGetShaderiv',
+ 'get_len_enum': 'GL_SHADER_SOURCE_LENGTH',
+ 'unit_test': False,
+ 'client_test': False,
+ },
+ 'GetString': {
+ 'type': 'Custom',
+ 'client_test': False,
+ 'cmd_args': 'GLenumStringType name, uint32 bucket_id',
+ },
+ 'GetTexParameterfv': {'type': 'GETn', 'result': ['SizedResult<GLfloat>']},
+ 'GetTexParameteriv': {'type': 'GETn', 'result': ['SizedResult<GLint>']},
+ 'GetTranslatedShaderSourceANGLE': {
+ 'type': 'STRn',
+ 'get_len_func': 'DoGetShaderiv',
+ 'get_len_enum': 'GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE',
+ 'unit_test': False,
+ 'extension': True,
+ },
+ 'GetUniformfv': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'result': ['SizedResult<GLfloat>'],
+ },
+ 'GetUniformiv': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'result': ['SizedResult<GLint>'],
+ },
+ 'GetUniformLocation': {
+ 'type': 'HandWritten',
+ 'immediate': True,
+ 'bucket': True,
+ 'needs_size': True,
+ 'cmd_args':
+ 'GLidProgram program, const char* name, NonImmediate GLint* location',
+ 'result': ['GLint'],
+ },
+ 'GetVertexAttribfv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLfloat>'],
+ 'impl_decl': False,
+ 'decoder_func': 'DoGetVertexAttribfv',
+ 'expectation': False,
+ 'client_test': False,
+ },
+ 'GetVertexAttribiv': {
+ 'type': 'GETn',
+ 'result': ['SizedResult<GLint>'],
+ 'impl_decl': False,
+ 'decoder_func': 'DoGetVertexAttribiv',
+ 'expectation': False,
+ 'client_test': False,
+ },
+ 'GetVertexAttribPointerv': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'result': ['SizedResult<GLuint>'],
+ 'client_test': False,
+ },
+ 'IsBuffer': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsBuffer',
+ 'expectation': False,
+ },
+ 'IsEnabled': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsEnabled',
+ 'impl_func': False,
+ 'expectation': False,
+ },
+ 'IsFramebuffer': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsFramebuffer',
+ 'expectation': False,
+ },
+ 'IsProgram': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsProgram',
+ 'expectation': False,
+ },
+ 'IsRenderbuffer': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsRenderbuffer',
+ 'expectation': False,
+ },
+ 'IsShader': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsShader',
+ 'expectation': False,
+ },
+ 'IsTexture': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsTexture',
+ 'expectation': False,
+ },
+ 'LinkProgram': {
+ 'decoder_func': 'DoLinkProgram',
+ 'impl_func': False,
+ },
+ 'MapBufferCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'MapBufferSubDataCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ 'pepper_interface': 'ChromiumMapSub',
+ },
+ 'MapImageCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'MapTexSubImage2DCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ 'pepper_interface': 'ChromiumMapSub',
+ },
+ 'PixelStorei': {'type': 'Manual'},
+ 'PostSubBufferCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'unit_test': False,
+ 'client_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'ProduceTextureCHROMIUM': {
+ 'decoder_func': 'DoProduceTextureCHROMIUM',
+ 'type': 'PUT',
+ 'data_type': 'GLbyte',
+ 'count': 64,
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'RenderbufferStorage': {
+ 'decoder_func': 'DoRenderbufferStorage',
+ 'gl_test_func': 'glRenderbufferStorageEXT',
+ 'expectation': False,
+ },
+ 'RenderbufferStorageMultisampleEXT': {
+ 'decoder_func': 'DoRenderbufferStorageMultisample',
+ 'gl_test_func': 'glRenderbufferStorageMultisampleEXT',
+ 'expectation': False,
+ 'unit_test': False,
+ 'extension': True,
+ 'pepper_interface': 'FramebufferMultisample',
+ },
+ 'ReadPixels': {
+ 'cmd_comment':
+ '// ReadPixels has the result separated from the pixel buffer so that\n'
+ '// it is easier to specify the result going to some specific place\n'
+ '// that exactly fits the rectangle of pixels.\n',
+ 'type': 'Custom',
+ 'immediate': False,
+ 'impl_func': False,
+ 'client_test': False,
+ 'cmd_args':
+ 'GLint x, GLint y, GLsizei width, GLsizei height, '
+ 'GLenumReadPixelFormat format, GLenumReadPixelType type, '
+ 'uint32 pixels_shm_id, uint32 pixels_shm_offset, '
+ 'uint32 result_shm_id, uint32 result_shm_offset, '
+ 'GLboolean async',
+ 'result': ['uint32'],
+ 'defer_reads': True,
+ },
+ 'RegisterSharedIdsCHROMIUM': {
+ 'type': 'Custom',
+ 'decoder_func': 'DoRegisterSharedIdsCHROMIUM',
+ 'impl_func': False,
+ 'expectation': False,
+ 'immediate': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'ReleaseShaderCompiler': {
+ 'decoder_func': 'DoReleaseShaderCompiler',
+ 'unit_test': False,
+ },
+ 'ShaderBinary': {
+ 'type': 'Custom',
+ 'client_test': False,
+ },
+ 'ShaderSource': {
+ 'type': 'Manual',
+ 'immediate': True,
+ 'bucket': True,
+ 'needs_size': True,
+ 'client_test': False,
+ 'cmd_args':
+ 'GLuint shader, const char* data',
+ },
+ 'StencilMask': {
+ 'type': 'StateSetFrontBack',
+ 'state': 'StencilMask',
+ 'no_gl': True,
+ 'expectation': False,
+ },
+ 'StencilMaskSeparate': {
+ 'type': 'StateSetFrontBackSeparate',
+ 'state': 'StencilMask',
+ 'no_gl': True,
+ 'expectation': False,
+ },
+ 'SwapBuffers': {
+ 'impl_func': False,
+ 'decoder_func': 'DoSwapBuffers',
+ 'unit_test': False,
+ 'client_test': False,
+ 'extension': True,
+ },
+ 'TexImage2D': {
+ 'type': 'Manual',
+ 'immediate': True,
+ 'client_test': False,
+ },
+ 'TexParameterf': {
+ 'decoder_func': 'DoTexParameterf',
+ 'gl_test_func': 'glTexParameteri',
+ 'valid_args': {
+ '2': 'GL_NEAREST'
+ },
+ },
+ 'TexParameteri': {
+ 'decoder_func': 'DoTexParameteri',
+ 'valid_args': {
+ '2': 'GL_NEAREST'
+ },
+ },
+ 'TexParameterfv': {
+ 'type': 'PUT',
+ 'data_type': 'GLfloat',
+ 'data_value': 'GL_NEAREST',
+ 'count': 1,
+ 'decoder_func': 'DoTexParameterfv',
+ 'gl_test_func': 'glTexParameteri',
+ 'first_element_only': True,
+ },
+ 'TexParameteriv': {
+ 'type': 'PUT',
+ 'data_type': 'GLint',
+ 'data_value': 'GL_NEAREST',
+ 'count': 1,
+ 'decoder_func': 'DoTexParameteriv',
+ 'gl_test_func': 'glTexParameteri',
+ 'first_element_only': True,
+ },
+ 'TexSubImage2D': {
+ 'type': 'Manual',
+ 'immediate': True,
+ 'client_test': False,
+ 'cmd_args': 'GLenumTextureTarget target, GLint level, '
+ 'GLint xoffset, GLint yoffset, '
+ 'GLsizei width, GLsizei height, '
+ 'GLenumTextureFormat format, GLenumPixelType type, '
+ 'const void* pixels, GLboolean internal'
+ },
+ 'Uniform1f': {'type': 'PUTXn', 'data_type': 'GLfloat', 'count': 1},
+ 'Uniform1fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 1,
+ 'decoder_func': 'DoUniform1fv',
+ },
+ 'Uniform1i': {'decoder_func': 'DoUniform1i', 'unit_test': False},
+ 'Uniform1iv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLint',
+ 'count': 1,
+ 'decoder_func': 'DoUniform1iv',
+ 'unit_test': False,
+ },
+ 'Uniform2i': {'type': 'PUTXn', 'data_type': 'GLint', 'count': 2},
+ 'Uniform2f': {'type': 'PUTXn', 'data_type': 'GLfloat', 'count': 2},
+ 'Uniform2fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 2,
+ 'decoder_func': 'DoUniform2fv',
+ },
+ 'Uniform2iv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLint',
+ 'count': 2,
+ 'decoder_func': 'DoUniform2iv',
+ },
+ 'Uniform3i': {'type': 'PUTXn', 'data_type': 'GLint', 'count': 3},
+ 'Uniform3f': {'type': 'PUTXn', 'data_type': 'GLfloat', 'count': 3},
+ 'Uniform3fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 3,
+ 'decoder_func': 'DoUniform3fv',
+ },
+ 'Uniform3iv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLint',
+ 'count': 3,
+ 'decoder_func': 'DoUniform3iv',
+ },
+ 'Uniform4i': {'type': 'PUTXn', 'data_type': 'GLint', 'count': 4},
+ 'Uniform4f': {'type': 'PUTXn', 'data_type': 'GLfloat', 'count': 4},
+ 'Uniform4fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 4,
+ 'decoder_func': 'DoUniform4fv',
+ },
+ 'Uniform4iv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLint',
+ 'count': 4,
+ 'decoder_func': 'DoUniform4iv',
+ },
+ 'UniformMatrix2fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 4,
+ 'decoder_func': 'DoUniformMatrix2fv',
+ },
+ 'UniformMatrix3fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 9,
+ 'decoder_func': 'DoUniformMatrix3fv',
+ },
+ 'UniformMatrix4fv': {
+ 'type': 'PUTn',
+ 'data_type': 'GLfloat',
+ 'count': 16,
+ 'decoder_func': 'DoUniformMatrix4fv',
+ },
+ 'UnmapBufferCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'UnmapBufferSubDataCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ 'pepper_interface': 'ChromiumMapSub',
+ },
+ 'UnmapImageCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'UnmapTexSubImage2DCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ 'pepper_interface': 'ChromiumMapSub',
+ },
+ 'UseProgram': {
+ 'decoder_func': 'DoUseProgram',
+ 'impl_func': False,
+ 'unit_test': False,
+ },
+ 'ValidateProgram': {'decoder_func': 'DoValidateProgram'},
+ 'VertexAttrib1f': {'decoder_func': 'DoVertexAttrib1f'},
+ 'VertexAttrib1fv': {
+ 'type': 'PUT',
+ 'data_type': 'GLfloat',
+ 'count': 1,
+ 'decoder_func': 'DoVertexAttrib1fv',
+ },
+ 'VertexAttrib2f': {'decoder_func': 'DoVertexAttrib2f'},
+ 'VertexAttrib2fv': {
+ 'type': 'PUT',
+ 'data_type': 'GLfloat',
+ 'count': 2,
+ 'decoder_func': 'DoVertexAttrib2fv',
+ },
+ 'VertexAttrib3f': {'decoder_func': 'DoVertexAttrib3f'},
+ 'VertexAttrib3fv': {
+ 'type': 'PUT',
+ 'data_type': 'GLfloat',
+ 'count': 3,
+ 'decoder_func': 'DoVertexAttrib3fv',
+ },
+ 'VertexAttrib4f': {'decoder_func': 'DoVertexAttrib4f'},
+ 'VertexAttrib4fv': {
+ 'type': 'PUT',
+ 'data_type': 'GLfloat',
+ 'count': 4,
+ 'decoder_func': 'DoVertexAttrib4fv',
+ },
+ 'VertexAttribPointer': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLuint indx, GLintVertexAttribSize size, '
+ 'GLenumVertexAttribType type, GLboolean normalized, '
+ 'GLsizei stride, GLuint offset',
+ 'client_test': False,
+ },
+ 'Scissor': {
+ 'type': 'StateSet',
+ 'state': 'Scissor',
+ },
+ 'Viewport': {
+ 'decoder_func': 'DoViewport',
+ },
+ 'ResizeCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'GetRequestableExtensionsCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'immediate': False,
+ 'cmd_args': 'uint32 bucket_id',
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'RequestExtensionCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'immediate': False,
+ 'client_test': False,
+ 'cmd_args': 'uint32 bucket_id',
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'RateLimitOffscreenContextCHROMIUM': {
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'CreateStreamTextureCHROMIUM': {
+ 'type': 'Custom',
+ 'cmd_args': 'GLuint client_id, void* result',
+ 'result': ['GLuint'],
+ 'immediate': False,
+ 'impl_func': False,
+ 'expectation': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'DestroyStreamTextureCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'expectation': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'TexImageIOSurface2DCHROMIUM': {
+ 'decoder_func': 'DoTexImageIOSurface2DCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'CopyTextureCHROMIUM': {
+ 'decoder_func': 'DoCopyTextureCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'TexStorage2DEXT': {
+ 'unit_test': False,
+ 'extension': True,
+ 'decoder_func': 'DoTexStorage2DEXT',
+ },
+ 'DrawArraysInstancedANGLE': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumDrawMode mode, GLint first, GLsizei count, '
+ 'GLsizei primcount',
+ 'extension': True,
+ 'unit_test': False,
+ 'pepper_interface': 'InstancedArrays',
+ 'defer_draws': True,
+ },
+ 'DrawBuffersEXT': {
+ 'type': 'PUTn',
+ 'decoder_func': 'DoDrawBuffersEXT',
+ 'data_type': 'GLenum',
+ 'count': 1,
+ 'client_test': False,
+ 'unit_test': False,
+ 'extension': True,
+ },
+ 'DrawElementsInstancedANGLE': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumDrawMode mode, GLsizei count, '
+ 'GLenumIndexType type, GLuint index_offset, GLsizei primcount',
+ 'extension': True,
+ 'unit_test': False,
+ 'client_test': False,
+ 'pepper_interface': 'InstancedArrays',
+ 'defer_draws': True,
+ },
+ 'VertexAttribDivisorANGLE': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLuint index, GLuint divisor',
+ 'extension': True,
+ 'unit_test': False,
+ 'pepper_interface': 'InstancedArrays',
+ },
+ 'GenQueriesEXT': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenQueriesARB',
+ 'resource_type': 'Query',
+ 'resource_types': 'Queries',
+ 'unit_test': False,
+ 'pepper_interface': 'Query',
+ },
+ 'DeleteQueriesEXT': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteQueriesARB',
+ 'resource_type': 'Query',
+ 'resource_types': 'Queries',
+ 'unit_test': False,
+ 'pepper_interface': 'Query',
+ },
+ 'IsQueryEXT': {
+ 'gen_cmd': False,
+ 'client_test': False,
+ 'pepper_interface': 'Query',
+ },
+ 'BeginQueryEXT': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumQueryTarget target, GLidQuery id, void* sync_data',
+ 'immediate': False,
+ 'gl_test_func': 'glBeginQuery',
+ 'pepper_interface': 'Query',
+ },
+ 'EndQueryEXT': {
+ 'type': 'Manual',
+ 'cmd_args': 'GLenumQueryTarget target, GLuint submit_count',
+ 'gl_test_func': 'glEndnQuery',
+ 'client_test': False,
+ 'pepper_interface': 'Query',
+ },
+ 'GetQueryivEXT': {
+ 'gen_cmd': False,
+ 'client_test': False,
+ 'gl_test_func': 'glGetQueryiv',
+ 'pepper_interface': 'Query',
+ },
+ 'GetQueryObjectuivEXT': {
+ 'gen_cmd': False,
+ 'client_test': False,
+ 'gl_test_func': 'glGetQueryObjectuiv',
+ 'pepper_interface': 'Query',
+ },
+ 'BindUniformLocationCHROMIUM': {
+ 'type': 'GLchar',
+ 'bucket': True,
+ 'needs_size': True,
+ 'gl_test_func': 'DoBindUniformLocationCHROMIUM',
+ },
+ 'InsertEventMarkerEXT': {
+ 'type': 'GLcharN',
+ 'decoder_func': 'DoInsertEventMarkerEXT',
+ 'expectation': False,
+ },
+ 'PushGroupMarkerEXT': {
+ 'type': 'GLcharN',
+ 'decoder_func': 'DoPushGroupMarkerEXT',
+ 'expectation': False,
+ },
+ 'PopGroupMarkerEXT': {
+ 'decoder_func': 'DoPopGroupMarkerEXT',
+ 'expectation': False,
+ 'impl_func': False,
+ },
+
+ 'GenVertexArraysOES': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenVertexArraysOES',
+ 'resource_type': 'VertexArray',
+ 'resource_types': 'VertexArrays',
+ 'unit_test': False,
+ },
+ 'BindVertexArrayOES': {
+ 'type': 'Bind',
+ 'gl_test_func': 'glBindVertexArrayOES',
+ 'decoder_func': 'DoBindVertexArrayOES',
+ 'gen_func': 'GenVertexArraysOES',
+ 'unit_test': False,
+ 'client_test': False,
+ },
+ 'DeleteVertexArraysOES': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteVertexArraysOES',
+ 'resource_type': 'VertexArray',
+ 'resource_types': 'VertexArrays',
+ 'unit_test': False,
+ },
+ 'IsVertexArrayOES': {
+ 'type': 'Is',
+ 'gl_test_func': 'glIsVertexArrayOES',
+ 'decoder_func': 'DoIsVertexArrayOES',
+ 'expectation': False,
+ 'unit_test': False,
+ },
+ 'BindTexImage2DCHROMIUM': {
+ 'decoder_func': 'DoBindTexImage2DCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'ReleaseTexImage2DCHROMIUM': {
+ 'decoder_func': 'DoReleaseTexImage2DCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'ShallowFinishCHROMIUM': {
+ 'impl_func': False,
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'ShallowFlushCHROMIUM': {
+ 'impl_func': False,
+ 'gen_cmd': False,
+ 'extension': True,
+ 'chromium': True,
+ 'client_test': False,
+ },
+ 'TraceBeginCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': False,
+ 'immediate': False,
+ 'client_test': False,
+ 'cmd_args': 'GLuint bucket_id',
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'TraceEndCHROMIUM': {
+ 'impl_func': False,
+ 'immediate': False,
+ 'client_test': False,
+ 'decoder_func': 'DoTraceEndCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'AsyncTexImage2DCHROMIUM': {
+ 'type': 'Manual',
+ 'immediate': False,
+ 'client_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'AsyncTexSubImage2DCHROMIUM': {
+ 'type': 'Manual',
+ 'immediate': False,
+ 'client_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'WaitAsyncTexImage2DCHROMIUM': {
+ 'type': 'Manual',
+ 'immediate': False,
+ 'client_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'DiscardFramebufferEXT': {
+ 'type': 'PUTn',
+ 'count': 1,
+ 'data_type': 'GLenum',
+ 'cmd_args': 'GLenum target, GLsizei count, '
+ 'const GLenum* attachments',
+ 'decoder_func': 'DoDiscardFramebufferEXT',
+ 'unit_test': False,
+ 'client_test': False,
+ 'extension': True,
+ },
+ 'LoseContextCHROMIUM': {
+ 'type': 'Manual',
+ 'impl_func': True,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'InsertSyncPointCHROMIUM': {
+ 'type': 'HandWritten',
+ 'impl_func': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'WaitSyncPointCHROMIUM': {
+ 'type': 'Custom',
+ 'impl_func': True,
+ 'extension': True,
+ 'chromium': True,
+ },
+}
+
+
+def Grouper(n, iterable, fillvalue=None):
+ """Collect data into fixed-length chunks or blocks"""
+ args = [iter(iterable)] * n
+ return itertools.izip_longest(fillvalue=fillvalue, *args)
+
+
+def SplitWords(input_string):
+ """Transforms a input_string into a list of lower-case components.
+
+ Args:
+ input_string: the input string.
+
+ Returns:
+ a list of lower-case words.
+ """
+ if input_string.find('_') > -1:
+ # 'some_TEXT_' -> 'some text'
+ return input_string.replace('_', ' ').strip().lower().split()
+ else:
+ if re.search('[A-Z]', input_string) and re.search('[a-z]', input_string):
+ # mixed case.
+ # look for capitalization to cut input_strings
+ # 'SomeText' -> 'Some Text'
+ input_string = re.sub('([A-Z])', r' \1', input_string).strip()
+ # 'Vector3' -> 'Vector 3'
+ input_string = re.sub('([^0-9])([0-9])', r'\1 \2', input_string)
+ return input_string.lower().split()
+
+
+def Lower(words):
+ """Makes a lower-case identifier from words.
+
+ Args:
+ words: a list of lower-case words.
+
+ Returns:
+ the lower-case identifier.
+ """
+ return '_'.join(words)
+
+
+def ToUnderscore(input_string):
+ """converts CamelCase to camel_case."""
+ words = SplitWords(input_string)
+ return Lower(words)
+
+
+class CWriter(object):
+ """Writes to a file formatting it for Google's style guidelines."""
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.file_num = 0
+ self.content = []
+
+ def SetFileNum(self, num):
+ """Used to help write number files and tests."""
+ self.file_num = num
+
+ def Write(self, string):
+ """Writes a string to a file spliting if it's > 80 characters."""
+ lines = string.splitlines()
+ num_lines = len(lines)
+ for ii in range(0, num_lines):
+ self.__WriteLine(lines[ii], ii < (num_lines - 1) or string[-1] == '\n')
+
+ def __FindSplit(self, string):
+ """Finds a place to split a string."""
+ splitter = string.find('=')
+ if splitter >= 1 and not string[splitter + 1] == '=' and splitter < 80:
+ return splitter
+ # parts = string.split('(')
+ parts = re.split("(?<=[^\"])\((?!\")", string)
+ fptr = re.compile('\*\w*\)')
+ if len(parts) > 1:
+ splitter = len(parts[0])
+ for ii in range(1, len(parts)):
+ # Don't split on the dot in "if (.condition)".
+ if (not parts[ii - 1][-3:] == "if " and
+ # Don't split "(.)" or "(.*fptr)".
+ (len(parts[ii]) > 0 and
+ not parts[ii][0] == ")" and not fptr.match(parts[ii]))
+ and splitter < 80):
+ return splitter
+ splitter += len(parts[ii]) + 1
+ done = False
+ end = len(string)
+ last_splitter = -1
+ while not done:
+ splitter = string[0:end].rfind(',')
+ if splitter < 0 or (splitter > 0 and string[splitter - 1] == '"'):
+ return last_splitter
+ elif splitter >= 80:
+ end = splitter
+ else:
+ return splitter
+
+ def __WriteLine(self, line, ends_with_eol):
+ """Given a signle line, writes it to a file, splitting if it's > 80 chars"""
+ if len(line) >= 80:
+ i = self.__FindSplit(line)
+ if i > 0:
+ line1 = line[0:i + 1]
+ if line1[-1] == ' ':
+ line1 = line1[:-1]
+ lineend = ''
+ if line1[0] == '#':
+ lineend = ' \\'
+ nolint = ''
+ if len(line1) > 80:
+ nolint = ' // NOLINT'
+ self.__AddLine(line1 + nolint + lineend + '\n')
+ match = re.match("( +)", line1)
+ indent = ""
+ if match:
+ indent = match.group(1)
+ splitter = line[i]
+ if not splitter == ',':
+ indent = " " + indent
+ self.__WriteLine(indent + line[i + 1:].lstrip(), True)
+ return
+ nolint = ''
+ if len(line) > 80:
+ nolint = ' // NOLINT'
+ self.__AddLine(line + nolint)
+ if ends_with_eol:
+ self.__AddLine('\n')
+
+ def __AddLine(self, line):
+ self.content.append(line)
+
+ def Close(self):
+ """Close the file."""
+ content = "".join(self.content)
+ write_file = True
+ if os.path.exists(self.filename):
+ old_file = open(self.filename, "rb");
+ old_content = old_file.read()
+ old_file.close();
+ if content == old_content:
+ write_file = False
+ if write_file:
+ file = open(self.filename, "wb")
+ file.write(content)
+ file.close()
+
+
+class CHeaderWriter(CWriter):
+ """Writes a C Header file."""
+
+ _non_alnum_re = re.compile(r'[^a-zA-Z0-9]')
+
+ def __init__(self, filename, file_comment = None):
+ CWriter.__init__(self, filename)
+
+ base = os.path.abspath(filename)
+ while os.path.basename(base) != 'src':
+ new_base = os.path.dirname(base)
+ assert new_base != base # Prevent infinite loop.
+ base = new_base
+
+ hpath = os.path.relpath(filename, base)
+ self.guard = self._non_alnum_re.sub('_', hpath).upper() + '_'
+
+ self.Write(_LICENSE)
+ self.Write(_DO_NOT_EDIT_WARNING)
+ if not file_comment == None:
+ self.Write(file_comment)
+ self.Write("#ifndef %s\n" % self.guard)
+ self.Write("#define %s\n\n" % self.guard)
+
+ def Close(self):
+ self.Write("#endif // %s\n\n" % self.guard)
+ CWriter.Close(self)
+
+class TypeHandler(object):
+ """This class emits code for a particular type of function."""
+
+ _remove_expected_call_re = re.compile(r' EXPECT_CALL.*?;\n', re.S)
+
+ def __init__(self):
+ pass
+
+ def InitFunction(self, func):
+ """Add or adjust anything type specific for this function."""
+ if func.GetInfo('needs_size') and not func.name.endswith('Bucket'):
+ func.AddCmdArg(DataSizeArgument('data_size'))
+
+ def AddImmediateFunction(self, generator, func):
+ """Adds an immediate version of a function."""
+ # Generate an immediate command if there is only 1 pointer arg.
+ immediate = func.GetInfo('immediate') # can be True, False or None
+ if immediate == True or immediate == None:
+ if func.num_pointer_args == 1 or immediate:
+ generator.AddFunction(ImmediateFunction(func))
+
+ def AddBucketFunction(self, generator, func):
+ """Adds a bucket version of a function."""
+ # Generate an immediate command if there is only 1 pointer arg.
+ bucket = func.GetInfo('bucket') # can be True, False or None
+ if bucket:
+ generator.AddFunction(BucketFunction(func))
+
+ def WriteStruct(self, func, file):
+ """Writes a structure that matches the arguments to a function."""
+ comment = func.GetInfo('cmd_comment')
+ if not comment == None:
+ file.Write(comment)
+ file.Write("struct %s {\n" % func.name)
+ file.Write(" typedef %s ValueType;\n" % func.name)
+ file.Write(" static const CommandId kCmdId = k%s;\n" % func.name)
+ func.WriteCmdArgFlag(file)
+ file.Write("\n")
+ result = func.GetInfo('result')
+ if not result == None:
+ if len(result) == 1:
+ file.Write(" typedef %s Result;\n\n" % result[0])
+ else:
+ file.Write(" struct Result {\n")
+ for line in result:
+ file.Write(" %s;\n" % line)
+ file.Write(" };\n\n")
+
+ func.WriteCmdComputeSize(file)
+ func.WriteCmdSetHeader(file)
+ func.WriteCmdInit(file)
+ func.WriteCmdSet(file)
+
+ file.Write(" gpu::CommandHeader header;\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s %s;\n" % (arg.cmd_type, arg.name))
+ file.Write("};\n")
+ file.Write("\n")
+
+ size = len(args) * _SIZE_OF_UINT32 + _SIZE_OF_COMMAND_HEADER
+ file.Write("COMPILE_ASSERT(sizeof(%s) == %d,\n" % (func.name, size))
+ file.Write(" Sizeof_%s_is_not_%d);\n" % (func.name, size))
+ file.Write("COMPILE_ASSERT(offsetof(%s, header) == 0,\n" % func.name)
+ file.Write(" OffsetOf_%s_header_not_0);\n" % func.name)
+ offset = _SIZE_OF_COMMAND_HEADER
+ for arg in args:
+ file.Write("COMPILE_ASSERT(offsetof(%s, %s) == %d,\n" %
+ (func.name, arg.name, offset))
+ file.Write(" OffsetOf_%s_%s_not_%d);\n" %
+ (func.name, arg.name, offset))
+ offset += _SIZE_OF_UINT32
+ if not result == None and len(result) > 1:
+ offset = 0;
+ for line in result:
+ parts = line.split()
+ name = parts[-1]
+ check = """
+COMPILE_ASSERT(offsetof(%(cmd_name)s::Result, %(field_name)s) == %(offset)d,
+ OffsetOf_%(cmd_name)s_Result_%(field_name)s_not_%(offset)d);
+"""
+ file.Write((check.strip() + "\n") % {
+ 'cmd_name': func.name,
+ 'field_name': name,
+ 'offset': offset,
+ })
+ offset += _SIZE_OF_UINT32
+ file.Write("\n")
+
+ def WriteHandlerImplementation(self, func, file):
+ """Writes the handler implementation for this command."""
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+
+ def WriteCmdSizeTest(self, func, file):
+ """Writes the size test for a command."""
+ file.Write(" EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);\n")
+
+ def WriteFormatTest(self, func, file):
+ """Writes a format test for a command."""
+ file.Write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+ file.Write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
+ (func.name, func.name))
+ file.Write(" void* next_cmd = cmd.Set(\n")
+ file.Write(" &cmd")
+ args = func.GetCmdArgs()
+ for value, arg in enumerate(args):
+ file.Write(",\n static_cast<%s>(%d)" % (arg.type, value + 11))
+ file.Write(");\n")
+ file.Write(" EXPECT_EQ(static_cast<uint32>(cmds::%s::kCmdId),\n" %
+ func.name)
+ file.Write(" cmd.header.command);\n")
+ func.type_handler.WriteCmdSizeTest(func, file)
+ for value, arg in enumerate(args):
+ file.Write(" EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" %
+ (arg.type, value + 11, arg.name))
+ file.Write(" CheckBytesWrittenMatchesExpectedSize(\n")
+ file.Write(" next_cmd, sizeof(cmd));\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Writes a format test for an immediate version of a command."""
+ pass
+
+ def WriteBucketFormatTest(self, func, file):
+ """Writes a format test for a bucket version of a command."""
+ pass
+
+ def WriteGetDataSizeCode(self, func, file):
+ """Writes the code to set data_size used in validation"""
+ pass
+
+ def WriteImmediateCmdSizeTest(self, func, file):
+ """Writes a size test for an immediate version of a command."""
+ file.Write(" // TODO(gman): Compute correct size.\n")
+ file.Write(" EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);\n")
+
+ def WriteImmediateHandlerImplementation (self, func, file):
+ """Writes the handler impl for the immediate version of a command."""
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+
+ def WriteBucketHandlerImplementation (self, func, file):
+ """Writes the handler impl for the bucket version of a command."""
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+
+ def WriteServiceImplementation(self, func, file):
+ """Writes the service implementation for a command."""
+ file.Write(
+ "error::Error GLES2DecoderImpl::Handle%s(\n" % func.name)
+ file.Write(
+ " uint32 immediate_data_size, const gles2::cmds::%s& c) {\n" %
+ func.name)
+ self.WriteHandlerDeferReadWrite(func, file);
+ if len(func.GetOriginalArgs()) > 0:
+ last_arg = func.GetLastOriginalArg()
+ all_but_last_arg = func.GetOriginalArgs()[:-1]
+ for arg in all_but_last_arg:
+ arg.WriteGetCode(file)
+ self.WriteGetDataSizeCode(func, file)
+ last_arg.WriteGetCode(file)
+ func.WriteHandlerValidation(file)
+ func.WriteHandlerImplementation(file)
+ file.Write(" return error::kNoError;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteImmediateServiceImplementation(self, func, file):
+ """Writes the service implementation for an immediate version of command."""
+ file.Write(
+ "error::Error GLES2DecoderImpl::Handle%s(\n" % func.name)
+ file.Write(
+ " uint32 immediate_data_size, const gles2::cmds::%s& c) {\n" %
+ func.name)
+ self.WriteHandlerDeferReadWrite(func, file);
+ last_arg = func.GetLastOriginalArg()
+ all_but_last_arg = func.GetOriginalArgs()[:-1]
+ for arg in all_but_last_arg:
+ arg.WriteGetCode(file)
+ self.WriteGetDataSizeCode(func, file)
+ last_arg.WriteGetCode(file)
+ func.WriteHandlerValidation(file)
+ func.WriteHandlerImplementation(file)
+ file.Write(" return error::kNoError;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteBucketServiceImplementation(self, func, file):
+ """Writes the service implementation for a bucket version of command."""
+ file.Write(
+ "error::Error GLES2DecoderImpl::Handle%s(\n" % func.name)
+ file.Write(
+ " uint32 immediate_data_size, const gles2::cmds::%s& c) {\n" %
+ func.name)
+ self.WriteHandlerDeferReadWrite(func, file);
+ last_arg = func.GetLastOriginalArg()
+ all_but_last_arg = func.GetOriginalArgs()[:-1]
+ for arg in all_but_last_arg:
+ arg.WriteGetCode(file)
+ self.WriteGetDataSizeCode(func, file)
+ last_arg.WriteGetCode(file)
+ func.WriteHandlerValidation(file)
+ func.WriteHandlerImplementation(file)
+ file.Write(" return error::kNoError;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteHandlerDeferReadWrite(self, func, file):
+ """Writes the code to handle deferring reads or writes."""
+ defer_reads = func.GetInfo('defer_reads')
+ defer_draws = func.GetInfo('defer_draws')
+ conditions = []
+ if defer_draws:
+ conditions.append('ShouldDeferDraws()');
+ if defer_reads:
+ conditions.append('ShouldDeferReads()');
+ if not conditions:
+ return
+ file.Write(" if (%s)\n" % ' || '.join(conditions))
+ file.Write(" return error::kDeferCommandUntilLater;\n")
+
+ def WriteValidUnitTest(self, func, file, test, extra = {}):
+ """Writes a valid unit test."""
+ if func.GetInfo('expectation') == False:
+ test = self._remove_expected_call_re.sub('', test)
+ name = func.name
+ arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ arg_strings.append(arg.GetValidArg(func, count, 0))
+ gl_arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ gl_arg_strings.append(arg.GetValidGLArg(func, count, 0))
+ gl_func_name = func.GetGLTestFunctionName()
+ vars = {
+ 'test_name': 'GLES2DecoderTest%d' % file.file_num,
+ 'name':name,
+ 'gl_func_name': gl_func_name,
+ 'args': ", ".join(arg_strings),
+ 'gl_args': ", ".join(gl_arg_strings),
+ }
+ vars.update(extra)
+ old_test = ""
+ while (old_test != test):
+ old_test = test
+ test = test % vars
+ file.Write(test % vars)
+
+ def WriteInvalidUnitTest(self, func, file, test, extra = {}):
+ """Writes a invalid unit test."""
+ for arg_index, arg in enumerate(func.GetOriginalArgs()):
+ num_invalid_values = arg.GetNumInvalidValues(func)
+ for value_index in range(0, num_invalid_values):
+ arg_strings = []
+ parse_result = "kNoError"
+ gl_error = None
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ if count == arg_index:
+ (arg_string, parse_result, gl_error) = arg.GetInvalidArg(
+ count, value_index)
+ else:
+ arg_string = arg.GetValidArg(func, count, 0)
+ arg_strings.append(arg_string)
+ gl_arg_strings = []
+ for arg in func.GetOriginalArgs():
+ gl_arg_strings.append("_")
+ gl_func_name = func.GetGLTestFunctionName()
+ gl_error_test = ''
+ if not gl_error == None:
+ gl_error_test = '\n EXPECT_EQ(%s, GetGLError());' % gl_error
+
+ vars = {
+ 'test_name': 'GLES2DecoderTest%d' % file.file_num ,
+ 'name': func.name,
+ 'arg_index': arg_index,
+ 'value_index': value_index,
+ 'gl_func_name': gl_func_name,
+ 'args': ", ".join(arg_strings),
+ 'all_but_last_args': ", ".join(arg_strings[:-1]),
+ 'gl_args': ", ".join(gl_arg_strings),
+ 'parse_result': parse_result,
+ 'gl_error_test': gl_error_test,
+ }
+ vars.update(extra)
+ file.Write(test % vars)
+
+ def WriteServiceUnitTest(self, func, file):
+ """Writes the service unit test for a command."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ self.WriteValidUnitTest(func, file, valid_test)
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Writes the service unit test for an immediate command."""
+ file.Write("// TODO(gman): %s\n" % func.name)
+
+ def WriteImmediateValidationCode(self, func, file):
+ """Writes the validation code for an immediate version of a command."""
+ pass
+
+ def WriteBucketServiceUnitTest(self, func, file):
+ """Writes the service unit test for a bucket command."""
+ file.Write("// TODO(gman): %s\n" % func.name)
+
+ def WriteBucketValidationCode(self, func, file):
+ """Writes the validation code for a bucket version of a command."""
+ file.Write("// TODO(gman): %s\n" % func.name)
+
+ def WriteGLES2ImplementationDeclaration(self, func, file):
+ """Writes the GLES2 Implemention declaration."""
+ impl_decl = func.GetInfo('impl_decl')
+ if impl_decl == None or impl_decl == True:
+ file.Write("virtual %s %s(%s) OVERRIDE;\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write("\n")
+
+ def WriteGLES2CLibImplementation(self, func, file):
+ file.Write("%s GLES2%s(%s) {\n" %
+ (func.return_type, func.name,
+ func.MakeTypedOriginalArgString("")))
+ result_string = "return "
+ if func.return_type == "void":
+ result_string = ""
+ file.Write(" %sgles2::GetGLContext()->%s(%s);\n" %
+ (result_string, func.original_name,
+ func.MakeOriginalArgString("")))
+ file.Write("}\n")
+
+ def WriteGLES2Header(self, func, file):
+ """Writes a re-write macro for GLES"""
+ file.Write("#define gl%s GLES2_GET_FUN(%s)\n" %(func.name, func.name))
+
+ def WriteClientGLCallLog(self, func, file):
+ """Writes a logging macro for the client side code."""
+ comma = ""
+ if len(func.GetOriginalArgs()):
+ comma = " << "
+ file.Write(
+ ' GPU_CLIENT_LOG("[" << GetLogPrefix() << "] gl%s("%s%s << ")");\n' %
+ (func.original_name, comma, func.MakeLogArgString()))
+
+ def WriteClientGLReturnLog(self, func, file):
+ """Writes the return value logging code."""
+ if func.return_type != "void":
+ file.Write(' GPU_CLIENT_LOG("return:" << result)\n')
+
+ def WriteGLES2ImplementationHeader(self, func, file):
+ """Writes the GLES2 Implemention."""
+ self.WriteGLES2ImplementationDeclaration(func, file)
+
+ def WriteGLES2TraceImplementationHeader(self, func, file):
+ """Writes the GLES2 Trace Implemention header."""
+ file.Write("virtual %s %s(%s) OVERRIDE;\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+
+ def WriteGLES2TraceImplementation(self, func, file):
+ """Writes the GLES2 Trace Implemention."""
+ file.Write("%s GLES2TraceImplementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ result_string = "return "
+ if func.return_type == "void":
+ result_string = ""
+ file.Write(' TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::%s");\n' %
+ func.name)
+ file.Write(" %sgl_->%s(%s);\n" %
+ (result_string, func.name, func.MakeOriginalArgString("")))
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteGLES2Implementation(self, func, file):
+ """Writes the GLES2 Implemention."""
+ impl_func = func.GetInfo('impl_func')
+ impl_decl = func.GetInfo('impl_decl')
+ gen_cmd = func.GetInfo('gen_cmd')
+ if (func.can_auto_generate and
+ (impl_func == None or impl_func == True) and
+ (impl_decl == None or impl_decl == True) and
+ (gen_cmd == None or gen_cmd == True)):
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ self.WriteClientGLCallLog(func, file)
+ func.WriteDestinationInitalizationValidation(file)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ file.Write(" helper_->%s(%s);\n" %
+ (func.name, func.MakeOriginalArgString("")))
+ file.Write(" CheckGLError();\n")
+ self.WriteClientGLReturnLog(func, file)
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteGLES2InterfaceHeader(self, func, file):
+ """Writes the GLES2 Interface."""
+ file.Write("virtual %s %s(%s) = 0;\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+
+ def WriteGLES2InterfaceStub(self, func, file):
+ """Writes the GLES2 Interface stub declaration."""
+ file.Write("virtual %s %s(%s) OVERRIDE;\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+
+ def WriteGLES2InterfaceStubImpl(self, func, file):
+ """Writes the GLES2 Interface stub declaration."""
+ args = func.GetOriginalArgs()
+ arg_string = ", ".join(
+ ["%s /* %s */" % (arg.type, arg.name) for arg in args])
+ file.Write("%s GLES2InterfaceStub::%s(%s) {\n" %
+ (func.return_type, func.original_name, arg_string))
+ if func.return_type != "void":
+ file.Write(" return 0;\n")
+ file.Write("}\n")
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Writes the GLES2 Implemention unit test."""
+ client_test = func.GetInfo('client_test')
+ if (func.can_auto_generate and
+ (client_test == None or client_test == True)):
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ struct Cmds {
+ cmds::%(name)s cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(%(cmd_args)s);
+
+ gl_->%(name)s(%(args)s);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+"""
+ cmd_arg_strings = []
+ for count, arg in enumerate(func.GetCmdArgs()):
+ cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func, count, 0))
+ count += 1
+ gl_arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ gl_arg_strings.append(arg.GetValidClientSideArg(func, count, 0))
+ file.Write(code % {
+ 'name': func.name,
+ 'args': ", ".join(gl_arg_strings),
+ 'cmd_args': ", ".join(cmd_arg_strings),
+ })
+ else:
+ if client_test != False:
+ file.Write("// TODO: Implement unit test for %s\n" % func.name)
+
+ def WriteDestinationInitalizationValidation(self, func, file):
+ """Writes the client side destintion initialization validation."""
+ for arg in func.GetOriginalArgs():
+ arg.WriteDestinationInitalizationValidation(file, func)
+
+ def WriteTraceEvent(self, func, file):
+ file.Write(' TRACE_EVENT0("gpu", "GLES2Implementation::%s");\n' %
+ func.original_name)
+
+ def WriteImmediateCmdComputeSize(self, func, file):
+ """Writes the size computation code for the immediate version of a cmd."""
+ file.Write(" static uint32 ComputeSize(uint32 size_in_bytes) {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(" sizeof(ValueType) + // NOLINT\n")
+ file.Write(" RoundSizeToMultipleOfEntries(size_in_bytes));\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSetHeader(self, func, file):
+ """Writes the SetHeader function for the immediate version of a cmd."""
+ file.Write(" void SetHeader(uint32 size_in_bytes) {\n")
+ file.Write(" header.SetCmdByTotalSize<ValueType>(size_in_bytes);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Writes the Init function for the immediate version of a command."""
+ raise NotImplementedError(func.name)
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Writes the Set function for the immediate version of a command."""
+ raise NotImplementedError(func.name)
+
+ def WriteCmdHelper(self, func, file):
+ """Writes the cmd helper definition for a cmd."""
+ code = """ void %(name)s(%(typed_args)s) {
+ gles2::cmds::%(name)s* c = GetCmdSpace<gles2::cmds::%(name)s>();
+ if (c) {
+ c->Init(%(args)s);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedCmdArgString(""),
+ "args": func.MakeCmdArgString(""),
+ })
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Writes the cmd helper definition for the immediate version of a cmd."""
+ code = """ void %(name)s(%(typed_args)s) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::%(name)s* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::%(name)s>(s);
+ if (c) {
+ c->Init(%(args)s);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedCmdArgString(""),
+ "args": func.MakeCmdArgString(""),
+ })
+
+
+class StateSetHandler(TypeHandler):
+ """Handler for commands that simply set state."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteHandlerImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ state_name = func.GetInfo('state')
+ state = _STATES[state_name]
+ states = state['states']
+ args = func.GetOriginalArgs()
+ code = []
+ for ndx,item in enumerate(states):
+ if 'range_checks' in item:
+ for range_check in item['range_checks']:
+ code.append("%s %s" % (args[ndx].name, range_check['check']))
+ if len(code):
+ file.Write(" if (%s) {\n" % " ||\n ".join(code))
+ file.Write(
+ ' LOCAL_SET_GL_ERROR(GL_INVALID_VALUE,'
+ ' "%s", "%s out of range");\n' %
+ (func.name, args[ndx].name))
+ file.Write(" return error::kNoError;\n")
+ file.Write(" }\n")
+ code = []
+ for ndx,item in enumerate(states):
+ code.append("state_.%s != %s" % (item['name'], args[ndx].name))
+ file.Write(" if (%s) {\n" % " ||\n ".join(code))
+ for ndx,item in enumerate(states):
+ file.Write(" state_.%s = %s;\n" % (item['name'], args[ndx].name))
+ if 'state_flag' in state:
+ file.Write(" %s = true;\n" % state['state_flag'])
+ if not func.GetInfo("no_gl"):
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+ file.Write(" }\n")
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ TypeHandler.WriteServiceUnitTest(self, func, file)
+ state_name = func.GetInfo('state')
+ state = _STATES[state_name]
+ states = state['states']
+ for ndx,item in enumerate(states):
+ if 'range_checks' in item:
+ for check_ndx, range_check in enumerate(item['range_checks']):
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidValue%(ndx)d_%(check_ndx)d) {
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+"""
+ name = func.name
+ arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ arg_strings.append(arg.GetValidArg(func, count, 0))
+ arg_strings[ndx] = range_check['test_value']
+ vars = {
+ 'test_name': 'GLES2DecoderTest%d' % file.file_num,
+ 'name': name,
+ 'ndx': ndx,
+ 'check_ndx': check_ndx,
+ 'args': ", ".join(arg_strings),
+ }
+ file.Write(valid_test % vars)
+
+
+class StateSetRGBAlphaHandler(TypeHandler):
+ """Handler for commands that simply set state that have rgb/alpha."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteHandlerImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ state_name = func.GetInfo('state')
+ state = _STATES[state_name]
+ states = state['states']
+ args = func.GetOriginalArgs()
+ num_args = len(args)
+ code = []
+ for ndx,item in enumerate(states):
+ code.append("state_.%s != %s" % (item['name'], args[ndx % num_args].name))
+ file.Write(" if (%s) {\n" % " ||\n ".join(code))
+ for ndx, item in enumerate(states):
+ file.Write(" state_.%s = %s;\n" %
+ (item['name'], args[ndx % num_args].name))
+ if 'state_flag' in state:
+ file.Write(" %s = true;\n" % state['state_flag'])
+ if not func.GetInfo("no_gl"):
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+ file.Write(" }\n")
+
+
+class StateSetFrontBackSeparateHandler(TypeHandler):
+ """Handler for commands that simply set state that have front/back."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteHandlerImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ state_name = func.GetInfo('state')
+ state = _STATES[state_name]
+ states = state['states']
+ args = func.GetOriginalArgs()
+ face = args[0].name
+ num_args = len(args)
+ file.Write(" bool changed = false;\n")
+ for group_ndx, group in enumerate(Grouper(num_args - 1, states)):
+ file.Write(" if (%s == %s || %s == GL_FRONT_AND_BACK) {\n" %
+ (face, ('GL_FRONT', 'GL_BACK')[group_ndx], face))
+ code = []
+ for ndx, item in enumerate(group):
+ code.append("state_.%s != %s" % (item['name'], args[ndx + 1].name))
+ file.Write(" changed |= %s;\n" % " ||\n ".join(code))
+ file.Write(" }\n")
+ file.Write(" if (changed) {\n")
+ for group_ndx, group in enumerate(Grouper(num_args - 1, states)):
+ file.Write(" if (%s == %s || %s == GL_FRONT_AND_BACK) {\n" %
+ (face, ('GL_FRONT', 'GL_BACK')[group_ndx], face))
+ for ndx, item in enumerate(group):
+ file.Write(" state_.%s = %s;\n" %
+ (item['name'], args[ndx + 1].name))
+ file.Write(" }\n")
+ if 'state_flag' in state:
+ file.Write(" %s = true;\n" % state['state_flag'])
+ if not func.GetInfo("no_gl"):
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+ file.Write(" }\n")
+
+
+class StateSetFrontBackHandler(TypeHandler):
+ """Handler for commands that simply set state that set both front/back."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteHandlerImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ state_name = func.GetInfo('state')
+ state = _STATES[state_name]
+ states = state['states']
+ args = func.GetOriginalArgs()
+ num_args = len(args)
+ code = []
+ for group_ndx, group in enumerate(Grouper(num_args, states)):
+ for ndx, item in enumerate(group):
+ code.append("state_.%s != %s" % (item['name'], args[ndx].name))
+ file.Write(" if (%s) {\n" % " ||\n ".join(code))
+ for group_ndx, group in enumerate(Grouper(num_args, states)):
+ for ndx, item in enumerate(group):
+ file.Write(" state_.%s = %s;\n" % (item['name'], args[ndx].name))
+ if 'state_flag' in state:
+ file.Write(" %s = true;\n" % state['state_flag'])
+ if not func.GetInfo("no_gl"):
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+ file.Write(" }\n")
+
+
+class StateSetNamedParameter(TypeHandler):
+ """Handler for commands that set a state chosen with an enum parameter."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteHandlerImplementation(self, func, file):
+ """Overridden from TypeHandler."""
+ state_name = func.GetInfo('state')
+ state = _STATES[state_name]
+ states = state['states']
+ args = func.GetOriginalArgs()
+ num_args = len(args)
+ assert num_args == 2
+ file.Write(" switch (%s) {\n" % args[0].name)
+ for state in states:
+ file.Write(" case %s:\n" % state['enum'])
+ file.Write(" if (state_.%s != %s) {\n" %
+ (state['name'], args[1].name))
+ file.Write(" state_.%s = %s;\n" % (state['name'], args[1].name))
+ if not func.GetInfo("no_gl"):
+ file.Write(" %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+ file.Write(" }\n")
+ file.Write(" break;\n")
+ file.Write(" default:\n")
+ file.Write(" NOTREACHED();\n")
+ file.Write(" }\n")
+
+
+class CustomHandler(TypeHandler):
+ """Handler for commands that are auto-generated but require minor tweaks."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteImmediateServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteBucketServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteImmediateCmdGetTotalSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" uint32 total_size = 0; // TODO(gman): get correct size.\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" void Init(%s) {\n" % func.MakeTypedCmdArgString("_"))
+ self.WriteImmediateCmdGetTotalSize(func, file)
+ file.Write(" SetHeader(total_size);\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ copy_args = func.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s) {\n" %
+ func.MakeTypedCmdArgString("_", True))
+ self.WriteImmediateCmdGetTotalSize(func, file)
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s);\n" % copy_args)
+ file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>("
+ "cmd, total_size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+
+class TodoHandler(CustomHandler):
+ """Handle for commands that are not yet implemented."""
+
+ def AddImmediateFunction(self, generator, func):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" // TODO: for now this is a no-op\n")
+ file.Write(
+ " SetGLError("
+ "GL_INVALID_OPERATION, \"gl%s\", \"not implemented\");\n" %
+ func.name)
+ if func.return_type != "void":
+ file.Write(" return 0;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(
+ "error::Error GLES2DecoderImpl::Handle%s(\n" % func.name)
+ file.Write(
+ " uint32 immediate_data_size, const gles2::cmds::%s& c) {\n" %
+ func.name)
+ file.Write(" // TODO: for now this is a no-op\n")
+ file.Write(
+ " LOCAL_SET_GL_ERROR("
+ "GL_INVALID_OPERATION, \"gl%s\", \"not implemented\");\n" %
+ func.name)
+ file.Write(" return error::kNoError;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class HandWrittenHandler(CustomHandler):
+ """Handler for comands where everything must be written by hand."""
+
+ def InitFunction(self, func):
+ """Add or adjust anything type specific for this function."""
+ CustomHandler.InitFunction(self, func)
+ func.can_auto_generate = False
+
+ def WriteStruct(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteDocs(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteBucketServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteImmediateServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteBucketServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteBucketCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): Write test for %s\n" % func.name)
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): Write test for %s\n" % func.name)
+
+ def WriteBucketFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): Write test for %s\n" % func.name)
+
+
+
+class ManualHandler(CustomHandler):
+ """Handler for commands who's handlers must be written by hand."""
+
+ def __init__(self):
+ CustomHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ if (func.name == 'CompressedTexImage2DBucket'):
+ func.cmd_args = func.cmd_args[:-1]
+ func.AddCmdArg(Argument('bucket_id', 'GLuint'))
+ else:
+ CustomHandler.InitFunction(self, func)
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteBucketServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteImmediateServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): Implement test for %s\n" % func.name)
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ if func.GetInfo('impl_func'):
+ super(ManualHandler, self).WriteGLES2Implementation(func, file)
+
+ def WriteGLES2ImplementationHeader(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("virtual %s %s(%s) OVERRIDE;\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write("\n")
+
+ def WriteImmediateCmdGetTotalSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ # TODO(gman): Move this data to _FUNCTION_INFO?
+ if func.name == 'ShaderSourceImmediate':
+ file.Write(" uint32 total_size = ComputeSize(_data_size);\n")
+ else:
+ CustomHandler.WriteImmediateCmdGetTotalSize(self, func, file)
+
+
+class DataHandler(TypeHandler):
+ """Handler for glBufferData, glBufferSubData, glTexImage2D, glTexSubImage2D,
+ glCompressedTexImage2D, glCompressedTexImageSub2D."""
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ if func.name == 'CompressedTexSubImage2DBucket':
+ func.cmd_args = func.cmd_args[:-1]
+ func.AddCmdArg(Argument('bucket_id', 'GLuint'))
+
+ def WriteGetDataSizeCode(self, func, file):
+ """Overrriden from TypeHandler."""
+ # TODO(gman): Move this data to _FUNCTION_INFO?
+ name = func.name
+ if name.endswith("Immediate"):
+ name = name[0:-9]
+ if name == 'BufferData' or name == 'BufferSubData':
+ file.Write(" uint32 data_size = size;\n")
+ elif (name == 'CompressedTexImage2D' or
+ name == 'CompressedTexSubImage2D'):
+ file.Write(" uint32 data_size = imageSize;\n")
+ elif (name == 'CompressedTexSubImage2DBucket'):
+ file.Write(" Bucket* bucket = GetBucket(c.bucket_id);\n")
+ file.Write(" uint32 data_size = bucket->size();\n")
+ file.Write(" GLsizei imageSize = data_size;\n")
+ elif name == 'TexImage2D' or name == 'TexSubImage2D':
+ code = """ uint32 data_size;
+ if (!GLES2Util::ComputeImageDataSize(
+ width, height, format, type, unpack_alignment_, &data_size)) {
+ return error::kOutOfBounds;
+ }
+"""
+ file.Write(code)
+ else:
+ file.Write("// uint32 data_size = 0; // TODO(gman): get correct size!\n")
+
+ def WriteImmediateCmdGetTotalSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ # TODO(gman): Move this data to _FUNCTION_INFO?
+ if func.name == 'BufferDataImmediate':
+ file.Write(" uint32 total_size = ComputeSize(_size);\n")
+ elif func.name == 'BufferSubDataImmediate':
+ file.Write(" uint32 total_size = ComputeSize(_size);\n")
+ elif func.name == 'CompressedTexImage2DImmediate':
+ file.Write(" uint32 total_size = ComputeSize(_imageSize);\n")
+ elif func.name == 'CompressedTexSubImage2DImmediate':
+ file.Write(" uint32 total_size = ComputeSize(_imageSize);\n")
+ elif func.name == 'TexImage2DImmediate':
+ file.Write(
+ " uint32 total_size = 0; // TODO(gman): get correct size\n")
+ elif func.name == 'TexSubImage2DImmediate':
+ file.Write(
+ " uint32 total_size = 0; // TODO(gman): get correct size\n")
+
+ def WriteImmediateCmdSizeTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ # TODO(gman): Move this data to _FUNCTION_INFO?
+ if func.name == 'BufferDataImmediate':
+ file.Write(" uint32 total_size = cmd.ComputeSize(cmd.size);\n")
+ elif func.name == 'BufferSubDataImmediate':
+ file.Write(" uint32 total_size = cmd.ComputeSize(cmd.size);\n")
+ elif func.name == 'CompressedTexImage2DImmediate':
+ file.Write(" uint32 total_size = cmd.ComputeSize(cmd.imageSize);\n")
+ elif func.name == 'CompressedTexSubImage2DImmediate':
+ file.Write(" uint32 total_size = cmd.ComputeSize(cmd.imageSize);\n")
+ elif func.name == 'TexImage2DImmediate':
+ file.Write(
+ " uint32 total_size = 0; // TODO(gman): get correct size\n")
+ elif func.name == 'TexSubImage2DImmediate':
+ file.Write(
+ " uint32 total_size = 0; // TODO(gman): get correct size\n")
+ file.Write(" EXPECT_EQ(sizeof(cmd), total_size);\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" void Init(%s) {\n" % func.MakeTypedCmdArgString("_"))
+ self.WriteImmediateCmdGetTotalSize(func, file)
+ file.Write(" SetHeader(total_size);\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ copy_args = func.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s) {\n" %
+ func.MakeTypedCmdArgString("_", True))
+ self.WriteImmediateCmdGetTotalSize(func, file)
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s);\n" % copy_args)
+ file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>("
+ "cmd, total_size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ # TODO(gman): Remove this exception.
+ file.Write("// TODO(gman): Implement test for %s\n" % func.name)
+ return
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("// TODO(gman): %s\n\n" % func.name)
+
+ def WriteBucketServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ if not func.name == 'CompressedTexSubImage2DBucket':
+ TypeHandler.WriteBucketServiceImplemenation(self, func, file)
+
+
+class BindHandler(TypeHandler):
+ """Handler for glBind___ type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+
+ if len(func.GetOriginalArgs()) == 1:
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(%(test_name)s, %(name)sValidArgsNewId) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(kNewServiceId));
+ EXPECT_CALL(*gl_, %(gl_gen_func_name)s(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(Get%(resource_type)s(kNewClientId) != NULL);
+}
+"""
+ gen_func_names = {
+ }
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'resource_type': func.GetOriginalArgs()[0].resource_type,
+ 'gl_gen_func_name': func.GetInfo("gen_func"),
+ })
+ else:
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(%(test_name)s, %(name)sValidArgsNewId) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(first_gl_arg)s, kNewServiceId));
+ EXPECT_CALL(*gl_, %(gl_gen_func_name)s(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(first_arg)s, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(Get%(resource_type)s(kNewClientId) != NULL);
+}
+"""
+ gen_func_names = {
+ }
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'first_arg': func.GetOriginalArgs()[0].GetValidArg(func, 0, 0),
+ 'first_gl_arg': func.GetOriginalArgs()[0].GetValidGLArg(func, 0, 0),
+ 'resource_type': func.GetOriginalArgs()[1].resource_type,
+ 'gl_gen_func_name': func.GetInfo("gen_func"),
+ })
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test)
+
+ def WriteGLES2Implementation(self, func, file):
+ """Writes the GLES2 Implemention."""
+
+ impl_func = func.GetInfo('impl_func')
+ impl_decl = func.GetInfo('impl_decl')
+
+ if (func.can_auto_generate and
+ (impl_func == None or impl_func == True) and
+ (impl_decl == None or impl_decl == True)):
+
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+
+ code = """ if (Is%(type)sReservedId(%(id)s)) {
+ SetGLError(GL_INVALID_OPERATION, "%(name)s\", \"%(id)s reserved id");
+ return;
+ }
+ if (Bind%(type)sHelper(%(arg_string)s)) {
+ helper_->%(name)s(%(arg_string)s);
+ }
+ CheckGLError();
+}
+
+"""
+ name_arg = None
+ if len(func.GetOriginalArgs()) == 1:
+ # Bind functions that have no target (like BindVertexArrayOES)
+ name_arg = func.GetOriginalArgs()[0]
+ else:
+ # Bind functions that have both a target and a name (like BindTexture)
+ name_arg = func.GetOriginalArgs()[1]
+
+ file.Write(code % {
+ 'name': func.name,
+ 'arg_string': func.MakeOriginalArgString(""),
+ 'id': name_arg.name,
+ 'type': name_arg.resource_type,
+ 'lc_type': name_arg.resource_type.lower(),
+ })
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ client_test = func.GetInfo('client_test')
+ if client_test == False:
+ return
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ struct Cmds {
+ cmds::%(name)s cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(%(cmd_args)s);
+
+ gl_->%(name)s(%(args)s);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ ClearCommands();
+ gl_->%(name)s(%(args)s);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+"""
+ cmd_arg_strings = []
+ for count, arg in enumerate(func.GetCmdArgs()):
+ cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func, count, 0))
+ count += 1
+ gl_arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ gl_arg_strings.append(arg.GetValidClientSideArg(func, count, 0))
+ file.Write(code % {
+ 'name': func.name,
+ 'args': ", ".join(gl_arg_strings),
+ 'cmd_args': ", ".join(cmd_arg_strings),
+ })
+
+
+class GENnHandler(TypeHandler):
+ """Handler for glGen___ type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteGetDataSizeCode(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+"""
+ file.Write(code)
+
+ def WriteHandlerImplementation (self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" if (!%sHelper(n, %s)) {\n"
+ " return error::kInvalidArguments;\n"
+ " }\n" %
+ (func.name, func.GetLastOriginalArg().name))
+
+ def WriteImmediateHandlerImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" if (!%sHelper(n, %s)) {\n"
+ " return error::kInvalidArguments;\n"
+ " }\n" %
+ (func.original_name, func.GetLastOriginalArg().name))
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ log_code = (""" GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << %s[i]);
+ }
+ });""" % func.GetOriginalArgs()[1].name)
+ args = {
+ 'log_code': log_code,
+ 'return_type': func.return_type,
+ 'name': func.original_name,
+ 'typed_args': func.MakeTypedOriginalArgString(""),
+ 'args': func.MakeOriginalArgString(""),
+ 'resource_types': func.GetInfo('resource_types'),
+ 'count_name': func.GetOriginalArgs()[0].name,
+ }
+ file.Write(
+ "%(return_type)s GLES2Implementation::%(name)s(%(typed_args)s) {\n" %
+ args)
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ code = """ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::k%(resource_types)s)->
+ MakeIds(this, 0, %(args)s);
+ %(name)sHelper(%(args)s);
+ helper_->%(name)sImmediate(%(args)s);
+ helper_->CommandBufferHelper::Flush();
+%(log_code)s
+ CheckGLError();
+}
+
+"""
+ file.Write(code % args)
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::%(name)sImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = k%(types)sStartId;
+ expected.data[1] = k%(types)sStartId + 1;
+ gl_->%(name)s(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(k%(types)sStartId, ids[0]);
+ EXPECT_EQ(k%(types)sStartId + 1, ids[1]);
+}
+"""
+ file.Write(code % {
+ 'name': func.name,
+ 'types': func.GetInfo('resource_types'),
+ })
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(Get%(resource_name)s(kNewClientId) != NULL);
+}
+"""
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'resource_name': func.GetInfo('resource_type'),
+ })
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_%(resource_name)s_id_;
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+}
+"""
+ self.WriteValidUnitTest(func, file, invalid_test, {
+ 'resource_name': func.GetInfo('resource_type').lower(),
+ })
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>();
+ GLuint temp = kNewClientId;
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(Get%(resource_name)s(kNewClientId) != NULL);
+}
+"""
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'resource_name': func.GetInfo('resource_type'),
+ })
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(_, _)).Times(0);
+ cmds::%(name)s* cmd = GetImmediateAs<cmds::%(name)s>();
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmd->Init(1, &client_%(resource_name)s_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_%(resource_name)s_id_)));
+}
+"""
+ self.WriteValidUnitTest(func, file, invalid_test, {
+ 'resource_name': func.GetInfo('resource_type').lower(),
+ })
+
+ def WriteImmediateCmdComputeSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" static uint32 ComputeDataSize(GLsizei n) {\n")
+ file.Write(
+ " return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+ file.Write(" static uint32 ComputeSize(GLsizei n) {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(" sizeof(ValueType) + ComputeDataSize(n)); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSetHeader(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" void SetHeader(GLsizei n) {\n")
+ file.Write(" header.SetCmdByTotalSize<ValueType>(ComputeSize(n));\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ file.Write(" void Init(%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_"),
+ last_arg.type, last_arg.name))
+ file.Write(" SetHeader(_n);\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" memcpy(ImmediateDataAddress(this),\n")
+ file.Write(" _%s, ComputeDataSize(_n));\n" % last_arg.name)
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ copy_args = func.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_", True),
+ last_arg.type, last_arg.name))
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" %
+ (copy_args, last_arg.name))
+ file.Write(" const uint32 size = ComputeSize(_n);\n")
+ file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>("
+ "cmd, size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ void %(name)s(%(typed_args)s) {
+ const uint32 size = gles2::cmds::%(name)s::ComputeSize(n);
+ gles2::cmds::%(name)s* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::%(name)s>(size);
+ if (c) {
+ c->Init(%(args)s);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedOriginalArgString(""),
+ "args": func.MakeOriginalArgString(""),
+ })
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+ file.Write(" static GLuint ids[] = { 12, 23, 34, };\n")
+ file.Write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
+ (func.name, func.name))
+ file.Write(" void* next_cmd = cmd.Set(\n")
+ file.Write(" &cmd, static_cast<GLsizei>(arraysize(ids)), ids);\n")
+ file.Write(" EXPECT_EQ(static_cast<uint32>(cmds::%s::kCmdId),\n" %
+ func.name)
+ file.Write(" cmd.header.command);\n")
+ file.Write(" EXPECT_EQ(sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(cmd.n * 4u),\n")
+ file.Write(" cmd.header.size * 4u);\n")
+ file.Write(" EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);\n");
+ file.Write(" CheckBytesWrittenMatchesExpectedSize(\n")
+ file.Write(" next_cmd, sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));\n")
+ file.Write(" // TODO(gman): Check that ids were inserted;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class CreateHandler(TypeHandler):
+ """Handler for glCreate___ type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ func.AddCmdArg(Argument("client_id", 'uint32'))
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s))
+ .WillOnce(Return(kNewServiceId));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s%(comma)skNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(Get%(resource_type)s(kNewClientId) != NULL);
+}
+"""
+ comma = ""
+ if len(func.GetOriginalArgs()):
+ comma =", "
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'comma': comma,
+ 'resource_type': func.name[6:],
+ })
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s%(comma)skNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test, {
+ 'comma': comma,
+ })
+
+ def WriteHandlerImplementation (self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" uint32 client_id = c.client_id;\n")
+ file.Write(" if (!%sHelper(%s)) {\n" %
+ (func.name, func.MakeCmdArgString("")))
+ file.Write(" return error::kInvalidArguments;\n")
+ file.Write(" }\n")
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ file.Write(" GLuint client_id;\n")
+ file.Write(
+ " GetIdHandler(id_namespaces::kProgramsAndShaders)->\n")
+ file.Write(" MakeIds(this, 0, 1, &client_id);\n")
+ file.Write(" helper_->%s(%s);\n" %
+ (func.name, func.MakeCmdArgString("")))
+ file.Write(' GPU_CLIENT_LOG("returned " << client_id);\n')
+ file.Write(" CheckGLError();\n")
+ file.Write(" return client_id;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class DeleteHandler(TypeHandler):
+ """Handler for glDelete___ single resource type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ file.Write(
+ " GPU_CLIENT_DCHECK(%s != 0);\n" % func.GetOriginalArgs()[-1].name)
+ file.Write(" %sHelper(%s);\n" %
+ (func.original_name, func.GetOriginalArgs()[-1].name))
+ file.Write(" CheckGLError();\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class DELnHandler(TypeHandler):
+ """Handler for glDelete___ type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteGetDataSizeCode(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+"""
+ file.Write(code)
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ GLuint ids[2] = { k%(types)sStartId, k%(types)sStartId + 1 };
+ struct Cmds {
+ cmds::%(name)sImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = k%(types)sStartId;
+ expected.data[1] = k%(types)sStartId + 1;
+ gl_->%(name)s(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+"""
+ file.Write(code % {
+ 'name': func.name,
+ 'types': func.GetInfo('resource_types'),
+ })
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ %(gl_func_name)s(1, Pointee(kService%(upper_resource_name)sId)))
+ .Times(1);
+ GetSharedMemoryAs<GLuint*>()[0] = client_%(resource_name)s_id_;
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ Get%(upper_resource_name)s(client_%(resource_name)s_id_) == NULL);
+}
+"""
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'resource_name': func.GetInfo('resource_type').lower(),
+ 'upper_resource_name': func.GetInfo('resource_type'),
+ })
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs) {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+"""
+ self.WriteValidUnitTest(func, file, invalid_test)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ %(gl_func_name)s(1, Pointee(kService%(upper_resource_name)sId)))
+ .Times(1);
+ cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmd.Init(1, &client_%(resource_name)s_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_%(resource_name)s_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ Get%(upper_resource_name)s(client_%(resource_name)s_id_) == NULL);
+}
+"""
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'resource_name': func.GetInfo('resource_type').lower(),
+ 'upper_resource_name': func.GetInfo('resource_type'),
+ })
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs) {
+ cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+"""
+ self.WriteValidUnitTest(func, file, invalid_test)
+
+ def WriteHandlerImplementation (self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" %sHelper(n, %s);\n" %
+ (func.name, func.GetLastOriginalArg().name))
+
+ def WriteImmediateHandlerImplementation (self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" %sHelper(n, %s);\n" %
+ (func.original_name, func.GetLastOriginalArg().name))
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ impl_decl = func.GetInfo('impl_decl')
+ if impl_decl == None or impl_decl == True:
+ args = {
+ 'return_type': func.return_type,
+ 'name': func.original_name,
+ 'typed_args': func.MakeTypedOriginalArgString(""),
+ 'args': func.MakeOriginalArgString(""),
+ 'resource_type': func.GetInfo('resource_type').lower(),
+ 'count_name': func.GetOriginalArgs()[0].name,
+ }
+ file.Write(
+ "%(return_type)s GLES2Implementation::%(name)s(%(typed_args)s) {\n" %
+ args)
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ file.Write(""" GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << %s[i]);
+ }
+ });
+""" % func.GetOriginalArgs()[1].name)
+ file.Write(""" GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(%s[i] != 0);
+ }
+ });
+""" % func.GetOriginalArgs()[1].name)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ code = """ %(name)sHelper(%(args)s);
+ CheckGLError();
+}
+
+"""
+ file.Write(code % args)
+
+ def WriteImmediateCmdComputeSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" static uint32 ComputeDataSize(GLsizei n) {\n")
+ file.Write(
+ " return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+ file.Write(" static uint32 ComputeSize(GLsizei n) {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(" sizeof(ValueType) + ComputeDataSize(n)); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSetHeader(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" void SetHeader(GLsizei n) {\n")
+ file.Write(" header.SetCmdByTotalSize<ValueType>(ComputeSize(n));\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ file.Write(" void Init(%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_"),
+ last_arg.type, last_arg.name))
+ file.Write(" SetHeader(_n);\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" memcpy(ImmediateDataAddress(this),\n")
+ file.Write(" _%s, ComputeDataSize(_n));\n" % last_arg.name)
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ copy_args = func.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_", True),
+ last_arg.type, last_arg.name))
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" %
+ (copy_args, last_arg.name))
+ file.Write(" const uint32 size = ComputeSize(_n);\n")
+ file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>("
+ "cmd, size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ void %(name)s(%(typed_args)s) {
+ const uint32 size = gles2::cmds::%(name)s::ComputeSize(n);
+ gles2::cmds::%(name)s* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::%(name)s>(size);
+ if (c) {
+ c->Init(%(args)s);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedOriginalArgString(""),
+ "args": func.MakeOriginalArgString(""),
+ })
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+ file.Write(" static GLuint ids[] = { 12, 23, 34, };\n")
+ file.Write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
+ (func.name, func.name))
+ file.Write(" void* next_cmd = cmd.Set(\n")
+ file.Write(" &cmd, static_cast<GLsizei>(arraysize(ids)), ids);\n")
+ file.Write(" EXPECT_EQ(static_cast<uint32>(cmds::%s::kCmdId),\n" %
+ func.name)
+ file.Write(" cmd.header.command);\n")
+ file.Write(" EXPECT_EQ(sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(cmd.n * 4u),\n")
+ file.Write(" cmd.header.size * 4u);\n")
+ file.Write(" EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);\n");
+ file.Write(" CheckBytesWrittenMatchesExpectedSize(\n")
+ file.Write(" next_cmd, sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));\n")
+ file.Write(" // TODO(gman): Check that ids were inserted;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class GETnHandler(TypeHandler):
+ """Handler for GETn for glGetBooleanv, glGetFloatv, ... type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def AddImmediateFunction(self, generator, func):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(
+ "error::Error GLES2DecoderImpl::Handle%s(\n" % func.name)
+ file.Write(
+ " uint32 immediate_data_size, const gles2::cmds::%s& c) {\n" %
+ func.name)
+ last_arg = func.GetLastOriginalArg()
+
+ all_but_last_args = func.GetOriginalArgs()[:-1]
+ for arg in all_but_last_args:
+ arg.WriteGetCode(file)
+
+ code = """ typedef cmds::%(func_name)s::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ %(last_arg_type)s params = result ? result->GetData() : NULL;
+"""
+ file.Write(code % {
+ 'last_arg_type': last_arg.type,
+ 'func_name': func.name,
+ })
+ func.WriteHandlerValidation(file)
+ code = """ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+"""
+ shadowed = func.GetInfo('shadowed')
+ if not shadowed:
+ file.Write(' LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("%s");\n' % func.name)
+ file.Write(code)
+ func.WriteHandlerImplementation(file)
+ if shadowed:
+ code = """ result->SetNumResults(num_values);
+ return error::kNoError;
+}
+"""
+ else:
+ code = """ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "%(func_name)s", "");
+ }
+ return error::kNoError;
+}
+
+"""
+ file.Write(code % {'func_name': func.name})
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ impl_decl = func.GetInfo('impl_decl')
+ if impl_decl == None or impl_decl == True:
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ all_but_last_args = func.GetOriginalArgs()[:-1]
+ arg_string = (
+ ", ".join(["%s" % arg.name for arg in all_but_last_args]))
+ all_arg_string = (
+ ", ".join(["%s" % arg.name for arg in func.GetOriginalArgs()]))
+ self.WriteTraceEvent(func, file)
+ code = """ if (%(func_name)sHelper(%(all_arg_string)s)) {
+ return;
+ }
+ typedef cmds::%(func_name)s::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->%(func_name)s(%(arg_string)s,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+"""
+ file.Write(code % {
+ 'func_name': func.name,
+ 'arg_string': arg_string,
+ 'all_arg_string': all_arg_string,
+ })
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Writes the GLES2 Implemention unit test."""
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ struct Cmds {
+ cmds::%(name)s cmd;
+ };
+ typedef cmds::%(name)s::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(%(cmd_args)s, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->%(name)s(%(args)s, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+"""
+ cmd_arg_strings = []
+ for count, arg in enumerate(func.GetCmdArgs()[0:-2]):
+ cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func, count, 0))
+ cmd_arg_strings[0] = '123'
+ gl_arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()[0:-1]):
+ gl_arg_strings.append(arg.GetValidClientSideArg(func, count, 0))
+ gl_arg_strings[0] = '123'
+ file.Write(code % {
+ 'name': func.name,
+ 'args': ", ".join(gl_arg_strings),
+ 'cmd_args': ", ".join(cmd_arg_strings),
+ })
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ typedef cmds::%(name)s::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(local_gl_args)s));
+ result->size = 0;
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ %(valid_pname)s),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ gl_arg_strings = []
+ valid_pname = ''
+ for count, arg in enumerate(func.GetOriginalArgs()[:-1]):
+ arg_value = arg.GetValidGLArg(func, count, 0)
+ gl_arg_strings.append(arg_value)
+ if arg.name == 'pname':
+ valid_pname = arg_value
+ if func.GetInfo('gl_test_func') == 'glGetIntegerv':
+ gl_arg_strings.append("_")
+ else:
+ gl_arg_strings.append("result->GetData()")
+
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'local_gl_args': ", ".join(gl_arg_strings),
+ 'valid_pname': valid_pname,
+ })
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s::Result* result =
+ static_cast<cmds::%(name)s::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test)
+
+
+class PUTHandler(TypeHandler):
+ """Handler for glTexParameter_v, glVertexAttrib_v functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteServiceUnitTest(self, func, file):
+ """Writes the service unit test for a command."""
+ expected_call = "EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));"
+ if func.GetInfo("first_element_only"):
+ gl_arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ gl_arg_strings.append(arg.GetValidGLArg(func, count, 0))
+ gl_arg_strings[-1] = "*" + gl_arg_strings[-1]
+ expected_call = ("EXPECT_CALL(*gl_, %%(gl_func_name)s(%s));" %
+ ", ".join(gl_arg_strings))
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ GetSharedMemoryAs<%(data_type)s*>()[0] = %(data_value)s;
+ %(expected_call)s
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ extra = {
+ 'data_type': func.GetInfo('data_type'),
+ 'data_value': func.GetInfo('data_value') or '0',
+ 'expected_call': expected_call,
+ }
+ self.WriteValidUnitTest(func, file, valid_test, extra)
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ GetSharedMemoryAs<%(data_type)s*>()[0] = %(data_value)s;
+ EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test, extra)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Writes the service unit test for a command."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ %(data_type)s temp[%(data_count)s] = { %(data_value)s, };
+ cmd.Init(%(gl_args)s, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ %(gl_func_name)s(%(gl_args)s, %(data_ref)sreinterpret_cast<
+ %(data_type)s*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ gl_arg_strings = []
+ gl_any_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()[0:-1]):
+ gl_arg_strings.append(arg.GetValidGLArg(func, count, 0))
+ gl_any_strings.append("_")
+ extra = {
+ 'data_ref': ("*" if func.GetInfo('first_element_only') else ""),
+ 'data_type': func.GetInfo('data_type'),
+ 'data_count': func.GetInfo('count'),
+ 'data_value': func.GetInfo('data_value') or '0',
+ 'gl_args': ", ".join(gl_arg_strings),
+ 'gl_any_args': ", ".join(gl_any_strings),
+ }
+ self.WriteValidUnitTest(func, file, valid_test, extra)
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_any_args)s, _)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ %(data_type)s temp[%(data_count)s] = { %(data_value)s, };
+ cmd.Init(%(all_but_last_args)s, &temp[0]);
+ EXPECT_EQ(error::%(parse_result)s,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test, extra)
+
+ def WriteGetDataSizeCode(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(%s), %d, &data_size)) {
+ return error::kOutOfBounds;
+ }
+"""
+ file.Write(code % (func.info.data_type, func.info.count))
+ if func.is_immediate:
+ file.Write(" if (data_size > immediate_data_size) {\n")
+ file.Write(" return error::kOutOfBounds;\n")
+ file.Write(" }\n")
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ last_arg_name = func.GetLastOriginalArg().name
+ values_str = ' << ", " << '.join(
+ ["%s[%d]" % (last_arg_name, ndx) for ndx in range(0, func.info.count)])
+ file.Write(' GPU_CLIENT_LOG("values: " << %s);\n' % values_str)
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ file.Write(" helper_->%sImmediate(%s);\n" %
+ (func.name, func.MakeOriginalArgString("")))
+ file.Write(" CheckGLError();\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Writes the GLES2 Implemention unit test."""
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ %(type)s data[%(count)d] = {0};
+ struct Cmds {
+ cmds::%(name)sImmediate cmd;
+ %(type)s data[%(count)d];
+ };
+
+ for (int jj = 0; jj < %(count)d; ++jj) {
+ data[jj] = static_cast<%(type)s>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(%(cmd_args)s, &data[0]);
+ gl_->%(name)s(%(args)s, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+"""
+ cmd_arg_strings = []
+ for count, arg in enumerate(func.GetCmdArgs()[0:-2]):
+ cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func, count, 0))
+ gl_arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()[0:-1]):
+ gl_arg_strings.append(arg.GetValidClientSideArg(func, count, 0))
+ file.Write(code % {
+ 'name': func.name,
+ 'type': func.GetInfo('data_type'),
+ 'count': func.GetInfo('count'),
+ 'args': ", ".join(gl_arg_strings),
+ 'cmd_args': ", ".join(cmd_arg_strings),
+ })
+
+ def WriteImmediateCmdComputeSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" static uint32 ComputeDataSize() {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(" sizeof(%s) * %d); // NOLINT\n" %
+ (func.info.data_type, func.info.count))
+ file.Write(" }\n")
+ file.Write("\n")
+ file.Write(" static uint32 ComputeSize() {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(
+ " sizeof(ValueType) + ComputeDataSize()); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSetHeader(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" void SetHeader() {\n")
+ file.Write(
+ " header.SetCmdByTotalSize<ValueType>(ComputeSize());\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ file.Write(" void Init(%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_"),
+ last_arg.type, last_arg.name))
+ file.Write(" SetHeader();\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" memcpy(ImmediateDataAddress(this),\n")
+ file.Write(" _%s, ComputeDataSize());\n" % last_arg.name)
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ copy_args = func.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_", True),
+ last_arg.type, last_arg.name))
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" %
+ (copy_args, last_arg.name))
+ file.Write(" const uint32 size = ComputeSize();\n")
+ file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>("
+ "cmd, size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ void %(name)s(%(typed_args)s) {
+ const uint32 size = gles2::cmds::%(name)s::ComputeSize();
+ gles2::cmds::%(name)s* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::%(name)s>(size);
+ if (c) {
+ c->Init(%(args)s);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedOriginalArgString(""),
+ "args": func.MakeOriginalArgString(""),
+ })
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+ file.Write(" const int kSomeBaseValueToTestWith = 51;\n")
+ file.Write(" static %s data[] = {\n" % func.info.data_type)
+ for v in range(0, func.info.count):
+ file.Write(" static_cast<%s>(kSomeBaseValueToTestWith + %d),\n" %
+ (func.info.data_type, v))
+ file.Write(" };\n")
+ file.Write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
+ (func.name, func.name))
+ file.Write(" void* next_cmd = cmd.Set(\n")
+ file.Write(" &cmd")
+ args = func.GetCmdArgs()
+ for value, arg in enumerate(args):
+ file.Write(",\n static_cast<%s>(%d)" % (arg.type, value + 11))
+ file.Write(",\n data);\n")
+ args = func.GetCmdArgs()
+ file.Write(" EXPECT_EQ(static_cast<uint32>(cmds::%s::kCmdId),\n"
+ % func.name)
+ file.Write(" cmd.header.command);\n")
+ file.Write(" EXPECT_EQ(sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(sizeof(data)),\n")
+ file.Write(" cmd.header.size * 4u);\n")
+ for value, arg in enumerate(args):
+ file.Write(" EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" %
+ (arg.type, value + 11, arg.name))
+ file.Write(" CheckBytesWrittenMatchesExpectedSize(\n")
+ file.Write(" next_cmd, sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(sizeof(data)));\n")
+ file.Write(" // TODO(gman): Check that data was inserted;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class PUTnHandler(TypeHandler):
+ """Handler for PUTn 'glUniform__v' type functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overridden from TypeHandler."""
+ TypeHandler.WriteServiceUnitTest(self, func, file)
+
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgsCountTooLarge) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ gl_arg_strings = []
+ arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()):
+ # hardcoded to match unit tests.
+ if count == 0:
+ # the location of the second element of the 2nd uniform.
+ # defined in GLES2DecoderBase::SetupShaderForUniform
+ gl_arg_strings.append("3")
+ arg_strings.append("ProgramManager::MakeFakeLocation(1, 1)")
+ elif count == 1:
+ # the number of elements that gl will be called with.
+ gl_arg_strings.append("3")
+ # the number of elements requested in the command.
+ arg_strings.append("5")
+ else:
+ gl_arg_strings.append(arg.GetValidGLArg(func, count, 0))
+ arg_strings.append(arg.GetValidArg(func, count, 0))
+ extra = {
+ 'gl_args': ", ".join(gl_arg_strings),
+ 'args': ", ".join(arg_strings),
+ }
+ self.WriteValidUnitTest(func, file, valid_test, extra)
+
+ def WriteImmediateServiceUnitTest(self, func, file):
+ """Overridden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+ EXPECT_CALL(
+ *gl_,
+ %(gl_func_name)s(%(gl_args)s,
+ reinterpret_cast<%(data_type)s*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ %(data_type)s temp[%(data_count)s * 2] = { 0, };
+ cmd.Init(%(args)s, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ gl_arg_strings = []
+ gl_any_strings = []
+ arg_strings = []
+ for count, arg in enumerate(func.GetOriginalArgs()[0:-1]):
+ gl_arg_strings.append(arg.GetValidGLArg(func, count, 0))
+ gl_any_strings.append("_")
+ arg_strings.append(arg.GetValidArg(func, count, 0))
+ extra = {
+ 'data_type': func.GetInfo('data_type'),
+ 'data_count': func.GetInfo('count'),
+ 'args': ", ".join(arg_strings),
+ 'gl_args': ", ".join(gl_arg_strings),
+ 'gl_any_args': ", ".join(gl_any_strings),
+ }
+ self.WriteValidUnitTest(func, file, valid_test, extra)
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ cmds::%(name)s& cmd = *GetImmediateAs<cmds::%(name)s>();
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_any_args)s, _)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ %(data_type)s temp[%(data_count)s * 2] = { 0, };
+ cmd.Init(%(all_but_last_args)s, &temp[0]);
+ EXPECT_EQ(error::%(parse_result)s,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test, extra)
+
+ def WriteGetDataSizeCode(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(%s), %d, &data_size)) {
+ return error::kOutOfBounds;
+ }
+"""
+ file.Write(code % (func.info.data_type, func.info.count))
+ if func.is_immediate:
+ file.Write(" if (data_size > immediate_data_size) {\n")
+ file.Write(" return error::kOutOfBounds;\n")
+ file.Write(" }\n")
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ last_arg_name = func.GetLastOriginalArg().name
+ file.Write(""" GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+""")
+ values_str = ' << ", " << '.join(
+ ["%s[%d + i * %d]" % (
+ last_arg_name, ndx, func.info.count) for ndx in range(
+ 0, func.info.count)])
+ file.Write(' GPU_CLIENT_LOG(" " << i << ": " << %s);\n' % values_str)
+ file.Write(" }\n });\n")
+ for arg in func.GetOriginalArgs():
+ arg.WriteClientSideValidationCode(file, func)
+ file.Write(" helper_->%sImmediate(%s);\n" %
+ (func.name, func.MakeOriginalArgString("")))
+ file.Write(" CheckGLError();\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Writes the GLES2 Implemention unit test."""
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ %(type)s data[%(count_param)d][%(count)d] = {{0}};
+ struct Cmds {
+ cmds::%(name)sImmediate cmd;
+ %(type)s data[%(count_param)d][%(count)d];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < %(count_param)d; ++ii) {
+ for (int jj = 0; jj < %(count)d; ++jj) {
+ data[ii][jj] = static_cast<%(type)s>(ii * %(count)d + jj);
+ }
+ }
+ expected.cmd.Init(%(cmd_args)s, &data[0][0]);
+ gl_->%(name)s(%(args)s, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+"""
+ cmd_arg_strings = []
+ for count, arg in enumerate(func.GetCmdArgs()[0:-2]):
+ cmd_arg_strings.append(arg.GetValidClientSideCmdArg(func, count, 0))
+ gl_arg_strings = []
+ count_param = 0
+ for count, arg in enumerate(func.GetOriginalArgs()[0:-1]):
+ gl_arg_strings.append(arg.GetValidClientSideArg(func, count, 0))
+ if arg.name == "count":
+ count_param = int(arg.GetValidClientSideArg(func, count, 0))
+ file.Write(code % {
+ 'name': func.name,
+ 'type': func.GetInfo('data_type'),
+ 'count': func.GetInfo('count'),
+ 'args': ", ".join(gl_arg_strings),
+ 'cmd_args': ", ".join(cmd_arg_strings),
+ 'count_param': count_param,
+ })
+
+ def WriteImmediateCmdComputeSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" static uint32 ComputeDataSize(GLsizei count) {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(" sizeof(%s) * %d * count); // NOLINT\n" %
+ (func.info.data_type, func.info.count))
+ file.Write(" }\n")
+ file.Write("\n")
+ file.Write(" static uint32 ComputeSize(GLsizei count) {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(
+ " sizeof(ValueType) + ComputeDataSize(count)); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSetHeader(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" void SetHeader(GLsizei count) {\n")
+ file.Write(
+ " header.SetCmdByTotalSize<ValueType>(ComputeSize(count));\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ file.Write(" void Init(%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_"),
+ last_arg.type, last_arg.name))
+ file.Write(" SetHeader(_count);\n")
+ args = func.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" memcpy(ImmediateDataAddress(this),\n")
+ file.Write(" _%s, ComputeDataSize(_count));\n" % last_arg.name)
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ copy_args = func.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s, %s _%s) {\n" %
+ (func.MakeTypedCmdArgString("_", True),
+ last_arg.type, last_arg.name))
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s, _%s);\n" %
+ (copy_args, last_arg.name))
+ file.Write(" const uint32 size = ComputeSize(_count);\n")
+ file.Write(" return NextImmediateCmdAddressTotalSize<ValueType>("
+ "cmd, size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ void %(name)s(%(typed_args)s) {
+ const uint32 size = gles2::cmds::%(name)s::ComputeSize(count);
+ gles2::cmds::%(name)s* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::%(name)s>(size);
+ if (c) {
+ c->Init(%(args)s);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedOriginalArgString(""),
+ "args": func.MakeOriginalArgString(""),
+ })
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ args = func.GetCmdArgs()
+ count_param = 0
+ for value, arg in enumerate(args):
+ if arg.name == "count":
+ count_param = int(arg.GetValidClientSideArg(func, value, 0))
+ file.Write("TEST_F(GLES2FormatTest, %s) {\n" % func.name)
+ file.Write(" const int kSomeBaseValueToTestWith = 51;\n")
+ file.Write(" static %s data[] = {\n" % func.info.data_type)
+ for v in range(0, func.info.count * count_param):
+ file.Write(" static_cast<%s>(kSomeBaseValueToTestWith + %d),\n" %
+ (func.info.data_type, v))
+ file.Write(" };\n")
+ file.Write(" cmds::%s& cmd = *GetBufferAs<cmds::%s>();\n" %
+ (func.name, func.name))
+ file.Write(" const GLsizei kNumElements = %d;\n" % count_param)
+ file.Write(" const size_t kExpectedCmdSize =\n")
+ file.Write(" sizeof(cmd) + kNumElements * sizeof(%s) * %d;\n" %
+ (func.info.data_type, func.info.count))
+ file.Write(" void* next_cmd = cmd.Set(\n")
+ file.Write(" &cmd")
+ for value, arg in enumerate(args):
+ file.Write(",\n static_cast<%s>(%d)" % (arg.type, value + 1))
+ file.Write(",\n data);\n")
+ file.Write(" EXPECT_EQ(static_cast<uint32>(cmds::%s::kCmdId),\n" %
+ func.name)
+ file.Write(" cmd.header.command);\n")
+ file.Write(" EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);\n")
+ for value, arg in enumerate(args):
+ file.Write(" EXPECT_EQ(static_cast<%s>(%d), cmd.%s);\n" %
+ (arg.type, value + 1, arg.name))
+ file.Write(" CheckBytesWrittenMatchesExpectedSize(\n")
+ file.Write(" next_cmd, sizeof(cmd) +\n")
+ file.Write(" RoundSizeToMultipleOfEntries(sizeof(data)));\n")
+ file.Write(" // TODO(gman): Check that data was inserted;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+
+class PUTXnHandler(TypeHandler):
+ """Handler for glUniform?f functions."""
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def WriteHandlerImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ %(type)s temp[%(count)s] = { %(values)s};
+ Do%(name)sv(%(location)s, 1, &temp[0]);
+"""
+ values = ""
+ args = func.GetOriginalArgs()
+ count = int(func.GetInfo('count'))
+ num_args = len(args)
+ for ii in range(count):
+ values += "%s, " % args[len(args) - count + ii].name
+
+ file.Write(code % {
+ 'name': func.name,
+ 'count': func.GetInfo('count'),
+ 'type': func.GetInfo('data_type'),
+ 'location': args[0].name,
+ 'args': func.MakeOriginalArgString(""),
+ 'values': values,
+ })
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(name)sv(%(local_args)s));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ args = func.GetOriginalArgs()
+ local_args = "%s, 1, _" % args[0].GetValidGLArg(func, 0, 0)
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'name': func.name,
+ 'count': func.GetInfo('count'),
+ 'local_args': local_args,
+ })
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(name)sv(_, _, _).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test, {
+ 'name': func.GetInfo('name'),
+ 'count': func.GetInfo('count'),
+ })
+
+
+class GLcharHandler(CustomHandler):
+ """Handler for functions that pass a single string ."""
+
+ def __init__(self):
+ CustomHandler.__init__(self)
+
+ def WriteImmediateCmdComputeSize(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(" static uint32 ComputeSize(uint32 data_size) {\n")
+ file.Write(" return static_cast<uint32>(\n")
+ file.Write(" sizeof(ValueType) + data_size); // NOLINT\n")
+ file.Write(" }\n")
+
+ def WriteImmediateCmdSetHeader(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """
+ void SetHeader(uint32 data_size) {
+ header.SetCmdBySize<ValueType>(data_size);
+ }
+"""
+ file.Write(code)
+
+ def WriteImmediateCmdInit(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ args = func.GetCmdArgs()
+ set_code = []
+ for arg in args:
+ set_code.append(" %s = _%s;" % (arg.name, arg.name))
+ code = """
+ void Init(%(typed_args)s, uint32 _data_size) {
+ SetHeader(_data_size);
+%(set_code)s
+ memcpy(ImmediateDataAddress(this), _%(last_arg)s, _data_size);
+ }
+
+"""
+ file.Write(code % {
+ "typed_args": func.MakeTypedOriginalArgString("_"),
+ "set_code": "\n".join(set_code),
+ "last_arg": last_arg.name
+ })
+
+ def WriteImmediateCmdSet(self, func, file):
+ """Overrriden from TypeHandler."""
+ last_arg = func.GetLastOriginalArg()
+ file.Write(" void* Set(void* cmd%s, uint32 _data_size) {\n" %
+ func.MakeTypedOriginalArgString("_", True))
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s, _data_size);\n" %
+ func.MakeOriginalArgString("_"))
+ file.Write(" return NextImmediateCmdAddress<ValueType>("
+ "cmd, _data_size);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteImmediateCmdHelper(self, func, file):
+ """Overrriden from TypeHandler."""
+ code = """ void %(name)s(%(typed_args)s) {
+ const uint32 data_size = strlen(name);
+ gles2::cmds::%(name)s* c =
+ GetImmediateCmdSpace<gles2::cmds::%(name)s>(data_size);
+ if (c) {
+ c->Init(%(args)s, data_size);
+ }
+ }
+
+"""
+ file.Write(code % {
+ "name": func.name,
+ "typed_args": func.MakeTypedOriginalArgString(""),
+ "args": func.MakeOriginalArgString(""),
+ })
+
+
+ def WriteImmediateFormatTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ init_code = []
+ check_code = []
+ all_but_last_arg = func.GetCmdArgs()[:-1]
+ for value, arg in enumerate(all_but_last_arg):
+ init_code.append(" static_cast<%s>(%d)," % (arg.type, value + 11))
+ for value, arg in enumerate(all_but_last_arg):
+ check_code.append(" EXPECT_EQ(static_cast<%s>(%d), cmd.%s);" %
+ (arg.type, value + 11, arg.name))
+ code = """
+TEST_F(GLES2FormatTest, %(func_name)s) {
+ cmds::%(func_name)s& cmd = *GetBufferAs<cmds::%(func_name)s>();
+ static const char* const test_str = \"test string\";
+ void* next_cmd = cmd.Set(
+ &cmd,
+%(init_code)s
+ test_str,
+ strlen(test_str));
+ EXPECT_EQ(static_cast<uint32>(cmds::%(func_name)s::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(strlen(test_str)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<char*>(next_cmd),
+ reinterpret_cast<char*>(&cmd) + sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(strlen(test_str)));
+%(check_code)s
+ EXPECT_EQ(static_cast<uint32>(strlen(test_str)), cmd.data_size);
+ EXPECT_EQ(0, memcmp(test_str, ImmediateDataAddress(&cmd), strlen(test_str)));
+ CheckBytesWritten(
+ next_cmd,
+ sizeof(cmd) + RoundSizeToMultipleOfEntries(strlen(test_str)),
+ sizeof(cmd) + strlen(test_str));
+}
+
+"""
+ file.Write(code % {
+ 'func_name': func.name,
+ 'init_code': "\n".join(init_code),
+ 'check_code': "\n".join(check_code),
+ })
+
+
+class GLcharNHandler(CustomHandler):
+ """Handler for functions that pass a single string with an optional len."""
+
+ def __init__(self):
+ CustomHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ func.cmd_args = []
+ func.AddCmdArg(Argument('bucket_id', 'GLuint'))
+
+ def AddImmediateFunction(self, generator, func):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def AddBucketFunction(self, generator, func):
+ """Overrriden from TypeHandler."""
+ pass
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write("""error::Error GLES2DecoderImpl::Handle%(name)s(
+ uint32 immediate_data_size, const gles2::cmds::%(name)s& c) {
+ GLuint bucket_id = static_cast<GLuint>(c.%(bucket_id)s);
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string str;
+ if (!bucket->GetAsString(&str)) {
+ return error::kInvalidArguments;
+ }
+ %(gl_func_name)s(0, str.c_str());
+ return error::kNoError;
+}
+
+""" % {
+ 'name': func.name,
+ 'gl_func_name': func.GetGLFunctionName(),
+ 'bucket_id': func.cmd_args[0].name,
+ })
+
+
+class IsHandler(TypeHandler):
+ """Handler for glIs____ type and glGetError functions."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ func.AddCmdArg(Argument("result_shm_id", 'uint32'))
+ func.AddCmdArg(Argument("result_shm_offset", 'uint32'))
+ if func.GetInfo('result') == None:
+ func.AddInfo('result', ['uint32'])
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s));
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s%(comma)sshared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ comma = ""
+ if len(func.GetOriginalArgs()):
+ comma =", "
+ self.WriteValidUnitTest(func, file, valid_test, {
+ 'comma': comma,
+ })
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs%(arg_index)d_%(value_index)d) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s%(comma)sshared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::%(parse_result)s, ExecuteCmd(cmd));%(gl_error_test)s
+}
+"""
+ self.WriteInvalidUnitTest(func, file, invalid_test, {
+ 'comma': comma,
+ })
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgsBadSharedMemoryId) {
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s)).Times(0);
+ SpecializedSetup<cmds::%(name)s, 0>(false);
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s%(comma)skInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(%(args)s%(comma)sshared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+"""
+ self.WriteValidUnitTest(func, file, invalid_test, {
+ 'comma': comma,
+ })
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ file.Write(
+ "error::Error GLES2DecoderImpl::Handle%s(\n" % func.name)
+ file.Write(
+ " uint32 immediate_data_size, const gles2::cmds::%s& c) {\n" %
+ func.name)
+ args = func.GetOriginalArgs()
+ for arg in args:
+ arg.WriteGetCode(file)
+
+ code = """ typedef cmds::%(func_name)s::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+"""
+ file.Write(code % {'func_name': func.name})
+ func.WriteHandlerValidation(file)
+ file.Write(" *result_dst = %s(%s);\n" %
+ (func.GetGLFunctionName(), func.MakeOriginalArgString("")))
+ file.Write(" return error::kNoError;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ impl_func = func.GetInfo('impl_func')
+ if impl_func == None or impl_func == True:
+ error_value = func.GetInfo("error_value") or "GL_FALSE"
+ file.Write("%s GLES2Implementation::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ file.Write(" GPU_CLIENT_SINGLE_THREAD_CHECK();\n")
+ self.WriteTraceEvent(func, file)
+ func.WriteDestinationInitalizationValidation(file)
+ self.WriteClientGLCallLog(func, file)
+ file.Write(" typedef cmds::%s::Result Result;\n" % func.name)
+ file.Write(" Result* result = GetResultAs<Result*>();\n")
+ file.Write(" if (!result) {\n")
+ file.Write(" return %s;\n" % error_value)
+ file.Write(" }\n")
+ file.Write(" *result = 0;\n")
+ arg_string = func.MakeOriginalArgString("")
+ comma = ""
+ if len(arg_string) > 0:
+ comma = ", "
+ file.Write(
+ " helper_->%s(%s%sGetResultShmId(), GetResultShmOffset());\n" %
+ (func.name, arg_string, comma))
+ file.Write(" WaitForCmd();\n")
+ file.Write(" %s result_value = *result;\n" % func.return_type)
+ file.Write(' GPU_CLIENT_LOG("returned " << result_value);\n')
+ file.Write(" CheckGLError();\n")
+ file.Write(" return result_value;\n")
+ file.Write("}\n")
+ file.Write("\n")
+
+ def WriteGLES2ImplementationUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ client_test = func.GetInfo('client_test')
+ if client_test == None or client_test == True:
+ code = """
+TEST_F(GLES2ImplementationTest, %(name)s) {
+ struct Cmds {
+ cmds::%(name)s cmd;
+ };
+
+ typedef cmds::%(name)s::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::%(name)s::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->%(name)s(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+"""
+ file.Write(code % {
+ 'name': func.name,
+ })
+
+
+class STRnHandler(TypeHandler):
+ """Handler for GetProgramInfoLog, GetShaderInfoLog, GetShaderSource, and
+ GetTranslatedShaderSourceANGLE."""
+
+ def __init__(self):
+ TypeHandler.__init__(self)
+
+ def InitFunction(self, func):
+ """Overrriden from TypeHandler."""
+ # remove all but the first cmd args.
+ cmd_args = func.GetCmdArgs()
+ func.ClearCmdArgs()
+ func.AddCmdArg(cmd_args[0])
+ # add on a bucket id.
+ func.AddCmdArg(Argument('bucket_id', 'uint32'))
+
+ def WriteGLES2Implementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ code_1 = """%(return_type)s GLES2Implementation::%(func_name)s(%(args)s) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+"""
+ code_2 = """ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] gl%(func_name)s" << "("
+ << %(arg0)s << ", "
+ << %(arg1)s << ", "
+ << static_cast<void*>(%(arg2)s) << ", "
+ << static_cast<void*>(%(arg3)s) << ")");
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->%(func_name)s(%(id_name)s, kResultBucketId);
+ std::string str;
+ GLsizei max_size = 0;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ if (bufsize > 0) {
+ max_size =
+ std::min(static_cast<size_t>(%(bufsize_name)s) - 1, str.size());
+ memcpy(%(dest_name)s, str.c_str(), max_size);
+ %(dest_name)s[max_size] = '\\0';
+ GPU_CLIENT_LOG("------\\n" << %(dest_name)s << "\\n------");
+ }
+ }
+ if (%(length_name)s != NULL) {
+ *%(length_name)s = max_size;
+ }
+ CheckGLError();
+}
+"""
+ args = func.GetOriginalArgs()
+ str_args = {
+ 'return_type': func.return_type,
+ 'func_name': func.original_name,
+ 'args': func.MakeTypedOriginalArgString(""),
+ 'id_name': args[0].name,
+ 'bufsize_name': args[1].name,
+ 'length_name': args[2].name,
+ 'dest_name': args[3].name,
+ 'arg0': args[0].name,
+ 'arg1': args[1].name,
+ 'arg2': args[2].name,
+ 'arg3': args[3].name,
+ }
+ file.Write(code_1 % str_args)
+ func.WriteDestinationInitalizationValidation(file)
+ file.Write(code_2 % str_args)
+
+ def WriteServiceUnitTest(self, func, file):
+ """Overrriden from TypeHandler."""
+ valid_test = """
+TEST_F(%(test_name)s, %(name)sValidArgs) {
+ const char* kInfo = "hello";
+ const uint32 kBucketId = 123;
+ SpecializedSetup<cmds::%(name)s, 0>(true);
+%(expect_len_code)s
+ EXPECT_CALL(*gl_, %(gl_func_name)s(%(gl_args)s))
+ .WillOnce(DoAll(SetArgumentPointee<2>(strlen(kInfo)),
+ SetArrayArgument<3>(kInfo, kInfo + strlen(kInfo) + 1)));
+ cmds::%(name)s cmd;
+ cmd.Init(%(args)s);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(strlen(kInfo) + 1, bucket->size());
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kInfo,
+ bucket->size()));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+"""
+ args = func.GetOriginalArgs()
+ id_name = args[0].GetValidGLArg(func, 0, 0)
+ get_len_func = func.GetInfo('get_len_func')
+ get_len_enum = func.GetInfo('get_len_enum')
+ sub = {
+ 'id_name': id_name,
+ 'get_len_func': get_len_func,
+ 'get_len_enum': get_len_enum,
+ 'gl_args': '%s, strlen(kInfo) + 1, _, _' %
+ args[0].GetValidGLArg(func, 0, 0),
+ 'args': '%s, kBucketId' % args[0].GetValidArg(func, 0, 0),
+ 'expect_len_code': '',
+ }
+ if get_len_func and get_len_func[0:2] == 'gl':
+ sub['expect_len_code'] = (
+ " EXPECT_CALL(*gl_, %s(%s, %s, _))\n"
+ " .WillOnce(SetArgumentPointee<2>(strlen(kInfo) + 1));") % (
+ get_len_func[2:], id_name, get_len_enum)
+ self.WriteValidUnitTest(func, file, valid_test, sub)
+
+ invalid_test = """
+TEST_F(%(test_name)s, %(name)sInvalidArgs) {
+ const uint32 kBucketId = 123;
+ EXPECT_CALL(*gl_, %(gl_func_name)s(_, _, _, _))
+ .Times(0);
+ cmds::%(name)s cmd;
+ cmd.Init(kInvalidClientId, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+"""
+ self.WriteValidUnitTest(func, file, invalid_test)
+
+ def WriteServiceImplementation(self, func, file):
+ """Overrriden from TypeHandler."""
+ pass
+
+
+class FunctionInfo(object):
+ """Holds info about a function."""
+
+ def __init__(self, info, type_handler):
+ for key in info:
+ setattr(self, key, info[key])
+ self.type_handler = type_handler
+ if not 'type' in info:
+ self.type = ''
+
+
+class Argument(object):
+ """A class that represents a function argument."""
+
+ cmd_type_map_ = {
+ 'GLenum': 'uint32',
+ 'GLint': 'int32',
+ 'GLintptr': 'int32',
+ 'GLsizei': 'int32',
+ 'GLsizeiptr': 'int32',
+ 'GLfloat': 'float',
+ 'GLclampf': 'float',
+ }
+ need_validation_ = ['GLsizei*', 'GLboolean*', 'GLenum*', 'GLint*']
+
+ def __init__(self, name, type):
+ self.name = name
+ self.optional = type.endswith("Optional*")
+ if self.optional:
+ type = type[:-9] + "*"
+ self.type = type
+
+ if type in self.cmd_type_map_:
+ self.cmd_type = self.cmd_type_map_[type]
+ else:
+ self.cmd_type = 'uint32'
+
+ def IsPointer(self):
+ """Returns true if argument is a pointer."""
+ return False
+
+ def AddCmdArgs(self, args):
+ """Adds command arguments for this argument to the given list."""
+ return args.append(self)
+
+ def AddInitArgs(self, args):
+ """Adds init arguments for this argument to the given list."""
+ return args.append(self)
+
+ def GetValidArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ valid_arg = func.GetValidArg(offset)
+ if valid_arg != None:
+ return valid_arg
+ return str(offset + 1)
+
+ def GetValidClientSideArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return str(offset + 1)
+
+ def GetValidClientSideCmdArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return str(offset + 1)
+
+ def GetValidGLArg(self, func, offset, index):
+ """Gets a valid GL value for this argument."""
+ valid_arg = func.GetValidArg(offset)
+ if valid_arg != None:
+ return valid_arg
+ return str(offset + 1)
+
+ def GetNumInvalidValues(self, func):
+ """returns the number of invalid values to be tested."""
+ return 0
+
+ def GetInvalidArg(self, offset, index):
+ """returns an invalid value and expected parse result by index."""
+ return ("---ERROR0---", "---ERROR2---", None)
+
+ def GetLogArg(self):
+ """Get argument appropriate for LOG macro."""
+ if self.type == 'GLboolean':
+ return 'GLES2Util::GetStringBool(%s)' % self.name
+ if self.type == 'GLenum':
+ return 'GLES2Util::GetStringEnum(%s)' % self.name
+ return self.name
+
+ def WriteGetCode(self, file):
+ """Writes the code to get an argument from a command structure."""
+ file.Write(" %s %s = static_cast<%s>(c.%s);\n" %
+ (self.type, self.name, self.type, self.name))
+
+ def WriteValidationCode(self, file, func):
+ """Writes the validation code for an argument."""
+ pass
+
+ def WriteClientSideValidationCode(self, file, func):
+ """Writes the validation code for an argument."""
+ pass
+
+ def WriteDestinationInitalizationValidation(self, file, func):
+ """Writes the client side destintion initialization validation."""
+ pass
+
+ def WriteDestinationInitalizationValidatationIfNeeded(self, file, func):
+ """Writes the client side destintion initialization validation if needed."""
+ parts = self.type.split(" ")
+ if len(parts) > 1:
+ return
+ if parts[0] in self.need_validation_:
+ file.Write(
+ " GPU_CLIENT_VALIDATE_DESTINATION_%sINITALIZATION(%s, %s);\n" %
+ ("OPTIONAL_" if self.optional else "", self.type[:-1], self.name))
+
+
+ def WriteGetAddress(self, file):
+ """Writes the code to get the address this argument refers to."""
+ pass
+
+ def GetImmediateVersion(self):
+ """Gets the immediate version of this argument."""
+ return self
+
+ def GetBucketVersion(self):
+ """Gets the bucket version of this argument."""
+ return self
+
+
+class BoolArgument(Argument):
+ """class for GLboolean"""
+
+ def __init__(self, name, type):
+ Argument.__init__(self, name, 'GLboolean')
+
+ def GetValidArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return 'true'
+
+ def GetValidClientSideArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return 'true'
+
+ def GetValidClientSideCmdArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return 'true'
+
+ def GetValidGLArg(self, func, offset, index):
+ """Gets a valid GL value for this argument."""
+ return 'true'
+
+
+class UniformLocationArgument(Argument):
+ """class for uniform locations."""
+
+ def __init__(self, name):
+ Argument.__init__(self, name, "GLint")
+
+ def WriteGetCode(self, file):
+ """Writes the code to get an argument from a command structure."""
+ code = """ %s %s = static_cast<%s>(c.%s);
+"""
+ file.Write(code % (self.type, self.name, self.type, self.name))
+
+ def GetValidArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return "%d" % (offset + 1)
+
+
+class DataSizeArgument(Argument):
+ """class for data_size which Bucket commands do not need."""
+
+ def __init__(self, name):
+ Argument.__init__(self, name, "uint32")
+
+ def GetBucketVersion(self):
+ return None
+
+
+class SizeArgument(Argument):
+ """class for GLsizei and GLsizeiptr."""
+
+ def __init__(self, name, type):
+ Argument.__init__(self, name, type)
+
+ def GetNumInvalidValues(self, func):
+ """overridden from Argument."""
+ if func.is_immediate:
+ return 0
+ return 1
+
+ def GetInvalidArg(self, offset, index):
+ """overridden from Argument."""
+ return ("-1", "kNoError", "GL_INVALID_VALUE")
+
+ def WriteValidationCode(self, file, func):
+ """overridden from Argument."""
+ file.Write(" if (%s < 0) {\n" % self.name)
+ file.Write(
+ " LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, \"gl%s\", \"%s < 0\");\n" %
+ (func.original_name, self.name))
+ file.Write(" return error::kNoError;\n")
+ file.Write(" }\n")
+
+ def WriteClientSideValidationCode(self, file, func):
+ """overridden from Argument."""
+ file.Write(" if (%s < 0) {\n" % self.name)
+ file.Write(
+ " SetGLError(GL_INVALID_VALUE, \"gl%s\", \"%s < 0\");\n" %
+ (func.original_name, self.name))
+ file.Write(" return;\n")
+ file.Write(" }\n")
+
+
+class SizeNotNegativeArgument(SizeArgument):
+ """class for GLsizeiNotNegative. It's NEVER allowed to be negative"""
+
+ def __init__(self, name, type, gl_type):
+ SizeArgument.__init__(self, name, gl_type)
+
+ def GetInvalidArg(self, offset, index):
+ """overridden from SizeArgument."""
+ return ("-1", "kOutOfBounds", "GL_NO_ERROR")
+
+ def WriteValidationCode(self, file, func):
+ """overridden from SizeArgument."""
+ pass
+
+
+class EnumBaseArgument(Argument):
+ """Base class for EnumArgument, IntArgument and ValidatedBoolArgument"""
+
+ def __init__(self, name, gl_type, type, gl_error):
+ Argument.__init__(self, name, gl_type)
+
+ self.local_type = type
+ self.gl_error = gl_error
+ name = type[len(gl_type):]
+ self.type_name = name
+ self.enum_info = _ENUM_LISTS[name]
+
+ def WriteValidationCode(self, file, func):
+ file.Write(" if (!validators_->%s.IsValid(%s)) {\n" %
+ (ToUnderscore(self.type_name), self.name))
+ if self.gl_error == "GL_INVALID_ENUM":
+ file.Write(
+ " LOCAL_SET_GL_ERROR_INVALID_ENUM(\"gl%s\", %s, \"%s\");\n" %
+ (func.original_name, self.name, self.name))
+ else:
+ file.Write(
+ " LOCAL_SET_GL_ERROR(%s, \"gl%s\", \"%s %s\");\n" %
+ (self.gl_error, func.original_name, self.name, self.gl_error))
+ file.Write(" return error::kNoError;\n")
+ file.Write(" }\n")
+
+ def GetValidArg(self, func, offset, index):
+ valid_arg = func.GetValidArg(offset)
+ if valid_arg != None:
+ return valid_arg
+ if 'valid' in self.enum_info:
+ valid = self.enum_info['valid']
+ num_valid = len(valid)
+ if index >= num_valid:
+ index = num_valid - 1
+ return valid[index]
+ return str(offset + 1)
+
+ def GetValidClientSideArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return self.GetValidArg(func, offset, index)
+
+ def GetValidClientSideCmdArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return self.GetValidArg(func, offset, index)
+
+ def GetValidGLArg(self, func, offset, index):
+ """Gets a valid value for this argument."""
+ return self.GetValidArg(func, offset, index)
+
+ def GetNumInvalidValues(self, func):
+ """returns the number of invalid values to be tested."""
+ if 'invalid' in self.enum_info:
+ invalid = self.enum_info['invalid']
+ return len(invalid)
+ return 0
+
+ def GetInvalidArg(self, offset, index):
+ """returns an invalid value by index."""
+ if 'invalid' in self.enum_info:
+ invalid = self.enum_info['invalid']
+ num_invalid = len(invalid)
+ if index >= num_invalid:
+ index = num_invalid - 1
+ return (invalid[index], "kNoError", self.gl_error)
+ return ("---ERROR1---", "kNoError", self.gl_error)
+
+
+class EnumArgument(EnumBaseArgument):
+ """A class that represents a GLenum argument"""
+
+ def __init__(self, name, type):
+ EnumBaseArgument.__init__(self, name, "GLenum", type, "GL_INVALID_ENUM")
+
+ def GetLogArg(self):
+ """Overridden from Argument."""
+ return ("GLES2Util::GetString%s(%s)" %
+ (self.type_name, self.name))
+
+
+class IntArgument(EnumBaseArgument):
+ """A class for a GLint argument that can only except specific values.
+
+ For example glTexImage2D takes a GLint for its internalformat
+ argument instead of a GLenum.
+ """
+
+ def __init__(self, name, type):
+ EnumBaseArgument.__init__(self, name, "GLint", type, "GL_INVALID_VALUE")
+
+
+class ValidatedBoolArgument(EnumBaseArgument):
+ """A class for a GLboolean argument that can only except specific values.
+
+ For example glUniformMatrix takes a GLboolean for it's transpose but it
+ must be false.
+ """
+
+ def __init__(self, name, type):
+ EnumBaseArgument.__init__(self, name, "GLboolean", type, "GL_INVALID_VALUE")
+
+ def GetLogArg(self):
+ """Overridden from Argument."""
+ return 'GLES2Util::GetStringBool(%s)' % self.name
+
+
+class ImmediatePointerArgument(Argument):
+ """A class that represents an immediate argument to a function.
+
+ An immediate argument is one where the data follows the command.
+ """
+
+ def __init__(self, name, type):
+ Argument.__init__(self, name, type)
+
+ def AddCmdArgs(self, args):
+ """Overridden from Argument."""
+ pass
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ file.Write(
+ " %s %s = GetImmediateDataAs<%s>(\n" %
+ (self.type, self.name, self.type))
+ file.Write(" c, data_size, immediate_data_size);\n")
+
+ def WriteValidationCode(self, file, func):
+ """Overridden from Argument."""
+ file.Write(" if (%s == NULL) {\n" % self.name)
+ file.Write(" return error::kOutOfBounds;\n")
+ file.Write(" }\n")
+
+ def GetImmediateVersion(self):
+ """Overridden from Argument."""
+ return None
+
+ def WriteDestinationInitalizationValidation(self, file, func):
+ """Overridden from Argument."""
+ self.WriteDestinationInitalizationValidatationIfNeeded(file, func)
+
+ def GetLogArg(self):
+ """Overridden from Argument."""
+ return "static_cast<const void*>(%s)" % self.name
+
+
+class BucketPointerArgument(Argument):
+ """A class that represents an bucket argument to a function."""
+
+ def __init__(self, name, type):
+ Argument.__init__(self, name, type)
+
+ def AddCmdArgs(self, args):
+ """Overridden from Argument."""
+ pass
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ file.Write(
+ " %s %s = bucket->GetData(0, data_size);\n" %
+ (self.type, self.name))
+
+ def WriteValidationCode(self, file, func):
+ """Overridden from Argument."""
+ pass
+
+ def GetImmediateVersion(self):
+ """Overridden from Argument."""
+ return None
+
+ def WriteDestinationInitalizationValidation(self, file, func):
+ """Overridden from Argument."""
+ self.WriteDestinationInitalizationValidatationIfNeeded(file, func)
+
+ def GetLogArg(self):
+ """Overridden from Argument."""
+ return "static_cast<const void*>(%s)" % self.name
+
+
+class PointerArgument(Argument):
+ """A class that represents a pointer argument to a function."""
+
+ def __init__(self, name, type):
+ Argument.__init__(self, name, type)
+
+ def IsPointer(self):
+ """Returns true if argument is a pointer."""
+ return True
+
+ def GetValidArg(self, func, offset, index):
+ """Overridden from Argument."""
+ return "shared_memory_id_, shared_memory_offset_"
+
+ def GetValidGLArg(self, func, offset, index):
+ """Overridden from Argument."""
+ return "reinterpret_cast<%s>(shared_memory_address_)" % self.type
+
+ def GetNumInvalidValues(self, func):
+ """Overridden from Argument."""
+ return 2
+
+ def GetInvalidArg(self, offset, index):
+ """Overridden from Argument."""
+ if index == 0:
+ return ("kInvalidSharedMemoryId, 0", "kOutOfBounds", None)
+ else:
+ return ("shared_memory_id_, kInvalidSharedMemoryOffset",
+ "kOutOfBounds", None)
+
+ def GetLogArg(self):
+ """Overridden from Argument."""
+ return "static_cast<const void*>(%s)" % self.name
+
+ def AddCmdArgs(self, args):
+ """Overridden from Argument."""
+ args.append(Argument("%s_shm_id" % self.name, 'uint32'))
+ args.append(Argument("%s_shm_offset" % self.name, 'uint32'))
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ file.Write(
+ " %s %s = GetSharedMemoryAs<%s>(\n" %
+ (self.type, self.name, self.type))
+ file.Write(
+ " c.%s_shm_id, c.%s_shm_offset, data_size);\n" %
+ (self.name, self.name))
+
+ def WriteGetAddress(self, file):
+ """Overridden from Argument."""
+ file.Write(
+ " %s %s = GetSharedMemoryAs<%s>(\n" %
+ (self.type, self.name, self.type))
+ file.Write(
+ " %s_shm_id, %s_shm_offset, %s_size);\n" %
+ (self.name, self.name, self.name))
+
+ def WriteValidationCode(self, file, func):
+ """Overridden from Argument."""
+ file.Write(" if (%s == NULL) {\n" % self.name)
+ file.Write(" return error::kOutOfBounds;\n")
+ file.Write(" }\n")
+
+ def GetImmediateVersion(self):
+ """Overridden from Argument."""
+ return ImmediatePointerArgument(self.name, self.type)
+
+ def GetBucketVersion(self):
+ """Overridden from Argument."""
+ if self.type == "const char*":
+ return InputStringBucketArgument(self.name, self.type)
+ return BucketPointerArgument(self.name, self.type)
+
+ def WriteDestinationInitalizationValidation(self, file, func):
+ """Overridden from Argument."""
+ self.WriteDestinationInitalizationValidatationIfNeeded(file, func)
+
+
+class InputStringBucketArgument(Argument):
+ """An string input argument where the string is passed in a bucket."""
+
+ def __init__(self, name, type):
+ Argument.__init__(self, name + "_bucket_id", "uint32")
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ code = """
+ Bucket* %(name)s_bucket = GetBucket(c.%(name)s);
+ if (!%(name)s_bucket) {
+ return error::kInvalidArguments;
+ }
+ std::string %(name)s_str;
+ if (!%(name)s_bucket->GetAsString(&%(name)s_str)) {
+ return error::kInvalidArguments;
+ }
+ const char* %(name)s = %(name)s_str.c_str();
+"""
+ file.Write(code % {
+ 'name': self.name,
+ })
+
+ def GetValidArg(self, func, offset, index):
+ return "kNameBucketId"
+
+ def GetValidGLArg(self, func, offset, index):
+ return "_"
+
+
+class NonImmediatePointerArgument(PointerArgument):
+ """A pointer argument that stays a pointer even in an immediate cmd."""
+
+ def __init__(self, name, type):
+ PointerArgument.__init__(self, name, type)
+
+ def IsPointer(self):
+ """Returns true if argument is a pointer."""
+ return False
+
+ def GetImmediateVersion(self):
+ """Overridden from Argument."""
+ return self
+
+
+class ResourceIdArgument(Argument):
+ """A class that represents a resource id argument to a function."""
+
+ def __init__(self, name, type):
+ match = re.match("(GLid\w+)", type)
+ self.resource_type = match.group(1)[4:]
+ type = type.replace(match.group(1), "GLuint")
+ Argument.__init__(self, name, type)
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ file.Write(" %s %s = c.%s;\n" % (self.type, self.name, self.name))
+
+ def GetValidArg(self, func, offset, index):
+ return "client_%s_id_" % self.resource_type.lower()
+
+ def GetValidGLArg(self, func, offset, index):
+ return "kService%sId" % self.resource_type
+
+
+class ResourceIdBindArgument(Argument):
+ """Represents a resource id argument to a bind function."""
+
+ def __init__(self, name, type):
+ match = re.match("(GLidBind\w+)", type)
+ self.resource_type = match.group(1)[8:]
+ type = type.replace(match.group(1), "GLuint")
+ Argument.__init__(self, name, type)
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ code = """ %(type)s %(name)s = c.%(name)s;
+"""
+ file.Write(code % {'type': self.type, 'name': self.name})
+
+ def GetValidArg(self, func, offset, index):
+ return "client_%s_id_" % self.resource_type.lower()
+
+ def GetValidGLArg(self, func, offset, index):
+ return "kService%sId" % self.resource_type
+
+
+class ResourceIdZeroArgument(Argument):
+ """Represents a resource id argument to a function that can be zero."""
+
+ def __init__(self, name, type):
+ match = re.match("(GLidZero\w+)", type)
+ self.resource_type = match.group(1)[8:]
+ type = type.replace(match.group(1), "GLuint")
+ Argument.__init__(self, name, type)
+
+ def WriteGetCode(self, file):
+ """Overridden from Argument."""
+ file.Write(" %s %s = c.%s;\n" % (self.type, self.name, self.name))
+
+ def GetValidArg(self, func, offset, index):
+ return "client_%s_id_" % self.resource_type.lower()
+
+ def GetValidGLArg(self, func, offset, index):
+ return "kService%sId" % self.resource_type
+
+ def GetNumInvalidValues(self, func):
+ """returns the number of invalid values to be tested."""
+ return 1
+
+ def GetInvalidArg(self, offset, index):
+ """returns an invalid value by index."""
+ return ("kInvalidClientId", "kNoError", "GL_INVALID_VALUE")
+
+
+class Function(object):
+ """A class that represents a function."""
+
+ def __init__(self, original_name, name, info, return_type, original_args,
+ args_for_cmds, cmd_args, init_args, num_pointer_args):
+ self.name = name
+ self.original_name = original_name
+ self.info = info
+ self.type_handler = info.type_handler
+ self.return_type = return_type
+ self.original_args = original_args
+ self.num_pointer_args = num_pointer_args
+ self.can_auto_generate = num_pointer_args == 0 and return_type == "void"
+ self.cmd_args = cmd_args
+ self.init_args = init_args
+ self.InitFunction()
+ self.args_for_cmds = args_for_cmds
+ self.is_immediate = False
+
+ def IsType(self, type_name):
+ """Returns true if function is a certain type."""
+ return self.info.type == type_name
+
+ def InitFunction(self):
+ """Calls the init function for the type handler."""
+ self.type_handler.InitFunction(self)
+
+ def GetInfo(self, name):
+ """Returns a value from the function info for this function."""
+ if hasattr(self.info, name):
+ return getattr(self.info, name)
+ return None
+
+ def GetValidArg(self, index):
+ """Gets a valid arg from the function info if one exists."""
+ valid_args = self.GetInfo('valid_args')
+ if valid_args and str(index) in valid_args:
+ return valid_args[str(index)]
+ return None
+
+ def AddInfo(self, name, value):
+ """Adds an info."""
+ setattr(self.info, name, value)
+
+ def IsCoreGLFunction(self):
+ return (not self.GetInfo('extension') and
+ not self.GetInfo('pepper_interface'))
+
+ def InPepperInterface(self, interface):
+ ext = self.GetInfo('pepper_interface')
+ if not interface.GetName():
+ return self.IsCoreGLFunction()
+ return ext == interface.GetName()
+
+ def InAnyPepperExtension(self):
+ return self.IsCoreGLFunction() or self.GetInfo('pepper_interface')
+
+ def GetGLFunctionName(self):
+ """Gets the function to call to execute GL for this command."""
+ if self.GetInfo('decoder_func'):
+ return self.GetInfo('decoder_func')
+ return "gl%s" % self.original_name
+
+ def GetGLTestFunctionName(self):
+ gl_func_name = self.GetInfo('gl_test_func')
+ if gl_func_name == None:
+ gl_func_name = self.GetGLFunctionName()
+ if gl_func_name.startswith("gl"):
+ gl_func_name = gl_func_name[2:]
+ else:
+ gl_func_name = self.original_name
+ return gl_func_name
+
+ def AddCmdArg(self, arg):
+ """Adds a cmd argument to this function."""
+ self.cmd_args.append(arg)
+
+ def GetCmdArgs(self):
+ """Gets the command args for this function."""
+ return self.cmd_args
+
+ def ClearCmdArgs(self):
+ """Clears the command args for this function."""
+ self.cmd_args = []
+
+ def GetInitArgs(self):
+ """Gets the init args for this function."""
+ return self.init_args
+
+ def GetOriginalArgs(self):
+ """Gets the original arguments to this function."""
+ return self.original_args
+
+ def GetLastOriginalArg(self):
+ """Gets the last original argument to this function."""
+ return self.original_args[len(self.original_args) - 1]
+
+ def __GetArgList(self, arg_string, add_comma):
+ """Adds a comma if arg_string is not empty and add_comma is true."""
+ comma = ""
+ if add_comma and len(arg_string):
+ comma = ", "
+ return "%s%s" % (comma, arg_string)
+
+ def MakeTypedOriginalArgString(self, prefix, add_comma = False):
+ """Gets a list of arguments as they arg in GL."""
+ args = self.GetOriginalArgs()
+ arg_string = ", ".join(
+ ["%s %s%s" % (arg.type, prefix, arg.name) for arg in args])
+ return self.__GetArgList(arg_string, add_comma)
+
+ def MakeOriginalArgString(self, prefix, add_comma = False, separator = ", "):
+ """Gets the list of arguments as they are in GL."""
+ args = self.GetOriginalArgs()
+ arg_string = separator.join(
+ ["%s%s" % (prefix, arg.name) for arg in args])
+ return self.__GetArgList(arg_string, add_comma)
+
+ def MakeTypedCmdArgString(self, prefix, add_comma = False):
+ """Gets a typed list of arguments as they need to be for command buffers."""
+ args = self.GetCmdArgs()
+ arg_string = ", ".join(
+ ["%s %s%s" % (arg.type, prefix, arg.name) for arg in args])
+ return self.__GetArgList(arg_string, add_comma)
+
+ def MakeCmdArgString(self, prefix, add_comma = False):
+ """Gets the list of arguments as they need to be for command buffers."""
+ args = self.GetCmdArgs()
+ arg_string = ", ".join(
+ ["%s%s" % (prefix, arg.name) for arg in args])
+ return self.__GetArgList(arg_string, add_comma)
+
+ def MakeTypedInitString(self, prefix, add_comma = False):
+ """Gets a typed list of arguments as they need to be for cmd Init/Set."""
+ args = self.GetInitArgs()
+ arg_string = ", ".join(
+ ["%s %s%s" % (arg.type, prefix, arg.name) for arg in args])
+ return self.__GetArgList(arg_string, add_comma)
+
+ def MakeInitString(self, prefix, add_comma = False):
+ """Gets the list of arguments as they need to be for cmd Init/Set."""
+ args = self.GetInitArgs()
+ arg_string = ", ".join(
+ ["%s%s" % (prefix, arg.name) for arg in args])
+ return self.__GetArgList(arg_string, add_comma)
+
+ def MakeLogArgString(self):
+ """Makes a string of the arguments for the LOG macros"""
+ args = self.GetOriginalArgs()
+ return ' << ", " << '.join([arg.GetLogArg() for arg in args])
+
+ def WriteCommandDescription(self, file):
+ """Writes a description of the command."""
+ file.Write("//! Command that corresponds to gl%s.\n" % self.original_name)
+
+ def WriteHandlerValidation(self, file):
+ """Writes validation code for the function."""
+ for arg in self.GetOriginalArgs():
+ arg.WriteValidationCode(file, self)
+ self.WriteValidationCode(file)
+
+ def WriteHandlerImplementation(self, file):
+ """Writes the handler implementation for this command."""
+ self.type_handler.WriteHandlerImplementation(self, file)
+
+ def WriteValidationCode(self, file):
+ """Writes the validation code for a command."""
+ pass
+
+ def WriteCmdArgFlag(self, file):
+ """Writes the cmd kArgFlags constant."""
+ file.Write(" static const cmd::ArgFlags kArgFlags = cmd::kFixed;\n")
+
+ def WriteCmdComputeSize(self, file):
+ """Writes the ComputeSize function for the command."""
+ file.Write(" static uint32 ComputeSize() {\n")
+ file.Write(
+ " return static_cast<uint32>(sizeof(ValueType)); // NOLINT\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteCmdSetHeader(self, file):
+ """Writes the cmd's SetHeader function."""
+ file.Write(" void SetHeader() {\n")
+ file.Write(" header.SetCmd<ValueType>();\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteCmdInit(self, file):
+ """Writes the cmd's Init function."""
+ file.Write(" void Init(%s) {\n" % self.MakeTypedCmdArgString("_"))
+ file.Write(" SetHeader();\n")
+ args = self.GetCmdArgs()
+ for arg in args:
+ file.Write(" %s = _%s;\n" % (arg.name, arg.name))
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteCmdSet(self, file):
+ """Writes the cmd's Set function."""
+ copy_args = self.MakeCmdArgString("_", False)
+ file.Write(" void* Set(void* cmd%s) {\n" %
+ self.MakeTypedCmdArgString("_", True))
+ file.Write(" static_cast<ValueType*>(cmd)->Init(%s);\n" % copy_args)
+ file.Write(" return NextCmdAddress<ValueType>(cmd);\n")
+ file.Write(" }\n")
+ file.Write("\n")
+
+ def WriteStruct(self, file):
+ self.type_handler.WriteStruct(self, file)
+
+ def WriteDocs(self, file):
+ self.type_handler.WriteDocs(self, file)
+
+ def WriteCmdHelper(self, file):
+ """Writes the cmd's helper."""
+ self.type_handler.WriteCmdHelper(self, file)
+
+ def WriteServiceImplementation(self, file):
+ """Writes the service implementation for a command."""
+ self.type_handler.WriteServiceImplementation(self, file)
+
+ def WriteServiceUnitTest(self, file):
+ """Writes the service implementation for a command."""
+ self.type_handler.WriteServiceUnitTest(self, file)
+
+ def WriteGLES2CLibImplementation(self, file):
+ """Writes the GLES2 C Lib Implemention."""
+ self.type_handler.WriteGLES2CLibImplementation(self, file)
+
+ def WriteGLES2InterfaceHeader(self, file):
+ """Writes the GLES2 Interface declaration."""
+ self.type_handler.WriteGLES2InterfaceHeader(self, file)
+
+ def WriteGLES2InterfaceStub(self, file):
+ """Writes the GLES2 Interface Stub declaration."""
+ self.type_handler.WriteGLES2InterfaceStub(self, file)
+
+ def WriteGLES2InterfaceStubImpl(self, file):
+ """Writes the GLES2 Interface Stub declaration."""
+ self.type_handler.WriteGLES2InterfaceStubImpl(self, file)
+
+ def WriteGLES2ImplementationHeader(self, file):
+ """Writes the GLES2 Implemention declaration."""
+ self.type_handler.WriteGLES2ImplementationHeader(self, file)
+
+ def WriteGLES2Implementation(self, file):
+ """Writes the GLES2 Implemention definition."""
+ self.type_handler.WriteGLES2Implementation(self, file)
+
+ def WriteGLES2TraceImplementationHeader(self, file):
+ """Writes the GLES2 Trace Implemention declaration."""
+ self.type_handler.WriteGLES2TraceImplementationHeader(self, file)
+
+ def WriteGLES2TraceImplementation(self, file):
+ """Writes the GLES2 Trace Implemention definition."""
+ self.type_handler.WriteGLES2TraceImplementation(self, file)
+
+ def WriteGLES2Header(self, file):
+ """Writes the GLES2 Implemention unit test."""
+ self.type_handler.WriteGLES2Header(self, file)
+
+ def WriteGLES2ImplementationUnitTest(self, file):
+ """Writes the GLES2 Implemention unit test."""
+ self.type_handler.WriteGLES2ImplementationUnitTest(self, file)
+
+ def WriteDestinationInitalizationValidation(self, file):
+ """Writes the client side destintion initialization validation."""
+ self.type_handler.WriteDestinationInitalizationValidation(self, file)
+
+ def WriteFormatTest(self, file):
+ """Writes the cmd's format test."""
+ self.type_handler.WriteFormatTest(self, file)
+
+
+class PepperInterface(object):
+ """A class that represents a function."""
+
+ def __init__(self, info):
+ self.name = info["name"]
+ self.dev = info["dev"]
+
+ def GetName(self):
+ return self.name
+
+ def GetInterfaceName(self):
+ upperint = ""
+ dev = ""
+ if self.name:
+ upperint = "_" + self.name.upper()
+ if self.dev:
+ dev = "_DEV"
+ return "PPB_OPENGLES2%s%s_INTERFACE" % (upperint, dev)
+
+ def GetInterfaceString(self):
+ dev = ""
+ if self.dev:
+ dev = "(Dev)"
+ return "PPB_OpenGLES2%s%s" % (self.name, dev)
+
+ def GetStructName(self):
+ dev = ""
+ if self.dev:
+ dev = "_Dev"
+ return "PPB_OpenGLES2%s%s" % (self.name, dev)
+
+
+class ImmediateFunction(Function):
+ """A class that represnets an immediate function command."""
+
+ def __init__(self, func):
+ new_args = []
+ for arg in func.GetOriginalArgs():
+ new_arg = arg.GetImmediateVersion()
+ if new_arg:
+ new_args.append(new_arg)
+
+ cmd_args = []
+ new_args_for_cmds = []
+ for arg in func.args_for_cmds:
+ new_arg = arg.GetImmediateVersion()
+ if new_arg:
+ new_args_for_cmds.append(new_arg)
+ new_arg.AddCmdArgs(cmd_args)
+
+ new_init_args = []
+ for arg in new_args_for_cmds:
+ arg.AddInitArgs(new_init_args)
+
+ Function.__init__(
+ self,
+ func.original_name,
+ "%sImmediate" % func.name,
+ func.info,
+ func.return_type,
+ new_args,
+ new_args_for_cmds,
+ cmd_args,
+ new_init_args,
+ 0)
+ self.is_immediate = True
+
+ def WriteCommandDescription(self, file):
+ """Overridden from Function"""
+ file.Write("//! Immediate version of command that corresponds to gl%s.\n" %
+ self.original_name)
+
+ def WriteServiceImplementation(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateServiceImplementation(self, file)
+
+ def WriteHandlerImplementation(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateHandlerImplementation(self, file)
+
+ def WriteServiceUnitTest(self, file):
+ """Writes the service implementation for a command."""
+ self.type_handler.WriteImmediateServiceUnitTest(self, file)
+
+ def WriteValidationCode(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateValidationCode(self, file)
+
+ def WriteCmdArgFlag(self, file):
+ """Overridden from Function"""
+ file.Write(" static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;\n")
+
+ def WriteCmdComputeSize(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateCmdComputeSize(self, file)
+
+ def WriteCmdSetHeader(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateCmdSetHeader(self, file)
+
+ def WriteCmdInit(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateCmdInit(self, file)
+
+ def WriteCmdSet(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateCmdSet(self, file)
+
+ def WriteCmdHelper(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateCmdHelper(self, file)
+
+ def WriteFormatTest(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteImmediateFormatTest(self, file)
+
+
+class BucketFunction(Function):
+ """A class that represnets a bucket version of a function command."""
+
+ def __init__(self, func):
+ new_args = []
+ for arg in func.GetOriginalArgs():
+ new_arg = arg.GetBucketVersion()
+ if new_arg:
+ new_args.append(new_arg)
+
+ cmd_args = []
+ new_args_for_cmds = []
+ for arg in func.args_for_cmds:
+ new_arg = arg.GetBucketVersion()
+ if new_arg:
+ new_args_for_cmds.append(new_arg)
+ new_arg.AddCmdArgs(cmd_args)
+
+ new_init_args = []
+ for arg in new_args_for_cmds:
+ arg.AddInitArgs(new_init_args)
+
+ Function.__init__(
+ self,
+ func.original_name,
+ "%sBucket" % func.name,
+ func.info,
+ func.return_type,
+ new_args,
+ new_args_for_cmds,
+ cmd_args,
+ new_init_args,
+ 0)
+
+# def InitFunction(self):
+# """Overridden from Function"""
+# pass
+
+ def WriteCommandDescription(self, file):
+ """Overridden from Function"""
+ file.Write("//! Bucket version of command that corresponds to gl%s.\n" %
+ self.original_name)
+
+ def WriteServiceImplementation(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteBucketServiceImplementation(self, file)
+
+ def WriteHandlerImplementation(self, file):
+ """Overridden from Function"""
+ self.type_handler.WriteBucketHandlerImplementation(self, file)
+
+ def WriteServiceUnitTest(self, file):
+ """Writes the service implementation for a command."""
+ self.type_handler.WriteBucketServiceUnitTest(self, file)
+
+
+def CreateArg(arg_string):
+ """Creates an Argument."""
+ arg_parts = arg_string.split()
+ if len(arg_parts) == 1 and arg_parts[0] == 'void':
+ return None
+ # Is this a pointer argument?
+ elif arg_string.find('*') >= 0:
+ if arg_parts[0] == 'NonImmediate':
+ return NonImmediatePointerArgument(
+ arg_parts[-1],
+ " ".join(arg_parts[1:-1]))
+ else:
+ return PointerArgument(
+ arg_parts[-1],
+ " ".join(arg_parts[0:-1]))
+ # Is this a resource argument? Must come after pointer check.
+ elif arg_parts[0].startswith('GLidBind'):
+ return ResourceIdBindArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif arg_parts[0].startswith('GLidZero'):
+ return ResourceIdZeroArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif arg_parts[0].startswith('GLid'):
+ return ResourceIdArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif arg_parts[0].startswith('GLenum') and len(arg_parts[0]) > 6:
+ return EnumArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif arg_parts[0].startswith('GLboolean') and len(arg_parts[0]) > 9:
+ return ValidatedBoolArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif arg_parts[0].startswith('GLboolean'):
+ return BoolArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif arg_parts[0].startswith('GLintUniformLocation'):
+ return UniformLocationArgument(arg_parts[-1])
+ elif (arg_parts[0].startswith('GLint') and len(arg_parts[0]) > 5 and
+ not arg_parts[0].startswith('GLintptr')):
+ return IntArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ elif (arg_parts[0].startswith('GLsizeiNotNegative') or
+ arg_parts[0].startswith('GLintptrNotNegative')):
+ return SizeNotNegativeArgument(arg_parts[-1],
+ " ".join(arg_parts[0:-1]),
+ arg_parts[0][0:-11])
+ elif arg_parts[0].startswith('GLsize'):
+ return SizeArgument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+ else:
+ return Argument(arg_parts[-1], " ".join(arg_parts[0:-1]))
+
+
+class GLGenerator(object):
+ """A class to generate GL command buffers."""
+
+ _function_re = re.compile(r'GL_APICALL(.*?)GL_APIENTRY (.*?) \((.*?)\);')
+
+ def __init__(self, verbose):
+ self.original_functions = []
+ self.functions = []
+ self.verbose = verbose
+ self.errors = 0
+ self._function_info = {}
+ self._empty_type_handler = TypeHandler()
+ self._empty_function_info = FunctionInfo({}, self._empty_type_handler)
+ self.pepper_interfaces = []
+ self.interface_info = {}
+
+ self._type_handlers = {
+ 'Bind': BindHandler(),
+ 'Create': CreateHandler(),
+ 'Custom': CustomHandler(),
+ 'Data': DataHandler(),
+ 'Delete': DeleteHandler(),
+ 'DELn': DELnHandler(),
+ 'GENn': GENnHandler(),
+ 'GETn': GETnHandler(),
+ 'GLchar': GLcharHandler(),
+ 'GLcharN': GLcharNHandler(),
+ 'HandWritten': HandWrittenHandler(),
+ 'Is': IsHandler(),
+ 'Manual': ManualHandler(),
+ 'PUT': PUTHandler(),
+ 'PUTn': PUTnHandler(),
+ 'PUTXn': PUTXnHandler(),
+ 'StateSet': StateSetHandler(),
+ 'StateSetRGBAlpha': StateSetRGBAlphaHandler(),
+ 'StateSetFrontBack': StateSetFrontBackHandler(),
+ 'StateSetFrontBackSeparate': StateSetFrontBackSeparateHandler(),
+ 'StateSetNamedParameter': StateSetNamedParameter(),
+ 'STRn': STRnHandler(),
+ 'Todo': TodoHandler(),
+ }
+
+ for func_name in _FUNCTION_INFO:
+ info = _FUNCTION_INFO[func_name]
+ type = ''
+ if 'type' in info:
+ type = info['type']
+ self._function_info[func_name] = FunctionInfo(info,
+ self.GetTypeHandler(type))
+ for interface in _PEPPER_INTERFACES:
+ interface = PepperInterface(interface)
+ self.pepper_interfaces.append(interface)
+ self.interface_info[interface.GetName()] = interface
+
+ def AddFunction(self, func):
+ """Adds a function."""
+ self.functions.append(func)
+
+ def GetTypeHandler(self, name):
+ """Gets a type info for the given type."""
+ if len(name):
+ if name in self._type_handlers:
+ return self._type_handlers[name]
+ else:
+ raise KeyError("no such type handler: %s" % name)
+ return self._empty_type_handler
+
+ def GetFunctionInfo(self, name):
+ """Gets a type info for the given function name."""
+ if name in self._function_info:
+ return self._function_info[name]
+ return self._empty_function_info
+
+ def Log(self, msg):
+ """Prints something if verbose is true."""
+ if self.verbose:
+ print msg
+
+ def Error(self, msg):
+ """Prints an error."""
+ print "Error: %s" % msg
+ self.errors += 1
+
+ def WriteLicense(self, file):
+ """Writes the license."""
+ file.Write(_LICENSE)
+
+ def WriteNamespaceOpen(self, file):
+ """Writes the code for the namespace."""
+ file.Write("namespace gpu {\n")
+ file.Write("namespace gles2 {\n")
+ file.Write("\n")
+
+ def WriteNamespaceClose(self, file):
+ """Writes the code to close the namespace."""
+ file.Write("} // namespace gles2\n")
+ file.Write("} // namespace gpu\n")
+ file.Write("\n")
+
+ def ParseArgs(self, arg_string):
+ """Parses a function arg string."""
+ args = []
+ num_pointer_args = 0
+ parts = arg_string.split(',')
+ is_gl_enum = False
+ for arg_string in parts:
+ if arg_string.startswith('GLenum '):
+ is_gl_enum = True
+ arg = CreateArg(arg_string)
+ if arg:
+ args.append(arg)
+ if arg.IsPointer():
+ num_pointer_args += 1
+ return (args, num_pointer_args, is_gl_enum)
+
+ def ParseGLH(self, filename):
+ """Parses the cmd_buffer_functions.txt file and extracts the functions"""
+ f = open("gpu/command_buffer/cmd_buffer_functions.txt", "r")
+ functions = f.read()
+ f.close()
+ for line in functions.splitlines():
+ match = self._function_re.match(line)
+ if match:
+ func_name = match.group(2)[2:]
+ func_info = self.GetFunctionInfo(func_name)
+ if func_info.type != 'Noop':
+ return_type = match.group(1).strip()
+ arg_string = match.group(3)
+ (args, num_pointer_args, is_gl_enum) = self.ParseArgs(arg_string)
+ # comment in to find out which functions use bare enums.
+ # if is_gl_enum:
+ # self.Log("%s uses bare GLenum" % func_name)
+ args_for_cmds = args
+ if hasattr(func_info, 'cmd_args'):
+ (args_for_cmds, num_pointer_args, is_gl_enum) = (
+ self.ParseArgs(getattr(func_info, 'cmd_args')))
+ cmd_args = []
+ for arg in args_for_cmds:
+ arg.AddCmdArgs(cmd_args)
+ init_args = []
+ for arg in args_for_cmds:
+ arg.AddInitArgs(init_args)
+ return_arg = CreateArg(return_type + " result")
+ if return_arg:
+ init_args.append(return_arg)
+ f = Function(func_name, func_name, func_info, return_type, args,
+ args_for_cmds, cmd_args, init_args, num_pointer_args)
+ self.original_functions.append(f)
+ gen_cmd = f.GetInfo('gen_cmd')
+ if gen_cmd == True or gen_cmd == None:
+ self.AddFunction(f)
+ f.type_handler.AddImmediateFunction(self, f)
+ f.type_handler.AddBucketFunction(self, f)
+
+ self.Log("Auto Generated Functions : %d" %
+ len([f for f in self.functions if f.can_auto_generate or
+ (not f.IsType('') and not f.IsType('Custom') and
+ not f.IsType('Todo'))]))
+
+ funcs = [f for f in self.functions if not f.can_auto_generate and
+ (f.IsType('') or f.IsType('Custom') or f.IsType('Todo'))]
+ self.Log("Non Auto Generated Functions: %d" % len(funcs))
+
+ for f in funcs:
+ self.Log(" %-10s %-20s gl%s" % (f.info.type, f.return_type, f.name))
+
+ def WriteCommandIds(self, filename):
+ """Writes the command buffer format"""
+ file = CHeaderWriter(filename)
+ file.Write("#define GLES2_COMMAND_LIST(OP) \\\n")
+ id = 256
+ for func in self.functions:
+ file.Write(" %-60s /* %d */ \\\n" %
+ ("OP(%s)" % func.name, id))
+ id += 1
+ file.Write("\n")
+
+ file.Write("enum CommandId {\n")
+ file.Write(" kStartPoint = cmd::kLastCommonId, "
+ "// All GLES2 commands start after this.\n")
+ file.Write("#define GLES2_CMD_OP(name) k ## name,\n")
+ file.Write(" GLES2_COMMAND_LIST(GLES2_CMD_OP)\n")
+ file.Write("#undef GLES2_CMD_OP\n")
+ file.Write(" kNumCommands\n")
+ file.Write("};\n")
+ file.Write("\n")
+ file.Close()
+
+ def WriteFormat(self, filename):
+ """Writes the command buffer format"""
+ file = CHeaderWriter(filename)
+ for func in self.functions:
+ if True:
+ #gen_cmd = func.GetInfo('gen_cmd')
+ #if gen_cmd == True or gen_cmd == None:
+ func.WriteStruct(file)
+ file.Write("\n")
+ file.Close()
+
+ def WriteDocs(self, filename):
+ """Writes the command buffer doc version of the commands"""
+ file = CWriter(filename)
+ for func in self.functions:
+ if True:
+ #gen_cmd = func.GetInfo('gen_cmd')
+ #if gen_cmd == True or gen_cmd == None:
+ func.WriteDocs(file)
+ file.Write("\n")
+ file.Close()
+
+ def WriteFormatTest(self, filename):
+ """Writes the command buffer format test."""
+ file = CHeaderWriter(
+ filename,
+ "// This file contains unit tests for gles2 commmands\n"
+ "// It is included by gles2_cmd_format_test.cc\n"
+ "\n")
+
+ for func in self.functions:
+ if True:
+ #gen_cmd = func.GetInfo('gen_cmd')
+ #if gen_cmd == True or gen_cmd == None:
+ func.WriteFormatTest(file)
+
+ file.Close()
+
+ def WriteCmdHelperHeader(self, filename):
+ """Writes the gles2 command helper."""
+ file = CHeaderWriter(filename)
+
+ for func in self.functions:
+ if True:
+ #gen_cmd = func.GetInfo('gen_cmd')
+ #if gen_cmd == True or gen_cmd == None:
+ func.WriteCmdHelper(file)
+
+ file.Close()
+
+ def WriteServiceContextStateHeader(self, filename):
+ """Writes the service context state header."""
+ file = CHeaderWriter(
+ filename,
+ "// It is included by context_state.h\n")
+ file.Write("struct EnableFlags {\n")
+ file.Write(" EnableFlags();\n")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" bool %s;\n" % capability['name'])
+ file.Write("};\n\n")
+
+ for state_name in sorted(_STATES.keys()):
+ state = _STATES[state_name]
+ for item in state['states']:
+ file.Write("%s %s;\n" % (item['type'], item['name']))
+ file.Write("\n")
+
+ file.Close()
+
+ def WriteClientContextStateHeader(self, filename):
+ """Writes the client context state header."""
+ file = CHeaderWriter(
+ filename,
+ "// It is included by client_context_state.h\n")
+ file.Write("struct EnableFlags {\n")
+ file.Write(" EnableFlags();\n")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" bool %s;\n" % capability['name'])
+ file.Write("};\n\n")
+
+ file.Close()
+
+ def WriteContextStateGetters(self, file, class_name):
+ """Writes the state getters."""
+ for gl_type in ["GLint", "GLfloat"]:
+ file.Write("""
+bool %s::GetStateAs%s(
+ GLenum pname, %s* params, GLsizei* num_written) const {
+ switch (pname) {
+""" % (class_name, gl_type, gl_type))
+ for state_name in sorted(_STATES.keys()):
+ state = _STATES[state_name]
+ if 'enum' in state:
+ file.Write(" case %s:\n" % state['enum'])
+ file.Write(" *num_written = %d;\n" % len(state['states']))
+ file.Write(" if (params) {\n")
+ for ndx,item in enumerate(state['states']):
+ file.Write(" params[%d] = static_cast<%s>(%s);\n" %
+ (ndx, gl_type, item['name']))
+ file.Write(" }\n")
+ file.Write(" return true;\n")
+ else:
+ for item in state['states']:
+ file.Write(" case %s:\n" % item['enum'])
+ file.Write(" *num_written = 1;\n")
+ file.Write(" if (params) {\n")
+ file.Write(" params[0] = static_cast<%s>(%s);\n" %
+ (gl_type, item['name']))
+ file.Write(" }\n")
+ file.Write(" return true;\n")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" case GL_%s:\n" % capability['name'].upper())
+ file.Write(" *num_written = 1;\n")
+ file.Write(" if (params) {\n")
+ file.Write(
+ " params[0] = static_cast<%s>(enable_flags.%s);\n" %
+ (gl_type, capability['name']))
+ file.Write(" }\n")
+ file.Write(" return true;\n")
+ file.Write(""" default:
+ return false;
+ }
+}
+""")
+
+ def WriteServiceContextStateImpl(self, filename):
+ """Writes the context state service implementation."""
+ file = CHeaderWriter(
+ filename,
+ "// It is included by context_state.cc\n")
+ code = []
+ for capability in _CAPABILITY_FLAGS:
+ code.append("%s(%s)" %
+ (capability['name'],
+ ('false', 'true')['default' in capability]))
+ file.Write("ContextState::EnableFlags::EnableFlags()\n : %s {\n}\n" %
+ ",\n ".join(code))
+ file.Write("\n")
+
+ file.Write("void ContextState::Initialize() {\n")
+ for state_name in sorted(_STATES.keys()):
+ state = _STATES[state_name]
+ for item in state['states']:
+ file.Write(" %s = %s;\n" % (item['name'], item['default']))
+ file.Write("}\n")
+
+ file.Write("""
+void ContextState::InitCapabilities() const {
+""")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" EnableDisable(GL_%s, enable_flags.%s);\n" %
+ (capability['name'].upper(), capability['name']))
+ file.Write("""}
+
+void ContextState::InitState() const {
+""")
+
+ # We need to sort the keys so the expectations match
+ for state_name in sorted(_STATES.keys()):
+ state = _STATES[state_name]
+ if state['type'] == 'FrontBack':
+ num_states = len(state['states'])
+ for ndx, group in enumerate(Grouper(num_states / 2, state['states'])):
+ args = []
+ for item in group:
+ args.append('%s' % item['name'])
+ file.Write(
+ " gl%s(%s, %s);\n" %
+ (state['func'], ('GL_FRONT', 'GL_BACK')[ndx], ", ".join(args)))
+ elif state['type'] == 'NamedParameter':
+ for item in state['states']:
+ if 'extension_flag' in item:
+ file.Write(" if (feature_info_->feature_flags().%s)\n " %
+ item['extension_flag'])
+ file.Write(" gl%s(%s, %s);\n" %
+ (state['func'], item['enum'], item['name']))
+ else:
+ args = []
+ for item in state['states']:
+ args.append('%s' % item['name'])
+ file.Write(" gl%s(%s);\n" % (state['func'], ", ".join(args)))
+ file.Write("}\n")
+
+ file.Write("""bool ContextState::GetEnabled(GLenum cap) const {
+ switch (cap) {
+""")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" case GL_%s:\n" % capability['name'].upper())
+ file.Write(" return enable_flags.%s;\n" % capability['name'])
+ file.Write(""" default:
+ GPU_NOTREACHED();
+ return false;
+ }
+}
+""")
+
+ self.WriteContextStateGetters(file, "ContextState")
+ file.Close()
+
+ def WriteClientContextStateImpl(self, filename):
+ """Writes the context state client side implementation."""
+ file = CHeaderWriter(
+ filename,
+ "// It is included by client_context_state.cc\n")
+ code = []
+ for capability in _CAPABILITY_FLAGS:
+ code.append("%s(%s)" %
+ (capability['name'],
+ ('false', 'true')['default' in capability]))
+ file.Write(
+ "ClientContextState::EnableFlags::EnableFlags()\n : %s {\n}\n" %
+ ",\n ".join(code))
+ file.Write("\n")
+
+ file.Write("""
+bool ClientContextState::SetCapabilityState(
+ GLenum cap, bool enabled, bool* changed) {
+ *changed = false;
+ switch (cap) {
+""")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" case GL_%s:\n" % capability['name'].upper())
+ file.Write(""" if (enable_flags.%(name)s != enabled) {
+ *changed = true;
+ enable_flags.%(name)s = enabled;
+ }
+ return true;
+""" % capability)
+ file.Write(""" default:
+ return false;
+ }
+}
+""")
+ file.Write("""bool ClientContextState::GetEnabled(
+ GLenum cap, bool* enabled) const {
+ switch (cap) {
+""")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" case GL_%s:\n" % capability['name'].upper())
+ file.Write(" *enabled = enable_flags.%s;\n" % capability['name'])
+ file.Write(" return true;\n")
+ file.Write(""" default:
+ return false;
+ }
+}
+""")
+ file.Close()
+
+ def WriteServiceImplementation(self, filename):
+ """Writes the service decorder implementation."""
+ file = CHeaderWriter(
+ filename,
+ "// It is included by gles2_cmd_decoder.cc\n")
+
+ for func in self.functions:
+ if True:
+ #gen_cmd = func.GetInfo('gen_cmd')
+ #if gen_cmd == True or gen_cmd == None:
+ func.WriteServiceImplementation(file)
+
+ file.Write("""
+bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) {
+ switch (cap) {
+""")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" case GL_%s:\n" % capability['name'].upper())
+ if 'state_flag' in capability:
+ file.Write(""" if (state_.enable_flags.%(name)s != enabled) {
+ state_.enable_flags.%(name)s = enabled;
+ %(state_flag)s = true;
+ }
+ return false;
+""" % capability)
+ else:
+ file.Write(""" state_.enable_flags.%(name)s = enabled;
+ return true;
+""" % capability)
+ file.Write(""" default:
+ NOTREACHED();
+ return false;
+ }
+}
+""")
+ file.Close()
+
+ def WriteServiceUnitTests(self, filename):
+ """Writes the service decorder unit tests."""
+ num_tests = len(self.functions)
+ FUNCTIONS_PER_FILE = 98 # hard code this so it doesn't change.
+ count = 0
+ for test_num in range(0, num_tests, FUNCTIONS_PER_FILE):
+ count += 1
+ name = filename % count
+ file = CHeaderWriter(
+ name,
+ "// It is included by gles2_cmd_decoder_unittest_%d.cc\n" % count)
+ file.SetFileNum(count)
+ end = test_num + FUNCTIONS_PER_FILE
+ if end > num_tests:
+ end = num_tests
+ for idx in range(test_num, end):
+ func = self.functions[idx]
+ if True:
+ #gen_cmd = func.GetInfo('gen_cmd')
+ #if gen_cmd == True or gen_cmd == None:
+ if func.GetInfo('unit_test') == False:
+ file.Write("// TODO(gman): %s\n" % func.name)
+ else:
+ func.WriteServiceUnitTest(file)
+
+ file.Close()
+ file = CHeaderWriter(
+ filename % 0,
+ "// It is included by gles2_cmd_decoder_unittest_base.cc\n")
+ file.Write(
+"""void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations() {
+""")
+ for capability in _CAPABILITY_FLAGS:
+ file.Write(" ExpectEnableDisable(GL_%s, %s);\n" %
+ (capability['name'].upper(),
+ ('false', 'true')['default' in capability]))
+ file.Write("""}
+
+void GLES2DecoderTestBase::SetupInitStateExpectations() {
+""")
+
+ # We need to sort the keys so the expectations match
+ for state_name in sorted(_STATES.keys()):
+ state = _STATES[state_name]
+ if state['type'] == 'FrontBack':
+ num_states = len(state['states'])
+ for ndx, group in enumerate(Grouper(num_states / 2, state['states'])):
+ args = []
+ for item in group:
+ if 'expected' in item:
+ args.append(item['expected'])
+ else:
+ args.append(item['default'])
+ file.Write(
+ " EXPECT_CALL(*gl_, %s(%s, %s))\n" %
+ (state['func'], ('GL_FRONT', 'GL_BACK')[ndx], ", ".join(args)))
+ file.Write(" .Times(1)\n")
+ file.Write(" .RetiresOnSaturation();\n")
+ elif state['type'] == 'NamedParameter':
+ for item in state['states']:
+ if 'extension_flag' in item:
+ continue
+ file.Write(
+ " EXPECT_CALL(*gl_, %s(%s, %s))\n" %
+ (state['func'], item['enum'], item['default']))
+ file.Write(" .Times(1)\n")
+ file.Write(" .RetiresOnSaturation();\n")
+ else:
+ args = []
+ for item in state['states']:
+ if 'expected' in item:
+ args.append(item['expected'])
+ else:
+ args.append(item['default'])
+ file.Write(" EXPECT_CALL(*gl_, %s(%s))\n" %
+ (state['func'], ", ".join(args)))
+ file.Write(" .Times(1)\n")
+ file.Write(" .RetiresOnSaturation();\n")
+ file.Write("""}
+""")
+ file.Close()
+
+ def WriteGLES2Header(self, filename):
+ """Writes the GLES2 header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file contains Chromium-specific GLES2 declarations.\n\n")
+
+ for func in self.original_functions:
+ func.WriteGLES2Header(file)
+
+ file.Write("\n")
+ file.Close()
+
+ def WriteGLES2CLibImplementation(self, filename):
+ """Writes the GLES2 c lib implementation."""
+ file = CHeaderWriter(
+ filename,
+ "// These functions emulate GLES2 over command buffers.\n")
+
+ for func in self.original_functions:
+ func.WriteGLES2CLibImplementation(file)
+
+ file.Write("""
+namespace gles2 {
+
+extern const NameToFunc g_gles2_function_table[] = {
+""")
+ for func in self.original_functions:
+ file.Write(
+ ' { "gl%s", reinterpret_cast<GLES2FunctionPointer>(gl%s), },\n' %
+ (func.name, func.name))
+ file.Write(""" { NULL, NULL, },
+};
+
+} // namespace gles2
+""")
+ file.Close()
+
+ def WriteGLES2InterfaceHeader(self, filename):
+ """Writes the GLES2 interface header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_interface.h to declare the\n"
+ "// GL api functions.\n")
+ for func in self.original_functions:
+ func.WriteGLES2InterfaceHeader(file)
+ file.Close()
+
+ def WriteGLES2InterfaceStub(self, filename):
+ """Writes the GLES2 interface stub header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_interface_stub.h.\n")
+ for func in self.original_functions:
+ func.WriteGLES2InterfaceStub(file)
+ file.Close()
+
+ def WriteGLES2InterfaceStubImpl(self, filename):
+ """Writes the GLES2 interface header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_interface_stub.cc.\n")
+ for func in self.original_functions:
+ func.WriteGLES2InterfaceStubImpl(file)
+ file.Close()
+
+ def WriteGLES2ImplementationHeader(self, filename):
+ """Writes the GLES2 Implementation header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_implementation.h to declare the\n"
+ "// GL api functions.\n")
+ for func in self.original_functions:
+ func.WriteGLES2ImplementationHeader(file)
+ file.Close()
+
+ def WriteGLES2Implementation(self, filename):
+ """Writes the GLES2 Implementation."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_implementation.cc to define the\n"
+ "// GL api functions.\n")
+ for func in self.original_functions:
+ func.WriteGLES2Implementation(file)
+ file.Close()
+
+ def WriteGLES2TraceImplementationHeader(self, filename):
+ """Writes the GLES2 Trace Implementation header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_trace_implementation.h\n")
+ for func in self.original_functions:
+ func.WriteGLES2TraceImplementationHeader(file)
+ file.Close()
+
+ def WriteGLES2TraceImplementation(self, filename):
+ """Writes the GLES2 Trace Implementation."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_trace_implementation.cc\n")
+ for func in self.original_functions:
+ func.WriteGLES2TraceImplementation(file)
+ file.Close()
+
+ def WriteGLES2ImplementationUnitTests(self, filename):
+ """Writes the GLES2 helper header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_implementation.h to declare the\n"
+ "// GL api functions.\n")
+ for func in self.original_functions:
+ func.WriteGLES2ImplementationUnitTest(file)
+ file.Close()
+
+ def WriteServiceUtilsHeader(self, filename):
+ """Writes the gles2 auto generated utility header."""
+ file = CHeaderWriter(filename)
+ for enum in sorted(_ENUM_LISTS.keys()):
+ file.Write("ValueValidator<%s> %s;\n" %
+ (_ENUM_LISTS[enum]['type'], ToUnderscore(enum)))
+ file.Write("\n")
+ file.Close()
+
+ def WriteServiceUtilsImplementation(self, filename):
+ """Writes the gles2 auto generated utility implementation."""
+ file = CHeaderWriter(filename)
+ enums = sorted(_ENUM_LISTS.keys())
+ for enum in enums:
+ if len(_ENUM_LISTS[enum]['valid']) > 0:
+ file.Write("static const %s valid_%s_table[] = {\n" %
+ (_ENUM_LISTS[enum]['type'], ToUnderscore(enum)))
+ for value in _ENUM_LISTS[enum]['valid']:
+ file.Write(" %s,\n" % value)
+ file.Write("};\n")
+ file.Write("\n")
+ file.Write("Validators::Validators()\n")
+ pre = ': '
+ post = ','
+ for count, enum in enumerate(enums):
+ if count + 1 == len(enums):
+ post = ' {'
+ if len(_ENUM_LISTS[enum]['valid']) > 0:
+ code = """ %(pre)s%(name)s(
+ valid_%(name)s_table, arraysize(valid_%(name)s_table))%(post)s
+"""
+ else:
+ code = """ %(pre)s%(name)s()%(post)s
+"""
+ file.Write(code % {
+ 'name': ToUnderscore(enum),
+ 'pre': pre,
+ 'post': post,
+ })
+ pre = ' '
+ file.Write("}\n\n");
+ file.Close()
+
+ def WriteCommonUtilsHeader(self, filename):
+ """Writes the gles2 common utility header."""
+ file = CHeaderWriter(filename)
+ enums = sorted(_ENUM_LISTS.keys())
+ for enum in enums:
+ if _ENUM_LISTS[enum]['type'] == 'GLenum':
+ file.Write("static std::string GetString%s(uint32 value);\n" % enum)
+ file.Write("\n")
+ file.Close()
+
+ def WriteCommonUtilsImpl(self, filename):
+ """Writes the gles2 common utility header."""
+ enum_re = re.compile(r'\#define\s+(GL_[a-zA-Z0-9_]+)\s+([0-9A-Fa-fx]+)')
+ dict = {}
+ for fname in ['../../third_party/khronos/GLES2/gl2.h',
+ '../../third_party/khronos/GLES2/gl2ext.h',
+ '../../gpu/GLES2/gl2chromium.h',
+ '../../gpu/GLES2/gl2extchromium.h']:
+ lines = open(fname).readlines()
+ for line in lines:
+ m = enum_re.match(line)
+ if m:
+ name = m.group(1)
+ value = m.group(2)
+ if len(value) <= 10 and not value in dict:
+ dict[value] = name
+
+ file = CHeaderWriter(filename)
+ file.Write("static const GLES2Util::EnumToString "
+ "enum_to_string_table[] = {\n")
+ for value in dict:
+ file.Write(' { %s, "%s", },\n' % (value, dict[value]))
+ file.Write("""};
+
+const GLES2Util::EnumToString* const GLES2Util::enum_to_string_table_ =
+ enum_to_string_table;
+const size_t GLES2Util::enum_to_string_table_len_ =
+ sizeof(enum_to_string_table) / sizeof(enum_to_string_table[0]);
+
+""")
+
+ enums = sorted(_ENUM_LISTS.keys())
+ for enum in enums:
+ if _ENUM_LISTS[enum]['type'] == 'GLenum':
+ file.Write("std::string GLES2Util::GetString%s(uint32 value) {\n" %
+ enum)
+ if len(_ENUM_LISTS[enum]['valid']) > 0:
+ file.Write(" static const EnumToString string_table[] = {\n")
+ for value in _ENUM_LISTS[enum]['valid']:
+ file.Write(' { %s, "%s" },\n' % (value, value))
+ file.Write(""" };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+""")
+ else:
+ file.Write(""" return GLES2Util::GetQualifiedEnumString(
+ NULL, 0, value);
+}
+
+""")
+ file.Close()
+
+ def WritePepperGLES2Interface(self, filename, dev):
+ """Writes the Pepper OpenGLES interface definition."""
+ file = CHeaderWriter(
+ filename,
+ "// OpenGL ES interface.\n",
+ 2)
+
+ file.Write("#include \"ppapi/c/pp_resource.h\"\n")
+ if dev:
+ file.Write("#include \"ppapi/c/ppb_opengles2.h\"\n\n")
+ else:
+ file.Write("\n#ifndef __gl2_h_\n")
+ for (k, v) in _GL_TYPES.iteritems():
+ file.Write("typedef %s %s;\n" % (v, k))
+ file.Write("#endif // __gl2_h_\n\n")
+
+ for interface in self.pepper_interfaces:
+ if interface.dev != dev:
+ continue
+ file.Write("#define %s_1_0 \"%s;1.0\"\n" %
+ (interface.GetInterfaceName(), interface.GetInterfaceString()))
+ file.Write("#define %s %s_1_0\n" %
+ (interface.GetInterfaceName(), interface.GetInterfaceName()))
+
+ file.Write("\nstruct %s {\n" % interface.GetStructName())
+ for func in self.original_functions:
+ if not func.InPepperInterface(interface):
+ continue
+
+ original_arg = func.MakeTypedOriginalArgString("")
+ context_arg = "PP_Resource context"
+ if len(original_arg):
+ arg = context_arg + ", " + original_arg
+ else:
+ arg = context_arg
+ file.Write(" %s (*%s)(%s);\n" % (func.return_type, func.name, arg))
+ file.Write("};\n\n")
+
+
+ file.Close()
+
+ def WritePepperGLES2Implementation(self, filename):
+ """Writes the Pepper OpenGLES interface implementation."""
+
+ file = CWriter(filename)
+ file.Write(_LICENSE)
+ file.Write(_DO_NOT_EDIT_WARNING)
+
+ file.Write("#include \"ppapi/shared_impl/ppb_opengles2_shared.h\"\n\n")
+ file.Write("#include \"base/logging.h\"\n")
+ file.Write("#include \"gpu/command_buffer/client/gles2_implementation.h\"\n")
+ file.Write("#include \"ppapi/shared_impl/ppb_graphics_3d_shared.h\"\n")
+ file.Write("#include \"ppapi/thunk/enter.h\"\n\n")
+
+ file.Write("namespace ppapi {\n\n")
+ file.Write("namespace {\n\n")
+
+ file.Write("gpu::gles2::GLES2Implementation*"
+ " GetGLES(PP_Resource context) {\n")
+ file.Write(" thunk::EnterResource<thunk::PPB_Graphics3D_API>"
+ " enter_g3d(context, false);\n")
+ file.Write(" DCHECK(enter_g3d.succeeded());\n")
+ file.Write(" return static_cast<PPB_Graphics3D_Shared*>"
+ "(enter_g3d.object())->gles2_impl();\n")
+ file.Write("}\n\n")
+
+ for func in self.original_functions:
+ if not func.InAnyPepperExtension():
+ continue
+
+ original_arg = func.MakeTypedOriginalArgString("")
+ context_arg = "PP_Resource context_id"
+ if len(original_arg):
+ arg = context_arg + ", " + original_arg
+ else:
+ arg = context_arg
+ file.Write("%s %s(%s) {\n" % (func.return_type, func.name, arg))
+
+ return_str = "" if func.return_type == "void" else "return "
+ file.Write(" %sGetGLES(context_id)->%s(%s);\n" %
+ (return_str, func.original_name,
+ func.MakeOriginalArgString("")))
+ file.Write("}\n\n")
+
+ file.Write("} // namespace\n")
+
+ for interface in self.pepper_interfaces:
+ file.Write("const %s* PPB_OpenGLES2_Shared::Get%sInterface() {\n" %
+ (interface.GetStructName(), interface.GetName()))
+ file.Write(" static const struct %s "
+ "ppb_opengles2 = {\n" % interface.GetStructName())
+ file.Write(" &")
+ file.Write(",\n &".join(
+ f.name for f in self.original_functions
+ if f.InPepperInterface(interface)))
+ file.Write("\n")
+
+ file.Write(" };\n")
+ file.Write(" return &ppb_opengles2;\n")
+ file.Write("}\n")
+
+ file.Write("} // namespace ppapi\n")
+ file.Close()
+
+ def WriteGLES2ToPPAPIBridge(self, filename):
+ """Connects GLES2 helper library to PPB_OpenGLES2 interface"""
+
+ file = CWriter(filename)
+ file.Write(_LICENSE)
+ file.Write(_DO_NOT_EDIT_WARNING)
+
+ file.Write("#ifndef GL_GLEXT_PROTOTYPES\n")
+ file.Write("#define GL_GLEXT_PROTOTYPES\n")
+ file.Write("#endif\n")
+ file.Write("#include <GLES2/gl2.h>\n")
+ file.Write("#include <GLES2/gl2ext.h>\n")
+ file.Write("#include \"ppapi/lib/gl/gles2/gl2ext_ppapi.h\"\n\n")
+
+ for func in self.original_functions:
+ if not func.InAnyPepperExtension():
+ continue
+
+ interface = self.interface_info[func.GetInfo('pepper_interface') or '']
+
+ file.Write("%s GL_APIENTRY gl%s(%s) {\n" %
+ (func.return_type, func.name,
+ func.MakeTypedOriginalArgString("")))
+ return_str = "" if func.return_type == "void" else "return "
+ interface_str = "glGet%sInterfacePPAPI()" % interface.GetName()
+ original_arg = func.MakeOriginalArgString("")
+ context_arg = "glGetCurrentContextPPAPI()"
+ if len(original_arg):
+ arg = context_arg + ", " + original_arg
+ else:
+ arg = context_arg
+ if interface.GetName():
+ file.Write(" const struct %s* ext = %s;\n" %
+ (interface.GetStructName(), interface_str))
+ file.Write(" if (ext)\n")
+ file.Write(" %sext->%s(%s);\n" %
+ (return_str, func.name, arg))
+ if return_str:
+ file.Write(" %s0;\n" % return_str)
+ else:
+ file.Write(" %s%s->%s(%s);\n" %
+ (return_str, interface_str, func.name, arg))
+ file.Write("}\n\n")
+ file.Close()
+
+def main(argv):
+ """This is the main function."""
+ parser = OptionParser()
+ parser.add_option(
+ "-g", "--generate-implementation-templates", action="store_true",
+ help="generates files that are generally hand edited..")
+ parser.add_option(
+ "--alternate-mode", type="choice",
+ choices=("ppapi", "chrome_ppapi", "chrome_ppapi_proxy", "nacl_ppapi"),
+ help="generate files for other projects. \"ppapi\" will generate ppapi "
+ "bindings. \"chrome_ppapi\" generate chrome implementation for ppapi. "
+ "\"chrome_ppapi_proxy\" will generate the glue for the chrome IPC ppapi"
+ "proxy. \"nacl_ppapi\" will generate NaCl implementation for ppapi")
+ parser.add_option(
+ "--output-dir",
+ help="base directory for resulting files, under chrome/src. default is "
+ "empty. Use this if you want the result stored under gen.")
+ parser.add_option(
+ "-v", "--verbose", action="store_true",
+ help="prints more output.")
+
+ (options, args) = parser.parse_args(args=argv)
+
+ # Add in states and capabilites to GLState
+ for state_name in sorted(_STATES.keys()):
+ state = _STATES[state_name]
+ if 'enum' in state:
+ _ENUM_LISTS['GLState']['valid'].append(state['enum'])
+ else:
+ for item in state['states']:
+ if 'extension_flag' in item:
+ continue
+ _ENUM_LISTS['GLState']['valid'].append(item['enum'])
+ for capability in _CAPABILITY_FLAGS:
+ _ENUM_LISTS['GLState']['valid'].append("GL_%s" % capability['name'].upper())
+
+ # This script lives under gpu/command_buffer, cd to base directory.
+ os.chdir(os.path.dirname(__file__) + "/../..")
+
+ gen = GLGenerator(options.verbose)
+ gen.ParseGLH("common/GLES2/gl2.h")
+
+ # Support generating files under gen/
+ if options.output_dir != None:
+ os.chdir(options.output_dir)
+
+ if options.alternate_mode == "ppapi":
+ # To trigger this action, do "make ppapi_gles_bindings"
+ os.chdir("ppapi");
+ gen.WritePepperGLES2Interface("c/ppb_opengles2.h", False)
+ gen.WritePepperGLES2Interface("c/dev/ppb_opengles2ext_dev.h", True)
+ gen.WriteGLES2ToPPAPIBridge("lib/gl/gles2/gles2.c")
+
+ elif options.alternate_mode == "chrome_ppapi":
+ # To trigger this action, do "make ppapi_gles_implementation"
+ gen.WritePepperGLES2Implementation(
+ "ppapi/shared_impl/ppb_opengles2_shared.cc")
+
+ else:
+ os.chdir("gpu/command_buffer")
+ gen.WriteCommandIds("common/gles2_cmd_ids_autogen.h")
+ gen.WriteFormat("common/gles2_cmd_format_autogen.h")
+ gen.WriteFormatTest("common/gles2_cmd_format_test_autogen.h")
+ gen.WriteGLES2InterfaceHeader("client/gles2_interface_autogen.h")
+ gen.WriteGLES2InterfaceStub("client/gles2_interface_stub_autogen.h")
+ gen.WriteGLES2InterfaceStubImpl(
+ "client/gles2_interface_stub_impl_autogen.h")
+ gen.WriteGLES2ImplementationHeader("client/gles2_implementation_autogen.h")
+ gen.WriteGLES2Implementation("client/gles2_implementation_impl_autogen.h")
+ gen.WriteGLES2ImplementationUnitTests(
+ "client/gles2_implementation_unittest_autogen.h")
+ gen.WriteGLES2TraceImplementationHeader(
+ "client/gles2_trace_implementation_autogen.h")
+ gen.WriteGLES2TraceImplementation(
+ "client/gles2_trace_implementation_impl_autogen.h")
+ gen.WriteGLES2CLibImplementation("client/gles2_c_lib_autogen.h")
+ gen.WriteCmdHelperHeader("client/gles2_cmd_helper_autogen.h")
+ gen.WriteServiceImplementation("service/gles2_cmd_decoder_autogen.h")
+ gen.WriteServiceContextStateHeader("service/context_state_autogen.h")
+ gen.WriteServiceContextStateImpl("service/context_state_impl_autogen.h")
+ gen.WriteClientContextStateHeader("client/client_context_state_autogen.h")
+ gen.WriteClientContextStateImpl(
+ "client/client_context_state_impl_autogen.h")
+ gen.WriteServiceUnitTests("service/gles2_cmd_decoder_unittest_%d_autogen.h")
+ gen.WriteServiceUtilsHeader("service/gles2_cmd_validation_autogen.h")
+ gen.WriteServiceUtilsImplementation(
+ "service/gles2_cmd_validation_implementation_autogen.h")
+ gen.WriteCommonUtilsHeader("common/gles2_cmd_utils_autogen.h")
+ gen.WriteCommonUtilsImpl("common/gles2_cmd_utils_implementation_autogen.h")
+ gen.WriteGLES2Header("../GLES2/gl2chromium_autogen.h")
+
+ if gen.errors > 0:
+ print "%d errors" % gen.errors
+ return 1
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/chromium/gpu/command_buffer/client/atomicops.cc b/chromium/gpu/command_buffer/client/atomicops.cc
new file mode 100644
index 00000000000..c4d5cb1117c
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/atomicops.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/atomicops.h"
+#include "gpu/command_buffer/common/logging.h"
+
+#if !defined(__native_client__)
+#include "base/atomicops.h"
+#include "base/synchronization/lock.h"
+#else
+#include <pthread.h>
+#endif
+
+namespace gpu {
+
+void MemoryBarrier() {
+#if defined(__native_client__)
+ __sync_synchronize();
+#else
+ base::subtle::MemoryBarrier();
+#endif
+}
+
+#if defined(__native_client__)
+
+class LockImpl {
+ public:
+ LockImpl()
+ : acquired_(false) {
+ pthread_mutex_init(&mutex_, NULL);
+ }
+
+ ~LockImpl() {
+ pthread_mutex_destroy(&mutex_);
+ }
+
+ void Acquire() {
+ pthread_mutex_lock(&mutex_);
+ acquired_ = true;
+ }
+
+ void Release() {
+ GPU_DCHECK(acquired_);
+ acquired_ = false;
+ pthread_mutex_unlock(&mutex_);
+ }
+
+ bool Try() {
+ bool acquired = pthread_mutex_trylock(&mutex_) == 0;
+ if (acquired) {
+ acquired_ = true;
+ }
+ return acquired;
+ }
+
+ void AssertAcquired() const {
+ GPU_DCHECK(acquired_);
+ }
+
+ private:
+ bool acquired_;
+ pthread_mutex_t mutex_;
+
+ DISALLOW_COPY_AND_ASSIGN(LockImpl);
+};
+
+#else // !__native_client__
+
+class LockImpl : public base::Lock {
+};
+
+#endif // !__native_client__
+
+Lock::Lock()
+ : lock_(new LockImpl()) {
+}
+
+Lock::~Lock() {
+}
+
+void Lock::Acquire() {
+ lock_->Acquire();
+}
+
+void Lock::Release() {
+ lock_->Release();
+}
+
+bool Lock::Try() {
+ return lock_->Try();
+}
+
+void Lock::AssertAcquired() const {
+ return lock_->AssertAcquired();
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/client/atomicops.h b/chromium/gpu/command_buffer/client/atomicops.h
new file mode 100644
index 00000000000..9e1628e0ad6
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/atomicops.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_ATOMICOPS_H_
+#define GPU_COMMAND_BUFFER_CLIENT_ATOMICOPS_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+GPU_EXPORT void MemoryBarrier();
+
+class LockImpl;
+class GPU_EXPORT Lock {
+ public:
+ Lock();
+ ~Lock();
+ void Acquire();
+ void Release();
+ bool Try();
+ void AssertAcquired() const;
+
+ private:
+ scoped_ptr<LockImpl> lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(Lock);
+};
+
+// A helper class that acquires the given Lock while the AutoLock is in scope.
+class GPU_EXPORT AutoLock {
+ public:
+ explicit AutoLock(Lock& lock) : lock_(lock) {
+ lock_.Acquire();
+ }
+
+ ~AutoLock() {
+ lock_.AssertAcquired();
+ lock_.Release();
+ }
+
+ private:
+ Lock& lock_;
+ DISALLOW_COPY_AND_ASSIGN(AutoLock);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_ATOMICOPS_H_
diff --git a/chromium/gpu/command_buffer/client/buffer_tracker.cc b/chromium/gpu/command_buffer/client/buffer_tracker.cc
new file mode 100644
index 00000000000..f5ead5af08c
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/buffer_tracker.cc
@@ -0,0 +1,68 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/buffer_tracker.h"
+
+#include "gpu/command_buffer/client/atomicops.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
+
+namespace gpu {
+namespace gles2 {
+
+BufferTracker::BufferTracker(MappedMemoryManager* manager)
+ : mapped_memory_(manager) {
+}
+
+BufferTracker::~BufferTracker() {
+ while (!buffers_.empty()) {
+ RemoveBuffer(buffers_.begin()->first);
+ }
+}
+
+BufferTracker::Buffer* BufferTracker::CreateBuffer(
+ GLuint id, GLsizeiptr size) {
+ GPU_DCHECK_NE(0u, id);
+ GPU_DCHECK_LE(0, size);
+ int32 shm_id = -1;
+ uint32 shm_offset = 0;
+ void* address = NULL;
+ if (size)
+ address = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
+
+ Buffer* buffer = new Buffer(id, size, shm_id, shm_offset, address);
+ std::pair<BufferMap::iterator, bool> result =
+ buffers_.insert(std::make_pair(id, buffer));
+ GPU_DCHECK(result.second);
+ return buffer;
+}
+
+BufferTracker::Buffer* BufferTracker::GetBuffer(GLuint client_id) {
+ BufferMap::iterator it = buffers_.find(client_id);
+ return it != buffers_.end() ? it->second : NULL;
+}
+
+void BufferTracker::RemoveBuffer(GLuint client_id) {
+ BufferMap::iterator it = buffers_.find(client_id);
+ if (it != buffers_.end()) {
+ Buffer* buffer = it->second;
+ buffers_.erase(it);
+ if (buffer->address_)
+ mapped_memory_->Free(buffer->address_);
+ delete buffer;
+ }
+}
+
+void BufferTracker::FreePendingToken(Buffer* buffer, int32 token) {
+ if (buffer->address_)
+ mapped_memory_->FreePendingToken(buffer->address_, token);
+ buffer->size_ = 0;
+ buffer->shm_id_ = 0;
+ buffer->shm_offset_ = 0;
+ buffer->address_ = NULL;
+}
+
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/buffer_tracker.h b/chromium/gpu/command_buffer/client/buffer_tracker.h
new file mode 100644
index 00000000000..e61c50188af
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/buffer_tracker.h
@@ -0,0 +1,113 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_BUFFER_TRACKER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_BUFFER_TRACKER_H_
+
+#include <GLES2/gl2.h>
+
+#include <queue>
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/hash_tables.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+
+namespace gpu {
+
+class CommandBufferHelper;
+class MappedMemoryManager;
+
+namespace gles2 {
+
+// Tracks buffer objects for client side of command buffer.
+class GLES2_IMPL_EXPORT BufferTracker {
+ public:
+ class GLES2_IMPL_EXPORT Buffer {
+ public:
+ Buffer(GLuint id,
+ unsigned int size,
+ int32 shm_id,
+ uint32 shm_offset,
+ void* address)
+ : id_(id),
+ size_(size),
+ shm_id_(shm_id),
+ shm_offset_(shm_offset),
+ address_(address),
+ mapped_(false),
+ transfer_ready_token_(0) {
+ }
+
+ GLenum id() const {
+ return id_;
+ }
+
+ unsigned int size() const {
+ return size_;
+ }
+
+ int32 shm_id() const {
+ return shm_id_;
+ }
+
+ uint32 shm_offset() const {
+ return shm_offset_;
+ }
+
+ void* address() const {
+ return address_;
+ }
+
+ void set_mapped(bool mapped) {
+ mapped_ = mapped;
+ }
+
+ bool mapped() const {
+ return mapped_;
+ }
+
+ void set_transfer_ready_token(int token) {
+ transfer_ready_token_ = token;
+ }
+
+ uint32 transfer_ready_token() const {
+ return transfer_ready_token_;
+ }
+
+ private:
+ friend class BufferTracker;
+ friend class BufferTrackerTest;
+
+ GLuint id_;
+ unsigned int size_;
+ int32 shm_id_;
+ uint32 shm_offset_;
+ void* address_;
+ bool mapped_;
+ int32 transfer_ready_token_;
+ };
+
+ BufferTracker(MappedMemoryManager* manager);
+ ~BufferTracker();
+
+ Buffer* CreateBuffer(GLuint id, GLsizeiptr size);
+ Buffer* GetBuffer(GLuint id);
+ void RemoveBuffer(GLuint id);
+
+ // Frees the block of memory associated with buffer, pending the passage
+ // of a token.
+ void FreePendingToken(Buffer*, int32 token);
+
+ private:
+ typedef gpu::hash_map<GLuint, Buffer*> BufferMap;
+
+ MappedMemoryManager* mapped_memory_;
+ BufferMap buffers_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferTracker);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_BUFFER_TRACKER_H_
diff --git a/chromium/gpu/command_buffer/client/buffer_tracker_unittest.cc b/chromium/gpu/command_buffer/client/buffer_tracker_unittest.cc
new file mode 100644
index 00000000000..86b69f06d20
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/buffer_tracker_unittest.cc
@@ -0,0 +1,129 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the BufferTracker.
+
+#include "gpu/command_buffer/client/buffer_tracker.h"
+
+#include <GLES2/gl2ext.h>
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/client/client_test_helper.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+class MockClientCommandBufferImpl : public MockClientCommandBuffer {
+ public:
+ MockClientCommandBufferImpl()
+ : MockClientCommandBuffer(),
+ context_lost_(false) {}
+ virtual ~MockClientCommandBufferImpl() {}
+
+ virtual Buffer CreateTransferBuffer(size_t size, int32* id) OVERRIDE {
+ if (context_lost_) {
+ *id = -1;
+ return gpu::Buffer();
+ }
+ return MockClientCommandBuffer::CreateTransferBuffer(size, id);
+ }
+
+ void set_context_lost(bool context_lost) {
+ context_lost_ = context_lost;
+ }
+
+ private:
+ bool context_lost_;
+};
+
+class BufferTrackerTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+
+ virtual void SetUp() {
+ command_buffer_.reset(new MockClientCommandBufferImpl());
+ helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+ buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
+ }
+
+ virtual void TearDown() {
+ buffer_tracker_.reset();
+ mapped_memory_.reset();
+ helper_.reset();
+ command_buffer_.reset();
+ }
+
+ scoped_ptr<MockClientCommandBufferImpl> command_buffer_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MappedMemoryManager> mapped_memory_;
+ scoped_ptr<BufferTracker> buffer_tracker_;
+};
+
+TEST_F(BufferTrackerTest, Basic) {
+ const GLuint kId1 = 123;
+ const GLuint kId2 = 124;
+ const GLsizeiptr size = 64;
+
+ // Check we can create a Buffer.
+ BufferTracker::Buffer* buffer = buffer_tracker_->CreateBuffer(kId1, size);
+ ASSERT_TRUE(buffer != NULL);
+ // Check we can get the same Buffer.
+ EXPECT_EQ(buffer, buffer_tracker_->GetBuffer(kId1));
+ // Check mapped memory address.
+ EXPECT_TRUE(buffer->address() != NULL);
+ // Check shared memory was allocated.
+ EXPECT_EQ(1lu, mapped_memory_->num_chunks());
+ // Check we get nothing for a non-existent buffer.
+ EXPECT_TRUE(buffer_tracker_->GetBuffer(kId2) == NULL);
+ // Check we can delete the buffer.
+ buffer_tracker_->RemoveBuffer(kId1);
+ // Check shared memory was freed.
+ mapped_memory_->FreeUnused();
+ EXPECT_EQ(0lu, mapped_memory_->num_chunks());
+ // Check we get nothing for a non-existent buffer.
+ EXPECT_TRUE(buffer_tracker_->GetBuffer(kId1) == NULL);
+}
+
+TEST_F(BufferTrackerTest, ZeroSize) {
+ const GLuint kId = 123;
+
+ // Check we can create a Buffer with zero size.
+ BufferTracker::Buffer* buffer = buffer_tracker_->CreateBuffer(kId, 0);
+ ASSERT_TRUE(buffer != NULL);
+ // Check mapped memory address.
+ EXPECT_TRUE(buffer->address() == NULL);
+ // Check no shared memory was allocated.
+ EXPECT_EQ(0lu, mapped_memory_->num_chunks());
+ // Check we can delete the buffer.
+ buffer_tracker_->RemoveBuffer(kId);
+}
+
+TEST_F(BufferTrackerTest, LostContext) {
+ const GLuint kId = 123;
+ const GLsizeiptr size = 64;
+
+ command_buffer_->set_context_lost(true);
+ // Check we can create a Buffer when after losing context.
+ BufferTracker::Buffer* buffer = buffer_tracker_->CreateBuffer(kId, size);
+ ASSERT_TRUE(buffer != NULL);
+ // Check mapped memory address.
+ EXPECT_EQ(64u, buffer->size());
+ // Check mapped memory address.
+ EXPECT_TRUE(buffer->address() == NULL);
+ // Check no shared memory was allocated.
+ EXPECT_EQ(0lu, mapped_memory_->num_chunks());
+ // Check we can delete the buffer.
+ buffer_tracker_->RemoveBuffer(kId);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/client_context_state.cc b/chromium/gpu/command_buffer/client/client_context_state.cc
new file mode 100644
index 00000000000..ecb33b6fa5b
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/client_context_state.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/client_context_state.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+namespace gles2 {
+
+ClientContextState::ClientContextState() {
+}
+
+ClientContextState::~ClientContextState() {
+}
+
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/client/client_context_state_impl_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/client_context_state.h b/chromium/gpu/command_buffer/client/client_context_state.h
new file mode 100644
index 00000000000..f5a93a6272c
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/client_context_state.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the ContextState class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_H_
+
+#include <GLES2/gl2.h>
+#include <vector>
+#include "gles2_impl_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+struct GLES2_IMPL_EXPORT ClientContextState {
+ ClientContextState();
+ ~ClientContextState();
+
+ // Returns true if state was cached in which case 'enabled' will be set to the
+ // current state.
+ bool GetEnabled(GLenum cap, bool* enabled) const;
+
+ // Sets the state of a capability.
+ // Returns true if the capability is one that is cached.
+ // 'changed' will be true if the state was different from 'enabled.
+ bool SetCapabilityState(GLenum cap, bool enabled, bool* changed);
+
+ #include "gpu/command_buffer/client/client_context_state_autogen.h"
+
+ EnableFlags enable_flags;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_H_
+
diff --git a/chromium/gpu/command_buffer/client/client_context_state_autogen.h b/chromium/gpu/command_buffer/client/client_context_state_autogen.h
new file mode 100644
index 00000000000..1714b2b5ce9
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/client_context_state_autogen.h
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by client_context_state.h
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_AUTOGEN_H_
+
+struct EnableFlags {
+ EnableFlags();
+ bool blend;
+ bool cull_face;
+ bool depth_test;
+ bool dither;
+ bool polygon_offset_fill;
+ bool sample_alpha_to_coverage;
+ bool sample_coverage;
+ bool scissor_test;
+ bool stencil_test;
+};
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/client_context_state_impl_autogen.h b/chromium/gpu/command_buffer/client/client_context_state_impl_autogen.h
new file mode 100644
index 00000000000..150816d04e3
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/client_context_state_impl_autogen.h
@@ -0,0 +1,123 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by client_context_state.cc
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_IMPL_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_IMPL_AUTOGEN_H_
+
+ClientContextState::EnableFlags::EnableFlags()
+ : blend(false),
+ cull_face(false),
+ depth_test(false),
+ dither(true),
+ polygon_offset_fill(false),
+ sample_alpha_to_coverage(false),
+ sample_coverage(false),
+ scissor_test(false),
+ stencil_test(false) {
+}
+
+
+bool ClientContextState::SetCapabilityState(
+ GLenum cap, bool enabled, bool* changed) {
+ *changed = false;
+ switch (cap) {
+ case GL_BLEND:
+ if (enable_flags.blend != enabled) {
+ *changed = true;
+ enable_flags.blend = enabled;
+ }
+ return true;
+ case GL_CULL_FACE:
+ if (enable_flags.cull_face != enabled) {
+ *changed = true;
+ enable_flags.cull_face = enabled;
+ }
+ return true;
+ case GL_DEPTH_TEST:
+ if (enable_flags.depth_test != enabled) {
+ *changed = true;
+ enable_flags.depth_test = enabled;
+ }
+ return true;
+ case GL_DITHER:
+ if (enable_flags.dither != enabled) {
+ *changed = true;
+ enable_flags.dither = enabled;
+ }
+ return true;
+ case GL_POLYGON_OFFSET_FILL:
+ if (enable_flags.polygon_offset_fill != enabled) {
+ *changed = true;
+ enable_flags.polygon_offset_fill = enabled;
+ }
+ return true;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ if (enable_flags.sample_alpha_to_coverage != enabled) {
+ *changed = true;
+ enable_flags.sample_alpha_to_coverage = enabled;
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE:
+ if (enable_flags.sample_coverage != enabled) {
+ *changed = true;
+ enable_flags.sample_coverage = enabled;
+ }
+ return true;
+ case GL_SCISSOR_TEST:
+ if (enable_flags.scissor_test != enabled) {
+ *changed = true;
+ enable_flags.scissor_test = enabled;
+ }
+ return true;
+ case GL_STENCIL_TEST:
+ if (enable_flags.stencil_test != enabled) {
+ *changed = true;
+ enable_flags.stencil_test = enabled;
+ }
+ return true;
+ default:
+ return false;
+ }
+}
+bool ClientContextState::GetEnabled(
+ GLenum cap, bool* enabled) const {
+ switch (cap) {
+ case GL_BLEND:
+ *enabled = enable_flags.blend;
+ return true;
+ case GL_CULL_FACE:
+ *enabled = enable_flags.cull_face;
+ return true;
+ case GL_DEPTH_TEST:
+ *enabled = enable_flags.depth_test;
+ return true;
+ case GL_DITHER:
+ *enabled = enable_flags.dither;
+ return true;
+ case GL_POLYGON_OFFSET_FILL:
+ *enabled = enable_flags.polygon_offset_fill;
+ return true;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ *enabled = enable_flags.sample_alpha_to_coverage;
+ return true;
+ case GL_SAMPLE_COVERAGE:
+ *enabled = enable_flags.sample_coverage;
+ return true;
+ case GL_SCISSOR_TEST:
+ *enabled = enable_flags.scissor_test;
+ return true;
+ case GL_STENCIL_TEST:
+ *enabled = enable_flags.stencil_test;
+ return true;
+ default:
+ return false;
+ }
+}
+#endif // GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_IMPL_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/client_test_helper.cc b/chromium/gpu/command_buffer/client/client_test_helper.cc
new file mode 100644
index 00000000000..cccfa3b96ef
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/client_test_helper.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for GLES2Implementation.
+
+#include "gpu/command_buffer/client/client_test_helper.h"
+
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::Invoke;
+
+namespace gpu {
+
+MockCommandBufferBase::~MockCommandBufferBase() {
+}
+
+bool MockCommandBufferBase::Initialize() {
+ return true;
+}
+
+CommandBuffer::State MockCommandBufferBase::GetState() {
+ return state_;
+}
+
+CommandBuffer::State MockCommandBufferBase::GetLastState() {
+ return state_;
+}
+
+int32 MockCommandBufferBase::GetLastToken() {
+ return state_.token;
+}
+
+void MockCommandBufferBase::SetGetOffset(int32 get_offset) {
+ state_.get_offset = get_offset;
+}
+
+CommandBuffer::State MockCommandBufferBase::FlushSync(
+ int32 put_offset, int32 last_known_get) {
+ state_.put_offset = put_offset;
+ state_.get_offset = put_offset;
+ OnFlush();
+ return state_;
+}
+
+void MockCommandBufferBase::SetGetBuffer(int transfer_buffer_id) {
+ ring_buffer_buffer_ = GetTransferBuffer(transfer_buffer_id);
+ ring_buffer_ = static_cast<CommandBufferEntry*>(ring_buffer_buffer_.ptr);
+ state_.num_entries = ring_buffer_buffer_.size / sizeof(ring_buffer_[0]);
+ state_.token = 10000; // All token checks in the tests should pass.
+}
+
+// Get's the Id of the next transfer buffer that will be returned
+// by CreateTransferBuffer. This is useful for testing expected ids.
+int32 MockCommandBufferBase::GetNextFreeTransferBufferId() {
+ for (size_t ii = 0; ii < arraysize(transfer_buffers_); ++ii) {
+ if (!transfer_buffers_[ii].get()) {
+ return kTransferBufferBaseId + ii;
+ }
+ }
+ return -1;
+}
+
+Buffer MockCommandBufferBase::CreateTransferBuffer(size_t size, int32* id) {
+ *id = GetNextFreeTransferBufferId();
+ if (*id >= 0) {
+ int32 ndx = *id - kTransferBufferBaseId;
+ transfer_buffers_[ndx].reset(new int8[size]);
+ transfer_buffer_buffers_[ndx].ptr = transfer_buffers_[ndx].get();
+ transfer_buffer_buffers_[ndx].size = size;
+ }
+ return GetTransferBuffer(*id);
+}
+
+void MockCommandBufferBase::DestroyTransferBufferHelper(int32 id) {
+ GPU_DCHECK_GE(id, kTransferBufferBaseId);
+ GPU_DCHECK_LT(id, kTransferBufferBaseId + kMaxTransferBuffers);
+ id -= kTransferBufferBaseId;
+ transfer_buffers_[id].reset();
+ transfer_buffer_buffers_[id] = Buffer();
+}
+
+Buffer MockCommandBufferBase::GetTransferBuffer(int32 id) {
+ GPU_DCHECK_GE(id, kTransferBufferBaseId);
+ GPU_DCHECK_LT(id, kTransferBufferBaseId + kMaxTransferBuffers);
+ return transfer_buffer_buffers_[id - kTransferBufferBaseId];
+}
+
+void MockCommandBufferBase::FlushHelper(int32 put_offset) {
+ state_.put_offset = put_offset;
+}
+
+void MockCommandBufferBase::SetToken(int32 token) {
+ GPU_NOTREACHED();
+ state_.token = token;
+}
+
+void MockCommandBufferBase::SetParseError(error::Error error) {
+ GPU_NOTREACHED();
+ state_.error = error;
+}
+
+void MockCommandBufferBase::SetContextLostReason(
+ error::ContextLostReason reason) {
+ GPU_NOTREACHED();
+ state_.context_lost_reason = reason;
+}
+
+uint32 MockCommandBufferBase::InsertSyncPoint() {
+ GPU_NOTREACHED();
+ return 0;
+}
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const int32 MockCommandBufferBase::kTransferBufferBaseId;
+const int32 MockCommandBufferBase::kMaxTransferBuffers;
+#endif
+
+MockClientCommandBuffer::MockClientCommandBuffer() {
+ DelegateToFake();
+}
+
+MockClientCommandBuffer::~MockClientCommandBuffer() {
+}
+
+void MockClientCommandBuffer::Flush(int32 put_offset) {
+ FlushHelper(put_offset);
+}
+
+void MockClientCommandBuffer::DelegateToFake() {
+ ON_CALL(*this, DestroyTransferBuffer(_))
+ .WillByDefault(Invoke(
+ this, &MockCommandBufferBase::DestroyTransferBufferHelper));
+}
+
+MockClientCommandBufferMockFlush::MockClientCommandBufferMockFlush() {
+ DelegateToFake();
+}
+
+MockClientCommandBufferMockFlush::~MockClientCommandBufferMockFlush() {
+}
+
+void MockClientCommandBufferMockFlush::DelegateToFake() {
+ MockClientCommandBuffer::DelegateToFake();
+ ON_CALL(*this, Flush(_))
+ .WillByDefault(Invoke(
+ this, &MockCommandBufferBase::FlushHelper));
+}
+
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/client_test_helper.h b/chromium/gpu/command_buffer/client/client_test_helper.h
new file mode 100644
index 00000000000..70107046660
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/client_test_helper.h
@@ -0,0 +1,87 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Helper classes for implementing gpu client side unit tests.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/compiler_specific.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class CommandBufferHelper;
+
+class MockCommandBufferBase : public CommandBuffer {
+ public:
+ static const int32 kTransferBufferBaseId = 0x123;
+ static const int32 kMaxTransferBuffers = 6;
+
+ MockCommandBufferBase() { }
+ virtual ~MockCommandBufferBase();
+
+ virtual bool Initialize() OVERRIDE;
+ virtual State GetState() OVERRIDE;
+ virtual State GetLastState() OVERRIDE;
+ virtual int32 GetLastToken() OVERRIDE;
+ virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE;
+ virtual void SetGetBuffer(int transfer_buffer_id) OVERRIDE;
+ virtual void SetGetOffset(int32 get_offset) OVERRIDE;
+ virtual Buffer CreateTransferBuffer(size_t size, int32* id) OVERRIDE;
+ virtual Buffer GetTransferBuffer(int32 id) OVERRIDE;
+ virtual void SetToken(int32 token) OVERRIDE;
+ virtual void SetParseError(error::Error error) OVERRIDE;
+ virtual void SetContextLostReason(error::ContextLostReason reason) OVERRIDE;
+ virtual uint32 InsertSyncPoint() OVERRIDE;
+
+ // Get's the Id of the next transfer buffer that will be returned
+ // by CreateTransferBuffer. This is useful for testing expected ids.
+ int32 GetNextFreeTransferBufferId();
+
+ void FlushHelper(int32 put_offset);
+ void DestroyTransferBufferHelper(int32 id);
+
+ virtual void OnFlush() = 0;
+
+ private:
+ scoped_ptr<int8[]> transfer_buffers_[kMaxTransferBuffers];
+ Buffer transfer_buffer_buffers_[kMaxTransferBuffers];
+ CommandBufferEntry* ring_buffer_;
+ Buffer ring_buffer_buffer_;
+ State state_;
+};
+
+class MockClientCommandBuffer : public MockCommandBufferBase {
+ public:
+ MockClientCommandBuffer();
+ virtual ~MockClientCommandBuffer();
+
+ // This is so we can use all the gmock functions when Flush is called.
+ MOCK_METHOD0(OnFlush, void());
+ MOCK_METHOD1(DestroyTransferBuffer, void(int32 id));
+
+ virtual void Flush(int32 put_offset) OVERRIDE;
+
+ void DelegateToFake();
+};
+
+class MockClientCommandBufferMockFlush : public MockClientCommandBuffer {
+ public:
+ MockClientCommandBufferMockFlush();
+ virtual ~MockClientCommandBufferMockFlush();
+
+ MOCK_METHOD1(Flush, void(int32 put_offset));
+
+ void DelegateToFake();
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CLIENT_TEST_HELPER_H_
+
diff --git a/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc b/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc
new file mode 100644
index 00000000000..b83934ff5a7
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/cmd_buffer_helper.cc
@@ -0,0 +1,276 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation of the command buffer helper class.
+
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/trace_event.h"
+
+namespace gpu {
+
+namespace {
+const int kCommandsPerFlushCheck = 100;
+const double kFlushDelay = 1.0 / (5.0 * 60.0);
+}
+
+CommandBufferHelper::CommandBufferHelper(CommandBuffer* command_buffer)
+ : command_buffer_(command_buffer),
+ ring_buffer_id_(-1),
+ ring_buffer_size_(0),
+ entries_(NULL),
+ total_entry_count_(0),
+ token_(0),
+ put_(0),
+ last_put_sent_(0),
+ commands_issued_(0),
+ usable_(true),
+ context_lost_(false),
+ flush_automatically_(true),
+ last_flush_time_(0) {
+}
+
+void CommandBufferHelper::SetAutomaticFlushes(bool enabled) {
+ flush_automatically_ = enabled;
+}
+
+bool CommandBufferHelper::IsContextLost() {
+ if (!context_lost_) {
+ context_lost_ = error::IsError(command_buffer()->GetLastError());
+ }
+ return context_lost_;
+}
+
+bool CommandBufferHelper::AllocateRingBuffer() {
+ if (!usable()) {
+ return false;
+ }
+
+ if (HaveRingBuffer()) {
+ return true;
+ }
+
+ int32 id = -1;
+ Buffer buffer = command_buffer_->CreateTransferBuffer(ring_buffer_size_, &id);
+ if (id < 0) {
+ ClearUsable();
+ return false;
+ }
+
+ ring_buffer_ = buffer;
+ ring_buffer_id_ = id;
+ command_buffer_->SetGetBuffer(id);
+
+ // TODO(gman): Do we really need to call GetState here? We know get & put = 0
+ // Also do we need to check state.num_entries?
+ CommandBuffer::State state = command_buffer_->GetState();
+ entries_ = static_cast<CommandBufferEntry*>(ring_buffer_.ptr);
+ int32 num_ring_buffer_entries =
+ ring_buffer_size_ / sizeof(CommandBufferEntry);
+ if (num_ring_buffer_entries > state.num_entries) {
+ ClearUsable();
+ return false;
+ }
+
+ total_entry_count_ = num_ring_buffer_entries;
+ put_ = state.put_offset;
+ return true;
+}
+
+void CommandBufferHelper::FreeResources() {
+ if (HaveRingBuffer()) {
+ command_buffer_->DestroyTransferBuffer(ring_buffer_id_);
+ ring_buffer_id_ = -1;
+ }
+}
+
+void CommandBufferHelper::FreeRingBuffer() {
+ GPU_CHECK((put_ == get_offset()) ||
+ error::IsError(command_buffer_->GetLastState().error));
+ FreeResources();
+}
+
+bool CommandBufferHelper::Initialize(int32 ring_buffer_size) {
+ ring_buffer_size_ = ring_buffer_size;
+ return AllocateRingBuffer();
+}
+
+CommandBufferHelper::~CommandBufferHelper() {
+ FreeResources();
+}
+
+bool CommandBufferHelper::FlushSync() {
+ if (!usable()) {
+ return false;
+ }
+ last_flush_time_ = clock();
+ last_put_sent_ = put_;
+ CommandBuffer::State state = command_buffer_->FlushSync(put_, get_offset());
+ return state.error == error::kNoError;
+}
+
+void CommandBufferHelper::Flush() {
+ if (usable() && last_put_sent_ != put_) {
+ last_flush_time_ = clock();
+ last_put_sent_ = put_;
+ command_buffer_->Flush(put_);
+ }
+}
+
+// Calls Flush() and then waits until the buffer is empty. Break early if the
+// error is set.
+bool CommandBufferHelper::Finish() {
+ TRACE_EVENT0("gpu", "CommandBufferHelper::Finish");
+ if (!usable()) {
+ return false;
+ }
+ // If there is no work just exit.
+ if (put_ == get_offset()) {
+ return true;
+ }
+ GPU_DCHECK(HaveRingBuffer());
+ do {
+ // Do not loop forever if the flush fails, meaning the command buffer reader
+ // has shutdown.
+ if (!FlushSync())
+ return false;
+ } while (put_ != get_offset());
+
+ return true;
+}
+
+// Inserts a new token into the command stream. It uses an increasing value
+// scheme so that we don't lose tokens (a token has passed if the current token
+// value is higher than that token). Calls Finish() if the token value wraps,
+// which will be rare.
+int32 CommandBufferHelper::InsertToken() {
+ AllocateRingBuffer();
+ if (!usable()) {
+ return token_;
+ }
+ GPU_DCHECK(HaveRingBuffer());
+ // Increment token as 31-bit integer. Negative values are used to signal an
+ // error.
+ token_ = (token_ + 1) & 0x7FFFFFFF;
+ cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
+ if (cmd) {
+ cmd->Init(token_);
+ if (token_ == 0) {
+ TRACE_EVENT0("gpu", "CommandBufferHelper::InsertToken(wrapped)");
+ // we wrapped
+ Finish();
+ GPU_DCHECK_EQ(token_, last_token_read());
+ }
+ }
+ return token_;
+}
+
+// Waits until the current token value is greater or equal to the value passed
+// in argument.
+void CommandBufferHelper::WaitForToken(int32 token) {
+ if (!usable() || !HaveRingBuffer()) {
+ return;
+ }
+ // Return immediately if corresponding InsertToken failed.
+ if (token < 0)
+ return;
+ if (token > token_) return; // we wrapped
+ while (last_token_read() < token) {
+ if (get_offset() == put_) {
+ GPU_LOG(FATAL) << "Empty command buffer while waiting on a token.";
+ return;
+ }
+ // Do not loop forever if the flush fails, meaning the command buffer reader
+ // has shutdown.
+ if (!FlushSync())
+ return;
+ }
+}
+
+// Waits for available entries, basically waiting until get >= put + count + 1.
+// It actually waits for contiguous entries, so it may need to wrap the buffer
+// around, adding a noops. Thus this function may change the value of put_. The
+// function will return early if an error occurs, in which case the available
+// space may not be available.
+void CommandBufferHelper::WaitForAvailableEntries(int32 count) {
+ AllocateRingBuffer();
+ if (!usable()) {
+ return;
+ }
+ GPU_DCHECK(HaveRingBuffer());
+ GPU_DCHECK(count < total_entry_count_);
+ if (put_ + count > total_entry_count_) {
+ // There's not enough room between the current put and the end of the
+ // buffer, so we need to wrap. We will add noops all the way to the end,
+ // but we need to make sure get wraps first, actually that get is 1 or
+ // more (since put will wrap to 0 after we add the noops).
+ GPU_DCHECK_LE(1, put_);
+ if (get_offset() > put_ || get_offset() == 0) {
+ TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries");
+ while (get_offset() > put_ || get_offset() == 0) {
+ // Do not loop forever if the flush fails, meaning the command buffer
+ // reader has shutdown.
+ if (!FlushSync())
+ return;
+ }
+ }
+ // Insert Noops to fill out the buffer.
+ int32 num_entries = total_entry_count_ - put_;
+ while (num_entries > 0) {
+ int32 num_to_skip = std::min(CommandHeader::kMaxSize, num_entries);
+ cmd::Noop::Set(&entries_[put_], num_to_skip);
+ put_ += num_to_skip;
+ num_entries -= num_to_skip;
+ }
+ put_ = 0;
+ }
+ if (AvailableEntries() < count) {
+ TRACE_EVENT0("gpu", "CommandBufferHelper::WaitForAvailableEntries1");
+ while (AvailableEntries() < count) {
+ // Do not loop forever if the flush fails, meaning the command buffer
+ // reader has shutdown.
+ if (!FlushSync())
+ return;
+ }
+ }
+ // Force a flush if the buffer is getting half full, or even earlier if the
+ // reader is known to be idle.
+ int32 pending =
+ (put_ + total_entry_count_ - last_put_sent_) % total_entry_count_;
+ int32 limit = total_entry_count_ /
+ ((get_offset() == last_put_sent_) ? 16 : 2);
+ if (pending > limit) {
+ Flush();
+ } else if (flush_automatically_ &&
+ (commands_issued_ % kCommandsPerFlushCheck == 0)) {
+#if !defined(OS_ANDROID)
+ // Allow this command buffer to be pre-empted by another if a "reasonable"
+ // amount of work has been done. On highend machines, this reduces the
+ // latency of GPU commands. However, on Android, this can cause the
+ // kernel to thrash between generating GPU commands and executing them.
+ clock_t current_time = clock();
+ if (current_time - last_flush_time_ > kFlushDelay * CLOCKS_PER_SEC)
+ Flush();
+#endif
+ }
+}
+
+CommandBufferEntry* CommandBufferHelper::GetSpace(uint32 entries) {
+ AllocateRingBuffer();
+ if (!usable()) {
+ return NULL;
+ }
+ GPU_DCHECK(HaveRingBuffer());
+ ++commands_issued_;
+ WaitForAvailableEntries(entries);
+ CommandBufferEntry* space = &entries_[put_];
+ put_ += entries;
+ GPU_DCHECK_LE(put_, total_entry_count_);
+ if (put_ == total_entry_count_) {
+ put_ = 0;
+ }
+ return space;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/cmd_buffer_helper.h b/chromium/gpu/command_buffer/client/cmd_buffer_helper.h
new file mode 100644
index 00000000000..e2639b3a264
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/cmd_buffer_helper.h
@@ -0,0 +1,271 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the command buffer helper class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
+
+#include <string.h>
+#include <time.h>
+
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+// Command buffer helper class. This class simplifies ring buffer management:
+// it will allocate the buffer, give it to the buffer interface, and let the
+// user add commands to it, while taking care of the synchronization (put and
+// get). It also provides a way to ensure commands have been executed, through
+// the token mechanism:
+//
+// helper.AddCommand(...);
+// helper.AddCommand(...);
+// int32 token = helper.InsertToken();
+// helper.AddCommand(...);
+// helper.AddCommand(...);
+// [...]
+//
+// helper.WaitForToken(token); // this doesn't return until the first two
+// // commands have been executed.
+class GPU_EXPORT CommandBufferHelper {
+ public:
+ explicit CommandBufferHelper(CommandBuffer* command_buffer);
+ virtual ~CommandBufferHelper();
+
+ // Initializes the CommandBufferHelper.
+ // Parameters:
+ // ring_buffer_size: The size of the ring buffer portion of the command
+ // buffer.
+ bool Initialize(int32 ring_buffer_size);
+
+ // Sets whether the command buffer should automatically flush periodically
+ // to try to increase performance. Defaults to true.
+ void SetAutomaticFlushes(bool enabled);
+
+ // True if the context is lost.
+ bool IsContextLost();
+
+ // Asynchronously flushes the commands, setting the put pointer to let the
+ // buffer interface know that new commands have been added. After a flush
+ // returns, the command buffer service is aware of all pending commands.
+ void Flush();
+
+ // Flushes the commands, setting the put pointer to let the buffer interface
+ // know that new commands have been added. After a flush returns, the command
+ // buffer service is aware of all pending commands and it is guaranteed to
+ // have made some progress in processing them. Returns whether the flush was
+ // successful. The flush will fail if the command buffer service has
+ // disconnected.
+ bool FlushSync();
+
+ // Waits until all the commands have been executed. Returns whether it
+ // was successful. The function will fail if the command buffer service has
+ // disconnected.
+ bool Finish();
+
+ // Waits until a given number of available entries are available.
+ // Parameters:
+ // count: number of entries needed. This value must be at most
+ // the size of the buffer minus one.
+ void WaitForAvailableEntries(int32 count);
+
+ // Inserts a new token into the command buffer. This token either has a value
+ // different from previously inserted tokens, or ensures that previously
+ // inserted tokens with that value have already passed through the command
+ // stream.
+ // Returns:
+ // the value of the new token or -1 if the command buffer reader has
+ // shutdown.
+ int32 InsertToken();
+
+ // Waits until the token of a particular value has passed through the command
+ // stream (i.e. commands inserted before that token have been executed).
+ // NOTE: This will call Flush if it needs to block.
+ // Parameters:
+ // the value of the token to wait for.
+ void WaitForToken(int32 token);
+
+ // Called prior to each command being issued. Waits for a certain amount of
+ // space to be available. Returns address of space.
+ CommandBufferEntry* GetSpace(uint32 entries);
+
+ // Typed version of GetSpace. Gets enough room for the given type and returns
+ // a reference to it.
+ template <typename T>
+ T* GetCmdSpace() {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ uint32 space_needed = ComputeNumEntries(sizeof(T));
+ void* data = GetSpace(space_needed);
+ return reinterpret_cast<T*>(data);
+ }
+
+ // Typed version of GetSpace for immediate commands.
+ template <typename T>
+ T* GetImmediateCmdSpace(size_t data_space) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ uint32 space_needed = ComputeNumEntries(sizeof(T) + data_space);
+ void* data = GetSpace(space_needed);
+ return reinterpret_cast<T*>(data);
+ }
+
+ // Typed version of GetSpace for immediate commands.
+ template <typename T>
+ T* GetImmediateCmdSpaceTotalSize(size_t total_space) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ uint32 space_needed = ComputeNumEntries(total_space);
+ void* data = GetSpace(space_needed);
+ return reinterpret_cast<T*>(data);
+ }
+
+ int32 last_token_read() const {
+ return command_buffer_->GetLastToken();
+ }
+
+ int32 get_offset() const {
+ return command_buffer_->GetLastState().get_offset;
+ }
+
+ // Common Commands
+ void Noop(uint32 skip_count) {
+ cmd::Noop* cmd = GetImmediateCmdSpace<cmd::Noop>(
+ (skip_count - 1) * sizeof(CommandBufferEntry));
+ if (cmd) {
+ cmd->Init(skip_count);
+ }
+ }
+
+ void SetToken(uint32 token) {
+ cmd::SetToken* cmd = GetCmdSpace<cmd::SetToken>();
+ if (cmd) {
+ cmd->Init(token);
+ }
+ }
+
+ void SetBucketSize(uint32 bucket_id, uint32 size) {
+ cmd::SetBucketSize* cmd = GetCmdSpace<cmd::SetBucketSize>();
+ if (cmd) {
+ cmd->Init(bucket_id, size);
+ }
+ }
+
+ void SetBucketData(uint32 bucket_id,
+ uint32 offset,
+ uint32 size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ cmd::SetBucketData* cmd = GetCmdSpace<cmd::SetBucketData>();
+ if (cmd) {
+ cmd->Init(bucket_id,
+ offset,
+ size,
+ shared_memory_id,
+ shared_memory_offset);
+ }
+ }
+
+ void SetBucketDataImmediate(
+ uint32 bucket_id, uint32 offset, const void* data, uint32 size) {
+ cmd::SetBucketDataImmediate* cmd =
+ GetImmediateCmdSpace<cmd::SetBucketDataImmediate>(size);
+ if (cmd) {
+ cmd->Init(bucket_id, offset, size);
+ memcpy(ImmediateDataAddress(cmd), data, size);
+ }
+ }
+
+ void GetBucketStart(uint32 bucket_id,
+ uint32 result_memory_id,
+ uint32 result_memory_offset,
+ uint32 data_memory_size,
+ uint32 data_memory_id,
+ uint32 data_memory_offset) {
+ cmd::GetBucketStart* cmd = GetCmdSpace<cmd::GetBucketStart>();
+ if (cmd) {
+ cmd->Init(bucket_id,
+ result_memory_id,
+ result_memory_offset,
+ data_memory_size,
+ data_memory_id,
+ data_memory_offset);
+ }
+ }
+
+ void GetBucketData(uint32 bucket_id,
+ uint32 offset,
+ uint32 size,
+ uint32 shared_memory_id,
+ uint32 shared_memory_offset) {
+ cmd::GetBucketData* cmd = GetCmdSpace<cmd::GetBucketData>();
+ if (cmd) {
+ cmd->Init(bucket_id,
+ offset,
+ size,
+ shared_memory_id,
+ shared_memory_offset);
+ }
+ }
+
+ CommandBuffer* command_buffer() const {
+ return command_buffer_;
+ }
+
+ Buffer get_ring_buffer() const {
+ return ring_buffer_;
+ }
+
+ void FreeRingBuffer();
+
+ bool HaveRingBuffer() const {
+ return ring_buffer_id_ != -1;
+ }
+
+ bool usable () const {
+ return usable_;
+ }
+
+ void ClearUsable() {
+ usable_ = false;
+ }
+
+ private:
+ // Waits until get changes, updating the value of get_.
+ void WaitForGetChange();
+
+ // Returns the number of available entries (they may not be contiguous).
+ int32 AvailableEntries() {
+ return (get_offset() - put_ - 1 + total_entry_count_) % total_entry_count_;
+ }
+
+ bool AllocateRingBuffer();
+ void FreeResources();
+
+ CommandBuffer* command_buffer_;
+ int32 ring_buffer_id_;
+ int32 ring_buffer_size_;
+ Buffer ring_buffer_;
+ CommandBufferEntry* entries_;
+ int32 total_entry_count_; // the total number of entries
+ int32 token_;
+ int32 put_;
+ int32 last_put_sent_;
+ int commands_issued_;
+ bool usable_;
+ bool context_lost_;
+ bool flush_automatically_;
+
+ // Using C runtime instead of base because this file cannot depend on base.
+ clock_t last_flush_time_;
+
+ friend class CommandBufferHelperTest;
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferHelper);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_CMD_BUFFER_HELPER_H_
diff --git a/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc b/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
new file mode 100644
index 00000000000..bd0e86e3f45
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/cmd_buffer_helper_test.cc
@@ -0,0 +1,333 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the Command Buffer Helper.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace gpu {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+const int32 kTotalNumCommandEntries = 10;
+const int32 kCommandBufferSizeBytes =
+ kTotalNumCommandEntries * sizeof(CommandBufferEntry);
+const int32 kUnusedCommandId = 5; // we use 0 and 2 currently.
+
+// Test fixture for CommandBufferHelper test - Creates a CommandBufferHelper,
+// using a CommandBufferEngine with a mock AsyncAPIInterface for its interface
+// (calling it directly, not through the RPC mechanism).
+class CommandBufferHelperTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, _, _))
+ .WillRepeatedly(Return(error::kNoError));
+
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ EXPECT_TRUE(manager->Initialize());
+ }
+ command_buffer_.reset(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ EXPECT_TRUE(command_buffer_->Initialize());
+
+ gpu_scheduler_.reset(new GpuScheduler(
+ command_buffer_.get(), api_mock_.get(), NULL));
+ command_buffer_->SetPutOffsetChangeCallback(base::Bind(
+ &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
+ command_buffer_->SetGetBufferChangeCallback(base::Bind(
+ &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+
+ api_mock_->set_engine(gpu_scheduler_.get());
+
+ helper_.reset(new CommandBufferHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
+ const CommandParser* GetParser() const {
+ return gpu_scheduler_->parser();
+ }
+
+ // Adds a command to the buffer through the helper, while adding it as an
+ // expected call on the API mock.
+ void AddCommandWithExpect(error::Error _return,
+ unsigned int command,
+ int arg_count,
+ CommandBufferEntry *args) {
+ CommandHeader header;
+ header.size = arg_count + 1;
+ header.command = command;
+ CommandBufferEntry* cmds = helper_->GetSpace(arg_count + 1);
+ CommandBufferOffset put = 0;
+ cmds[put++].value_header = header;
+ for (int ii = 0; ii < arg_count; ++ii) {
+ cmds[put++] = args[ii];
+ }
+
+ EXPECT_CALL(*api_mock_, DoCommand(command, arg_count,
+ Truly(AsyncAPIMock::IsArgs(arg_count, args))))
+ .InSequence(sequence_)
+ .WillOnce(Return(_return));
+ }
+
+ // Checks that the buffer from put to put+size is free in the parser.
+ void CheckFreeSpace(CommandBufferOffset put, unsigned int size) {
+ CommandBufferOffset parser_put = GetParser()->put();
+ CommandBufferOffset parser_get = GetParser()->get();
+ CommandBufferOffset limit = put + size;
+ if (parser_get > parser_put) {
+ // "busy" buffer wraps, so "free" buffer is between put (inclusive) and
+ // get (exclusive).
+ EXPECT_LE(parser_put, put);
+ EXPECT_GT(parser_get, limit);
+ } else {
+ // "busy" buffer does not wrap, so the "free" buffer is the top side (from
+ // put to the limit) and the bottom side (from 0 to get).
+ if (put >= parser_put) {
+ // we're on the top side, check we are below the limit.
+ EXPECT_GE(kTotalNumCommandEntries, limit);
+ } else {
+ // we're on the bottom side, check we are below get.
+ EXPECT_GT(parser_get, limit);
+ }
+ }
+ }
+
+ int32 GetGetOffset() {
+ return command_buffer_->GetState().get_offset;
+ }
+
+ int32 GetPutOffset() {
+ return command_buffer_->GetState().put_offset;
+ }
+
+ error::Error GetError() {
+ return command_buffer_->GetState().error;
+ }
+
+ CommandBufferOffset get_helper_put() { return helper_->put_; }
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool_;
+#endif
+ base::MessageLoop message_loop_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GpuScheduler> gpu_scheduler_;
+ scoped_ptr<CommandBufferHelper> helper_;
+ Sequence sequence_;
+};
+
+// Checks that commands in the buffer are properly executed, and that the
+// status/error stay valid.
+TEST_F(CommandBufferHelperTest, TestCommandProcessing) {
+ // Check initial state of the engine - it should have been configured by the
+ // helper.
+ EXPECT_TRUE(GetParser() != NULL);
+ EXPECT_EQ(error::kNoError, GetError());
+ EXPECT_EQ(0, GetGetOffset());
+
+ // Add 3 commands through the helper
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
+
+ CommandBufferEntry args1[2];
+ args1[0].value_uint32 = 3;
+ args1[1].value_float = 4.f;
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args1);
+
+ CommandBufferEntry args2[2];
+ args2[0].value_uint32 = 5;
+ args2[1].value_float = 6.f;
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 2, args2);
+
+ // Wait until it's done.
+ helper_->Finish();
+ // Check that the engine has no more work to do.
+ EXPECT_TRUE(GetParser()->IsEmpty());
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks that commands in the buffer are properly executed when wrapping the
+// buffer, and that the status/error stay valid.
+TEST_F(CommandBufferHelperTest, TestCommandWrapping) {
+ // Add 5 commands of size 3 through the helper to make sure we do wrap.
+ CommandBufferEntry args1[2];
+ args1[0].value_uint32 = 5;
+ args1[1].value_float = 4.f;
+
+ for (unsigned int i = 0; i < 5; ++i) {
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + i, 2, args1);
+ }
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks the case where the command inserted exactly matches the space left in
+// the command buffer.
+TEST_F(CommandBufferHelperTest, TestCommandWrappingExactMultiple) {
+ const int32 kCommandSize = 5;
+ const size_t kNumArgs = kCommandSize - 1;
+ COMPILE_ASSERT(kTotalNumCommandEntries % kCommandSize == 0,
+ Not_multiple_of_num_command_entries);
+ CommandBufferEntry args1[kNumArgs];
+ for (size_t ii = 0; ii < kNumArgs; ++ii) {
+ args1[0].value_uint32 = ii + 1;
+ }
+
+ for (unsigned int i = 0; i < 5; ++i) {
+ AddCommandWithExpect(
+ error::kNoError, i + kUnusedCommandId, kNumArgs, args1);
+ }
+
+ helper_->Finish();
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks that asking for available entries work, and that the parser
+// effectively won't use that space.
+TEST_F(CommandBufferHelperTest, TestAvailableEntries) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Add 2 commands through the helper - 8 entries
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 1, 0, NULL);
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 2, 0, NULL);
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
+
+ // Ask for 5 entries.
+ helper_->WaitForAvailableEntries(5);
+
+ CommandBufferOffset put = get_helper_put();
+ CheckFreeSpace(put, 5);
+
+ // Add more commands.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 5, 2, args);
+
+ // Wait until everything is done done.
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+// Checks that the InsertToken/WaitForToken work.
+TEST_F(CommandBufferHelperTest, TestToken) {
+ CommandBufferEntry args[2];
+ args[0].value_uint32 = 3;
+ args[1].value_float = 4.f;
+
+ // Add a first command.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 3, 2, args);
+ // keep track of the buffer position.
+ CommandBufferOffset command1_put = get_helper_put();
+ int32 token = helper_->InsertToken();
+
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+ // Add another command.
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId + 4, 2, args);
+ helper_->WaitForToken(token);
+ // check that the get pointer is beyond the first command.
+ EXPECT_LE(command1_put, GetGetOffset());
+ helper_->Finish();
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+
+ // Check the error status.
+ EXPECT_EQ(error::kNoError, GetError());
+}
+
+TEST_F(CommandBufferHelperTest, FreeRingBuffer) {
+ EXPECT_TRUE(helper_->HaveRingBuffer());
+
+ // Test freeing ring buffer.
+ helper_->FreeRingBuffer();
+ EXPECT_FALSE(helper_->HaveRingBuffer());
+
+ // Test that InsertToken allocates a new one
+ int32 token = helper_->InsertToken();
+ EXPECT_TRUE(helper_->HaveRingBuffer());
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillOnce(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+ helper_->WaitForToken(token);
+ helper_->FreeRingBuffer();
+ EXPECT_FALSE(helper_->HaveRingBuffer());
+
+ // Test that WaitForAvailableEntries allocates a new one
+ AddCommandWithExpect(error::kNoError, kUnusedCommandId, 0, NULL);
+ EXPECT_TRUE(helper_->HaveRingBuffer());
+ helper_->Finish();
+ helper_->FreeRingBuffer();
+ EXPECT_FALSE(helper_->HaveRingBuffer());
+
+ // Check that the commands did happen.
+ Mock::VerifyAndClearExpectations(api_mock_.get());
+}
+
+TEST_F(CommandBufferHelperTest, Noop) {
+ for (int ii = 1; ii < 4; ++ii) {
+ CommandBufferOffset put_before = get_helper_put();
+ helper_->Noop(ii);
+ CommandBufferOffset put_after = get_helper_put();
+ EXPECT_EQ(ii, put_after - put_before);
+ }
+}
+
+TEST_F(CommandBufferHelperTest, IsContextLost) {
+ EXPECT_FALSE(helper_->IsContextLost());
+ command_buffer_->SetParseError(error::kGenericError);
+ EXPECT_TRUE(helper_->IsContextLost());
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/fenced_allocator.cc b/chromium/gpu/command_buffer/client/fenced_allocator.cc
new file mode 100644
index 00000000000..6eb9ab3a148
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/fenced_allocator.cc
@@ -0,0 +1,235 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation of the FencedAllocator class.
+
+#include "gpu/command_buffer/client/fenced_allocator.h"
+#include <algorithm>
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+
+namespace gpu {
+
+namespace {
+
+// Allocation alignment, must be a power of two.
+const unsigned int kAllocAlignment = 16;
+
+// Round down to the largest multiple of kAllocAlignment no greater than |size|.
+unsigned int RoundDown(unsigned int size) {
+ return size & ~(kAllocAlignment - 1);
+}
+
+// Round up to the smallest multiple of kAllocAlignment no smaller than |size|.
+unsigned int RoundUp(unsigned int size) {
+ return (size + (kAllocAlignment - 1)) & ~(kAllocAlignment - 1);
+}
+
+} // namespace
+
+#ifndef _MSC_VER
+const FencedAllocator::Offset FencedAllocator::kInvalidOffset;
+#endif
+
+FencedAllocator::FencedAllocator(unsigned int size,
+ CommandBufferHelper *helper)
+ : helper_(helper) {
+ Block block = { FREE, 0, RoundDown(size), kUnusedToken };
+ blocks_.push_back(block);
+}
+
+FencedAllocator::~FencedAllocator() {
+ // Free blocks pending tokens.
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ if (blocks_[i].state == FREE_PENDING_TOKEN) {
+ i = WaitForTokenAndFreeBlock(i);
+ }
+ }
+ // These checks are not valid if the service has crashed or lost the context.
+ // GPU_DCHECK_EQ(blocks_.size(), 1u);
+ // GPU_DCHECK_EQ(blocks_[0].state, FREE);
+}
+
+// Looks for a non-allocated block that is big enough. Search in the FREE
+// blocks first (for direct usage), first-fit, then in the FREE_PENDING_TOKEN
+// blocks, waiting for them. The current implementation isn't smart about
+// optimizing what to wait for, just looks inside the block in order (first-fit
+// as well).
+FencedAllocator::Offset FencedAllocator::Alloc(unsigned int size) {
+ // size of 0 is not allowed because it would be inconsistent to only sometimes
+ // have it succeed. Example: Alloc(SizeOfBuffer), Alloc(0).
+ if (size == 0) {
+ return kInvalidOffset;
+ }
+
+ // Round up the allocation size to ensure alignment.
+ size = RoundUp(size);
+
+ // Try first to allocate in a free block.
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ Block &block = blocks_[i];
+ if (block.state == FREE && block.size >= size) {
+ return AllocInBlock(i, size);
+ }
+ }
+
+ // No free block is available. Look for blocks pending tokens, and wait for
+ // them to be re-usable.
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ if (blocks_[i].state != FREE_PENDING_TOKEN)
+ continue;
+ i = WaitForTokenAndFreeBlock(i);
+ if (blocks_[i].size >= size)
+ return AllocInBlock(i, size);
+ }
+ return kInvalidOffset;
+}
+
+// Looks for the corresponding block, mark it FREE, and collapse it if
+// necessary.
+void FencedAllocator::Free(FencedAllocator::Offset offset) {
+ BlockIndex index = GetBlockByOffset(offset);
+ GPU_DCHECK_NE(blocks_[index].state, FREE);
+ blocks_[index].state = FREE;
+ CollapseFreeBlock(index);
+}
+
+// Looks for the corresponding block, mark it FREE_PENDING_TOKEN.
+void FencedAllocator::FreePendingToken(
+ FencedAllocator::Offset offset, int32 token) {
+ BlockIndex index = GetBlockByOffset(offset);
+ Block &block = blocks_[index];
+ block.state = FREE_PENDING_TOKEN;
+ block.token = token;
+}
+
+// Gets the max of the size of the blocks marked as free.
+unsigned int FencedAllocator::GetLargestFreeSize() {
+ FreeUnused();
+ unsigned int max_size = 0;
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ Block &block = blocks_[i];
+ if (block.state == FREE)
+ max_size = std::max(max_size, block.size);
+ }
+ return max_size;
+}
+
+// Gets the size of the largest segment of blocks that are either FREE or
+// FREE_PENDING_TOKEN.
+unsigned int FencedAllocator::GetLargestFreeOrPendingSize() {
+ unsigned int max_size = 0;
+ unsigned int current_size = 0;
+ for (unsigned int i = 0; i < blocks_.size(); ++i) {
+ Block &block = blocks_[i];
+ if (block.state == IN_USE) {
+ max_size = std::max(max_size, current_size);
+ current_size = 0;
+ } else {
+ GPU_DCHECK(block.state == FREE || block.state == FREE_PENDING_TOKEN);
+ current_size += block.size;
+ }
+ }
+ return std::max(max_size, current_size);
+}
+
+// Makes sure that:
+// - there is at least one block.
+// - there are no contiguous FREE blocks (they should have been collapsed).
+// - the successive offsets match the block sizes, and they are in order.
+bool FencedAllocator::CheckConsistency() {
+ if (blocks_.size() < 1) return false;
+ for (unsigned int i = 0; i < blocks_.size() - 1; ++i) {
+ Block &current = blocks_[i];
+ Block &next = blocks_[i + 1];
+ // This test is NOT included in the next one, because offset is unsigned.
+ if (next.offset <= current.offset)
+ return false;
+ if (next.offset != current.offset + current.size)
+ return false;
+ if (current.state == FREE && next.state == FREE)
+ return false;
+ }
+ return true;
+}
+
+bool FencedAllocator::InUse() {
+ return blocks_.size() != 1 || blocks_[0].state != FREE;
+}
+
+// Collapse the block to the next one, then to the previous one. Provided the
+// structure is consistent, those are the only blocks eligible for collapse.
+FencedAllocator::BlockIndex FencedAllocator::CollapseFreeBlock(
+ BlockIndex index) {
+ if (index + 1 < blocks_.size()) {
+ Block &next = blocks_[index + 1];
+ if (next.state == FREE) {
+ blocks_[index].size += next.size;
+ blocks_.erase(blocks_.begin() + index + 1);
+ }
+ }
+ if (index > 0) {
+ Block &prev = blocks_[index - 1];
+ if (prev.state == FREE) {
+ prev.size += blocks_[index].size;
+ blocks_.erase(blocks_.begin() + index);
+ --index;
+ }
+ }
+ return index;
+}
+
+// Waits for the block's token, then mark the block as free, then collapse it.
+FencedAllocator::BlockIndex FencedAllocator::WaitForTokenAndFreeBlock(
+ BlockIndex index) {
+ Block &block = blocks_[index];
+ GPU_DCHECK_EQ(block.state, FREE_PENDING_TOKEN);
+ helper_->WaitForToken(block.token);
+ block.state = FREE;
+ return CollapseFreeBlock(index);
+}
+
+// Frees any blocks pending a token for which the token has been read.
+void FencedAllocator::FreeUnused() {
+ int32 last_token_read = helper_->last_token_read();
+ for (unsigned int i = 0; i < blocks_.size();) {
+ Block& block = blocks_[i];
+ if (block.state == FREE_PENDING_TOKEN && block.token <= last_token_read) {
+ block.state = FREE;
+ i = CollapseFreeBlock(i);
+ } else {
+ ++i;
+ }
+ }
+}
+
+// If the block is exactly the requested size, simply mark it IN_USE, otherwise
+// split it and mark the first one (of the requested size) IN_USE.
+FencedAllocator::Offset FencedAllocator::AllocInBlock(BlockIndex index,
+ unsigned int size) {
+ Block &block = blocks_[index];
+ GPU_DCHECK_GE(block.size, size);
+ GPU_DCHECK_EQ(block.state, FREE);
+ Offset offset = block.offset;
+ if (block.size == size) {
+ block.state = IN_USE;
+ return offset;
+ }
+ Block newblock = { FREE, offset + size, block.size - size, kUnusedToken};
+ block.state = IN_USE;
+ block.size = size;
+ // this is the last thing being done because it may invalidate block;
+ blocks_.insert(blocks_.begin() + index + 1, newblock);
+ return offset;
+}
+
+// The blocks are in offset order, so we can do a binary search.
+FencedAllocator::BlockIndex FencedAllocator::GetBlockByOffset(Offset offset) {
+ Block templ = { IN_USE, offset, 0, kUnusedToken };
+ Container::iterator it = std::lower_bound(blocks_.begin(), blocks_.end(),
+ templ, OffsetCmp());
+ GPU_DCHECK(it != blocks_.end() && it->offset == offset);
+ return it-blocks_.begin();
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/fenced_allocator.h b/chromium/gpu/command_buffer/client/fenced_allocator.h
new file mode 100644
index 00000000000..90288d9fb8f
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/fenced_allocator.h
@@ -0,0 +1,254 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the definition of the FencedAllocator class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_
+#define GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_
+
+#include <vector>
+
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+class CommandBufferHelper;
+
+// FencedAllocator provides a mechanism to manage allocations within a fixed
+// block of memory (storing the book-keeping externally). Furthermore this
+// class allows to free data "pending" the passage of a command buffer token,
+// that is, the memory won't be reused until the command buffer has processed
+// that token.
+//
+// NOTE: Although this class is intended to be used in the command buffer
+// environment which is multi-process, this class isn't "thread safe", because
+// it isn't meant to be shared across modules. It is thread-compatible though
+// (see http://www.corp.google.com/eng/doc/cpp_primer.html#thread_safety).
+class GPU_EXPORT FencedAllocator {
+ public:
+ typedef unsigned int Offset;
+ // Invalid offset, returned by Alloc in case of failure.
+ static const Offset kInvalidOffset = 0xffffffffU;
+
+ // Creates a FencedAllocator. Note that the size of the buffer is passed, but
+ // not its base address: everything is handled as offsets into the buffer.
+ FencedAllocator(unsigned int size,
+ CommandBufferHelper *helper);
+
+ ~FencedAllocator();
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the offset of the allocated memory block, or kInvalidOffset if out of
+ // memory.
+ Offset Alloc(unsigned int size);
+
+ // Frees a block of memory.
+ //
+ // Parameters:
+ // offset: the offset of the memory block to free.
+ void Free(Offset offset);
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // offset: the offset of the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(Offset offset, int32 token);
+
+ // Frees any blocks pending a token for which the token has been read.
+ void FreeUnused();
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSize();
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait. Allocating a block of this size will succeed, but may
+ // block.
+ unsigned int GetLargestFreeOrPendingSize();
+
+ // Checks for consistency inside the book-keeping structures. Used for
+ // testing.
+ bool CheckConsistency();
+
+ // True if any memory is allocated.
+ bool InUse();
+
+ private:
+ // Status of a block of memory, for book-keeping.
+ enum State {
+ IN_USE,
+ FREE,
+ FREE_PENDING_TOKEN
+ };
+
+ // Book-keeping sturcture that describes a block of memory.
+ struct Block {
+ State state;
+ Offset offset;
+ unsigned int size;
+ int32 token; // token to wait for in the FREE_PENDING_TOKEN case.
+ };
+
+ // Comparison functor for memory block sorting.
+ class OffsetCmp {
+ public:
+ bool operator() (const Block &left, const Block &right) {
+ return left.offset < right.offset;
+ }
+ };
+
+ typedef std::vector<Block> Container;
+ typedef unsigned int BlockIndex;
+
+ static const int32 kUnusedToken = 0;
+
+ // Gets the index of a memory block, given its offset.
+ BlockIndex GetBlockByOffset(Offset offset);
+
+ // Collapse a free block with its neighbours if they are free. Returns the
+ // index of the collapsed block.
+ // NOTE: this will invalidate block indices.
+ BlockIndex CollapseFreeBlock(BlockIndex index);
+
+ // Waits for a FREE_PENDING_TOKEN block to be usable, and free it. Returns
+ // the new index of that block (since it may have been collapsed).
+ // NOTE: this will invalidate block indices.
+ BlockIndex WaitForTokenAndFreeBlock(BlockIndex index);
+
+ // Allocates a block of memory inside a given block, splitting it in two
+ // (unless that block is of the exact requested size).
+ // NOTE: this will invalidate block indices.
+ // Returns the offset of the allocated block (NOTE: this is different from
+ // the other functions that return a block index).
+ Offset AllocInBlock(BlockIndex index, unsigned int size);
+
+ CommandBufferHelper *helper_;
+ Container blocks_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocator);
+};
+
+// This class functions just like FencedAllocator, but its API uses pointers
+// instead of offsets.
+class FencedAllocatorWrapper {
+ public:
+ FencedAllocatorWrapper(unsigned int size,
+ CommandBufferHelper* helper,
+ void* base)
+ : allocator_(size, helper),
+ base_(base) { }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ void *Alloc(unsigned int size) {
+ FencedAllocator::Offset offset = allocator_.Alloc(size);
+ return GetPointer(offset);
+ }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ // This is a type-safe version of Alloc, returning a typed pointer.
+ //
+ // Parameters:
+ // count: the number of elements to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ template <typename T> T *AllocTyped(unsigned int count) {
+ return static_cast<T *>(Alloc(count * sizeof(T)));
+ }
+
+ // Frees a block of memory.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ void Free(void *pointer) {
+ GPU_DCHECK(pointer);
+ allocator_.Free(GetOffset(pointer));
+ }
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(void *pointer, int32 token) {
+ GPU_DCHECK(pointer);
+ allocator_.FreePendingToken(GetOffset(pointer), token);
+ }
+
+ // Frees any blocks pending a token for which the token has been read.
+ void FreeUnused() {
+ allocator_.FreeUnused();
+ }
+
+ // Gets a pointer to a memory block given the base memory and the offset.
+ // It translates FencedAllocator::kInvalidOffset to NULL.
+ void *GetPointer(FencedAllocator::Offset offset) {
+ return (offset == FencedAllocator::kInvalidOffset) ?
+ NULL : static_cast<char *>(base_) + offset;
+ }
+
+ // Gets the offset to a memory block given the base memory and the address.
+ // It translates NULL to FencedAllocator::kInvalidOffset.
+ FencedAllocator::Offset GetOffset(void *pointer) {
+ return pointer ?
+ static_cast<FencedAllocator::Offset>(
+ static_cast<char*>(pointer) - static_cast<char*>(base_)) :
+ FencedAllocator::kInvalidOffset;
+ }
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSize() {
+ return allocator_.GetLargestFreeSize();
+ }
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait.
+ unsigned int GetLargestFreeOrPendingSize() {
+ return allocator_.GetLargestFreeOrPendingSize();
+ }
+
+ // Checks for consistency inside the book-keeping structures. Used for
+ // testing.
+ bool CheckConsistency() {
+ return allocator_.CheckConsistency();
+ }
+
+ // True if any memory is allocated.
+ bool InUse() {
+ return allocator_.InUse();
+ }
+
+ FencedAllocator &allocator() { return allocator_; }
+
+ private:
+ FencedAllocator allocator_;
+ void* base_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(FencedAllocatorWrapper);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_FENCED_ALLOCATOR_H_
diff --git a/chromium/gpu/command_buffer/client/fenced_allocator_test.cc b/chromium/gpu/command_buffer/client/fenced_allocator_test.cc
new file mode 100644
index 00000000000..cc99ed36522
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/fenced_allocator_test.cc
@@ -0,0 +1,578 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the tests for the FencedAllocator class.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/memory/aligned_memory.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/client/fenced_allocator.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace gpu {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+class BaseFencedAllocatorTest : public testing::Test {
+ protected:
+ static const unsigned int kBufferSize = 1024;
+ static const int kAllocAlignment = 16;
+
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
+ .WillRepeatedly(Return(error::kNoError));
+ // Forward the SetToken calls to the engine
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillRepeatedly(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ EXPECT_TRUE(manager->Initialize());
+ }
+ command_buffer_.reset(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ EXPECT_TRUE(command_buffer_->Initialize());
+
+ gpu_scheduler_.reset(new GpuScheduler(
+ command_buffer_.get(), api_mock_.get(), NULL));
+ command_buffer_->SetPutOffsetChangeCallback(base::Bind(
+ &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
+ command_buffer_->SetGetBufferChangeCallback(base::Bind(
+ &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+
+ api_mock_->set_engine(gpu_scheduler_.get());
+
+ helper_.reset(new CommandBufferHelper(command_buffer_.get()));
+ helper_->Initialize(kBufferSize);
+ }
+
+ int32 GetToken() {
+ return command_buffer_->GetState().token;
+ }
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool_;
+#endif
+ base::MessageLoop message_loop_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GpuScheduler> gpu_scheduler_;
+ scoped_ptr<CommandBufferHelper> helper_;
+};
+
+#ifndef _MSC_VER
+const unsigned int BaseFencedAllocatorTest::kBufferSize;
+#endif
+
+// Test fixture for FencedAllocator test - Creates a FencedAllocator, using a
+// CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
+// it directly, not through the RPC mechanism), making sure Noops are ignored
+// and SetToken are properly forwarded to the engine.
+class FencedAllocatorTest : public BaseFencedAllocatorTest {
+ protected:
+ virtual void SetUp() {
+ BaseFencedAllocatorTest::SetUp();
+ allocator_.reset(new FencedAllocator(kBufferSize, helper_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ BaseFencedAllocatorTest::TearDown();
+ }
+
+ scoped_ptr<FencedAllocator> allocator_;
+};
+
+// Checks basic alloc and free.
+TEST_F(FencedAllocatorTest, TestBasic) {
+ allocator_->CheckConsistency();
+ EXPECT_FALSE(allocator_->InUse());
+
+ const unsigned int kSize = 16;
+ FencedAllocator::Offset offset = allocator_->Alloc(kSize);
+ EXPECT_TRUE(allocator_->InUse());
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_GE(kBufferSize, offset+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ allocator_->Free(offset);
+ EXPECT_FALSE(allocator_->InUse());
+ EXPECT_TRUE(allocator_->CheckConsistency());
+}
+
+// Test alloc 0 fails.
+TEST_F(FencedAllocatorTest, TestAllocZero) {
+ FencedAllocator::Offset offset = allocator_->Alloc(0);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_FALSE(allocator_->InUse());
+ EXPECT_TRUE(allocator_->CheckConsistency());
+}
+
+// Checks out-of-memory condition.
+TEST_F(FencedAllocatorTest, TestOutOfMemory) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ FencedAllocator::Offset offsets[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ offsets[i] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
+ EXPECT_GE(kBufferSize, offsets[i]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ FencedAllocator::Offset offset_failed = allocator_->Alloc(kSize);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, reallocate with half the size
+ allocator_->Free(offsets[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ offsets[0] = allocator_->Alloc(kSize/2);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]);
+ EXPECT_GE(kBufferSize, offsets[0]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // This allocation should fail as well.
+ offset_failed = allocator_->Alloc(kSize);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(offsets[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+// Checks the free-pending-token mechanism.
+TEST_F(FencedAllocatorTest, TestFreePendingToken) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ FencedAllocator::Offset offsets[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ offsets[i] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
+ EXPECT_GE(kBufferSize, offsets[i]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ FencedAllocator::Offset offset_failed = allocator_->Alloc(kSize);
+ EXPECT_EQ(FencedAllocator::kInvalidOffset, offset_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, pending fence.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offsets[0], token);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, GetToken());
+
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed.
+ offsets[0] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[0]);
+ EXPECT_GE(kBufferSize, offsets[0]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, GetToken());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(offsets[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+// Checks the free-pending-token mechanism using FreeUnused
+TEST_F(FencedAllocatorTest, FreeUnused) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ FencedAllocator::Offset offsets[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ offsets[i] = allocator_->Alloc(kSize);
+ EXPECT_NE(FencedAllocator::kInvalidOffset, offsets[i]);
+ EXPECT_GE(kBufferSize, offsets[i]+kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+ EXPECT_TRUE(allocator_->InUse());
+
+ // No memory should be available.
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSize());
+
+ // Free one successful allocation, pending fence.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offsets[0], token);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Force the command buffer to process the token.
+ helper_->Finish();
+
+ // Tell the allocator to update what's available based on the current token.
+ allocator_->FreeUnused();
+
+ // Check that the new largest free size takes into account the unused block.
+ EXPECT_EQ(kSize, allocator_->GetLargestFreeSize());
+
+ // Free two more.
+ token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offsets[1], token);
+ token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offsets[2], token);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Check that nothing has changed.
+ EXPECT_EQ(kSize, allocator_->GetLargestFreeSize());
+
+ // Force the command buffer to process the token.
+ helper_->Finish();
+
+ // Tell the allocator to update what's available based on the current token.
+ allocator_->FreeUnused();
+
+ // Check that the new largest free size takes into account the unused blocks.
+ EXPECT_EQ(kSize * 3, allocator_->GetLargestFreeSize());
+ EXPECT_TRUE(allocator_->InUse());
+
+ // Free up everything.
+ for (unsigned int i = 3; i < kAllocCount; ++i) {
+ allocator_->Free(offsets[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+ EXPECT_FALSE(allocator_->InUse());
+}
+
+// Tests GetLargestFreeSize
+TEST_F(FencedAllocatorTest, TestGetLargestFreeSize) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSize());
+
+ FencedAllocator::Offset offset = allocator_->Alloc(kBufferSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSize());
+ allocator_->Free(offset);
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSize());
+
+ const unsigned int kSize = 16;
+ offset = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ // The following checks that the buffer is allocated "smartly" - which is
+ // dependent on the implementation. But both first-fit or best-fit would
+ // ensure that.
+ EXPECT_EQ(kBufferSize - kSize, allocator_->GetLargestFreeSize());
+
+ // Allocate 2 more buffers (now 3), and then free the first two. This is to
+ // ensure a hole. Note that this is dependent on the first-fit current
+ // implementation.
+ FencedAllocator::Offset offset1 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
+ FencedAllocator::Offset offset2 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset2);
+ allocator_->Free(offset);
+ allocator_->Free(offset1);
+ EXPECT_EQ(kBufferSize - 3 * kSize, allocator_->GetLargestFreeSize());
+
+ offset = allocator_->Alloc(kBufferSize - 3 * kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_EQ(2 * kSize, allocator_->GetLargestFreeSize());
+
+ offset1 = allocator_->Alloc(2 * kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSize());
+
+ allocator_->Free(offset);
+ allocator_->Free(offset1);
+ allocator_->Free(offset2);
+}
+
+// Tests GetLargestFreeOrPendingSize
+TEST_F(FencedAllocatorTest, TestGetLargestFreeOrPendingSize) {
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+
+ FencedAllocator::Offset offset = allocator_->Alloc(kBufferSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeOrPendingSize());
+ allocator_->Free(offset);
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+
+ const unsigned int kSize = 16;
+ offset = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ // The following checks that the buffer is allocates "smartly" - which is
+ // dependent on the implementation. But both first-fit or best-fit would
+ // ensure that.
+ EXPECT_EQ(kBufferSize - kSize, allocator_->GetLargestFreeOrPendingSize());
+
+ // Allocate 2 more buffers (now 3), and then free the first two. This is to
+ // ensure a hole. Note that this is dependent on the first-fit current
+ // implementation.
+ FencedAllocator::Offset offset1 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset1);
+ FencedAllocator::Offset offset2 = allocator_->Alloc(kSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset2);
+ allocator_->Free(offset);
+ allocator_->Free(offset1);
+ EXPECT_EQ(kBufferSize - 3 * kSize,
+ allocator_->GetLargestFreeOrPendingSize());
+
+ // Free the last one, pending a token.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(offset2, token);
+
+ // Now all the buffers have been freed...
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+ // .. but one is still waiting for the token.
+ EXPECT_EQ(kBufferSize - 3 * kSize,
+ allocator_->GetLargestFreeSize());
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, GetToken());
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed, but it will succeed.
+ offset = allocator_->Alloc(kBufferSize);
+ ASSERT_NE(FencedAllocator::kInvalidOffset, offset);
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, GetToken());
+ allocator_->Free(offset);
+
+ // Everything now has been freed...
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+ // ... for real.
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSize());
+}
+
+// Test fixture for FencedAllocatorWrapper test - Creates a
+// FencedAllocatorWrapper, using a CommandBufferHelper with a mock
+// AsyncAPIInterface for its interface (calling it directly, not through the
+// RPC mechanism), making sure Noops are ignored and SetToken are properly
+// forwarded to the engine.
+class FencedAllocatorWrapperTest : public BaseFencedAllocatorTest {
+ protected:
+ virtual void SetUp() {
+ BaseFencedAllocatorTest::SetUp();
+
+ // Though allocating this buffer isn't strictly necessary, it makes
+ // allocations point to valid addresses, so they could be used for
+ // something.
+ buffer_.reset(static_cast<char*>(base::AlignedAlloc(
+ kBufferSize, kAllocAlignment)));
+ allocator_.reset(new FencedAllocatorWrapper(kBufferSize, helper_.get(),
+ buffer_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ BaseFencedAllocatorTest::TearDown();
+ }
+
+ scoped_ptr<FencedAllocatorWrapper> allocator_;
+ scoped_ptr_malloc<char, base::ScopedPtrAlignedFree> buffer_;
+};
+
+// Checks basic alloc and free.
+TEST_F(FencedAllocatorWrapperTest, TestBasic) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ void *pointer = allocator_->Alloc(kSize);
+ ASSERT_TRUE(pointer);
+ EXPECT_LE(buffer_.get(), static_cast<char *>(pointer));
+ EXPECT_GE(kBufferSize, static_cast<char *>(pointer) - buffer_.get() + kSize);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ allocator_->Free(pointer);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ char *pointer_char = allocator_->AllocTyped<char>(kSize);
+ ASSERT_TRUE(pointer_char);
+ EXPECT_LE(buffer_.get(), pointer_char);
+ EXPECT_GE(buffer_.get() + kBufferSize, pointer_char + kSize);
+ allocator_->Free(pointer_char);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ unsigned int *pointer_uint = allocator_->AllocTyped<unsigned int>(kSize);
+ ASSERT_TRUE(pointer_uint);
+ EXPECT_LE(buffer_.get(), reinterpret_cast<char *>(pointer_uint));
+ EXPECT_GE(buffer_.get() + kBufferSize,
+ reinterpret_cast<char *>(pointer_uint + kSize));
+
+ // Check that it did allocate kSize * sizeof(unsigned int). We can't tell
+ // directly, except from the remaining size.
+ EXPECT_EQ(kBufferSize - kSize * sizeof(*pointer_uint),
+ allocator_->GetLargestFreeSize());
+ allocator_->Free(pointer_uint);
+}
+
+// Test alloc 0 fails.
+TEST_F(FencedAllocatorWrapperTest, TestAllocZero) {
+ allocator_->CheckConsistency();
+
+ void *pointer = allocator_->Alloc(0);
+ ASSERT_FALSE(pointer);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+}
+
+// Checks that allocation offsets are aligned to multiples of 16 bytes.
+TEST_F(FencedAllocatorWrapperTest, TestAlignment) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize1 = 75;
+ void *pointer1 = allocator_->Alloc(kSize1);
+ ASSERT_TRUE(pointer1);
+ EXPECT_EQ(reinterpret_cast<intptr_t>(pointer1) & (kAllocAlignment - 1), 0);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ const unsigned int kSize2 = 43;
+ void *pointer2 = allocator_->Alloc(kSize2);
+ ASSERT_TRUE(pointer2);
+ EXPECT_EQ(reinterpret_cast<intptr_t>(pointer2) & (kAllocAlignment - 1), 0);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ allocator_->Free(pointer2);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ allocator_->Free(pointer1);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+}
+
+// Checks out-of-memory condition.
+TEST_F(FencedAllocatorWrapperTest, TestOutOfMemory) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ void *pointers[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ pointers[i] = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ void *pointer_failed = allocator_->Alloc(kSize);
+ EXPECT_FALSE(pointer_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, reallocate with half the size
+ allocator_->Free(pointers[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ pointers[0] = allocator_->Alloc(kSize/2);
+ EXPECT_TRUE(pointers[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // This allocation should fail as well.
+ pointer_failed = allocator_->Alloc(kSize);
+ EXPECT_FALSE(pointer_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+// Checks the free-pending-token mechanism.
+TEST_F(FencedAllocatorWrapperTest, TestFreePendingToken) {
+ allocator_->CheckConsistency();
+
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ // Allocate several buffers to fill in the memory.
+ void *pointers[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ pointers[i] = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+
+ // This allocation should fail.
+ void *pointer_failed = allocator_->Alloc(kSize);
+ EXPECT_FALSE(pointer_failed);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // Free one successful allocation, pending fence.
+ int32 token = helper_.get()->InsertToken();
+ allocator_->FreePendingToken(pointers[0], token);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, GetToken());
+
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed.
+ pointers[0] = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointers[0]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, GetToken());
+
+ // Free up everything.
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ allocator_->Free(pointers[i]);
+ EXPECT_TRUE(allocator_->CheckConsistency());
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/gl_in_process_context.cc b/chromium/gpu/command_buffer/client/gl_in_process_context.cc
new file mode 100644
index 00000000000..cdbfc9f47c3
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gl_in_process_context.cc
@@ -0,0 +1,431 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gl_in_process_context.h"
+
+#include <set>
+#include <utility>
+#include <vector>
+
+#include <GLES2/gl2.h>
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES 1
+#endif
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_factory.h"
+#include "gpu/command_buffer/client/image_factory.h"
+#include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/service/in_process_command_buffer.h"
+#include "ui/gfx/size.h"
+#include "ui/gl/gl_image.h"
+
+namespace gpu {
+
+namespace {
+
+const int32 kCommandBufferSize = 1024 * 1024;
+// TODO(kbr): make the transfer buffer size configurable via context
+// creation attributes.
+const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
+const size_t kMinTransferBufferSize = 1 * 256 * 1024;
+const size_t kMaxTransferBufferSize = 16 * 1024 * 1024;
+
+static GpuMemoryBufferFactory* g_gpu_memory_buffer_factory = NULL;
+
+class GLInProcessContextImpl
+ : public GLInProcessContext,
+ public gles2::ImageFactory,
+ public base::SupportsWeakPtr<GLInProcessContextImpl> {
+ public:
+ explicit GLInProcessContextImpl();
+ virtual ~GLInProcessContextImpl();
+
+ bool Initialize(scoped_refptr<gfx::GLSurface> surface,
+ bool is_offscreen,
+ bool share_resources,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ const char* allowed_extensions,
+ const GLInProcessContextAttribs& attribs,
+ gfx::GpuPreference gpu_preference);
+
+ // GLInProcessContext implementation:
+ virtual void SetContextLostCallback(const base::Closure& callback) OVERRIDE;
+ virtual void SignalSyncPoint(unsigned sync_point,
+ const base::Closure& callback) OVERRIDE;
+ virtual void SignalQuery(unsigned query, const base::Closure& callback)
+ OVERRIDE;
+ virtual gles2::GLES2Implementation* GetImplementation() OVERRIDE;
+
+ // ImageFactory implementation:
+ virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
+ int width, int height, GLenum internalformat,
+ unsigned* image_id) OVERRIDE;
+ virtual void DeleteGpuMemoryBuffer(unsigned image_id) OVERRIDE;
+
+ private:
+ void Destroy();
+ void PollQueryCallbacks();
+ void CallQueryCallback(size_t index);
+ void OnContextLost();
+ void OnSignalSyncPoint(const base::Closure& callback);
+
+ scoped_ptr<gles2::GLES2CmdHelper> gles2_helper_;
+ scoped_ptr<TransferBuffer> transfer_buffer_;
+ scoped_ptr<gles2::GLES2Implementation> gles2_implementation_;
+ scoped_ptr<InProcessCommandBuffer> command_buffer_;
+
+ typedef std::pair<unsigned, base::Closure> QueryCallback;
+ std::vector<QueryCallback> query_callbacks_;
+
+ unsigned int share_group_id_;
+ bool context_lost_;
+ base::Closure context_lost_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLInProcessContextImpl);
+};
+
+base::LazyInstance<base::Lock> g_all_shared_contexts_lock =
+ LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<std::set<GLInProcessContextImpl*> > g_all_shared_contexts =
+ LAZY_INSTANCE_INITIALIZER;
+
+size_t SharedContextCount() {
+ base::AutoLock lock(g_all_shared_contexts_lock.Get());
+ return g_all_shared_contexts.Get().size();
+}
+
+scoped_ptr<gfx::GpuMemoryBuffer> GLInProcessContextImpl::CreateGpuMemoryBuffer(
+ int width, int height, GLenum internalformat, unsigned int* image_id) {
+ scoped_ptr<gfx::GpuMemoryBuffer> buffer(
+ g_gpu_memory_buffer_factory->CreateGpuMemoryBuffer(width,
+ height,
+ internalformat));
+ if (!buffer)
+ return scoped_ptr<gfx::GpuMemoryBuffer>();
+
+ *image_id = command_buffer_->CreateImageForGpuMemoryBuffer(
+ buffer->GetHandle(), gfx::Size(width, height));
+ return buffer.Pass();
+}
+
+void GLInProcessContextImpl::DeleteGpuMemoryBuffer(unsigned int image_id) {
+ command_buffer_->RemoveImage(image_id);
+}
+
+GLInProcessContextImpl::GLInProcessContextImpl()
+ : share_group_id_(0), context_lost_(false) {}
+
+GLInProcessContextImpl::~GLInProcessContextImpl() {
+ {
+ base::AutoLock lock(g_all_shared_contexts_lock.Get());
+ g_all_shared_contexts.Get().erase(this);
+ }
+ Destroy();
+}
+
+void GLInProcessContextImpl::SignalSyncPoint(unsigned sync_point,
+ const base::Closure& callback) {
+ DCHECK(!callback.is_null());
+ base::Closure wrapped_callback = base::Bind(
+ &GLInProcessContextImpl::OnSignalSyncPoint, AsWeakPtr(), callback);
+ command_buffer_->SignalSyncPoint(sync_point, wrapped_callback);
+}
+
+gles2::GLES2Implementation* GLInProcessContextImpl::GetImplementation() {
+ return gles2_implementation_.get();
+}
+
+void GLInProcessContextImpl::SetContextLostCallback(
+ const base::Closure& callback) {
+ context_lost_callback_ = callback;
+}
+
+void GLInProcessContextImpl::OnContextLost() {
+ context_lost_ = true;
+ if (!context_lost_callback_.is_null()) {
+ context_lost_callback_.Run();
+ }
+}
+
+void GLInProcessContextImpl::OnSignalSyncPoint(const base::Closure& callback) {
+ // TODO: Should it always trigger callbacks?
+ if (!context_lost_)
+ callback.Run();
+}
+
+bool GLInProcessContextImpl::Initialize(
+ scoped_refptr<gfx::GLSurface> surface,
+ bool is_offscreen,
+ bool share_resources,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ const char* allowed_extensions,
+ const GLInProcessContextAttribs& attribs,
+ gfx::GpuPreference gpu_preference) {
+ DCHECK(size.width() >= 0 && size.height() >= 0);
+
+ const int32 ALPHA_SIZE = 0x3021;
+ const int32 BLUE_SIZE = 0x3022;
+ const int32 GREEN_SIZE = 0x3023;
+ const int32 RED_SIZE = 0x3024;
+ const int32 DEPTH_SIZE = 0x3025;
+ const int32 STENCIL_SIZE = 0x3026;
+ const int32 SAMPLES = 0x3031;
+ const int32 SAMPLE_BUFFERS = 0x3032;
+ const int32 NONE = 0x3038;
+
+ std::vector<int32> attrib_vector;
+ if (attribs.alpha_size >= 0) {
+ attrib_vector.push_back(ALPHA_SIZE);
+ attrib_vector.push_back(attribs.alpha_size);
+ }
+ if (attribs.blue_size >= 0) {
+ attrib_vector.push_back(BLUE_SIZE);
+ attrib_vector.push_back(attribs.blue_size);
+ }
+ if (attribs.green_size >= 0) {
+ attrib_vector.push_back(GREEN_SIZE);
+ attrib_vector.push_back(attribs.green_size);
+ }
+ if (attribs.red_size >= 0) {
+ attrib_vector.push_back(RED_SIZE);
+ attrib_vector.push_back(attribs.red_size);
+ }
+ if (attribs.depth_size >= 0) {
+ attrib_vector.push_back(DEPTH_SIZE);
+ attrib_vector.push_back(attribs.depth_size);
+ }
+ if (attribs.stencil_size >= 0) {
+ attrib_vector.push_back(STENCIL_SIZE);
+ attrib_vector.push_back(attribs.stencil_size);
+ }
+ if (attribs.samples >= 0) {
+ attrib_vector.push_back(SAMPLES);
+ attrib_vector.push_back(attribs.samples);
+ }
+ if (attribs.sample_buffers >= 0) {
+ attrib_vector.push_back(SAMPLE_BUFFERS);
+ attrib_vector.push_back(attribs.sample_buffers);
+ }
+ attrib_vector.push_back(NONE);
+
+ base::Closure wrapped_callback =
+ base::Bind(&GLInProcessContextImpl::OnContextLost, AsWeakPtr());
+ command_buffer_.reset(new InProcessCommandBuffer());
+
+ scoped_ptr<base::AutoLock> scoped_shared_context_lock;
+ scoped_refptr<gles2::ShareGroup> share_group;
+ if (share_resources) {
+ scoped_shared_context_lock.reset(
+ new base::AutoLock(g_all_shared_contexts_lock.Get()));
+ for (std::set<GLInProcessContextImpl*>::const_iterator it =
+ g_all_shared_contexts.Get().begin();
+ it != g_all_shared_contexts.Get().end();
+ it++) {
+ const GLInProcessContextImpl* context = *it;
+ if (!context->context_lost_) {
+ share_group = context->gles2_implementation_->share_group();
+ DCHECK(share_group);
+ share_group_id_ = context->share_group_id_;
+ break;
+ }
+ share_group_id_ = std::max(share_group_id_, context->share_group_id_);
+ }
+ if (!share_group && !++share_group_id_)
+ ++share_group_id_;
+ }
+ if (!command_buffer_->Initialize(surface,
+ is_offscreen,
+ share_resources,
+ window,
+ size,
+ allowed_extensions,
+ attrib_vector,
+ gpu_preference,
+ wrapped_callback,
+ share_group_id_)) {
+ LOG(INFO) << "Failed to initialize InProcessCommmandBuffer";
+ return false;
+ }
+
+ // Create the GLES2 helper, which writes the command buffer protocol.
+ gles2_helper_.reset(new gles2::GLES2CmdHelper(command_buffer_.get()));
+ if (!gles2_helper_->Initialize(kCommandBufferSize)) {
+ LOG(INFO) << "Failed to initialize GLES2CmdHelper";
+ Destroy();
+ return false;
+ }
+
+ // Create a transfer buffer.
+ transfer_buffer_.reset(new TransferBuffer(gles2_helper_.get()));
+
+ // Create the object exposing the OpenGL API.
+ gles2_implementation_.reset(new gles2::GLES2Implementation(
+ gles2_helper_.get(),
+ share_group,
+ transfer_buffer_.get(),
+ false,
+ this));
+
+ if (share_resources) {
+ g_all_shared_contexts.Get().insert(this);
+ scoped_shared_context_lock.reset();
+ }
+
+ if (!gles2_implementation_->Initialize(
+ kStartTransferBufferSize,
+ kMinTransferBufferSize,
+ kMaxTransferBufferSize)) {
+ return false;
+ }
+
+ return true;
+}
+
+void GLInProcessContextImpl::Destroy() {
+ while (!query_callbacks_.empty()) {
+ CallQueryCallback(0);
+ }
+
+ if (gles2_implementation_) {
+ // First flush the context to ensure that any pending frees of resources
+ // are completed. Otherwise, if this context is part of a share group,
+ // those resources might leak. Also, any remaining side effects of commands
+ // issued on this context might not be visible to other contexts in the
+ // share group.
+ gles2_implementation_->Flush();
+
+ gles2_implementation_.reset();
+ }
+
+ transfer_buffer_.reset();
+ gles2_helper_.reset();
+ command_buffer_.reset();
+}
+
+void GLInProcessContextImpl::CallQueryCallback(size_t index) {
+ DCHECK_LT(index, query_callbacks_.size());
+ QueryCallback query_callback = query_callbacks_[index];
+ query_callbacks_[index] = query_callbacks_.back();
+ query_callbacks_.pop_back();
+ query_callback.second.Run();
+}
+
+// TODO(sievers): Move this to the service side
+void GLInProcessContextImpl::PollQueryCallbacks() {
+ for (size_t i = 0; i < query_callbacks_.size();) {
+ unsigned query = query_callbacks_[i].first;
+ GLuint param = 0;
+ gles2::GLES2Implementation* gl = GetImplementation();
+ if (gl->IsQueryEXT(query)) {
+ gl->GetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &param);
+ } else {
+ param = 1;
+ }
+ if (param) {
+ CallQueryCallback(i);
+ } else {
+ i++;
+ }
+ }
+ if (!query_callbacks_.empty()) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&GLInProcessContextImpl::PollQueryCallbacks,
+ this->AsWeakPtr()),
+ base::TimeDelta::FromMilliseconds(5));
+ }
+}
+
+void GLInProcessContextImpl::SignalQuery(
+ unsigned query,
+ const base::Closure& callback) {
+ query_callbacks_.push_back(std::make_pair(query, callback));
+ // If size > 1, there is already a poll callback pending.
+ if (query_callbacks_.size() == 1) {
+ PollQueryCallbacks();
+ }
+}
+
+} // anonymous namespace
+
+GLInProcessContextAttribs::GLInProcessContextAttribs()
+ : alpha_size(-1),
+ blue_size(-1),
+ green_size(-1),
+ red_size(-1),
+ depth_size(-1),
+ stencil_size(-1),
+ samples(-1),
+ sample_buffers(-1) {}
+
+// static
+GLInProcessContext* GLInProcessContext::CreateContext(
+ bool is_offscreen,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ bool share_resources,
+ const char* allowed_extensions,
+ const GLInProcessContextAttribs& attribs,
+ gfx::GpuPreference gpu_preference) {
+ scoped_ptr<GLInProcessContextImpl> context(
+ new GLInProcessContextImpl());
+ if (!context->Initialize(
+ NULL /* surface */,
+ is_offscreen,
+ share_resources,
+ window,
+ size,
+ allowed_extensions,
+ attribs,
+ gpu_preference))
+ return NULL;
+
+ return context.release();
+}
+
+// static
+GLInProcessContext* GLInProcessContext::CreateWithSurface(
+ scoped_refptr<gfx::GLSurface> surface,
+ bool share_resources,
+ const char* allowed_extensions,
+ const GLInProcessContextAttribs& attribs,
+ gfx::GpuPreference gpu_preference) {
+ scoped_ptr<GLInProcessContextImpl> context(
+ new GLInProcessContextImpl());
+ if (!context->Initialize(
+ surface,
+ surface->IsOffscreen(),
+ share_resources,
+ gfx::kNullAcceleratedWidget,
+ surface->GetSize(),
+ allowed_extensions,
+ attribs,
+ gpu_preference))
+ return NULL;
+
+ return context.release();
+}
+
+// static
+void GLInProcessContext::SetGpuMemoryBufferFactory(
+ GpuMemoryBufferFactory* factory) {
+ DCHECK_EQ(0u, SharedContextCount());
+ g_gpu_memory_buffer_factory = factory;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/gl_in_process_context.h b/chromium/gpu/command_buffer/client/gl_in_process_context.h
new file mode 100644
index 00000000000..09f8140ee0e
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gl_in_process_context.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GL_IN_PROCESS_CONTEXT_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GL_IN_PROCESS_CONTEXT_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "gles2_impl_export.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gpu_preference.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace gpu {
+
+namespace gles2 {
+class GLES2Implementation;
+}
+
+class GpuMemoryBufferFactory;
+
+// The default uninitialized value is -1.
+struct GLES2_IMPL_EXPORT GLInProcessContextAttribs {
+ GLInProcessContextAttribs();
+
+ int32 alpha_size;
+ int32 blue_size;
+ int32 green_size;
+ int32 red_size;
+ int32 depth_size;
+ int32 stencil_size;
+ int32 samples;
+ int32 sample_buffers;
+};
+
+class GLES2_IMPL_EXPORT GLInProcessContext {
+ public:
+ virtual ~GLInProcessContext() {}
+
+ // Must be called before any GLInProcessContext instances are created.
+ static void SetGpuMemoryBufferFactory(GpuMemoryBufferFactory* factory);
+
+ // Create a GLInProcessContext, if |is_offscreen| is true, renders to an
+ // offscreen context. |attrib_list| must be NULL or a NONE-terminated list
+ // of attribute/value pairs.
+ static GLInProcessContext* CreateContext(
+ bool is_offscreen,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ bool share_resources,
+ const char* allowed_extensions,
+ const GLInProcessContextAttribs& attribs,
+ gfx::GpuPreference gpu_preference);
+
+ // Create context with the provided GLSurface. All other arguments match
+ // CreateContext factory above. Can only be called if the command buffer
+ // service runs on the same thread as this client because GLSurface is not
+ // thread safe.
+ static GLInProcessContext* CreateWithSurface(
+ scoped_refptr<gfx::GLSurface> surface,
+ bool share_resources,
+ const char* allowed_extensions,
+ const GLInProcessContextAttribs& attribs,
+ gfx::GpuPreference gpu_preference);
+
+ virtual void SetContextLostCallback(const base::Closure& callback) = 0;
+
+ virtual void SignalSyncPoint(unsigned sync_point,
+ const base::Closure& callback) = 0;
+
+ virtual void SignalQuery(unsigned query, const base::Closure& callback) = 0;
+
+ // Allows direct access to the GLES2 implementation so a GLInProcessContext
+ // can be used without making it current.
+ virtual gles2::GLES2Implementation* GetImplementation() = 0;
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GL_IN_PROCESS_CONTEXT_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_c_lib.cc b/chromium/gpu/command_buffer/client/gles2_c_lib.cc
new file mode 100644
index 00000000000..fbe7b55eab1
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_c_lib.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// These functions emulate GLES2 over command buffers for C.
+
+#include <assert.h>
+#include <stdlib.h>
+#include "gpu/command_buffer/client/gles2_lib.h"
+
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+extern "C" {
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/client/gles2_c_lib_autogen.h"
+} // extern "C"
+
+
diff --git a/chromium/gpu/command_buffer/client/gles2_c_lib_autogen.h b/chromium/gpu/command_buffer/client/gles2_c_lib_autogen.h
new file mode 100644
index 00000000000..cc9a5cf49be
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -0,0 +1,1122 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// These functions emulate GLES2 over command buffers.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_AUTOGEN_H_
+
+void GLES2ActiveTexture(GLenum texture) {
+ gles2::GetGLContext()->ActiveTexture(texture);
+}
+void GLES2AttachShader(GLuint program, GLuint shader) {
+ gles2::GetGLContext()->AttachShader(program, shader);
+}
+void GLES2BindAttribLocation(GLuint program, GLuint index, const char* name) {
+ gles2::GetGLContext()->BindAttribLocation(program, index, name);
+}
+void GLES2BindBuffer(GLenum target, GLuint buffer) {
+ gles2::GetGLContext()->BindBuffer(target, buffer);
+}
+void GLES2BindFramebuffer(GLenum target, GLuint framebuffer) {
+ gles2::GetGLContext()->BindFramebuffer(target, framebuffer);
+}
+void GLES2BindRenderbuffer(GLenum target, GLuint renderbuffer) {
+ gles2::GetGLContext()->BindRenderbuffer(target, renderbuffer);
+}
+void GLES2BindTexture(GLenum target, GLuint texture) {
+ gles2::GetGLContext()->BindTexture(target, texture);
+}
+void GLES2BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ gles2::GetGLContext()->BlendColor(red, green, blue, alpha);
+}
+void GLES2BlendEquation(GLenum mode) {
+ gles2::GetGLContext()->BlendEquation(mode);
+}
+void GLES2BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
+ gles2::GetGLContext()->BlendEquationSeparate(modeRGB, modeAlpha);
+}
+void GLES2BlendFunc(GLenum sfactor, GLenum dfactor) {
+ gles2::GetGLContext()->BlendFunc(sfactor, dfactor);
+}
+void GLES2BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ gles2::GetGLContext()->BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+void GLES2BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ gles2::GetGLContext()->BufferData(target, size, data, usage);
+}
+void GLES2BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ gles2::GetGLContext()->BufferSubData(target, offset, size, data);
+}
+GLenum GLES2CheckFramebufferStatus(GLenum target) {
+ return gles2::GetGLContext()->CheckFramebufferStatus(target);
+}
+void GLES2Clear(GLbitfield mask) {
+ gles2::GetGLContext()->Clear(mask);
+}
+void GLES2ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ gles2::GetGLContext()->ClearColor(red, green, blue, alpha);
+}
+void GLES2ClearDepthf(GLclampf depth) {
+ gles2::GetGLContext()->ClearDepthf(depth);
+}
+void GLES2ClearStencil(GLint s) {
+ gles2::GetGLContext()->ClearStencil(s);
+}
+void GLES2ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ gles2::GetGLContext()->ColorMask(red, green, blue, alpha);
+}
+void GLES2CompileShader(GLuint shader) {
+ gles2::GetGLContext()->CompileShader(shader);
+}
+void GLES2CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize, const void* data) {
+ gles2::GetGLContext()->CompressedTexImage2D(
+ target, level, internalformat, width, height, border, imageSize, data);
+}
+void GLES2CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
+ gles2::GetGLContext()->CompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+void GLES2CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) {
+ gles2::GetGLContext()->CopyTexImage2D(
+ target, level, internalformat, x, y, width, height, border);
+}
+void GLES2CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) {
+ gles2::GetGLContext()->CopyTexSubImage2D(
+ target, level, xoffset, yoffset, x, y, width, height);
+}
+GLuint GLES2CreateProgram() {
+ return gles2::GetGLContext()->CreateProgram();
+}
+GLuint GLES2CreateShader(GLenum type) {
+ return gles2::GetGLContext()->CreateShader(type);
+}
+void GLES2CullFace(GLenum mode) {
+ gles2::GetGLContext()->CullFace(mode);
+}
+void GLES2DeleteBuffers(GLsizei n, const GLuint* buffers) {
+ gles2::GetGLContext()->DeleteBuffers(n, buffers);
+}
+void GLES2DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) {
+ gles2::GetGLContext()->DeleteFramebuffers(n, framebuffers);
+}
+void GLES2DeleteProgram(GLuint program) {
+ gles2::GetGLContext()->DeleteProgram(program);
+}
+void GLES2DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) {
+ gles2::GetGLContext()->DeleteRenderbuffers(n, renderbuffers);
+}
+void GLES2DeleteShader(GLuint shader) {
+ gles2::GetGLContext()->DeleteShader(shader);
+}
+void GLES2DeleteTextures(GLsizei n, const GLuint* textures) {
+ gles2::GetGLContext()->DeleteTextures(n, textures);
+}
+void GLES2DepthFunc(GLenum func) {
+ gles2::GetGLContext()->DepthFunc(func);
+}
+void GLES2DepthMask(GLboolean flag) {
+ gles2::GetGLContext()->DepthMask(flag);
+}
+void GLES2DepthRangef(GLclampf zNear, GLclampf zFar) {
+ gles2::GetGLContext()->DepthRangef(zNear, zFar);
+}
+void GLES2DetachShader(GLuint program, GLuint shader) {
+ gles2::GetGLContext()->DetachShader(program, shader);
+}
+void GLES2Disable(GLenum cap) {
+ gles2::GetGLContext()->Disable(cap);
+}
+void GLES2DisableVertexAttribArray(GLuint index) {
+ gles2::GetGLContext()->DisableVertexAttribArray(index);
+}
+void GLES2DrawArrays(GLenum mode, GLint first, GLsizei count) {
+ gles2::GetGLContext()->DrawArrays(mode, first, count);
+}
+void GLES2DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) {
+ gles2::GetGLContext()->DrawElements(mode, count, type, indices);
+}
+void GLES2Enable(GLenum cap) {
+ gles2::GetGLContext()->Enable(cap);
+}
+void GLES2EnableVertexAttribArray(GLuint index) {
+ gles2::GetGLContext()->EnableVertexAttribArray(index);
+}
+void GLES2Finish() {
+ gles2::GetGLContext()->Finish();
+}
+void GLES2Flush() {
+ gles2::GetGLContext()->Flush();
+}
+void GLES2FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) {
+ gles2::GetGLContext()->FramebufferRenderbuffer(
+ target, attachment, renderbuffertarget, renderbuffer);
+}
+void GLES2FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) {
+ gles2::GetGLContext()->FramebufferTexture2D(
+ target, attachment, textarget, texture, level);
+}
+void GLES2FrontFace(GLenum mode) {
+ gles2::GetGLContext()->FrontFace(mode);
+}
+void GLES2GenBuffers(GLsizei n, GLuint* buffers) {
+ gles2::GetGLContext()->GenBuffers(n, buffers);
+}
+void GLES2GenerateMipmap(GLenum target) {
+ gles2::GetGLContext()->GenerateMipmap(target);
+}
+void GLES2GenFramebuffers(GLsizei n, GLuint* framebuffers) {
+ gles2::GetGLContext()->GenFramebuffers(n, framebuffers);
+}
+void GLES2GenRenderbuffers(GLsizei n, GLuint* renderbuffers) {
+ gles2::GetGLContext()->GenRenderbuffers(n, renderbuffers);
+}
+void GLES2GenTextures(GLsizei n, GLuint* textures) {
+ gles2::GetGLContext()->GenTextures(n, textures);
+}
+void GLES2GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ gles2::GetGLContext()->GetActiveAttrib(
+ program, index, bufsize, length, size, type, name);
+}
+void GLES2GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ gles2::GetGLContext()->GetActiveUniform(
+ program, index, bufsize, length, size, type, name);
+}
+void GLES2GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+ gles2::GetGLContext()->GetAttachedShaders(program, maxcount, count, shaders);
+}
+GLint GLES2GetAttribLocation(GLuint program, const char* name) {
+ return gles2::GetGLContext()->GetAttribLocation(program, name);
+}
+void GLES2GetBooleanv(GLenum pname, GLboolean* params) {
+ gles2::GetGLContext()->GetBooleanv(pname, params);
+}
+void GLES2GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetBufferParameteriv(target, pname, params);
+}
+GLenum GLES2GetError() {
+ return gles2::GetGLContext()->GetError();
+}
+void GLES2GetFloatv(GLenum pname, GLfloat* params) {
+ gles2::GetGLContext()->GetFloatv(pname, params);
+}
+void GLES2GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetFramebufferAttachmentParameteriv(
+ target, attachment, pname, params);
+}
+void GLES2GetIntegerv(GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetIntegerv(pname, params);
+}
+void GLES2GetProgramiv(GLuint program, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetProgramiv(program, pname, params);
+}
+void GLES2GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
+ gles2::GetGLContext()->GetProgramInfoLog(program, bufsize, length, infolog);
+}
+void GLES2GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetRenderbufferParameteriv(target, pname, params);
+}
+void GLES2GetShaderiv(GLuint shader, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetShaderiv(shader, pname, params);
+}
+void GLES2GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
+ gles2::GetGLContext()->GetShaderInfoLog(shader, bufsize, length, infolog);
+}
+void GLES2GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+ gles2::GetGLContext()->GetShaderPrecisionFormat(
+ shadertype, precisiontype, range, precision);
+}
+void GLES2GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ gles2::GetGLContext()->GetShaderSource(shader, bufsize, length, source);
+}
+const GLubyte* GLES2GetString(GLenum name) {
+ return gles2::GetGLContext()->GetString(name);
+}
+void GLES2GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) {
+ gles2::GetGLContext()->GetTexParameterfv(target, pname, params);
+}
+void GLES2GetTexParameteriv(GLenum target, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetTexParameteriv(target, pname, params);
+}
+void GLES2GetUniformfv(GLuint program, GLint location, GLfloat* params) {
+ gles2::GetGLContext()->GetUniformfv(program, location, params);
+}
+void GLES2GetUniformiv(GLuint program, GLint location, GLint* params) {
+ gles2::GetGLContext()->GetUniformiv(program, location, params);
+}
+GLint GLES2GetUniformLocation(GLuint program, const char* name) {
+ return gles2::GetGLContext()->GetUniformLocation(program, name);
+}
+void GLES2GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) {
+ gles2::GetGLContext()->GetVertexAttribfv(index, pname, params);
+}
+void GLES2GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetVertexAttribiv(index, pname, params);
+}
+void GLES2GetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) {
+ gles2::GetGLContext()->GetVertexAttribPointerv(index, pname, pointer);
+}
+void GLES2Hint(GLenum target, GLenum mode) {
+ gles2::GetGLContext()->Hint(target, mode);
+}
+GLboolean GLES2IsBuffer(GLuint buffer) {
+ return gles2::GetGLContext()->IsBuffer(buffer);
+}
+GLboolean GLES2IsEnabled(GLenum cap) {
+ return gles2::GetGLContext()->IsEnabled(cap);
+}
+GLboolean GLES2IsFramebuffer(GLuint framebuffer) {
+ return gles2::GetGLContext()->IsFramebuffer(framebuffer);
+}
+GLboolean GLES2IsProgram(GLuint program) {
+ return gles2::GetGLContext()->IsProgram(program);
+}
+GLboolean GLES2IsRenderbuffer(GLuint renderbuffer) {
+ return gles2::GetGLContext()->IsRenderbuffer(renderbuffer);
+}
+GLboolean GLES2IsShader(GLuint shader) {
+ return gles2::GetGLContext()->IsShader(shader);
+}
+GLboolean GLES2IsTexture(GLuint texture) {
+ return gles2::GetGLContext()->IsTexture(texture);
+}
+void GLES2LineWidth(GLfloat width) {
+ gles2::GetGLContext()->LineWidth(width);
+}
+void GLES2LinkProgram(GLuint program) {
+ gles2::GetGLContext()->LinkProgram(program);
+}
+void GLES2PixelStorei(GLenum pname, GLint param) {
+ gles2::GetGLContext()->PixelStorei(pname, param);
+}
+void GLES2PolygonOffset(GLfloat factor, GLfloat units) {
+ gles2::GetGLContext()->PolygonOffset(factor, units);
+}
+void GLES2ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ void* pixels) {
+ gles2::GetGLContext()->ReadPixels(x, y, width, height, format, type, pixels);
+}
+void GLES2ReleaseShaderCompiler() {
+ gles2::GetGLContext()->ReleaseShaderCompiler();
+}
+void GLES2RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ gles2::GetGLContext()->RenderbufferStorage(
+ target, internalformat, width, height);
+}
+void GLES2SampleCoverage(GLclampf value, GLboolean invert) {
+ gles2::GetGLContext()->SampleCoverage(value, invert);
+}
+void GLES2Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
+ gles2::GetGLContext()->Scissor(x, y, width, height);
+}
+void GLES2ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) {
+ gles2::GetGLContext()->ShaderBinary(
+ n, shaders, binaryformat, binary, length);
+}
+void GLES2ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* str,
+ const GLint* length) {
+ gles2::GetGLContext()->ShaderSource(shader, count, str, length);
+}
+void GLES2ShallowFinishCHROMIUM() {
+ gles2::GetGLContext()->ShallowFinishCHROMIUM();
+}
+void GLES2ShallowFlushCHROMIUM() {
+ gles2::GetGLContext()->ShallowFlushCHROMIUM();
+}
+void GLES2StencilFunc(GLenum func, GLint ref, GLuint mask) {
+ gles2::GetGLContext()->StencilFunc(func, ref, mask);
+}
+void GLES2StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) {
+ gles2::GetGLContext()->StencilFuncSeparate(face, func, ref, mask);
+}
+void GLES2StencilMask(GLuint mask) {
+ gles2::GetGLContext()->StencilMask(mask);
+}
+void GLES2StencilMaskSeparate(GLenum face, GLuint mask) {
+ gles2::GetGLContext()->StencilMaskSeparate(face, mask);
+}
+void GLES2StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+ gles2::GetGLContext()->StencilOp(fail, zfail, zpass);
+}
+void GLES2StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ gles2::GetGLContext()->StencilOpSeparate(face, fail, zfail, zpass);
+}
+void GLES2TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) {
+ gles2::GetGLContext()->TexImage2D(
+ target, level, internalformat, width, height, border, format, type,
+ pixels);
+}
+void GLES2TexParameterf(GLenum target, GLenum pname, GLfloat param) {
+ gles2::GetGLContext()->TexParameterf(target, pname, param);
+}
+void GLES2TexParameterfv(GLenum target, GLenum pname, const GLfloat* params) {
+ gles2::GetGLContext()->TexParameterfv(target, pname, params);
+}
+void GLES2TexParameteri(GLenum target, GLenum pname, GLint param) {
+ gles2::GetGLContext()->TexParameteri(target, pname, param);
+}
+void GLES2TexParameteriv(GLenum target, GLenum pname, const GLint* params) {
+ gles2::GetGLContext()->TexParameteriv(target, pname, params);
+}
+void GLES2TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ gles2::GetGLContext()->TexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+void GLES2Uniform1f(GLint location, GLfloat x) {
+ gles2::GetGLContext()->Uniform1f(location, x);
+}
+void GLES2Uniform1fv(GLint location, GLsizei count, const GLfloat* v) {
+ gles2::GetGLContext()->Uniform1fv(location, count, v);
+}
+void GLES2Uniform1i(GLint location, GLint x) {
+ gles2::GetGLContext()->Uniform1i(location, x);
+}
+void GLES2Uniform1iv(GLint location, GLsizei count, const GLint* v) {
+ gles2::GetGLContext()->Uniform1iv(location, count, v);
+}
+void GLES2Uniform2f(GLint location, GLfloat x, GLfloat y) {
+ gles2::GetGLContext()->Uniform2f(location, x, y);
+}
+void GLES2Uniform2fv(GLint location, GLsizei count, const GLfloat* v) {
+ gles2::GetGLContext()->Uniform2fv(location, count, v);
+}
+void GLES2Uniform2i(GLint location, GLint x, GLint y) {
+ gles2::GetGLContext()->Uniform2i(location, x, y);
+}
+void GLES2Uniform2iv(GLint location, GLsizei count, const GLint* v) {
+ gles2::GetGLContext()->Uniform2iv(location, count, v);
+}
+void GLES2Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ gles2::GetGLContext()->Uniform3f(location, x, y, z);
+}
+void GLES2Uniform3fv(GLint location, GLsizei count, const GLfloat* v) {
+ gles2::GetGLContext()->Uniform3fv(location, count, v);
+}
+void GLES2Uniform3i(GLint location, GLint x, GLint y, GLint z) {
+ gles2::GetGLContext()->Uniform3i(location, x, y, z);
+}
+void GLES2Uniform3iv(GLint location, GLsizei count, const GLint* v) {
+ gles2::GetGLContext()->Uniform3iv(location, count, v);
+}
+void GLES2Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ gles2::GetGLContext()->Uniform4f(location, x, y, z, w);
+}
+void GLES2Uniform4fv(GLint location, GLsizei count, const GLfloat* v) {
+ gles2::GetGLContext()->Uniform4fv(location, count, v);
+}
+void GLES2Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) {
+ gles2::GetGLContext()->Uniform4i(location, x, y, z, w);
+}
+void GLES2Uniform4iv(GLint location, GLsizei count, const GLint* v) {
+ gles2::GetGLContext()->Uniform4iv(location, count, v);
+}
+void GLES2UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ gles2::GetGLContext()->UniformMatrix2fv(location, count, transpose, value);
+}
+void GLES2UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ gles2::GetGLContext()->UniformMatrix3fv(location, count, transpose, value);
+}
+void GLES2UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ gles2::GetGLContext()->UniformMatrix4fv(location, count, transpose, value);
+}
+void GLES2UseProgram(GLuint program) {
+ gles2::GetGLContext()->UseProgram(program);
+}
+void GLES2ValidateProgram(GLuint program) {
+ gles2::GetGLContext()->ValidateProgram(program);
+}
+void GLES2VertexAttrib1f(GLuint indx, GLfloat x) {
+ gles2::GetGLContext()->VertexAttrib1f(indx, x);
+}
+void GLES2VertexAttrib1fv(GLuint indx, const GLfloat* values) {
+ gles2::GetGLContext()->VertexAttrib1fv(indx, values);
+}
+void GLES2VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) {
+ gles2::GetGLContext()->VertexAttrib2f(indx, x, y);
+}
+void GLES2VertexAttrib2fv(GLuint indx, const GLfloat* values) {
+ gles2::GetGLContext()->VertexAttrib2fv(indx, values);
+}
+void GLES2VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ gles2::GetGLContext()->VertexAttrib3f(indx, x, y, z);
+}
+void GLES2VertexAttrib3fv(GLuint indx, const GLfloat* values) {
+ gles2::GetGLContext()->VertexAttrib3fv(indx, values);
+}
+void GLES2VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ gles2::GetGLContext()->VertexAttrib4f(indx, x, y, z, w);
+}
+void GLES2VertexAttrib4fv(GLuint indx, const GLfloat* values) {
+ gles2::GetGLContext()->VertexAttrib4fv(indx, values);
+}
+void GLES2VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) {
+ gles2::GetGLContext()->VertexAttribPointer(
+ indx, size, type, normalized, stride, ptr);
+}
+void GLES2Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+ gles2::GetGLContext()->Viewport(x, y, width, height);
+}
+void GLES2BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ gles2::GetGLContext()->BlitFramebufferEXT(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+void GLES2RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) {
+ gles2::GetGLContext()->RenderbufferStorageMultisampleEXT(
+ target, samples, internalformat, width, height);
+}
+void GLES2FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) {
+ gles2::GetGLContext()->FramebufferTexture2DMultisampleEXT(
+ target, attachment, textarget, texture, level, samples);
+}
+void GLES2TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) {
+ gles2::GetGLContext()->TexStorage2DEXT(
+ target, levels, internalFormat, width, height);
+}
+void GLES2GenQueriesEXT(GLsizei n, GLuint* queries) {
+ gles2::GetGLContext()->GenQueriesEXT(n, queries);
+}
+void GLES2DeleteQueriesEXT(GLsizei n, const GLuint* queries) {
+ gles2::GetGLContext()->DeleteQueriesEXT(n, queries);
+}
+GLboolean GLES2IsQueryEXT(GLuint id) {
+ return gles2::GetGLContext()->IsQueryEXT(id);
+}
+void GLES2BeginQueryEXT(GLenum target, GLuint id) {
+ gles2::GetGLContext()->BeginQueryEXT(target, id);
+}
+void GLES2EndQueryEXT(GLenum target) {
+ gles2::GetGLContext()->EndQueryEXT(target);
+}
+void GLES2GetQueryivEXT(GLenum target, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetQueryivEXT(target, pname, params);
+}
+void GLES2GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) {
+ gles2::GetGLContext()->GetQueryObjectuivEXT(id, pname, params);
+}
+void GLES2InsertEventMarkerEXT(GLsizei length, const GLchar* marker) {
+ gles2::GetGLContext()->InsertEventMarkerEXT(length, marker);
+}
+void GLES2PushGroupMarkerEXT(GLsizei length, const GLchar* marker) {
+ gles2::GetGLContext()->PushGroupMarkerEXT(length, marker);
+}
+void GLES2PopGroupMarkerEXT() {
+ gles2::GetGLContext()->PopGroupMarkerEXT();
+}
+void GLES2GenVertexArraysOES(GLsizei n, GLuint* arrays) {
+ gles2::GetGLContext()->GenVertexArraysOES(n, arrays);
+}
+void GLES2DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) {
+ gles2::GetGLContext()->DeleteVertexArraysOES(n, arrays);
+}
+GLboolean GLES2IsVertexArrayOES(GLuint array) {
+ return gles2::GetGLContext()->IsVertexArrayOES(array);
+}
+void GLES2BindVertexArrayOES(GLuint array) {
+ gles2::GetGLContext()->BindVertexArrayOES(array);
+}
+void GLES2SwapBuffers() {
+ gles2::GetGLContext()->SwapBuffers();
+}
+GLuint GLES2GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
+ return gles2::GetGLContext()->GetMaxValueInBufferCHROMIUM(
+ buffer_id, count, type, offset);
+}
+void GLES2GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
+ gles2::GetGLContext()->GenSharedIdsCHROMIUM(namespace_id, id_offset, n, ids);
+}
+void GLES2DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ gles2::GetGLContext()->DeleteSharedIdsCHROMIUM(namespace_id, n, ids);
+}
+void GLES2RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ gles2::GetGLContext()->RegisterSharedIdsCHROMIUM(namespace_id, n, ids);
+}
+GLboolean GLES2EnableFeatureCHROMIUM(const char* feature) {
+ return gles2::GetGLContext()->EnableFeatureCHROMIUM(feature);
+}
+void* GLES2MapBufferCHROMIUM(GLuint target, GLenum access) {
+ return gles2::GetGLContext()->MapBufferCHROMIUM(target, access);
+}
+GLboolean GLES2UnmapBufferCHROMIUM(GLuint target) {
+ return gles2::GetGLContext()->UnmapBufferCHROMIUM(target);
+}
+void* GLES2MapImageCHROMIUM(GLuint image_id, GLenum access) {
+ return gles2::GetGLContext()->MapImageCHROMIUM(image_id, access);
+}
+void GLES2UnmapImageCHROMIUM(GLuint image_id) {
+ gles2::GetGLContext()->UnmapImageCHROMIUM(image_id);
+}
+void* GLES2MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
+ return gles2::GetGLContext()->MapBufferSubDataCHROMIUM(
+ target, offset, size, access);
+}
+void GLES2UnmapBufferSubDataCHROMIUM(const void* mem) {
+ gles2::GetGLContext()->UnmapBufferSubDataCHROMIUM(mem);
+}
+void* GLES2MapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access) {
+ return gles2::GetGLContext()->MapTexSubImage2DCHROMIUM(
+ target, level, xoffset, yoffset, width, height, format, type, access);
+}
+void GLES2UnmapTexSubImage2DCHROMIUM(const void* mem) {
+ gles2::GetGLContext()->UnmapTexSubImage2DCHROMIUM(mem);
+}
+void GLES2ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) {
+ gles2::GetGLContext()->ResizeCHROMIUM(width, height, scale_factor);
+}
+const GLchar* GLES2GetRequestableExtensionsCHROMIUM() {
+ return gles2::GetGLContext()->GetRequestableExtensionsCHROMIUM();
+}
+void GLES2RequestExtensionCHROMIUM(const char* extension) {
+ gles2::GetGLContext()->RequestExtensionCHROMIUM(extension);
+}
+void GLES2RateLimitOffscreenContextCHROMIUM() {
+ gles2::GetGLContext()->RateLimitOffscreenContextCHROMIUM();
+}
+void GLES2GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
+ gles2::GetGLContext()->GetMultipleIntegervCHROMIUM(
+ pnames, count, results, size);
+}
+void GLES2GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+ gles2::GetGLContext()->GetProgramInfoCHROMIUM(program, bufsize, size, info);
+}
+GLuint GLES2CreateStreamTextureCHROMIUM(GLuint texture) {
+ return gles2::GetGLContext()->CreateStreamTextureCHROMIUM(texture);
+}
+void GLES2DestroyStreamTextureCHROMIUM(GLuint texture) {
+ gles2::GetGLContext()->DestroyStreamTextureCHROMIUM(texture);
+}
+GLuint GLES2CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) {
+ return gles2::GetGLContext()->CreateImageCHROMIUM(
+ width, height, internalformat);
+}
+void GLES2DestroyImageCHROMIUM(GLuint image_id) {
+ gles2::GetGLContext()->DestroyImageCHROMIUM(image_id);
+}
+void GLES2GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) {
+ gles2::GetGLContext()->GetImageParameterivCHROMIUM(image_id, pname, params);
+}
+void GLES2GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ gles2::GetGLContext()->GetTranslatedShaderSourceANGLE(
+ shader, bufsize, length, source);
+}
+void GLES2PostSubBufferCHROMIUM(GLint x, GLint y, GLint width, GLint height) {
+ gles2::GetGLContext()->PostSubBufferCHROMIUM(x, y, width, height);
+}
+void GLES2TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) {
+ gles2::GetGLContext()->TexImageIOSurface2DCHROMIUM(
+ target, width, height, ioSurfaceId, plane);
+}
+void GLES2CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) {
+ gles2::GetGLContext()->CopyTextureCHROMIUM(
+ target, source_id, dest_id, level, internalformat, dest_type);
+}
+void GLES2DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
+ gles2::GetGLContext()->DrawArraysInstancedANGLE(
+ mode, first, count, primcount);
+}
+void GLES2DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) {
+ gles2::GetGLContext()->DrawElementsInstancedANGLE(
+ mode, count, type, indices, primcount);
+}
+void GLES2VertexAttribDivisorANGLE(GLuint index, GLuint divisor) {
+ gles2::GetGLContext()->VertexAttribDivisorANGLE(index, divisor);
+}
+void GLES2GenMailboxCHROMIUM(GLbyte* mailbox) {
+ gles2::GetGLContext()->GenMailboxCHROMIUM(mailbox);
+}
+void GLES2ProduceTextureCHROMIUM(GLenum target, const GLbyte* mailbox) {
+ gles2::GetGLContext()->ProduceTextureCHROMIUM(target, mailbox);
+}
+void GLES2ConsumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) {
+ gles2::GetGLContext()->ConsumeTextureCHROMIUM(target, mailbox);
+}
+void GLES2BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) {
+ gles2::GetGLContext()->BindUniformLocationCHROMIUM(program, location, name);
+}
+void GLES2BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
+ gles2::GetGLContext()->BindTexImage2DCHROMIUM(target, imageId);
+}
+void GLES2ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) {
+ gles2::GetGLContext()->ReleaseTexImage2DCHROMIUM(target, imageId);
+}
+void GLES2TraceBeginCHROMIUM(const char* name) {
+ gles2::GetGLContext()->TraceBeginCHROMIUM(name);
+}
+void GLES2TraceEndCHROMIUM() {
+ gles2::GetGLContext()->TraceEndCHROMIUM();
+}
+void GLES2AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* data) {
+ gles2::GetGLContext()->AsyncTexSubImage2DCHROMIUM(
+ target, level, xoffset, yoffset, width, height, format, type, data);
+}
+void GLES2AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) {
+ gles2::GetGLContext()->AsyncTexImage2DCHROMIUM(
+ target, level, internalformat, width, height, border, format, type,
+ pixels);
+}
+void GLES2WaitAsyncTexImage2DCHROMIUM(GLenum target) {
+ gles2::GetGLContext()->WaitAsyncTexImage2DCHROMIUM(target);
+}
+void GLES2DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) {
+ gles2::GetGLContext()->DiscardFramebufferEXT(target, count, attachments);
+}
+void GLES2LoseContextCHROMIUM(GLenum current, GLenum other) {
+ gles2::GetGLContext()->LoseContextCHROMIUM(current, other);
+}
+GLuint GLES2InsertSyncPointCHROMIUM() {
+ return gles2::GetGLContext()->InsertSyncPointCHROMIUM();
+}
+void GLES2WaitSyncPointCHROMIUM(GLuint sync_point) {
+ gles2::GetGLContext()->WaitSyncPointCHROMIUM(sync_point);
+}
+void GLES2DrawBuffersEXT(GLsizei count, const GLenum* bufs) {
+ gles2::GetGLContext()->DrawBuffersEXT(count, bufs);
+}
+
+namespace gles2 {
+
+extern const NameToFunc g_gles2_function_table[] = {
+ { "glActiveTexture", reinterpret_cast<GLES2FunctionPointer>(
+ glActiveTexture), },
+ { "glAttachShader", reinterpret_cast<GLES2FunctionPointer>(
+ glAttachShader), },
+ { "glBindAttribLocation", reinterpret_cast<GLES2FunctionPointer>(
+ glBindAttribLocation), },
+ { "glBindBuffer", reinterpret_cast<GLES2FunctionPointer>(glBindBuffer), },
+ { "glBindFramebuffer", reinterpret_cast<GLES2FunctionPointer>(
+ glBindFramebuffer), },
+ { "glBindRenderbuffer", reinterpret_cast<GLES2FunctionPointer>(
+ glBindRenderbuffer), },
+ { "glBindTexture", reinterpret_cast<GLES2FunctionPointer>(glBindTexture), },
+ { "glBlendColor", reinterpret_cast<GLES2FunctionPointer>(glBlendColor), },
+ { "glBlendEquation", reinterpret_cast<GLES2FunctionPointer>(
+ glBlendEquation), },
+ { "glBlendEquationSeparate", reinterpret_cast<GLES2FunctionPointer>(
+ glBlendEquationSeparate), },
+ { "glBlendFunc", reinterpret_cast<GLES2FunctionPointer>(glBlendFunc), },
+ { "glBlendFuncSeparate", reinterpret_cast<GLES2FunctionPointer>(
+ glBlendFuncSeparate), },
+ { "glBufferData", reinterpret_cast<GLES2FunctionPointer>(glBufferData), },
+ { "glBufferSubData", reinterpret_cast<GLES2FunctionPointer>(
+ glBufferSubData), },
+ { "glCheckFramebufferStatus", reinterpret_cast<GLES2FunctionPointer>(
+ glCheckFramebufferStatus), },
+ { "glClear", reinterpret_cast<GLES2FunctionPointer>(glClear), },
+ { "glClearColor", reinterpret_cast<GLES2FunctionPointer>(glClearColor), },
+ { "glClearDepthf", reinterpret_cast<GLES2FunctionPointer>(glClearDepthf), },
+ { "glClearStencil", reinterpret_cast<GLES2FunctionPointer>(
+ glClearStencil), },
+ { "glColorMask", reinterpret_cast<GLES2FunctionPointer>(glColorMask), },
+ { "glCompileShader", reinterpret_cast<GLES2FunctionPointer>(
+ glCompileShader), },
+ { "glCompressedTexImage2D", reinterpret_cast<GLES2FunctionPointer>(
+ glCompressedTexImage2D), },
+ { "glCompressedTexSubImage2D", reinterpret_cast<GLES2FunctionPointer>(
+ glCompressedTexSubImage2D), },
+ { "glCopyTexImage2D", reinterpret_cast<GLES2FunctionPointer>(
+ glCopyTexImage2D), },
+ { "glCopyTexSubImage2D", reinterpret_cast<GLES2FunctionPointer>(
+ glCopyTexSubImage2D), },
+ { "glCreateProgram", reinterpret_cast<GLES2FunctionPointer>(
+ glCreateProgram), },
+ { "glCreateShader", reinterpret_cast<GLES2FunctionPointer>(
+ glCreateShader), },
+ { "glCullFace", reinterpret_cast<GLES2FunctionPointer>(glCullFace), },
+ { "glDeleteBuffers", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteBuffers), },
+ { "glDeleteFramebuffers", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteFramebuffers), },
+ { "glDeleteProgram", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteProgram), },
+ { "glDeleteRenderbuffers", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteRenderbuffers), },
+ { "glDeleteShader", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteShader), },
+ { "glDeleteTextures", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteTextures), },
+ { "glDepthFunc", reinterpret_cast<GLES2FunctionPointer>(glDepthFunc), },
+ { "glDepthMask", reinterpret_cast<GLES2FunctionPointer>(glDepthMask), },
+ { "glDepthRangef", reinterpret_cast<GLES2FunctionPointer>(glDepthRangef), },
+ { "glDetachShader", reinterpret_cast<GLES2FunctionPointer>(
+ glDetachShader), },
+ { "glDisable", reinterpret_cast<GLES2FunctionPointer>(glDisable), },
+ { "glDisableVertexAttribArray", reinterpret_cast<GLES2FunctionPointer>(
+ glDisableVertexAttribArray), },
+ { "glDrawArrays", reinterpret_cast<GLES2FunctionPointer>(glDrawArrays), },
+ { "glDrawElements", reinterpret_cast<GLES2FunctionPointer>(
+ glDrawElements), },
+ { "glEnable", reinterpret_cast<GLES2FunctionPointer>(glEnable), },
+ { "glEnableVertexAttribArray", reinterpret_cast<GLES2FunctionPointer>(
+ glEnableVertexAttribArray), },
+ { "glFinish", reinterpret_cast<GLES2FunctionPointer>(glFinish), },
+ { "glFlush", reinterpret_cast<GLES2FunctionPointer>(glFlush), },
+ { "glFramebufferRenderbuffer", reinterpret_cast<GLES2FunctionPointer>(
+ glFramebufferRenderbuffer), },
+ { "glFramebufferTexture2D", reinterpret_cast<GLES2FunctionPointer>(
+ glFramebufferTexture2D), },
+ { "glFrontFace", reinterpret_cast<GLES2FunctionPointer>(glFrontFace), },
+ { "glGenBuffers", reinterpret_cast<GLES2FunctionPointer>(glGenBuffers), },
+ { "glGenerateMipmap", reinterpret_cast<GLES2FunctionPointer>(
+ glGenerateMipmap), },
+ { "glGenFramebuffers", reinterpret_cast<GLES2FunctionPointer>(
+ glGenFramebuffers), },
+ { "glGenRenderbuffers", reinterpret_cast<GLES2FunctionPointer>(
+ glGenRenderbuffers), },
+ { "glGenTextures", reinterpret_cast<GLES2FunctionPointer>(glGenTextures), },
+ { "glGetActiveAttrib", reinterpret_cast<GLES2FunctionPointer>(
+ glGetActiveAttrib), },
+ { "glGetActiveUniform", reinterpret_cast<GLES2FunctionPointer>(
+ glGetActiveUniform), },
+ { "glGetAttachedShaders", reinterpret_cast<GLES2FunctionPointer>(
+ glGetAttachedShaders), },
+ { "glGetAttribLocation", reinterpret_cast<GLES2FunctionPointer>(
+ glGetAttribLocation), },
+ { "glGetBooleanv", reinterpret_cast<GLES2FunctionPointer>(glGetBooleanv), },
+ { "glGetBufferParameteriv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetBufferParameteriv), },
+ { "glGetError", reinterpret_cast<GLES2FunctionPointer>(glGetError), },
+ { "glGetFloatv", reinterpret_cast<GLES2FunctionPointer>(glGetFloatv), },
+ { "glGetFramebufferAttachmentParameteriv", reinterpret_cast<GLES2FunctionPointer>(glGetFramebufferAttachmentParameteriv), }, // NOLINT
+ { "glGetIntegerv", reinterpret_cast<GLES2FunctionPointer>(glGetIntegerv), },
+ { "glGetProgramiv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetProgramiv), },
+ { "glGetProgramInfoLog", reinterpret_cast<GLES2FunctionPointer>(
+ glGetProgramInfoLog), },
+ { "glGetRenderbufferParameteriv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetRenderbufferParameteriv), },
+ { "glGetShaderiv", reinterpret_cast<GLES2FunctionPointer>(glGetShaderiv), },
+ { "glGetShaderInfoLog", reinterpret_cast<GLES2FunctionPointer>(
+ glGetShaderInfoLog), },
+ { "glGetShaderPrecisionFormat", reinterpret_cast<GLES2FunctionPointer>(
+ glGetShaderPrecisionFormat), },
+ { "glGetShaderSource", reinterpret_cast<GLES2FunctionPointer>(
+ glGetShaderSource), },
+ { "glGetString", reinterpret_cast<GLES2FunctionPointer>(glGetString), },
+ { "glGetTexParameterfv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetTexParameterfv), },
+ { "glGetTexParameteriv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetTexParameteriv), },
+ { "glGetUniformfv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetUniformfv), },
+ { "glGetUniformiv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetUniformiv), },
+ { "glGetUniformLocation", reinterpret_cast<GLES2FunctionPointer>(
+ glGetUniformLocation), },
+ { "glGetVertexAttribfv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetVertexAttribfv), },
+ { "glGetVertexAttribiv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetVertexAttribiv), },
+ { "glGetVertexAttribPointerv", reinterpret_cast<GLES2FunctionPointer>(
+ glGetVertexAttribPointerv), },
+ { "glHint", reinterpret_cast<GLES2FunctionPointer>(glHint), },
+ { "glIsBuffer", reinterpret_cast<GLES2FunctionPointer>(glIsBuffer), },
+ { "glIsEnabled", reinterpret_cast<GLES2FunctionPointer>(glIsEnabled), },
+ { "glIsFramebuffer", reinterpret_cast<GLES2FunctionPointer>(
+ glIsFramebuffer), },
+ { "glIsProgram", reinterpret_cast<GLES2FunctionPointer>(glIsProgram), },
+ { "glIsRenderbuffer", reinterpret_cast<GLES2FunctionPointer>(
+ glIsRenderbuffer), },
+ { "glIsShader", reinterpret_cast<GLES2FunctionPointer>(glIsShader), },
+ { "glIsTexture", reinterpret_cast<GLES2FunctionPointer>(glIsTexture), },
+ { "glLineWidth", reinterpret_cast<GLES2FunctionPointer>(glLineWidth), },
+ { "glLinkProgram", reinterpret_cast<GLES2FunctionPointer>(glLinkProgram), },
+ { "glPixelStorei", reinterpret_cast<GLES2FunctionPointer>(glPixelStorei), },
+ { "glPolygonOffset", reinterpret_cast<GLES2FunctionPointer>(
+ glPolygonOffset), },
+ { "glReadPixels", reinterpret_cast<GLES2FunctionPointer>(glReadPixels), },
+ { "glReleaseShaderCompiler", reinterpret_cast<GLES2FunctionPointer>(
+ glReleaseShaderCompiler), },
+ { "glRenderbufferStorage", reinterpret_cast<GLES2FunctionPointer>(
+ glRenderbufferStorage), },
+ { "glSampleCoverage", reinterpret_cast<GLES2FunctionPointer>(
+ glSampleCoverage), },
+ { "glScissor", reinterpret_cast<GLES2FunctionPointer>(glScissor), },
+ { "glShaderBinary", reinterpret_cast<GLES2FunctionPointer>(
+ glShaderBinary), },
+ { "glShaderSource", reinterpret_cast<GLES2FunctionPointer>(
+ glShaderSource), },
+ { "glShallowFinishCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glShallowFinishCHROMIUM), },
+ { "glShallowFlushCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glShallowFlushCHROMIUM), },
+ { "glStencilFunc", reinterpret_cast<GLES2FunctionPointer>(glStencilFunc), },
+ { "glStencilFuncSeparate", reinterpret_cast<GLES2FunctionPointer>(
+ glStencilFuncSeparate), },
+ { "glStencilMask", reinterpret_cast<GLES2FunctionPointer>(glStencilMask), },
+ { "glStencilMaskSeparate", reinterpret_cast<GLES2FunctionPointer>(
+ glStencilMaskSeparate), },
+ { "glStencilOp", reinterpret_cast<GLES2FunctionPointer>(glStencilOp), },
+ { "glStencilOpSeparate", reinterpret_cast<GLES2FunctionPointer>(
+ glStencilOpSeparate), },
+ { "glTexImage2D", reinterpret_cast<GLES2FunctionPointer>(glTexImage2D), },
+ { "glTexParameterf", reinterpret_cast<GLES2FunctionPointer>(
+ glTexParameterf), },
+ { "glTexParameterfv", reinterpret_cast<GLES2FunctionPointer>(
+ glTexParameterfv), },
+ { "glTexParameteri", reinterpret_cast<GLES2FunctionPointer>(
+ glTexParameteri), },
+ { "glTexParameteriv", reinterpret_cast<GLES2FunctionPointer>(
+ glTexParameteriv), },
+ { "glTexSubImage2D", reinterpret_cast<GLES2FunctionPointer>(
+ glTexSubImage2D), },
+ { "glUniform1f", reinterpret_cast<GLES2FunctionPointer>(glUniform1f), },
+ { "glUniform1fv", reinterpret_cast<GLES2FunctionPointer>(glUniform1fv), },
+ { "glUniform1i", reinterpret_cast<GLES2FunctionPointer>(glUniform1i), },
+ { "glUniform1iv", reinterpret_cast<GLES2FunctionPointer>(glUniform1iv), },
+ { "glUniform2f", reinterpret_cast<GLES2FunctionPointer>(glUniform2f), },
+ { "glUniform2fv", reinterpret_cast<GLES2FunctionPointer>(glUniform2fv), },
+ { "glUniform2i", reinterpret_cast<GLES2FunctionPointer>(glUniform2i), },
+ { "glUniform2iv", reinterpret_cast<GLES2FunctionPointer>(glUniform2iv), },
+ { "glUniform3f", reinterpret_cast<GLES2FunctionPointer>(glUniform3f), },
+ { "glUniform3fv", reinterpret_cast<GLES2FunctionPointer>(glUniform3fv), },
+ { "glUniform3i", reinterpret_cast<GLES2FunctionPointer>(glUniform3i), },
+ { "glUniform3iv", reinterpret_cast<GLES2FunctionPointer>(glUniform3iv), },
+ { "glUniform4f", reinterpret_cast<GLES2FunctionPointer>(glUniform4f), },
+ { "glUniform4fv", reinterpret_cast<GLES2FunctionPointer>(glUniform4fv), },
+ { "glUniform4i", reinterpret_cast<GLES2FunctionPointer>(glUniform4i), },
+ { "glUniform4iv", reinterpret_cast<GLES2FunctionPointer>(glUniform4iv), },
+ { "glUniformMatrix2fv", reinterpret_cast<GLES2FunctionPointer>(
+ glUniformMatrix2fv), },
+ { "glUniformMatrix3fv", reinterpret_cast<GLES2FunctionPointer>(
+ glUniformMatrix3fv), },
+ { "glUniformMatrix4fv", reinterpret_cast<GLES2FunctionPointer>(
+ glUniformMatrix4fv), },
+ { "glUseProgram", reinterpret_cast<GLES2FunctionPointer>(glUseProgram), },
+ { "glValidateProgram", reinterpret_cast<GLES2FunctionPointer>(
+ glValidateProgram), },
+ { "glVertexAttrib1f", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib1f), },
+ { "glVertexAttrib1fv", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib1fv), },
+ { "glVertexAttrib2f", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib2f), },
+ { "glVertexAttrib2fv", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib2fv), },
+ { "glVertexAttrib3f", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib3f), },
+ { "glVertexAttrib3fv", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib3fv), },
+ { "glVertexAttrib4f", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib4f), },
+ { "glVertexAttrib4fv", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttrib4fv), },
+ { "glVertexAttribPointer", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttribPointer), },
+ { "glViewport", reinterpret_cast<GLES2FunctionPointer>(glViewport), },
+ { "glBlitFramebufferEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glBlitFramebufferEXT), },
+ { "glRenderbufferStorageMultisampleEXT", reinterpret_cast<GLES2FunctionPointer>(glRenderbufferStorageMultisampleEXT), }, // NOLINT
+ { "glFramebufferTexture2DMultisampleEXT", reinterpret_cast<GLES2FunctionPointer>(glFramebufferTexture2DMultisampleEXT), }, // NOLINT
+ { "glTexStorage2DEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glTexStorage2DEXT), },
+ { "glGenQueriesEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glGenQueriesEXT), },
+ { "glDeleteQueriesEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteQueriesEXT), },
+ { "glIsQueryEXT", reinterpret_cast<GLES2FunctionPointer>(glIsQueryEXT), },
+ { "glBeginQueryEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glBeginQueryEXT), },
+ { "glEndQueryEXT", reinterpret_cast<GLES2FunctionPointer>(glEndQueryEXT), },
+ { "glGetQueryivEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glGetQueryivEXT), },
+ { "glGetQueryObjectuivEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glGetQueryObjectuivEXT), },
+ { "glInsertEventMarkerEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glInsertEventMarkerEXT), },
+ { "glPushGroupMarkerEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glPushGroupMarkerEXT), },
+ { "glPopGroupMarkerEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glPopGroupMarkerEXT), },
+ { "glGenVertexArraysOES", reinterpret_cast<GLES2FunctionPointer>(
+ glGenVertexArraysOES), },
+ { "glDeleteVertexArraysOES", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteVertexArraysOES), },
+ { "glIsVertexArrayOES", reinterpret_cast<GLES2FunctionPointer>(
+ glIsVertexArrayOES), },
+ { "glBindVertexArrayOES", reinterpret_cast<GLES2FunctionPointer>(
+ glBindVertexArrayOES), },
+ { "glSwapBuffers", reinterpret_cast<GLES2FunctionPointer>(glSwapBuffers), },
+ { "glGetMaxValueInBufferCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glGetMaxValueInBufferCHROMIUM), },
+ { "glGenSharedIdsCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glGenSharedIdsCHROMIUM), },
+ { "glDeleteSharedIdsCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glDeleteSharedIdsCHROMIUM), },
+ { "glRegisterSharedIdsCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glRegisterSharedIdsCHROMIUM), },
+ { "glEnableFeatureCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glEnableFeatureCHROMIUM), },
+ { "glMapBufferCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glMapBufferCHROMIUM), },
+ { "glUnmapBufferCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glUnmapBufferCHROMIUM), },
+ { "glMapImageCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glMapImageCHROMIUM), },
+ { "glUnmapImageCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glUnmapImageCHROMIUM), },
+ { "glMapBufferSubDataCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glMapBufferSubDataCHROMIUM), },
+ { "glUnmapBufferSubDataCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glUnmapBufferSubDataCHROMIUM), },
+ { "glMapTexSubImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glMapTexSubImage2DCHROMIUM), },
+ { "glUnmapTexSubImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glUnmapTexSubImage2DCHROMIUM), },
+ { "glResizeCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glResizeCHROMIUM), },
+ { "glGetRequestableExtensionsCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(glGetRequestableExtensionsCHROMIUM), }, // NOLINT
+ { "glRequestExtensionCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glRequestExtensionCHROMIUM), },
+ { "glRateLimitOffscreenContextCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(glRateLimitOffscreenContextCHROMIUM), }, // NOLINT
+ { "glGetMultipleIntegervCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glGetMultipleIntegervCHROMIUM), },
+ { "glGetProgramInfoCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glGetProgramInfoCHROMIUM), },
+ { "glCreateStreamTextureCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glCreateStreamTextureCHROMIUM), },
+ { "glDestroyStreamTextureCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glDestroyStreamTextureCHROMIUM), },
+ { "glCreateImageCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glCreateImageCHROMIUM), },
+ { "glDestroyImageCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glDestroyImageCHROMIUM), },
+ { "glGetImageParameterivCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glGetImageParameterivCHROMIUM), },
+ { "glGetTranslatedShaderSourceANGLE", reinterpret_cast<GLES2FunctionPointer>(
+ glGetTranslatedShaderSourceANGLE), },
+ { "glPostSubBufferCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glPostSubBufferCHROMIUM), },
+ { "glTexImageIOSurface2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glTexImageIOSurface2DCHROMIUM), },
+ { "glCopyTextureCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glCopyTextureCHROMIUM), },
+ { "glDrawArraysInstancedANGLE", reinterpret_cast<GLES2FunctionPointer>(
+ glDrawArraysInstancedANGLE), },
+ { "glDrawElementsInstancedANGLE", reinterpret_cast<GLES2FunctionPointer>(
+ glDrawElementsInstancedANGLE), },
+ { "glVertexAttribDivisorANGLE", reinterpret_cast<GLES2FunctionPointer>(
+ glVertexAttribDivisorANGLE), },
+ { "glGenMailboxCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glGenMailboxCHROMIUM), },
+ { "glProduceTextureCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glProduceTextureCHROMIUM), },
+ { "glConsumeTextureCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glConsumeTextureCHROMIUM), },
+ { "glBindUniformLocationCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glBindUniformLocationCHROMIUM), },
+ { "glBindTexImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glBindTexImage2DCHROMIUM), },
+ { "glReleaseTexImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glReleaseTexImage2DCHROMIUM), },
+ { "glTraceBeginCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glTraceBeginCHROMIUM), },
+ { "glTraceEndCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glTraceEndCHROMIUM), },
+ { "glAsyncTexSubImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glAsyncTexSubImage2DCHROMIUM), },
+ { "glAsyncTexImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glAsyncTexImage2DCHROMIUM), },
+ { "glWaitAsyncTexImage2DCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glWaitAsyncTexImage2DCHROMIUM), },
+ { "glDiscardFramebufferEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glDiscardFramebufferEXT), },
+ { "glLoseContextCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glLoseContextCHROMIUM), },
+ { "glInsertSyncPointCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glInsertSyncPointCHROMIUM), },
+ { "glWaitSyncPointCHROMIUM", reinterpret_cast<GLES2FunctionPointer>(
+ glWaitSyncPointCHROMIUM), },
+ { "glDrawBuffersEXT", reinterpret_cast<GLES2FunctionPointer>(
+ glDrawBuffersEXT), },
+ { NULL, NULL, },
+};
+
+} // namespace gles2
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_c_lib_export.h b/chromium/gpu/command_buffer/client/gles2_c_lib_export.h
new file mode 100644
index 00000000000..ceacc6eb426
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_c_lib_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_EXPORT_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(GLES2_C_LIB_IMPLEMENTATION)
+#define GLES2_C_LIB_EXPORT __declspec(dllexport)
+#else
+#define GLES2_C_LIB_EXPORT __declspec(dllimport)
+#endif // defined(GLES2_C_LIB_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(GLES2_C_LIB_IMPLEMENTATION)
+#define GLES2_C_LIB_EXPORT __attribute__((visibility("default")))
+#else
+#define GLES2_C_LIB_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define GLES2_C_LIB_EXPORT
+#endif
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_EXPORT_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_cmd_helper.cc b/chromium/gpu/command_buffer/client/gles2_cmd_helper.cc
new file mode 100644
index 00000000000..d52970a3c0e
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_cmd_helper.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+
+namespace gpu {
+namespace gles2 {
+
+GLES2CmdHelper::GLES2CmdHelper(CommandBuffer* command_buffer)
+ : CommandBufferHelper(command_buffer) {
+}
+
+GLES2CmdHelper::~GLES2CmdHelper() {
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
+
diff --git a/chromium/gpu/command_buffer/client/gles2_cmd_helper.h b/chromium/gpu/command_buffer/client/gles2_cmd_helper.h
new file mode 100644
index 00000000000..7361a9b3e0d
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_cmd_helper.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_H_
+
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+// A class that helps write GL command buffers.
+class GPU_EXPORT GLES2CmdHelper : public CommandBufferHelper {
+ public:
+ explicit GLES2CmdHelper(CommandBuffer* command_buffer);
+ virtual ~GLES2CmdHelper();
+
+ // Include the auto-generated part of this class. We split this because it
+ // means we can easily edit the non-auto generated parts right here in this
+ // file instead of having to edit some template or the code generator.
+ #include "gpu/command_buffer/client/gles2_cmd_helper_autogen.h"
+
+ // Helpers that could not be auto-generated.
+ // TODO(gman): Auto generate these.
+
+ void GetAttribLocation(
+ GLuint program, uint32 name_shm_id, uint32 name_shm_offset,
+ uint32 location_shm_id, uint32 location_shm_offset, uint32 data_size) {
+ gles2::cmds::GetAttribLocation* c =
+ GetCmdSpace<gles2::cmds::GetAttribLocation>();
+ if (c) {
+ c->Init(
+ program, name_shm_id, name_shm_offset, location_shm_id,
+ location_shm_offset, data_size);
+ }
+ }
+
+ void GetAttribLocationImmediate(
+ GLuint program, const char* name,
+ uint32 location_shm_id, uint32 location_shm_offset) {
+ const uint32 size = gles2::cmds::GetAttribLocationImmediate::ComputeSize(
+ name);
+ gles2::cmds::GetAttribLocationImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GetAttribLocationImmediate>(
+ size);
+ if (c) {
+ c->Init(program, name, location_shm_id, location_shm_offset);
+ }
+ }
+
+ void GetAttribLocationBucket(
+ GLuint program, uint32 name_bucket_id,
+ uint32 location_shm_id, uint32 location_shm_offset) {
+ gles2::cmds::GetAttribLocationBucket* c =
+ GetCmdSpace<gles2::cmds::GetAttribLocationBucket>();
+ if (c) {
+ c->Init(program, name_bucket_id, location_shm_id, location_shm_offset);
+ }
+ }
+
+ void GetUniformLocation(
+ GLuint program, uint32 name_shm_id, uint32 name_shm_offset,
+ uint32 location_shm_id, uint32 location_shm_offset, uint32 data_size) {
+ gles2::cmds::GetUniformLocation* c =
+ GetCmdSpace<gles2::cmds::GetUniformLocation>();
+ if (c) {
+ c->Init(
+ program, name_shm_id, name_shm_offset, location_shm_id,
+ location_shm_offset, data_size);
+ }
+ }
+
+ void GetUniformLocationImmediate(
+ GLuint program, const char* name,
+ uint32 location_shm_id, uint32 location_shm_offset) {
+ const uint32 size = gles2::cmds::GetUniformLocationImmediate::ComputeSize(
+ name);
+ gles2::cmds::GetUniformLocationImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GetUniformLocationImmediate>(
+ size);
+ if (c) {
+ c->Init(program, name, location_shm_id, location_shm_offset);
+ }
+ }
+
+ void GetUniformLocationBucket(
+ GLuint program, uint32 name_bucket_id,
+ uint32 location_shm_id, uint32 location_shm_offset) {
+ gles2::cmds::GetUniformLocationBucket* c =
+ GetCmdSpace<gles2::cmds::GetUniformLocationBucket>();
+ if (c) {
+ c->Init(program, name_bucket_id, location_shm_id, location_shm_offset);
+ }
+ }
+
+ GLuint InsertSyncPointCHROMIUM() {
+ CommandBufferHelper::Flush();
+ return command_buffer()->InsertSyncPoint();
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GLES2CmdHelper);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/chromium/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
new file mode 100644
index 00000000000..8d2fd7d5ef4
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -0,0 +1,2114 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
+
+ void ActiveTexture(GLenum texture) {
+ gles2::cmds::ActiveTexture* c = GetCmdSpace<gles2::cmds::ActiveTexture>();
+ if (c) {
+ c->Init(texture);
+ }
+ }
+
+ void AttachShader(GLuint program, GLuint shader) {
+ gles2::cmds::AttachShader* c = GetCmdSpace<gles2::cmds::AttachShader>();
+ if (c) {
+ c->Init(program, shader);
+ }
+ }
+
+ void BindAttribLocation(
+ GLuint program, GLuint index, uint32 name_shm_id, uint32 name_shm_offset,
+ uint32 data_size) {
+ gles2::cmds::BindAttribLocation* c =
+ GetCmdSpace<gles2::cmds::BindAttribLocation>();
+ if (c) {
+ c->Init(program, index, name_shm_id, name_shm_offset, data_size);
+ }
+ }
+
+ void BindAttribLocationImmediate(
+ GLuint program, GLuint index, const char* name) {
+ const uint32 data_size = strlen(name);
+ gles2::cmds::BindAttribLocationImmediate* c =
+ GetImmediateCmdSpace<gles2::cmds::BindAttribLocationImmediate>(
+ data_size);
+ if (c) {
+ c->Init(program, index, name, data_size);
+ }
+ }
+
+ void BindAttribLocationBucket(
+ GLuint program, GLuint index, uint32 name_bucket_id) {
+ gles2::cmds::BindAttribLocationBucket* c =
+ GetCmdSpace<gles2::cmds::BindAttribLocationBucket>();
+ if (c) {
+ c->Init(program, index, name_bucket_id);
+ }
+ }
+
+ void BindBuffer(GLenum target, GLuint buffer) {
+ gles2::cmds::BindBuffer* c = GetCmdSpace<gles2::cmds::BindBuffer>();
+ if (c) {
+ c->Init(target, buffer);
+ }
+ }
+
+ void BindFramebuffer(GLenum target, GLuint framebuffer) {
+ gles2::cmds::BindFramebuffer* c =
+ GetCmdSpace<gles2::cmds::BindFramebuffer>();
+ if (c) {
+ c->Init(target, framebuffer);
+ }
+ }
+
+ void BindRenderbuffer(GLenum target, GLuint renderbuffer) {
+ gles2::cmds::BindRenderbuffer* c =
+ GetCmdSpace<gles2::cmds::BindRenderbuffer>();
+ if (c) {
+ c->Init(target, renderbuffer);
+ }
+ }
+
+ void BindTexture(GLenum target, GLuint texture) {
+ gles2::cmds::BindTexture* c = GetCmdSpace<gles2::cmds::BindTexture>();
+ if (c) {
+ c->Init(target, texture);
+ }
+ }
+
+ void BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ gles2::cmds::BlendColor* c = GetCmdSpace<gles2::cmds::BlendColor>();
+ if (c) {
+ c->Init(red, green, blue, alpha);
+ }
+ }
+
+ void BlendEquation(GLenum mode) {
+ gles2::cmds::BlendEquation* c = GetCmdSpace<gles2::cmds::BlendEquation>();
+ if (c) {
+ c->Init(mode);
+ }
+ }
+
+ void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) {
+ gles2::cmds::BlendEquationSeparate* c =
+ GetCmdSpace<gles2::cmds::BlendEquationSeparate>();
+ if (c) {
+ c->Init(modeRGB, modeAlpha);
+ }
+ }
+
+ void BlendFunc(GLenum sfactor, GLenum dfactor) {
+ gles2::cmds::BlendFunc* c = GetCmdSpace<gles2::cmds::BlendFunc>();
+ if (c) {
+ c->Init(sfactor, dfactor);
+ }
+ }
+
+ void BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ gles2::cmds::BlendFuncSeparate* c =
+ GetCmdSpace<gles2::cmds::BlendFuncSeparate>();
+ if (c) {
+ c->Init(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+ }
+
+ void BufferData(
+ GLenum target, GLsizeiptr size, uint32 data_shm_id,
+ uint32 data_shm_offset, GLenum usage) {
+ gles2::cmds::BufferData* c = GetCmdSpace<gles2::cmds::BufferData>();
+ if (c) {
+ c->Init(target, size, data_shm_id, data_shm_offset, usage);
+ }
+ }
+
+ void BufferDataImmediate(GLenum target, GLsizeiptr size, GLenum usage) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::BufferDataImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::BufferDataImmediate>(s);
+ if (c) {
+ c->Init(target, size, usage);
+ }
+ }
+
+ void BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, uint32 data_shm_id,
+ uint32 data_shm_offset) {
+ gles2::cmds::BufferSubData* c = GetCmdSpace<gles2::cmds::BufferSubData>();
+ if (c) {
+ c->Init(target, offset, size, data_shm_id, data_shm_offset);
+ }
+ }
+
+ void BufferSubDataImmediate(
+ GLenum target, GLintptr offset, GLsizeiptr size) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::BufferSubDataImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::BufferSubDataImmediate>(s);
+ if (c) {
+ c->Init(target, offset, size);
+ }
+ }
+
+ void CheckFramebufferStatus(
+ GLenum target, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::CheckFramebufferStatus* c =
+ GetCmdSpace<gles2::cmds::CheckFramebufferStatus>();
+ if (c) {
+ c->Init(target, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void Clear(GLbitfield mask) {
+ gles2::cmds::Clear* c = GetCmdSpace<gles2::cmds::Clear>();
+ if (c) {
+ c->Init(mask);
+ }
+ }
+
+ void ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ gles2::cmds::ClearColor* c = GetCmdSpace<gles2::cmds::ClearColor>();
+ if (c) {
+ c->Init(red, green, blue, alpha);
+ }
+ }
+
+ void ClearDepthf(GLclampf depth) {
+ gles2::cmds::ClearDepthf* c = GetCmdSpace<gles2::cmds::ClearDepthf>();
+ if (c) {
+ c->Init(depth);
+ }
+ }
+
+ void ClearStencil(GLint s) {
+ gles2::cmds::ClearStencil* c = GetCmdSpace<gles2::cmds::ClearStencil>();
+ if (c) {
+ c->Init(s);
+ }
+ }
+
+ void ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ gles2::cmds::ColorMask* c = GetCmdSpace<gles2::cmds::ColorMask>();
+ if (c) {
+ c->Init(red, green, blue, alpha);
+ }
+ }
+
+ void CompileShader(GLuint shader) {
+ gles2::cmds::CompileShader* c = GetCmdSpace<gles2::cmds::CompileShader>();
+ if (c) {
+ c->Init(shader);
+ }
+ }
+
+ void CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize, uint32 data_shm_id,
+ uint32 data_shm_offset) {
+ gles2::cmds::CompressedTexImage2D* c =
+ GetCmdSpace<gles2::cmds::CompressedTexImage2D>();
+ if (c) {
+ c->Init(
+ target, level, internalformat, width, height, border, imageSize,
+ data_shm_id, data_shm_offset);
+ }
+ }
+
+ void CompressedTexImage2DImmediate(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::CompressedTexImage2DImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::CompressedTexImage2DImmediate>(s); // NOLINT
+ if (c) {
+ c->Init(target, level, internalformat, width, height, border, imageSize);
+ }
+ }
+
+ void CompressedTexImage2DBucket(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLuint bucket_id) {
+ gles2::cmds::CompressedTexImage2DBucket* c =
+ GetCmdSpace<gles2::cmds::CompressedTexImage2DBucket>();
+ if (c) {
+ c->Init(target, level, internalformat, width, height, border, bucket_id);
+ }
+ }
+
+ void CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize, uint32 data_shm_id,
+ uint32 data_shm_offset) {
+ gles2::cmds::CompressedTexSubImage2D* c =
+ GetCmdSpace<gles2::cmds::CompressedTexSubImage2D>();
+ if (c) {
+ c->Init(
+ target, level, xoffset, yoffset, width, height, format, imageSize,
+ data_shm_id, data_shm_offset);
+ }
+ }
+
+ void CompressedTexSubImage2DImmediate(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::CompressedTexSubImage2DImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::CompressedTexSubImage2DImmediate>(s); // NOLINT
+ if (c) {
+ c->Init(
+ target, level, xoffset, yoffset, width, height, format, imageSize);
+ }
+ }
+
+ void CompressedTexSubImage2DBucket(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLuint bucket_id) {
+ gles2::cmds::CompressedTexSubImage2DBucket* c =
+ GetCmdSpace<gles2::cmds::CompressedTexSubImage2DBucket>();
+ if (c) {
+ c->Init(
+ target, level, xoffset, yoffset, width, height, format, bucket_id);
+ }
+ }
+
+ void CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) {
+ gles2::cmds::CopyTexImage2D* c =
+ GetCmdSpace<gles2::cmds::CopyTexImage2D>();
+ if (c) {
+ c->Init(target, level, internalformat, x, y, width, height, border);
+ }
+ }
+
+ void CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x,
+ GLint y, GLsizei width, GLsizei height) {
+ gles2::cmds::CopyTexSubImage2D* c =
+ GetCmdSpace<gles2::cmds::CopyTexSubImage2D>();
+ if (c) {
+ c->Init(target, level, xoffset, yoffset, x, y, width, height);
+ }
+ }
+
+ void CreateProgram(uint32 client_id) {
+ gles2::cmds::CreateProgram* c = GetCmdSpace<gles2::cmds::CreateProgram>();
+ if (c) {
+ c->Init(client_id);
+ }
+ }
+
+ void CreateShader(GLenum type, uint32 client_id) {
+ gles2::cmds::CreateShader* c = GetCmdSpace<gles2::cmds::CreateShader>();
+ if (c) {
+ c->Init(type, client_id);
+ }
+ }
+
+ void CullFace(GLenum mode) {
+ gles2::cmds::CullFace* c = GetCmdSpace<gles2::cmds::CullFace>();
+ if (c) {
+ c->Init(mode);
+ }
+ }
+
+ void DeleteBuffers(
+ GLsizei n, uint32 buffers_shm_id, uint32 buffers_shm_offset) {
+ gles2::cmds::DeleteBuffers* c = GetCmdSpace<gles2::cmds::DeleteBuffers>();
+ if (c) {
+ c->Init(n, buffers_shm_id, buffers_shm_offset);
+ }
+ }
+
+ void DeleteBuffersImmediate(GLsizei n, const GLuint* buffers) {
+ const uint32 size = gles2::cmds::DeleteBuffersImmediate::ComputeSize(n);
+ gles2::cmds::DeleteBuffersImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteBuffersImmediate>(
+ size);
+ if (c) {
+ c->Init(n, buffers);
+ }
+ }
+
+ void DeleteFramebuffers(
+ GLsizei n, uint32 framebuffers_shm_id, uint32 framebuffers_shm_offset) {
+ gles2::cmds::DeleteFramebuffers* c =
+ GetCmdSpace<gles2::cmds::DeleteFramebuffers>();
+ if (c) {
+ c->Init(n, framebuffers_shm_id, framebuffers_shm_offset);
+ }
+ }
+
+ void DeleteFramebuffersImmediate(GLsizei n, const GLuint* framebuffers) {
+ const uint32 size =
+ gles2::cmds::DeleteFramebuffersImmediate::ComputeSize(n);
+ gles2::cmds::DeleteFramebuffersImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteFramebuffersImmediate>(
+ size);
+ if (c) {
+ c->Init(n, framebuffers);
+ }
+ }
+
+ void DeleteProgram(GLuint program) {
+ gles2::cmds::DeleteProgram* c = GetCmdSpace<gles2::cmds::DeleteProgram>();
+ if (c) {
+ c->Init(program);
+ }
+ }
+
+ void DeleteRenderbuffers(
+ GLsizei n, uint32 renderbuffers_shm_id,
+ uint32 renderbuffers_shm_offset) {
+ gles2::cmds::DeleteRenderbuffers* c =
+ GetCmdSpace<gles2::cmds::DeleteRenderbuffers>();
+ if (c) {
+ c->Init(n, renderbuffers_shm_id, renderbuffers_shm_offset);
+ }
+ }
+
+ void DeleteRenderbuffersImmediate(GLsizei n, const GLuint* renderbuffers) {
+ const uint32 size =
+ gles2::cmds::DeleteRenderbuffersImmediate::ComputeSize(n);
+ gles2::cmds::DeleteRenderbuffersImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteRenderbuffersImmediate>(size); // NOLINT
+ if (c) {
+ c->Init(n, renderbuffers);
+ }
+ }
+
+ void DeleteShader(GLuint shader) {
+ gles2::cmds::DeleteShader* c = GetCmdSpace<gles2::cmds::DeleteShader>();
+ if (c) {
+ c->Init(shader);
+ }
+ }
+
+ void DeleteTextures(
+ GLsizei n, uint32 textures_shm_id, uint32 textures_shm_offset) {
+ gles2::cmds::DeleteTextures* c =
+ GetCmdSpace<gles2::cmds::DeleteTextures>();
+ if (c) {
+ c->Init(n, textures_shm_id, textures_shm_offset);
+ }
+ }
+
+ void DeleteTexturesImmediate(GLsizei n, const GLuint* textures) {
+ const uint32 size = gles2::cmds::DeleteTexturesImmediate::ComputeSize(n);
+ gles2::cmds::DeleteTexturesImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteTexturesImmediate>(
+ size);
+ if (c) {
+ c->Init(n, textures);
+ }
+ }
+
+ void DepthFunc(GLenum func) {
+ gles2::cmds::DepthFunc* c = GetCmdSpace<gles2::cmds::DepthFunc>();
+ if (c) {
+ c->Init(func);
+ }
+ }
+
+ void DepthMask(GLboolean flag) {
+ gles2::cmds::DepthMask* c = GetCmdSpace<gles2::cmds::DepthMask>();
+ if (c) {
+ c->Init(flag);
+ }
+ }
+
+ void DepthRangef(GLclampf zNear, GLclampf zFar) {
+ gles2::cmds::DepthRangef* c = GetCmdSpace<gles2::cmds::DepthRangef>();
+ if (c) {
+ c->Init(zNear, zFar);
+ }
+ }
+
+ void DetachShader(GLuint program, GLuint shader) {
+ gles2::cmds::DetachShader* c = GetCmdSpace<gles2::cmds::DetachShader>();
+ if (c) {
+ c->Init(program, shader);
+ }
+ }
+
+ void Disable(GLenum cap) {
+ gles2::cmds::Disable* c = GetCmdSpace<gles2::cmds::Disable>();
+ if (c) {
+ c->Init(cap);
+ }
+ }
+
+ void DisableVertexAttribArray(GLuint index) {
+ gles2::cmds::DisableVertexAttribArray* c =
+ GetCmdSpace<gles2::cmds::DisableVertexAttribArray>();
+ if (c) {
+ c->Init(index);
+ }
+ }
+
+ void DrawArrays(GLenum mode, GLint first, GLsizei count) {
+ gles2::cmds::DrawArrays* c = GetCmdSpace<gles2::cmds::DrawArrays>();
+ if (c) {
+ c->Init(mode, first, count);
+ }
+ }
+
+ void DrawElements(
+ GLenum mode, GLsizei count, GLenum type, GLuint index_offset) {
+ gles2::cmds::DrawElements* c = GetCmdSpace<gles2::cmds::DrawElements>();
+ if (c) {
+ c->Init(mode, count, type, index_offset);
+ }
+ }
+
+ void Enable(GLenum cap) {
+ gles2::cmds::Enable* c = GetCmdSpace<gles2::cmds::Enable>();
+ if (c) {
+ c->Init(cap);
+ }
+ }
+
+ void EnableVertexAttribArray(GLuint index) {
+ gles2::cmds::EnableVertexAttribArray* c =
+ GetCmdSpace<gles2::cmds::EnableVertexAttribArray>();
+ if (c) {
+ c->Init(index);
+ }
+ }
+
+ void Finish() {
+ gles2::cmds::Finish* c = GetCmdSpace<gles2::cmds::Finish>();
+ if (c) {
+ c->Init();
+ }
+ }
+
+ void Flush() {
+ gles2::cmds::Flush* c = GetCmdSpace<gles2::cmds::Flush>();
+ if (c) {
+ c->Init();
+ }
+ }
+
+ void FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) {
+ gles2::cmds::FramebufferRenderbuffer* c =
+ GetCmdSpace<gles2::cmds::FramebufferRenderbuffer>();
+ if (c) {
+ c->Init(target, attachment, renderbuffertarget, renderbuffer);
+ }
+ }
+
+ void FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) {
+ gles2::cmds::FramebufferTexture2D* c =
+ GetCmdSpace<gles2::cmds::FramebufferTexture2D>();
+ if (c) {
+ c->Init(target, attachment, textarget, texture, level);
+ }
+ }
+
+ void FrontFace(GLenum mode) {
+ gles2::cmds::FrontFace* c = GetCmdSpace<gles2::cmds::FrontFace>();
+ if (c) {
+ c->Init(mode);
+ }
+ }
+
+ void GenBuffers(
+ GLsizei n, uint32 buffers_shm_id, uint32 buffers_shm_offset) {
+ gles2::cmds::GenBuffers* c = GetCmdSpace<gles2::cmds::GenBuffers>();
+ if (c) {
+ c->Init(n, buffers_shm_id, buffers_shm_offset);
+ }
+ }
+
+ void GenBuffersImmediate(GLsizei n, GLuint* buffers) {
+ const uint32 size = gles2::cmds::GenBuffersImmediate::ComputeSize(n);
+ gles2::cmds::GenBuffersImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GenBuffersImmediate>(size);
+ if (c) {
+ c->Init(n, buffers);
+ }
+ }
+
+ void GenerateMipmap(GLenum target) {
+ gles2::cmds::GenerateMipmap* c =
+ GetCmdSpace<gles2::cmds::GenerateMipmap>();
+ if (c) {
+ c->Init(target);
+ }
+ }
+
+ void GenFramebuffers(
+ GLsizei n, uint32 framebuffers_shm_id, uint32 framebuffers_shm_offset) {
+ gles2::cmds::GenFramebuffers* c =
+ GetCmdSpace<gles2::cmds::GenFramebuffers>();
+ if (c) {
+ c->Init(n, framebuffers_shm_id, framebuffers_shm_offset);
+ }
+ }
+
+ void GenFramebuffersImmediate(GLsizei n, GLuint* framebuffers) {
+ const uint32 size = gles2::cmds::GenFramebuffersImmediate::ComputeSize(n);
+ gles2::cmds::GenFramebuffersImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GenFramebuffersImmediate>(
+ size);
+ if (c) {
+ c->Init(n, framebuffers);
+ }
+ }
+
+ void GenRenderbuffers(
+ GLsizei n, uint32 renderbuffers_shm_id,
+ uint32 renderbuffers_shm_offset) {
+ gles2::cmds::GenRenderbuffers* c =
+ GetCmdSpace<gles2::cmds::GenRenderbuffers>();
+ if (c) {
+ c->Init(n, renderbuffers_shm_id, renderbuffers_shm_offset);
+ }
+ }
+
+ void GenRenderbuffersImmediate(GLsizei n, GLuint* renderbuffers) {
+ const uint32 size = gles2::cmds::GenRenderbuffersImmediate::ComputeSize(n);
+ gles2::cmds::GenRenderbuffersImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GenRenderbuffersImmediate>(
+ size);
+ if (c) {
+ c->Init(n, renderbuffers);
+ }
+ }
+
+ void GenTextures(
+ GLsizei n, uint32 textures_shm_id, uint32 textures_shm_offset) {
+ gles2::cmds::GenTextures* c = GetCmdSpace<gles2::cmds::GenTextures>();
+ if (c) {
+ c->Init(n, textures_shm_id, textures_shm_offset);
+ }
+ }
+
+ void GenTexturesImmediate(GLsizei n, GLuint* textures) {
+ const uint32 size = gles2::cmds::GenTexturesImmediate::ComputeSize(n);
+ gles2::cmds::GenTexturesImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GenTexturesImmediate>(size);
+ if (c) {
+ c->Init(n, textures);
+ }
+ }
+
+ void GetActiveAttrib(
+ GLuint program, GLuint index, uint32 name_bucket_id, uint32 result_shm_id,
+ uint32 result_shm_offset) {
+ gles2::cmds::GetActiveAttrib* c =
+ GetCmdSpace<gles2::cmds::GetActiveAttrib>();
+ if (c) {
+ c->Init(
+ program, index, name_bucket_id, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void GetActiveUniform(
+ GLuint program, GLuint index, uint32 name_bucket_id, uint32 result_shm_id,
+ uint32 result_shm_offset) {
+ gles2::cmds::GetActiveUniform* c =
+ GetCmdSpace<gles2::cmds::GetActiveUniform>();
+ if (c) {
+ c->Init(
+ program, index, name_bucket_id, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void GetAttachedShaders(
+ GLuint program, uint32 result_shm_id, uint32 result_shm_offset,
+ uint32 result_size) {
+ gles2::cmds::GetAttachedShaders* c =
+ GetCmdSpace<gles2::cmds::GetAttachedShaders>();
+ if (c) {
+ c->Init(program, result_shm_id, result_shm_offset, result_size);
+ }
+ }
+
+ void GetBooleanv(
+ GLenum pname, uint32 params_shm_id, uint32 params_shm_offset) {
+ gles2::cmds::GetBooleanv* c = GetCmdSpace<gles2::cmds::GetBooleanv>();
+ if (c) {
+ c->Init(pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetBufferParameteriv(
+ GLenum target, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetBufferParameteriv* c =
+ GetCmdSpace<gles2::cmds::GetBufferParameteriv>();
+ if (c) {
+ c->Init(target, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetError(uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::GetError* c = GetCmdSpace<gles2::cmds::GetError>();
+ if (c) {
+ c->Init(result_shm_id, result_shm_offset);
+ }
+ }
+
+ void GetFloatv(
+ GLenum pname, uint32 params_shm_id, uint32 params_shm_offset) {
+ gles2::cmds::GetFloatv* c = GetCmdSpace<gles2::cmds::GetFloatv>();
+ if (c) {
+ c->Init(pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetFramebufferAttachmentParameteriv* c =
+ GetCmdSpace<gles2::cmds::GetFramebufferAttachmentParameteriv>();
+ if (c) {
+ c->Init(target, attachment, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetIntegerv(
+ GLenum pname, uint32 params_shm_id, uint32 params_shm_offset) {
+ gles2::cmds::GetIntegerv* c = GetCmdSpace<gles2::cmds::GetIntegerv>();
+ if (c) {
+ c->Init(pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetProgramiv(
+ GLuint program, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetProgramiv* c = GetCmdSpace<gles2::cmds::GetProgramiv>();
+ if (c) {
+ c->Init(program, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetProgramInfoLog(GLuint program, uint32 bucket_id) {
+ gles2::cmds::GetProgramInfoLog* c =
+ GetCmdSpace<gles2::cmds::GetProgramInfoLog>();
+ if (c) {
+ c->Init(program, bucket_id);
+ }
+ }
+
+ void GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetRenderbufferParameteriv* c =
+ GetCmdSpace<gles2::cmds::GetRenderbufferParameteriv>();
+ if (c) {
+ c->Init(target, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetShaderiv(
+ GLuint shader, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetShaderiv* c = GetCmdSpace<gles2::cmds::GetShaderiv>();
+ if (c) {
+ c->Init(shader, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetShaderInfoLog(GLuint shader, uint32 bucket_id) {
+ gles2::cmds::GetShaderInfoLog* c =
+ GetCmdSpace<gles2::cmds::GetShaderInfoLog>();
+ if (c) {
+ c->Init(shader, bucket_id);
+ }
+ }
+
+ void GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, uint32 result_shm_id,
+ uint32 result_shm_offset) {
+ gles2::cmds::GetShaderPrecisionFormat* c =
+ GetCmdSpace<gles2::cmds::GetShaderPrecisionFormat>();
+ if (c) {
+ c->Init(shadertype, precisiontype, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void GetShaderSource(GLuint shader, uint32 bucket_id) {
+ gles2::cmds::GetShaderSource* c =
+ GetCmdSpace<gles2::cmds::GetShaderSource>();
+ if (c) {
+ c->Init(shader, bucket_id);
+ }
+ }
+
+ void GetString(GLenum name, uint32 bucket_id) {
+ gles2::cmds::GetString* c = GetCmdSpace<gles2::cmds::GetString>();
+ if (c) {
+ c->Init(name, bucket_id);
+ }
+ }
+
+ void GetTexParameterfv(
+ GLenum target, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetTexParameterfv* c =
+ GetCmdSpace<gles2::cmds::GetTexParameterfv>();
+ if (c) {
+ c->Init(target, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetTexParameteriv(
+ GLenum target, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetTexParameteriv* c =
+ GetCmdSpace<gles2::cmds::GetTexParameteriv>();
+ if (c) {
+ c->Init(target, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetUniformfv(
+ GLuint program, GLint location, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetUniformfv* c = GetCmdSpace<gles2::cmds::GetUniformfv>();
+ if (c) {
+ c->Init(program, location, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetUniformiv(
+ GLuint program, GLint location, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetUniformiv* c = GetCmdSpace<gles2::cmds::GetUniformiv>();
+ if (c) {
+ c->Init(program, location, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetVertexAttribfv(
+ GLuint index, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetVertexAttribfv* c =
+ GetCmdSpace<gles2::cmds::GetVertexAttribfv>();
+ if (c) {
+ c->Init(index, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetVertexAttribiv(
+ GLuint index, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::GetVertexAttribiv* c =
+ GetCmdSpace<gles2::cmds::GetVertexAttribiv>();
+ if (c) {
+ c->Init(index, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void GetVertexAttribPointerv(
+ GLuint index, GLenum pname, uint32 pointer_shm_id,
+ uint32 pointer_shm_offset) {
+ gles2::cmds::GetVertexAttribPointerv* c =
+ GetCmdSpace<gles2::cmds::GetVertexAttribPointerv>();
+ if (c) {
+ c->Init(index, pname, pointer_shm_id, pointer_shm_offset);
+ }
+ }
+
+ void Hint(GLenum target, GLenum mode) {
+ gles2::cmds::Hint* c = GetCmdSpace<gles2::cmds::Hint>();
+ if (c) {
+ c->Init(target, mode);
+ }
+ }
+
+ void IsBuffer(
+ GLuint buffer, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsBuffer* c = GetCmdSpace<gles2::cmds::IsBuffer>();
+ if (c) {
+ c->Init(buffer, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void IsEnabled(GLenum cap, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsEnabled* c = GetCmdSpace<gles2::cmds::IsEnabled>();
+ if (c) {
+ c->Init(cap, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void IsFramebuffer(
+ GLuint framebuffer, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsFramebuffer* c = GetCmdSpace<gles2::cmds::IsFramebuffer>();
+ if (c) {
+ c->Init(framebuffer, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void IsProgram(
+ GLuint program, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsProgram* c = GetCmdSpace<gles2::cmds::IsProgram>();
+ if (c) {
+ c->Init(program, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void IsRenderbuffer(
+ GLuint renderbuffer, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsRenderbuffer* c =
+ GetCmdSpace<gles2::cmds::IsRenderbuffer>();
+ if (c) {
+ c->Init(renderbuffer, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void IsShader(
+ GLuint shader, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsShader* c = GetCmdSpace<gles2::cmds::IsShader>();
+ if (c) {
+ c->Init(shader, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void IsTexture(
+ GLuint texture, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsTexture* c = GetCmdSpace<gles2::cmds::IsTexture>();
+ if (c) {
+ c->Init(texture, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void LineWidth(GLfloat width) {
+ gles2::cmds::LineWidth* c = GetCmdSpace<gles2::cmds::LineWidth>();
+ if (c) {
+ c->Init(width);
+ }
+ }
+
+ void LinkProgram(GLuint program) {
+ gles2::cmds::LinkProgram* c = GetCmdSpace<gles2::cmds::LinkProgram>();
+ if (c) {
+ c->Init(program);
+ }
+ }
+
+ void PixelStorei(GLenum pname, GLint param) {
+ gles2::cmds::PixelStorei* c = GetCmdSpace<gles2::cmds::PixelStorei>();
+ if (c) {
+ c->Init(pname, param);
+ }
+ }
+
+ void PolygonOffset(GLfloat factor, GLfloat units) {
+ gles2::cmds::PolygonOffset* c = GetCmdSpace<gles2::cmds::PolygonOffset>();
+ if (c) {
+ c->Init(factor, units);
+ }
+ }
+
+ void ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, uint32 pixels_shm_id, uint32 pixels_shm_offset,
+ uint32 result_shm_id, uint32 result_shm_offset, GLboolean async) {
+ gles2::cmds::ReadPixels* c = GetCmdSpace<gles2::cmds::ReadPixels>();
+ if (c) {
+ c->Init(
+ x, y, width, height, format, type, pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset, async);
+ }
+ }
+
+ void ReleaseShaderCompiler() {
+ gles2::cmds::ReleaseShaderCompiler* c =
+ GetCmdSpace<gles2::cmds::ReleaseShaderCompiler>();
+ if (c) {
+ c->Init();
+ }
+ }
+
+ void RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ gles2::cmds::RenderbufferStorage* c =
+ GetCmdSpace<gles2::cmds::RenderbufferStorage>();
+ if (c) {
+ c->Init(target, internalformat, width, height);
+ }
+ }
+
+ void SampleCoverage(GLclampf value, GLboolean invert) {
+ gles2::cmds::SampleCoverage* c =
+ GetCmdSpace<gles2::cmds::SampleCoverage>();
+ if (c) {
+ c->Init(value, invert);
+ }
+ }
+
+ void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) {
+ gles2::cmds::Scissor* c = GetCmdSpace<gles2::cmds::Scissor>();
+ if (c) {
+ c->Init(x, y, width, height);
+ }
+ }
+
+ void ShaderBinary(
+ GLsizei n, uint32 shaders_shm_id, uint32 shaders_shm_offset,
+ GLenum binaryformat, uint32 binary_shm_id, uint32 binary_shm_offset,
+ GLsizei length) {
+ gles2::cmds::ShaderBinary* c = GetCmdSpace<gles2::cmds::ShaderBinary>();
+ if (c) {
+ c->Init(
+ n, shaders_shm_id, shaders_shm_offset, binaryformat, binary_shm_id,
+ binary_shm_offset, length);
+ }
+ }
+
+ void ShaderSource(
+ GLuint shader, uint32 data_shm_id, uint32 data_shm_offset,
+ uint32 data_size) {
+ gles2::cmds::ShaderSource* c = GetCmdSpace<gles2::cmds::ShaderSource>();
+ if (c) {
+ c->Init(shader, data_shm_id, data_shm_offset, data_size);
+ }
+ }
+
+ void ShaderSourceImmediate(GLuint shader, uint32 data_size) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::ShaderSourceImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::ShaderSourceImmediate>(s);
+ if (c) {
+ c->Init(shader, data_size);
+ }
+ }
+
+ void ShaderSourceBucket(GLuint shader, uint32 data_bucket_id) {
+ gles2::cmds::ShaderSourceBucket* c =
+ GetCmdSpace<gles2::cmds::ShaderSourceBucket>();
+ if (c) {
+ c->Init(shader, data_bucket_id);
+ }
+ }
+
+ void StencilFunc(GLenum func, GLint ref, GLuint mask) {
+ gles2::cmds::StencilFunc* c = GetCmdSpace<gles2::cmds::StencilFunc>();
+ if (c) {
+ c->Init(func, ref, mask);
+ }
+ }
+
+ void StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) {
+ gles2::cmds::StencilFuncSeparate* c =
+ GetCmdSpace<gles2::cmds::StencilFuncSeparate>();
+ if (c) {
+ c->Init(face, func, ref, mask);
+ }
+ }
+
+ void StencilMask(GLuint mask) {
+ gles2::cmds::StencilMask* c = GetCmdSpace<gles2::cmds::StencilMask>();
+ if (c) {
+ c->Init(mask);
+ }
+ }
+
+ void StencilMaskSeparate(GLenum face, GLuint mask) {
+ gles2::cmds::StencilMaskSeparate* c =
+ GetCmdSpace<gles2::cmds::StencilMaskSeparate>();
+ if (c) {
+ c->Init(face, mask);
+ }
+ }
+
+ void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+ gles2::cmds::StencilOp* c = GetCmdSpace<gles2::cmds::StencilOp>();
+ if (c) {
+ c->Init(fail, zfail, zpass);
+ }
+ }
+
+ void StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ gles2::cmds::StencilOpSeparate* c =
+ GetCmdSpace<gles2::cmds::StencilOpSeparate>();
+ if (c) {
+ c->Init(face, fail, zfail, zpass);
+ }
+ }
+
+ void TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ uint32 pixels_shm_id, uint32 pixels_shm_offset) {
+ gles2::cmds::TexImage2D* c = GetCmdSpace<gles2::cmds::TexImage2D>();
+ if (c) {
+ c->Init(
+ target, level, internalformat, width, height, border, format, type,
+ pixels_shm_id, pixels_shm_offset);
+ }
+ }
+
+ void TexImage2DImmediate(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::TexImage2DImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::TexImage2DImmediate>(s);
+ if (c) {
+ c->Init(
+ target, level, internalformat, width, height, border, format, type);
+ }
+ }
+
+ void TexParameterf(GLenum target, GLenum pname, GLfloat param) {
+ gles2::cmds::TexParameterf* c = GetCmdSpace<gles2::cmds::TexParameterf>();
+ if (c) {
+ c->Init(target, pname, param);
+ }
+ }
+
+ void TexParameterfv(
+ GLenum target, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::TexParameterfv* c =
+ GetCmdSpace<gles2::cmds::TexParameterfv>();
+ if (c) {
+ c->Init(target, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void TexParameterfvImmediate(
+ GLenum target, GLenum pname, const GLfloat* params) {
+ const uint32 size = gles2::cmds::TexParameterfvImmediate::ComputeSize();
+ gles2::cmds::TexParameterfvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::TexParameterfvImmediate>(
+ size);
+ if (c) {
+ c->Init(target, pname, params);
+ }
+ }
+
+ void TexParameteri(GLenum target, GLenum pname, GLint param) {
+ gles2::cmds::TexParameteri* c = GetCmdSpace<gles2::cmds::TexParameteri>();
+ if (c) {
+ c->Init(target, pname, param);
+ }
+ }
+
+ void TexParameteriv(
+ GLenum target, GLenum pname, uint32 params_shm_id,
+ uint32 params_shm_offset) {
+ gles2::cmds::TexParameteriv* c =
+ GetCmdSpace<gles2::cmds::TexParameteriv>();
+ if (c) {
+ c->Init(target, pname, params_shm_id, params_shm_offset);
+ }
+ }
+
+ void TexParameterivImmediate(
+ GLenum target, GLenum pname, const GLint* params) {
+ const uint32 size = gles2::cmds::TexParameterivImmediate::ComputeSize();
+ gles2::cmds::TexParameterivImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::TexParameterivImmediate>(
+ size);
+ if (c) {
+ c->Init(target, pname, params);
+ }
+ }
+
+ void TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, uint32 pixels_shm_id,
+ uint32 pixels_shm_offset, GLboolean internal) {
+ gles2::cmds::TexSubImage2D* c = GetCmdSpace<gles2::cmds::TexSubImage2D>();
+ if (c) {
+ c->Init(
+ target, level, xoffset, yoffset, width, height, format, type,
+ pixels_shm_id, pixels_shm_offset, internal);
+ }
+ }
+
+ void TexSubImage2DImmediate(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLboolean internal) {
+ const uint32 s = 0; // TODO(gman): compute correct size
+ gles2::cmds::TexSubImage2DImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::TexSubImage2DImmediate>(s);
+ if (c) {
+ c->Init(
+ target, level, xoffset, yoffset, width, height, format, type,
+ internal);
+ }
+ }
+
+ void Uniform1f(GLint location, GLfloat x) {
+ gles2::cmds::Uniform1f* c = GetCmdSpace<gles2::cmds::Uniform1f>();
+ if (c) {
+ c->Init(location, x);
+ }
+ }
+
+ void Uniform1fv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform1fv* c = GetCmdSpace<gles2::cmds::Uniform1fv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform1fvImmediate(GLint location, GLsizei count, const GLfloat* v) {
+ const uint32 size = gles2::cmds::Uniform1fvImmediate::ComputeSize(count);
+ gles2::cmds::Uniform1fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform1fvImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform1i(GLint location, GLint x) {
+ gles2::cmds::Uniform1i* c = GetCmdSpace<gles2::cmds::Uniform1i>();
+ if (c) {
+ c->Init(location, x);
+ }
+ }
+
+ void Uniform1iv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform1iv* c = GetCmdSpace<gles2::cmds::Uniform1iv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform1ivImmediate(GLint location, GLsizei count, const GLint* v) {
+ const uint32 size = gles2::cmds::Uniform1ivImmediate::ComputeSize(count);
+ gles2::cmds::Uniform1ivImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform1ivImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform2f(GLint location, GLfloat x, GLfloat y) {
+ gles2::cmds::Uniform2f* c = GetCmdSpace<gles2::cmds::Uniform2f>();
+ if (c) {
+ c->Init(location, x, y);
+ }
+ }
+
+ void Uniform2fv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform2fv* c = GetCmdSpace<gles2::cmds::Uniform2fv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform2fvImmediate(GLint location, GLsizei count, const GLfloat* v) {
+ const uint32 size = gles2::cmds::Uniform2fvImmediate::ComputeSize(count);
+ gles2::cmds::Uniform2fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform2fvImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform2i(GLint location, GLint x, GLint y) {
+ gles2::cmds::Uniform2i* c = GetCmdSpace<gles2::cmds::Uniform2i>();
+ if (c) {
+ c->Init(location, x, y);
+ }
+ }
+
+ void Uniform2iv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform2iv* c = GetCmdSpace<gles2::cmds::Uniform2iv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform2ivImmediate(GLint location, GLsizei count, const GLint* v) {
+ const uint32 size = gles2::cmds::Uniform2ivImmediate::ComputeSize(count);
+ gles2::cmds::Uniform2ivImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform2ivImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ gles2::cmds::Uniform3f* c = GetCmdSpace<gles2::cmds::Uniform3f>();
+ if (c) {
+ c->Init(location, x, y, z);
+ }
+ }
+
+ void Uniform3fv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform3fv* c = GetCmdSpace<gles2::cmds::Uniform3fv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform3fvImmediate(GLint location, GLsizei count, const GLfloat* v) {
+ const uint32 size = gles2::cmds::Uniform3fvImmediate::ComputeSize(count);
+ gles2::cmds::Uniform3fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform3fvImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform3i(GLint location, GLint x, GLint y, GLint z) {
+ gles2::cmds::Uniform3i* c = GetCmdSpace<gles2::cmds::Uniform3i>();
+ if (c) {
+ c->Init(location, x, y, z);
+ }
+ }
+
+ void Uniform3iv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform3iv* c = GetCmdSpace<gles2::cmds::Uniform3iv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform3ivImmediate(GLint location, GLsizei count, const GLint* v) {
+ const uint32 size = gles2::cmds::Uniform3ivImmediate::ComputeSize(count);
+ gles2::cmds::Uniform3ivImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform3ivImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ gles2::cmds::Uniform4f* c = GetCmdSpace<gles2::cmds::Uniform4f>();
+ if (c) {
+ c->Init(location, x, y, z, w);
+ }
+ }
+
+ void Uniform4fv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform4fv* c = GetCmdSpace<gles2::cmds::Uniform4fv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform4fvImmediate(GLint location, GLsizei count, const GLfloat* v) {
+ const uint32 size = gles2::cmds::Uniform4fvImmediate::ComputeSize(count);
+ gles2::cmds::Uniform4fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform4fvImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) {
+ gles2::cmds::Uniform4i* c = GetCmdSpace<gles2::cmds::Uniform4i>();
+ if (c) {
+ c->Init(location, x, y, z, w);
+ }
+ }
+
+ void Uniform4iv(
+ GLint location, GLsizei count, uint32 v_shm_id, uint32 v_shm_offset) {
+ gles2::cmds::Uniform4iv* c = GetCmdSpace<gles2::cmds::Uniform4iv>();
+ if (c) {
+ c->Init(location, count, v_shm_id, v_shm_offset);
+ }
+ }
+
+ void Uniform4ivImmediate(GLint location, GLsizei count, const GLint* v) {
+ const uint32 size = gles2::cmds::Uniform4ivImmediate::ComputeSize(count);
+ gles2::cmds::Uniform4ivImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::Uniform4ivImmediate>(size);
+ if (c) {
+ c->Init(location, count, v);
+ }
+ }
+
+ void UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose, uint32 value_shm_id,
+ uint32 value_shm_offset) {
+ gles2::cmds::UniformMatrix2fv* c =
+ GetCmdSpace<gles2::cmds::UniformMatrix2fv>();
+ if (c) {
+ c->Init(location, count, transpose, value_shm_id, value_shm_offset);
+ }
+ }
+
+ void UniformMatrix2fvImmediate(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) {
+ const uint32 size =
+ gles2::cmds::UniformMatrix2fvImmediate::ComputeSize(count);
+ gles2::cmds::UniformMatrix2fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::UniformMatrix2fvImmediate>(
+ size);
+ if (c) {
+ c->Init(location, count, transpose, value);
+ }
+ }
+
+ void UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose, uint32 value_shm_id,
+ uint32 value_shm_offset) {
+ gles2::cmds::UniformMatrix3fv* c =
+ GetCmdSpace<gles2::cmds::UniformMatrix3fv>();
+ if (c) {
+ c->Init(location, count, transpose, value_shm_id, value_shm_offset);
+ }
+ }
+
+ void UniformMatrix3fvImmediate(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) {
+ const uint32 size =
+ gles2::cmds::UniformMatrix3fvImmediate::ComputeSize(count);
+ gles2::cmds::UniformMatrix3fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::UniformMatrix3fvImmediate>(
+ size);
+ if (c) {
+ c->Init(location, count, transpose, value);
+ }
+ }
+
+ void UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose, uint32 value_shm_id,
+ uint32 value_shm_offset) {
+ gles2::cmds::UniformMatrix4fv* c =
+ GetCmdSpace<gles2::cmds::UniformMatrix4fv>();
+ if (c) {
+ c->Init(location, count, transpose, value_shm_id, value_shm_offset);
+ }
+ }
+
+ void UniformMatrix4fvImmediate(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) {
+ const uint32 size =
+ gles2::cmds::UniformMatrix4fvImmediate::ComputeSize(count);
+ gles2::cmds::UniformMatrix4fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::UniformMatrix4fvImmediate>(
+ size);
+ if (c) {
+ c->Init(location, count, transpose, value);
+ }
+ }
+
+ void UseProgram(GLuint program) {
+ gles2::cmds::UseProgram* c = GetCmdSpace<gles2::cmds::UseProgram>();
+ if (c) {
+ c->Init(program);
+ }
+ }
+
+ void ValidateProgram(GLuint program) {
+ gles2::cmds::ValidateProgram* c =
+ GetCmdSpace<gles2::cmds::ValidateProgram>();
+ if (c) {
+ c->Init(program);
+ }
+ }
+
+ void VertexAttrib1f(GLuint indx, GLfloat x) {
+ gles2::cmds::VertexAttrib1f* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib1f>();
+ if (c) {
+ c->Init(indx, x);
+ }
+ }
+
+ void VertexAttrib1fv(
+ GLuint indx, uint32 values_shm_id, uint32 values_shm_offset) {
+ gles2::cmds::VertexAttrib1fv* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib1fv>();
+ if (c) {
+ c->Init(indx, values_shm_id, values_shm_offset);
+ }
+ }
+
+ void VertexAttrib1fvImmediate(GLuint indx, const GLfloat* values) {
+ const uint32 size = gles2::cmds::VertexAttrib1fvImmediate::ComputeSize();
+ gles2::cmds::VertexAttrib1fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::VertexAttrib1fvImmediate>(
+ size);
+ if (c) {
+ c->Init(indx, values);
+ }
+ }
+
+ void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) {
+ gles2::cmds::VertexAttrib2f* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib2f>();
+ if (c) {
+ c->Init(indx, x, y);
+ }
+ }
+
+ void VertexAttrib2fv(
+ GLuint indx, uint32 values_shm_id, uint32 values_shm_offset) {
+ gles2::cmds::VertexAttrib2fv* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib2fv>();
+ if (c) {
+ c->Init(indx, values_shm_id, values_shm_offset);
+ }
+ }
+
+ void VertexAttrib2fvImmediate(GLuint indx, const GLfloat* values) {
+ const uint32 size = gles2::cmds::VertexAttrib2fvImmediate::ComputeSize();
+ gles2::cmds::VertexAttrib2fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::VertexAttrib2fvImmediate>(
+ size);
+ if (c) {
+ c->Init(indx, values);
+ }
+ }
+
+ void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ gles2::cmds::VertexAttrib3f* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib3f>();
+ if (c) {
+ c->Init(indx, x, y, z);
+ }
+ }
+
+ void VertexAttrib3fv(
+ GLuint indx, uint32 values_shm_id, uint32 values_shm_offset) {
+ gles2::cmds::VertexAttrib3fv* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib3fv>();
+ if (c) {
+ c->Init(indx, values_shm_id, values_shm_offset);
+ }
+ }
+
+ void VertexAttrib3fvImmediate(GLuint indx, const GLfloat* values) {
+ const uint32 size = gles2::cmds::VertexAttrib3fvImmediate::ComputeSize();
+ gles2::cmds::VertexAttrib3fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::VertexAttrib3fvImmediate>(
+ size);
+ if (c) {
+ c->Init(indx, values);
+ }
+ }
+
+ void VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ gles2::cmds::VertexAttrib4f* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib4f>();
+ if (c) {
+ c->Init(indx, x, y, z, w);
+ }
+ }
+
+ void VertexAttrib4fv(
+ GLuint indx, uint32 values_shm_id, uint32 values_shm_offset) {
+ gles2::cmds::VertexAttrib4fv* c =
+ GetCmdSpace<gles2::cmds::VertexAttrib4fv>();
+ if (c) {
+ c->Init(indx, values_shm_id, values_shm_offset);
+ }
+ }
+
+ void VertexAttrib4fvImmediate(GLuint indx, const GLfloat* values) {
+ const uint32 size = gles2::cmds::VertexAttrib4fvImmediate::ComputeSize();
+ gles2::cmds::VertexAttrib4fvImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::VertexAttrib4fvImmediate>(
+ size);
+ if (c) {
+ c->Init(indx, values);
+ }
+ }
+
+ void VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized,
+ GLsizei stride, GLuint offset) {
+ gles2::cmds::VertexAttribPointer* c =
+ GetCmdSpace<gles2::cmds::VertexAttribPointer>();
+ if (c) {
+ c->Init(indx, size, type, normalized, stride, offset);
+ }
+ }
+
+ void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+ gles2::cmds::Viewport* c = GetCmdSpace<gles2::cmds::Viewport>();
+ if (c) {
+ c->Init(x, y, width, height);
+ }
+ }
+
+ void BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ gles2::cmds::BlitFramebufferEXT* c =
+ GetCmdSpace<gles2::cmds::BlitFramebufferEXT>();
+ if (c) {
+ c->Init(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask,
+ filter);
+ }
+ }
+
+ void RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) {
+ gles2::cmds::RenderbufferStorageMultisampleEXT* c =
+ GetCmdSpace<gles2::cmds::RenderbufferStorageMultisampleEXT>();
+ if (c) {
+ c->Init(target, samples, internalformat, width, height);
+ }
+ }
+
+ void FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) {
+ gles2::cmds::FramebufferTexture2DMultisampleEXT* c =
+ GetCmdSpace<gles2::cmds::FramebufferTexture2DMultisampleEXT>();
+ if (c) {
+ c->Init(target, attachment, textarget, texture, level, samples);
+ }
+ }
+
+ void TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) {
+ gles2::cmds::TexStorage2DEXT* c =
+ GetCmdSpace<gles2::cmds::TexStorage2DEXT>();
+ if (c) {
+ c->Init(target, levels, internalFormat, width, height);
+ }
+ }
+
+ void GenQueriesEXT(
+ GLsizei n, uint32 queries_shm_id, uint32 queries_shm_offset) {
+ gles2::cmds::GenQueriesEXT* c = GetCmdSpace<gles2::cmds::GenQueriesEXT>();
+ if (c) {
+ c->Init(n, queries_shm_id, queries_shm_offset);
+ }
+ }
+
+ void GenQueriesEXTImmediate(GLsizei n, GLuint* queries) {
+ const uint32 size = gles2::cmds::GenQueriesEXTImmediate::ComputeSize(n);
+ gles2::cmds::GenQueriesEXTImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GenQueriesEXTImmediate>(
+ size);
+ if (c) {
+ c->Init(n, queries);
+ }
+ }
+
+ void DeleteQueriesEXT(
+ GLsizei n, uint32 queries_shm_id, uint32 queries_shm_offset) {
+ gles2::cmds::DeleteQueriesEXT* c =
+ GetCmdSpace<gles2::cmds::DeleteQueriesEXT>();
+ if (c) {
+ c->Init(n, queries_shm_id, queries_shm_offset);
+ }
+ }
+
+ void DeleteQueriesEXTImmediate(GLsizei n, const GLuint* queries) {
+ const uint32 size = gles2::cmds::DeleteQueriesEXTImmediate::ComputeSize(n);
+ gles2::cmds::DeleteQueriesEXTImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteQueriesEXTImmediate>(
+ size);
+ if (c) {
+ c->Init(n, queries);
+ }
+ }
+
+ void BeginQueryEXT(
+ GLenum target, GLuint id, uint32 sync_data_shm_id,
+ uint32 sync_data_shm_offset) {
+ gles2::cmds::BeginQueryEXT* c = GetCmdSpace<gles2::cmds::BeginQueryEXT>();
+ if (c) {
+ c->Init(target, id, sync_data_shm_id, sync_data_shm_offset);
+ }
+ }
+
+ void EndQueryEXT(GLenum target, GLuint submit_count) {
+ gles2::cmds::EndQueryEXT* c = GetCmdSpace<gles2::cmds::EndQueryEXT>();
+ if (c) {
+ c->Init(target, submit_count);
+ }
+ }
+
+ void InsertEventMarkerEXT(GLuint bucket_id) {
+ gles2::cmds::InsertEventMarkerEXT* c =
+ GetCmdSpace<gles2::cmds::InsertEventMarkerEXT>();
+ if (c) {
+ c->Init(bucket_id);
+ }
+ }
+
+ void PushGroupMarkerEXT(GLuint bucket_id) {
+ gles2::cmds::PushGroupMarkerEXT* c =
+ GetCmdSpace<gles2::cmds::PushGroupMarkerEXT>();
+ if (c) {
+ c->Init(bucket_id);
+ }
+ }
+
+ void PopGroupMarkerEXT() {
+ gles2::cmds::PopGroupMarkerEXT* c =
+ GetCmdSpace<gles2::cmds::PopGroupMarkerEXT>();
+ if (c) {
+ c->Init();
+ }
+ }
+
+ void GenVertexArraysOES(
+ GLsizei n, uint32 arrays_shm_id, uint32 arrays_shm_offset) {
+ gles2::cmds::GenVertexArraysOES* c =
+ GetCmdSpace<gles2::cmds::GenVertexArraysOES>();
+ if (c) {
+ c->Init(n, arrays_shm_id, arrays_shm_offset);
+ }
+ }
+
+ void GenVertexArraysOESImmediate(GLsizei n, GLuint* arrays) {
+ const uint32 size =
+ gles2::cmds::GenVertexArraysOESImmediate::ComputeSize(n);
+ gles2::cmds::GenVertexArraysOESImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::GenVertexArraysOESImmediate>(
+ size);
+ if (c) {
+ c->Init(n, arrays);
+ }
+ }
+
+ void DeleteVertexArraysOES(
+ GLsizei n, uint32 arrays_shm_id, uint32 arrays_shm_offset) {
+ gles2::cmds::DeleteVertexArraysOES* c =
+ GetCmdSpace<gles2::cmds::DeleteVertexArraysOES>();
+ if (c) {
+ c->Init(n, arrays_shm_id, arrays_shm_offset);
+ }
+ }
+
+ void DeleteVertexArraysOESImmediate(GLsizei n, const GLuint* arrays) {
+ const uint32 size =
+ gles2::cmds::DeleteVertexArraysOESImmediate::ComputeSize(n);
+ gles2::cmds::DeleteVertexArraysOESImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DeleteVertexArraysOESImmediate>(size); // NOLINT
+ if (c) {
+ c->Init(n, arrays);
+ }
+ }
+
+ void IsVertexArrayOES(
+ GLuint array, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::IsVertexArrayOES* c =
+ GetCmdSpace<gles2::cmds::IsVertexArrayOES>();
+ if (c) {
+ c->Init(array, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void BindVertexArrayOES(GLuint array) {
+ gles2::cmds::BindVertexArrayOES* c =
+ GetCmdSpace<gles2::cmds::BindVertexArrayOES>();
+ if (c) {
+ c->Init(array);
+ }
+ }
+
+ void SwapBuffers() {
+ gles2::cmds::SwapBuffers* c = GetCmdSpace<gles2::cmds::SwapBuffers>();
+ if (c) {
+ c->Init();
+ }
+ }
+
+ void GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset,
+ uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::GetMaxValueInBufferCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::GetMaxValueInBufferCHROMIUM>();
+ if (c) {
+ c->Init(
+ buffer_id, count, type, offset, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, uint32 ids_shm_id,
+ uint32 ids_shm_offset) {
+ gles2::cmds::GenSharedIdsCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::GenSharedIdsCHROMIUM>();
+ if (c) {
+ c->Init(namespace_id, id_offset, n, ids_shm_id, ids_shm_offset);
+ }
+ }
+
+ void DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, uint32 ids_shm_id,
+ uint32 ids_shm_offset) {
+ gles2::cmds::DeleteSharedIdsCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::DeleteSharedIdsCHROMIUM>();
+ if (c) {
+ c->Init(namespace_id, n, ids_shm_id, ids_shm_offset);
+ }
+ }
+
+ void RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, uint32 ids_shm_id,
+ uint32 ids_shm_offset) {
+ gles2::cmds::RegisterSharedIdsCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::RegisterSharedIdsCHROMIUM>();
+ if (c) {
+ c->Init(namespace_id, n, ids_shm_id, ids_shm_offset);
+ }
+ }
+
+ void EnableFeatureCHROMIUM(
+ GLuint bucket_id, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::EnableFeatureCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::EnableFeatureCHROMIUM>();
+ if (c) {
+ c->Init(bucket_id, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) {
+ gles2::cmds::ResizeCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::ResizeCHROMIUM>();
+ if (c) {
+ c->Init(width, height, scale_factor);
+ }
+ }
+
+ void GetRequestableExtensionsCHROMIUM(uint32 bucket_id) {
+ gles2::cmds::GetRequestableExtensionsCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::GetRequestableExtensionsCHROMIUM>();
+ if (c) {
+ c->Init(bucket_id);
+ }
+ }
+
+ void RequestExtensionCHROMIUM(uint32 bucket_id) {
+ gles2::cmds::RequestExtensionCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::RequestExtensionCHROMIUM>();
+ if (c) {
+ c->Init(bucket_id);
+ }
+ }
+
+ void GetMultipleIntegervCHROMIUM(
+ uint32 pnames_shm_id, uint32 pnames_shm_offset, GLuint count,
+ uint32 results_shm_id, uint32 results_shm_offset, GLsizeiptr size) {
+ gles2::cmds::GetMultipleIntegervCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::GetMultipleIntegervCHROMIUM>();
+ if (c) {
+ c->Init(
+ pnames_shm_id, pnames_shm_offset, count, results_shm_id,
+ results_shm_offset, size);
+ }
+ }
+
+ void GetProgramInfoCHROMIUM(GLuint program, uint32 bucket_id) {
+ gles2::cmds::GetProgramInfoCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::GetProgramInfoCHROMIUM>();
+ if (c) {
+ c->Init(program, bucket_id);
+ }
+ }
+
+ void CreateStreamTextureCHROMIUM(
+ GLuint client_id, uint32 result_shm_id, uint32 result_shm_offset) {
+ gles2::cmds::CreateStreamTextureCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::CreateStreamTextureCHROMIUM>();
+ if (c) {
+ c->Init(client_id, result_shm_id, result_shm_offset);
+ }
+ }
+
+ void DestroyStreamTextureCHROMIUM(GLuint texture) {
+ gles2::cmds::DestroyStreamTextureCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::DestroyStreamTextureCHROMIUM>();
+ if (c) {
+ c->Init(texture);
+ }
+ }
+
+ void GetTranslatedShaderSourceANGLE(GLuint shader, uint32 bucket_id) {
+ gles2::cmds::GetTranslatedShaderSourceANGLE* c =
+ GetCmdSpace<gles2::cmds::GetTranslatedShaderSourceANGLE>();
+ if (c) {
+ c->Init(shader, bucket_id);
+ }
+ }
+
+ void PostSubBufferCHROMIUM(GLint x, GLint y, GLint width, GLint height) {
+ gles2::cmds::PostSubBufferCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::PostSubBufferCHROMIUM>();
+ if (c) {
+ c->Init(x, y, width, height);
+ }
+ }
+
+ void TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) {
+ gles2::cmds::TexImageIOSurface2DCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::TexImageIOSurface2DCHROMIUM>();
+ if (c) {
+ c->Init(target, width, height, ioSurfaceId, plane);
+ }
+ }
+
+ void CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) {
+ gles2::cmds::CopyTextureCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::CopyTextureCHROMIUM>();
+ if (c) {
+ c->Init(target, source_id, dest_id, level, internalformat, dest_type);
+ }
+ }
+
+ void DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
+ gles2::cmds::DrawArraysInstancedANGLE* c =
+ GetCmdSpace<gles2::cmds::DrawArraysInstancedANGLE>();
+ if (c) {
+ c->Init(mode, first, count, primcount);
+ }
+ }
+
+ void DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, GLuint index_offset,
+ GLsizei primcount) {
+ gles2::cmds::DrawElementsInstancedANGLE* c =
+ GetCmdSpace<gles2::cmds::DrawElementsInstancedANGLE>();
+ if (c) {
+ c->Init(mode, count, type, index_offset, primcount);
+ }
+ }
+
+ void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) {
+ gles2::cmds::VertexAttribDivisorANGLE* c =
+ GetCmdSpace<gles2::cmds::VertexAttribDivisorANGLE>();
+ if (c) {
+ c->Init(index, divisor);
+ }
+ }
+
+ void GenMailboxCHROMIUM(GLuint bucket_id) {
+ gles2::cmds::GenMailboxCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::GenMailboxCHROMIUM>();
+ if (c) {
+ c->Init(bucket_id);
+ }
+ }
+
+ void ProduceTextureCHROMIUM(
+ GLenum target, uint32 mailbox_shm_id, uint32 mailbox_shm_offset) {
+ gles2::cmds::ProduceTextureCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::ProduceTextureCHROMIUM>();
+ if (c) {
+ c->Init(target, mailbox_shm_id, mailbox_shm_offset);
+ }
+ }
+
+ void ProduceTextureCHROMIUMImmediate(GLenum target, const GLbyte* mailbox) {
+ const uint32 size =
+ gles2::cmds::ProduceTextureCHROMIUMImmediate::ComputeSize();
+ gles2::cmds::ProduceTextureCHROMIUMImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::ProduceTextureCHROMIUMImmediate>(size); // NOLINT
+ if (c) {
+ c->Init(target, mailbox);
+ }
+ }
+
+ void ConsumeTextureCHROMIUM(
+ GLenum target, uint32 mailbox_shm_id, uint32 mailbox_shm_offset) {
+ gles2::cmds::ConsumeTextureCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::ConsumeTextureCHROMIUM>();
+ if (c) {
+ c->Init(target, mailbox_shm_id, mailbox_shm_offset);
+ }
+ }
+
+ void ConsumeTextureCHROMIUMImmediate(GLenum target, const GLbyte* mailbox) {
+ const uint32 size =
+ gles2::cmds::ConsumeTextureCHROMIUMImmediate::ComputeSize();
+ gles2::cmds::ConsumeTextureCHROMIUMImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::ConsumeTextureCHROMIUMImmediate>(size); // NOLINT
+ if (c) {
+ c->Init(target, mailbox);
+ }
+ }
+
+ void BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, uint32 name_shm_id,
+ uint32 name_shm_offset, uint32 data_size) {
+ gles2::cmds::BindUniformLocationCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::BindUniformLocationCHROMIUM>();
+ if (c) {
+ c->Init(program, location, name_shm_id, name_shm_offset, data_size);
+ }
+ }
+
+ void BindUniformLocationCHROMIUMImmediate(
+ GLuint program, GLint location, const char* name) {
+ const uint32 data_size = strlen(name);
+ gles2::cmds::BindUniformLocationCHROMIUMImmediate* c =
+ GetImmediateCmdSpace<gles2::cmds::BindUniformLocationCHROMIUMImmediate>(
+ data_size);
+ if (c) {
+ c->Init(program, location, name, data_size);
+ }
+ }
+
+ void BindUniformLocationCHROMIUMBucket(
+ GLuint program, GLint location, uint32 name_bucket_id) {
+ gles2::cmds::BindUniformLocationCHROMIUMBucket* c =
+ GetCmdSpace<gles2::cmds::BindUniformLocationCHROMIUMBucket>();
+ if (c) {
+ c->Init(program, location, name_bucket_id);
+ }
+ }
+
+ void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
+ gles2::cmds::BindTexImage2DCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::BindTexImage2DCHROMIUM>();
+ if (c) {
+ c->Init(target, imageId);
+ }
+ }
+
+ void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) {
+ gles2::cmds::ReleaseTexImage2DCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::ReleaseTexImage2DCHROMIUM>();
+ if (c) {
+ c->Init(target, imageId);
+ }
+ }
+
+ void TraceBeginCHROMIUM(GLuint bucket_id) {
+ gles2::cmds::TraceBeginCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::TraceBeginCHROMIUM>();
+ if (c) {
+ c->Init(bucket_id);
+ }
+ }
+
+ void TraceEndCHROMIUM() {
+ gles2::cmds::TraceEndCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::TraceEndCHROMIUM>();
+ if (c) {
+ c->Init();
+ }
+ }
+
+ void AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, uint32 data_shm_id,
+ uint32 data_shm_offset) {
+ gles2::cmds::AsyncTexSubImage2DCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::AsyncTexSubImage2DCHROMIUM>();
+ if (c) {
+ c->Init(
+ target, level, xoffset, yoffset, width, height, format, type,
+ data_shm_id, data_shm_offset);
+ }
+ }
+
+ void AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ uint32 pixels_shm_id, uint32 pixels_shm_offset) {
+ gles2::cmds::AsyncTexImage2DCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::AsyncTexImage2DCHROMIUM>();
+ if (c) {
+ c->Init(
+ target, level, internalformat, width, height, border, format, type,
+ pixels_shm_id, pixels_shm_offset);
+ }
+ }
+
+ void WaitAsyncTexImage2DCHROMIUM(GLenum target) {
+ gles2::cmds::WaitAsyncTexImage2DCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::WaitAsyncTexImage2DCHROMIUM>();
+ if (c) {
+ c->Init(target);
+ }
+ }
+
+ void DiscardFramebufferEXT(
+ GLenum target, GLsizei count, uint32 attachments_shm_id,
+ uint32 attachments_shm_offset) {
+ gles2::cmds::DiscardFramebufferEXT* c =
+ GetCmdSpace<gles2::cmds::DiscardFramebufferEXT>();
+ if (c) {
+ c->Init(target, count, attachments_shm_id, attachments_shm_offset);
+ }
+ }
+
+ void DiscardFramebufferEXTImmediate(
+ GLenum target, GLsizei count, const GLenum* attachments) {
+ const uint32 size =
+ gles2::cmds::DiscardFramebufferEXTImmediate::ComputeSize(count);
+ gles2::cmds::DiscardFramebufferEXTImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DiscardFramebufferEXTImmediate>(size); // NOLINT
+ if (c) {
+ c->Init(target, count, attachments);
+ }
+ }
+
+ void LoseContextCHROMIUM(GLenum current, GLenum other) {
+ gles2::cmds::LoseContextCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::LoseContextCHROMIUM>();
+ if (c) {
+ c->Init(current, other);
+ }
+ }
+
+ void WaitSyncPointCHROMIUM(GLuint sync_point) {
+ gles2::cmds::WaitSyncPointCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::WaitSyncPointCHROMIUM>();
+ if (c) {
+ c->Init(sync_point);
+ }
+ }
+
+ void DrawBuffersEXT(
+ GLsizei count, uint32 bufs_shm_id, uint32 bufs_shm_offset) {
+ gles2::cmds::DrawBuffersEXT* c =
+ GetCmdSpace<gles2::cmds::DrawBuffersEXT>();
+ if (c) {
+ c->Init(count, bufs_shm_id, bufs_shm_offset);
+ }
+ }
+
+ void DrawBuffersEXTImmediate(GLsizei count, const GLenum* bufs) {
+ const uint32 size =
+ gles2::cmds::DrawBuffersEXTImmediate::ComputeSize(count);
+ gles2::cmds::DrawBuffersEXTImmediate* c =
+ GetImmediateCmdSpaceTotalSize<gles2::cmds::DrawBuffersEXTImmediate>(
+ size);
+ if (c) {
+ c->Init(count, bufs);
+ }
+ }
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_impl_export.h b/chromium/gpu/command_buffer/client/gles2_impl_export.h
new file mode 100644
index 00000000000..ee63565da01
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_impl_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPL_EXPORT_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPL_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(GLES2_IMPL_IMPLEMENTATION)
+#define GLES2_IMPL_EXPORT __declspec(dllexport)
+#else
+#define GLES2_IMPL_EXPORT __declspec(dllimport)
+#endif // defined(GLES2_IMPL_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(GLES2_IMPL_IMPLEMENTATION)
+#define GLES2_IMPL_EXPORT __attribute__((visibility("default")))
+#else
+#define GLES2_IMPL_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define GLES2_IMPL_EXPORT
+#endif
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPL_EXPORT_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation.cc b/chromium/gpu/command_buffer/client/gles2_implementation.cc
new file mode 100644
index 00000000000..9285b6d82ef
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_implementation.cc
@@ -0,0 +1,3831 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A class to emulate GLES2 over command buffers.
+
+#include "gpu/command_buffer/client/gles2_implementation.h"
+
+#include <algorithm>
+#include <map>
+#include <queue>
+#include <set>
+#include <limits>
+#include <stdio.h>
+#include <string.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+#include "gpu/command_buffer/client/buffer_tracker.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
+#include "gpu/command_buffer/client/program_info_manager.h"
+#include "gpu/command_buffer/client/query_tracker.h"
+#include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/command_buffer/client/vertex_array_object_manager.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/common/trace_event.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+#if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+#define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
+#endif
+
+#if defined(GPU_CLIENT_DEBUG)
+#include "ui/gl/gl_switches.h"
+#include "base/command_line.h"
+#endif
+
+namespace gpu {
+namespace gles2 {
+
+// A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
+static GLuint ToGLuint(const void* ptr) {
+ return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
+}
+
+#if !defined(_MSC_VER)
+const size_t GLES2Implementation::kMaxSizeOfSimpleResult;
+const unsigned int GLES2Implementation::kStartingOffset;
+#endif
+
+GLES2Implementation::GLStaticState::GLStaticState() {
+}
+
+GLES2Implementation::GLStaticState::~GLStaticState() {
+}
+
+GLES2Implementation::GLStaticState::IntState::IntState()
+ : max_combined_texture_image_units(0),
+ max_cube_map_texture_size(0),
+ max_fragment_uniform_vectors(0),
+ max_renderbuffer_size(0),
+ max_texture_image_units(0),
+ max_texture_size(0),
+ max_varying_vectors(0),
+ max_vertex_attribs(0),
+ max_vertex_texture_image_units(0),
+ max_vertex_uniform_vectors(0),
+ num_compressed_texture_formats(0),
+ num_shader_binary_formats(0) {
+}
+
+GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
+ GLES2Implementation* gles2_implementation)
+ : gles2_implementation_(gles2_implementation) {
+ GPU_CHECK_EQ(0, gles2_implementation_->use_count_);
+ ++gles2_implementation_->use_count_;
+}
+
+GLES2Implementation::SingleThreadChecker::~SingleThreadChecker() {
+ --gles2_implementation_->use_count_;
+ GPU_CHECK_EQ(0, gles2_implementation_->use_count_);
+}
+
+GLES2Implementation::GLES2Implementation(
+ GLES2CmdHelper* helper,
+ ShareGroup* share_group,
+ TransferBufferInterface* transfer_buffer,
+ bool bind_generates_resource,
+ ImageFactory* image_factory)
+ : helper_(helper),
+ transfer_buffer_(transfer_buffer),
+ angle_pack_reverse_row_order_status_(kUnknownExtensionStatus),
+ chromium_framebuffer_multisample_(kUnknownExtensionStatus),
+ pack_alignment_(4),
+ unpack_alignment_(4),
+ unpack_flip_y_(false),
+ unpack_row_length_(0),
+ unpack_skip_rows_(0),
+ unpack_skip_pixels_(0),
+ pack_reverse_row_order_(false),
+ active_texture_unit_(0),
+ bound_framebuffer_(0),
+ bound_read_framebuffer_(0),
+ bound_renderbuffer_(0),
+ current_program_(0),
+ bound_array_buffer_id_(0),
+ bound_pixel_pack_transfer_buffer_id_(0),
+ bound_pixel_unpack_transfer_buffer_id_(0),
+ error_bits_(0),
+ debug_(false),
+ use_count_(0),
+ current_query_(NULL),
+ error_message_callback_(NULL),
+ image_factory_(image_factory) {
+ GPU_DCHECK(helper);
+ GPU_DCHECK(transfer_buffer);
+
+ char temp[128];
+ sprintf(temp, "%p", static_cast<void*>(this));
+ this_in_hex_ = std::string(temp);
+
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUClientLogging);
+ });
+
+ share_group_ =
+ (share_group ? share_group : new ShareGroup(bind_generates_resource));
+
+ memset(&reserved_ids_, 0, sizeof(reserved_ids_));
+}
+
+bool GLES2Implementation::Initialize(
+ unsigned int starting_transfer_buffer_size,
+ unsigned int min_transfer_buffer_size,
+ unsigned int max_transfer_buffer_size) {
+ GPU_DCHECK_GE(starting_transfer_buffer_size, min_transfer_buffer_size);
+ GPU_DCHECK_LE(starting_transfer_buffer_size, max_transfer_buffer_size);
+ GPU_DCHECK_GE(min_transfer_buffer_size, kStartingOffset);
+
+ if (!transfer_buffer_->Initialize(
+ starting_transfer_buffer_size,
+ kStartingOffset,
+ min_transfer_buffer_size,
+ max_transfer_buffer_size,
+ kAlignment,
+ kSizeToFlush)) {
+ return false;
+ }
+
+ mapped_memory_.reset(new MappedMemoryManager(helper_));
+ SetSharedMemoryChunkSizeMultiple(1024 * 1024 * 2);
+
+ if (!QueryAndCacheStaticState())
+ return false;
+
+ util_.set_num_compressed_texture_formats(
+ static_state_.int_state.num_compressed_texture_formats);
+ util_.set_num_shader_binary_formats(
+ static_state_.int_state.num_shader_binary_formats);
+
+ texture_units_.reset(
+ new TextureUnit[
+ static_state_.int_state.max_combined_texture_image_units]);
+
+ query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
+ buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
+ gpu_memory_buffer_tracker_.reset(new GpuMemoryBufferTracker(image_factory_));
+
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ GetIdHandler(id_namespaces::kBuffers)->MakeIds(
+ this, kClientSideArrayId, arraysize(reserved_ids_), &reserved_ids_[0]);
+#endif
+
+ vertex_array_object_manager_.reset(new VertexArrayObjectManager(
+ static_state_.int_state.max_vertex_attribs,
+ reserved_ids_[0],
+ reserved_ids_[1]));
+
+ return true;
+}
+
+bool GLES2Implementation::QueryAndCacheStaticState() {
+ // Setup query for multiple GetIntegerv's
+ static const GLenum pnames[] = {
+ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
+ GL_MAX_CUBE_MAP_TEXTURE_SIZE,
+ GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+ GL_MAX_RENDERBUFFER_SIZE,
+ GL_MAX_TEXTURE_IMAGE_UNITS,
+ GL_MAX_TEXTURE_SIZE,
+ GL_MAX_VARYING_VECTORS,
+ GL_MAX_VERTEX_ATTRIBS,
+ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+ GL_MAX_VERTEX_UNIFORM_VECTORS,
+ GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+ GL_NUM_SHADER_BINARY_FORMATS,
+ };
+
+ GetMultipleIntegervState integerv_state(
+ pnames, arraysize(pnames),
+ &static_state_.int_state.max_combined_texture_image_units,
+ sizeof(static_state_.int_state));
+ if (!GetMultipleIntegervSetup(&integerv_state)) {
+ return false;
+ }
+
+ // Setup query for multiple GetShaderPrecisionFormat's
+ static const GLenum precision_params[][2] = {
+ { GL_VERTEX_SHADER, GL_LOW_INT },
+ { GL_VERTEX_SHADER, GL_MEDIUM_INT },
+ { GL_VERTEX_SHADER, GL_HIGH_INT },
+ { GL_VERTEX_SHADER, GL_LOW_FLOAT },
+ { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
+ { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
+ { GL_FRAGMENT_SHADER, GL_LOW_INT },
+ { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
+ { GL_FRAGMENT_SHADER, GL_HIGH_INT },
+ { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
+ { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
+ { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
+ };
+
+ GetAllShaderPrecisionFormatsState precision_state(
+ precision_params, arraysize(precision_params));
+ GetAllShaderPrecisionFormatsSetup(&precision_state);
+
+ // Allocate and partition transfer buffer for all requests
+ void* buffer = transfer_buffer_->Alloc(
+ integerv_state.transfer_buffer_size_needed +
+ precision_state.transfer_buffer_size_needed);
+ if (!buffer) {
+ SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
+ "Transfer buffer allocation failed.");
+ return false;
+ }
+ integerv_state.buffer = buffer;
+ precision_state.results_buffer =
+ static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
+
+ // Make all the requests and wait once for all the results.
+ GetMultipleIntegervRequest(&integerv_state);
+ GetAllShaderPrecisionFormatsRequest(&precision_state);
+ WaitForCmd();
+ GetMultipleIntegervOnCompleted(&integerv_state);
+ GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
+
+ // TODO(gman): We should be able to free without a token.
+ transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
+ CheckGLError();
+
+ return true;
+}
+
+GLES2Implementation::~GLES2Implementation() {
+ // Make sure the queries are finished otherwise we'll delete the
+ // shared memory (mapped_memory_) which will free the memory used
+ // by the queries. The GPU process when validating that memory is still
+ // shared will fail and abort (ie, it will stop running).
+ WaitForCmd();
+ query_tracker_.reset();
+
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ DeleteBuffers(arraysize(reserved_ids_), &reserved_ids_[0]);
+#endif
+ buffer_tracker_.reset();
+
+ // Make sure the commands make it the service.
+ WaitForCmd();
+}
+
+GLES2CmdHelper* GLES2Implementation::helper() const {
+ return helper_;
+}
+
+IdHandlerInterface* GLES2Implementation::GetIdHandler(int namespace_id) const {
+ return share_group_->GetIdHandler(namespace_id);
+}
+
+void* GLES2Implementation::GetResultBuffer() {
+ return transfer_buffer_->GetResultBuffer();
+}
+
+int32 GLES2Implementation::GetResultShmId() {
+ return transfer_buffer_->GetShmId();
+}
+
+uint32 GLES2Implementation::GetResultShmOffset() {
+ return transfer_buffer_->GetResultOffset();
+}
+
+void GLES2Implementation::SetSharedMemoryChunkSizeMultiple(
+ unsigned int multiple) {
+ mapped_memory_->set_chunk_size_multiple(multiple);
+}
+
+void GLES2Implementation::FreeUnusedSharedMemory() {
+ mapped_memory_->FreeUnused();
+}
+
+void GLES2Implementation::FreeEverything() {
+ WaitForCmd();
+ query_tracker_->Shrink();
+ FreeUnusedSharedMemory();
+ transfer_buffer_->Free();
+ helper_->FreeRingBuffer();
+}
+
+void GLES2Implementation::WaitForCmd() {
+ TRACE_EVENT0("gpu", "GLES2::WaitForCmd");
+ helper_->CommandBufferHelper::Finish();
+}
+
+bool GLES2Implementation::IsExtensionAvailable(const char* ext) {
+ const char* extensions =
+ reinterpret_cast<const char*>(GetStringHelper(GL_EXTENSIONS));
+ if (!extensions)
+ return false;
+
+ int length = strlen(ext);
+ while (true) {
+ int n = strcspn(extensions, " ");
+ if (n == length && 0 == strncmp(ext, extensions, length)) {
+ return true;
+ }
+ if ('\0' == extensions[n]) {
+ return false;
+ }
+ extensions += n + 1;
+ }
+}
+
+bool GLES2Implementation::IsExtensionAvailableHelper(
+ const char* extension, ExtensionStatus* status) {
+ switch (*status) {
+ case kAvailableExtensionStatus:
+ return true;
+ case kUnavailableExtensionStatus:
+ return false;
+ default: {
+ bool available = IsExtensionAvailable(extension);
+ *status = available ? kAvailableExtensionStatus :
+ kUnavailableExtensionStatus;
+ return available;
+ }
+ }
+}
+
+bool GLES2Implementation::IsAnglePackReverseRowOrderAvailable() {
+ return IsExtensionAvailableHelper(
+ "GL_ANGLE_pack_reverse_row_order",
+ &angle_pack_reverse_row_order_status_);
+}
+
+bool GLES2Implementation::IsChromiumFramebufferMultisampleAvailable() {
+ return IsExtensionAvailableHelper(
+ "GL_CHROMIUM_framebuffer_multisample",
+ &chromium_framebuffer_multisample_);
+}
+
+const std::string& GLES2Implementation::GetLogPrefix() const {
+ const std::string& prefix(debug_marker_manager_.GetMarker());
+ return prefix.empty() ? this_in_hex_ : prefix;
+}
+
+GLenum GLES2Implementation::GetError() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetError()");
+ GLenum err = GetGLError();
+ GPU_CLIENT_LOG("returned " << GLES2Util::GetStringError(err));
+ return err;
+}
+
+GLenum GLES2Implementation::GetClientSideGLError() {
+ if (error_bits_ == 0) {
+ return GL_NO_ERROR;
+ }
+
+ GLenum error = GL_NO_ERROR;
+ for (uint32 mask = 1; mask != 0; mask = mask << 1) {
+ if ((error_bits_ & mask) != 0) {
+ error = GLES2Util::GLErrorBitToGLError(mask);
+ break;
+ }
+ }
+ error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
+ return error;
+}
+
+GLenum GLES2Implementation::GetGLError() {
+ TRACE_EVENT0("gpu", "GLES2::GetGLError");
+ // Check the GL error first, then our wrapped error.
+ typedef cmds::GetError::Result Result;
+ Result* result = GetResultAs<Result*>();
+ // If we couldn't allocate a result the context is lost.
+ if (!result) {
+ return GL_NO_ERROR;
+ }
+ *result = GL_NO_ERROR;
+ helper_->GetError(GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLenum error = *result;
+ if (error == GL_NO_ERROR) {
+ error = GetClientSideGLError();
+ } else {
+ // There was an error, clear the corresponding wrapped error.
+ error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
+ }
+ return error;
+}
+
+#if defined(GL_CLIENT_FAIL_GL_ERRORS)
+void GLES2Implementation::FailGLError(GLenum error) {
+ if (error != GL_NO_ERROR) {
+ GPU_NOTREACHED() << "Error";
+ }
+}
+// NOTE: Calling GetGLError overwrites data in the result buffer.
+void GLES2Implementation::CheckGLError() {
+ FailGLError(GetGLError());
+}
+#endif // defined(GPU_CLIENT_FAIL_GL_ERRORS)
+
+void GLES2Implementation::SetGLError(
+ GLenum error, const char* function_name, const char* msg) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] Client Synthesized Error: "
+ << GLES2Util::GetStringError(error) << ": "
+ << function_name << ": " << msg);
+ FailGLError(error);
+ if (msg) {
+ last_error_ = msg;
+ }
+ if (error_message_callback_) {
+ std::string temp(GLES2Util::GetStringError(error) + " : " +
+ function_name + ": " + (msg ? msg : ""));
+ error_message_callback_->OnErrorMessage(temp.c_str(), 0);
+ }
+ error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
+}
+
+void GLES2Implementation::SetGLErrorInvalidEnum(
+ const char* function_name, GLenum value, const char* label) {
+ SetGLError(GL_INVALID_ENUM, function_name,
+ (std::string(label) + " was " +
+ GLES2Util::GetStringEnum(value)).c_str());
+}
+
+bool GLES2Implementation::GetBucketContents(uint32 bucket_id,
+ std::vector<int8>* data) {
+ TRACE_EVENT0("gpu", "GLES2::GetBucketContents");
+ GPU_DCHECK(data);
+ const uint32 kStartSize = 32 * 1024;
+ ScopedTransferBufferPtr buffer(kStartSize, helper_, transfer_buffer_);
+ if (!buffer.valid()) {
+ return false;
+ }
+ typedef cmd::GetBucketStart::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return false;
+ }
+ *result = 0;
+ helper_->GetBucketStart(
+ bucket_id, GetResultShmId(), GetResultShmOffset(),
+ buffer.size(), buffer.shm_id(), buffer.offset());
+ WaitForCmd();
+ uint32 size = *result;
+ data->resize(size);
+ if (size > 0u) {
+ uint32 offset = 0;
+ while (size) {
+ if (!buffer.valid()) {
+ buffer.Reset(size);
+ if (!buffer.valid()) {
+ return false;
+ }
+ helper_->GetBucketData(
+ bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
+ WaitForCmd();
+ }
+ uint32 size_to_copy = std::min(size, buffer.size());
+ memcpy(&(*data)[offset], buffer.address(), size_to_copy);
+ offset += size_to_copy;
+ size -= size_to_copy;
+ buffer.Release();
+ };
+ // Free the bucket. This is not required but it does free up the memory.
+ // and we don't have to wait for the result so from the client's perspective
+ // it's cheap.
+ helper_->SetBucketSize(bucket_id, 0);
+ }
+ return true;
+}
+
+void GLES2Implementation::SetBucketContents(
+ uint32 bucket_id, const void* data, size_t size) {
+ GPU_DCHECK(data);
+ helper_->SetBucketSize(bucket_id, size);
+ if (size > 0u) {
+ uint32 offset = 0;
+ while (size) {
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
+ if (!buffer.valid()) {
+ return;
+ }
+ memcpy(buffer.address(), static_cast<const int8*>(data) + offset,
+ buffer.size());
+ helper_->SetBucketData(
+ bucket_id, offset, buffer.size(), buffer.shm_id(), buffer.offset());
+ offset += buffer.size();
+ size -= buffer.size();
+ }
+ }
+}
+
+void GLES2Implementation::SetBucketAsCString(
+ uint32 bucket_id, const char* str) {
+ // NOTE: strings are passed NULL terminated. That means the empty
+ // string will have a size of 1 and no-string will have a size of 0
+ if (str) {
+ SetBucketContents(bucket_id, str, strlen(str) + 1);
+ } else {
+ helper_->SetBucketSize(bucket_id, 0);
+ }
+}
+
+bool GLES2Implementation::GetBucketAsString(
+ uint32 bucket_id, std::string* str) {
+ GPU_DCHECK(str);
+ std::vector<int8> data;
+ // NOTE: strings are passed NULL terminated. That means the empty
+ // string will have a size of 1 and no-string will have a size of 0
+ if (!GetBucketContents(bucket_id, &data)) {
+ return false;
+ }
+ if (data.empty()) {
+ return false;
+ }
+ str->assign(&data[0], &data[0] + data.size() - 1);
+ return true;
+}
+
+void GLES2Implementation::SetBucketAsString(
+ uint32 bucket_id, const std::string& str) {
+ // NOTE: strings are passed NULL terminated. That means the empty
+ // string will have a size of 1 and no-string will have a size of 0
+ SetBucketContents(bucket_id, str.c_str(), str.size() + 1);
+}
+
+void GLES2Implementation::Disable(GLenum cap) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDisable("
+ << GLES2Util::GetStringCapability(cap) << ")");
+ bool changed = false;
+ if (!state_.SetCapabilityState(cap, false, &changed) || changed) {
+ helper_->Disable(cap);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::Enable(GLenum cap) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnable("
+ << GLES2Util::GetStringCapability(cap) << ")");
+ bool changed = false;
+ if (!state_.SetCapabilityState(cap, true, &changed) || changed) {
+ helper_->Enable(cap);
+ }
+ CheckGLError();
+}
+
+GLboolean GLES2Implementation::IsEnabled(GLenum cap) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsEnabled("
+ << GLES2Util::GetStringCapability(cap) << ")");
+ bool state = false;
+ if (!state_.GetEnabled(cap, &state)) {
+ typedef cmds::IsEnabled::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsEnabled(cap, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ state = (*result) != 0;
+ }
+
+ GPU_CLIENT_LOG("returned " << state);
+ CheckGLError();
+ return state;
+}
+
+bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
+ switch (pname) {
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ *params = static_state_.int_state.max_combined_texture_image_units;
+ return true;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
+ *params = static_state_.int_state.max_cube_map_texture_size;
+ return true;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+ *params = static_state_.int_state.max_fragment_uniform_vectors;
+ return true;
+ case GL_MAX_RENDERBUFFER_SIZE:
+ *params = static_state_.int_state.max_renderbuffer_size;
+ return true;
+ case GL_MAX_TEXTURE_IMAGE_UNITS:
+ *params = static_state_.int_state.max_texture_image_units;
+ return true;
+ case GL_MAX_TEXTURE_SIZE:
+ *params = static_state_.int_state.max_texture_size;
+ return true;
+ case GL_MAX_VARYING_VECTORS:
+ *params = static_state_.int_state.max_varying_vectors;
+ return true;
+ case GL_MAX_VERTEX_ATTRIBS:
+ *params = static_state_.int_state.max_vertex_attribs;
+ return true;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+ *params = static_state_.int_state.max_vertex_texture_image_units;
+ return true;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS:
+ *params = static_state_.int_state.max_vertex_uniform_vectors;
+ return true;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ *params = static_state_.int_state.num_compressed_texture_formats;
+ return true;
+ case GL_NUM_SHADER_BINARY_FORMATS:
+ *params = static_state_.int_state.num_shader_binary_formats;
+ return true;
+ case GL_ARRAY_BUFFER_BINDING:
+ if (share_group_->bind_generates_resource()) {
+ *params = bound_array_buffer_id_;
+ return true;
+ }
+ return false;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+ if (share_group_->bind_generates_resource()) {
+ *params =
+ vertex_array_object_manager_->bound_element_array_buffer();
+ return true;
+ }
+ return false;
+ case GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
+ *params = bound_pixel_pack_transfer_buffer_id_;
+ return true;
+ case GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM:
+ *params = bound_pixel_unpack_transfer_buffer_id_;
+ return true;
+ case GL_ACTIVE_TEXTURE:
+ *params = active_texture_unit_ + GL_TEXTURE0;
+ return true;
+ case GL_TEXTURE_BINDING_2D:
+ if (share_group_->bind_generates_resource()) {
+ *params = texture_units_[active_texture_unit_].bound_texture_2d;
+ return true;
+ }
+ return false;
+ case GL_TEXTURE_BINDING_CUBE_MAP:
+ if (share_group_->bind_generates_resource()) {
+ *params = texture_units_[active_texture_unit_].bound_texture_cube_map;
+ return true;
+ }
+ return false;
+ case GL_FRAMEBUFFER_BINDING:
+ if (share_group_->bind_generates_resource()) {
+ *params = bound_framebuffer_;
+ return true;
+ }
+ return false;
+ case GL_READ_FRAMEBUFFER_BINDING:
+ if (IsChromiumFramebufferMultisampleAvailable() &&
+ share_group_->bind_generates_resource()) {
+ *params = bound_read_framebuffer_;
+ return true;
+ }
+ return false;
+ case GL_RENDERBUFFER_BINDING:
+ if (share_group_->bind_generates_resource()) {
+ *params = bound_renderbuffer_;
+ return true;
+ }
+ return false;
+ default:
+ return false;
+ }
+}
+
+bool GLES2Implementation::GetBooleanvHelper(GLenum pname, GLboolean* params) {
+ // TODO(gman): Make this handle pnames that return more than 1 value.
+ GLint value;
+ if (!GetHelper(pname, &value)) {
+ return false;
+ }
+ *params = static_cast<GLboolean>(value);
+ return true;
+}
+
+bool GLES2Implementation::GetFloatvHelper(GLenum pname, GLfloat* params) {
+ // TODO(gman): Make this handle pnames that return more than 1 value.
+ GLint value;
+ if (!GetHelper(pname, &value)) {
+ return false;
+ }
+ *params = static_cast<GLfloat>(value);
+ return true;
+}
+
+bool GLES2Implementation::GetIntegervHelper(GLenum pname, GLint* params) {
+ return GetHelper(pname, params);
+}
+
+GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUMHelper(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
+ typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return 0;
+ }
+ *result = 0;
+ helper_->GetMaxValueInBufferCHROMIUM(
+ buffer_id, count, type, offset, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ return *result;
+}
+
+GLuint GLES2Implementation::GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMaxValueInBufferCHROMIUM("
+ << buffer_id << ", " << count << ", "
+ << GLES2Util::GetStringGetMaxIndexType(type)
+ << ", " << offset << ")");
+ GLuint result = GetMaxValueInBufferCHROMIUMHelper(
+ buffer_id, count, type, offset);
+ GPU_CLIENT_LOG("returned " << result);
+ CheckGLError();
+ return result;
+}
+
+void GLES2Implementation::RestoreElementAndArrayBuffers(bool restore) {
+ if (restore) {
+ RestoreArrayBuffer(restore);
+ // Restore the element array binding.
+ // We only need to restore it if it wasn't a client side array.
+ if (vertex_array_object_manager_->bound_element_array_buffer() == 0) {
+ helper_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ }
+}
+
+void GLES2Implementation::RestoreArrayBuffer(bool restore) {
+ if (restore) {
+ // Restore the user's current binding.
+ helper_->BindBuffer(GL_ARRAY_BUFFER, bound_array_buffer_id_);
+ }
+}
+
+void GLES2Implementation::DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElements("
+ << GLES2Util::GetStringDrawMode(mode) << ", "
+ << count << ", "
+ << GLES2Util::GetStringIndexType(type) << ", "
+ << static_cast<const void*>(indices) << ")");
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawElements", "count less than 0.");
+ return;
+ }
+ if (count == 0) {
+ return;
+ }
+ GLuint offset = 0;
+ bool simulated = false;
+ if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
+ "glDrawElements", this, helper_, count, type, 0, indices,
+ &offset, &simulated)) {
+ return;
+ }
+ helper_->DrawElements(mode, count, type, offset);
+ RestoreElementAndArrayBuffers(simulated);
+ CheckGLError();
+}
+
+void GLES2Implementation::Flush() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFlush()");
+ // Insert the cmd to call glFlush
+ helper_->Flush();
+ // Flush our command buffer
+ // (tell the service to execute up to the flush cmd.)
+ helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::ShallowFlushCHROMIUM() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShallowFlushCHROMIUM()");
+ // Flush our command buffer
+ // (tell the service to execute up to the flush cmd.)
+ helper_->CommandBufferHelper::Flush();
+}
+
+void GLES2Implementation::Finish() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ FinishHelper();
+}
+
+void GLES2Implementation::ShallowFinishCHROMIUM() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ // Flush our command buffer (tell the service to execute up to the flush cmd
+ // and don't return until it completes).
+ helper_->CommandBufferHelper::Finish();
+}
+
+bool GLES2Implementation::MustBeContextLost() {
+ bool context_lost = helper_->IsContextLost();
+ if (!context_lost) {
+ WaitForCmd();
+ context_lost = helper_->IsContextLost();
+ }
+ GPU_CHECK(context_lost);
+ return context_lost;
+}
+
+void GLES2Implementation::FinishHelper() {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFinish()");
+ TRACE_EVENT0("gpu", "GLES2::Finish");
+ // Insert the cmd to call glFinish
+ helper_->Finish();
+ // Finish our command buffer
+ // (tell the service to execute up to the Finish cmd and wait for it to
+ // execute.)
+ helper_->CommandBufferHelper::Finish();
+}
+
+void GLES2Implementation::SwapBuffers() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSwapBuffers()");
+ // TODO(piman): Strictly speaking we'd want to insert the token after the
+ // swap, but the state update with the updated token might not have happened
+ // by the time the SwapBuffer callback gets called, forcing us to synchronize
+ // with the GPU process more than needed. So instead, make it happen before.
+ // All it means is that we could be slightly looser on the kMaxSwapBuffers
+ // semantics if the client doesn't use the callback mechanism, and by chance
+ // the scheduler yields between the InsertToken and the SwapBuffers.
+ swap_buffers_tokens_.push(helper_->InsertToken());
+ helper_->SwapBuffers();
+ helper_->CommandBufferHelper::Flush();
+ // Wait if we added too many swap buffers. Add 1 to kMaxSwapBuffers to
+ // compensate for TODO above.
+ if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
+ helper_->WaitForToken(swap_buffers_tokens_.front());
+ swap_buffers_tokens_.pop();
+ }
+}
+
+void GLES2Implementation::GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenSharedIdsCHROMIUM("
+ << namespace_id << ", " << id_offset << ", " << n << ", " <<
+ static_cast<void*>(ids) << ")");
+ TRACE_EVENT0("gpu", "GLES2::GenSharedIdsCHROMIUM");
+ GLsizei num = n;
+ GLuint* dst = ids;
+ while (num) {
+ ScopedTransferBufferArray<GLint> id_buffer(num, helper_, transfer_buffer_);
+ if (!id_buffer.valid()) {
+ return;
+ }
+ helper_->GenSharedIdsCHROMIUM(
+ namespace_id, id_offset, id_buffer.num_elements(),
+ id_buffer.shm_id(), id_buffer.offset());
+ WaitForCmd();
+ memcpy(dst, id_buffer.address(), sizeof(*dst) * id_buffer.num_elements());
+ num -= id_buffer.num_elements();
+ dst += id_buffer.num_elements();
+ }
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
+ }
+ });
+}
+
+void GLES2Implementation::DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteSharedIdsCHROMIUM("
+ << namespace_id << ", " << n << ", "
+ << static_cast<const void*>(ids) << ")");
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
+ }
+ });
+ TRACE_EVENT0("gpu", "GLES2::DeleteSharedIdsCHROMIUM");
+ while (n) {
+ ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
+ if (!id_buffer.valid()) {
+ return;
+ }
+ memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
+ helper_->DeleteSharedIdsCHROMIUM(
+ namespace_id, id_buffer.num_elements(),
+ id_buffer.shm_id(), id_buffer.offset());
+ WaitForCmd();
+ n -= id_buffer.num_elements();
+ ids += id_buffer.num_elements();
+ }
+}
+
+void GLES2Implementation::RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRegisterSharedIdsCHROMIUM("
+ << namespace_id << ", " << n << ", "
+ << static_cast<const void*>(ids) << ")");
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << namespace_id << ", " << ids[i]);
+ }
+ });
+ TRACE_EVENT0("gpu", "GLES2::RegisterSharedIdsCHROMIUM");
+ while (n) {
+ ScopedTransferBufferArray<GLint> id_buffer(n, helper_, transfer_buffer_);
+ if (!id_buffer.valid()) {
+ return;
+ }
+ memcpy(id_buffer.address(), ids, sizeof(*ids) * id_buffer.num_elements());
+ helper_->RegisterSharedIdsCHROMIUM(
+ namespace_id, id_buffer.num_elements(),
+ id_buffer.shm_id(), id_buffer.offset());
+ WaitForCmd();
+ n -= id_buffer.num_elements();
+ ids += id_buffer.num_elements();
+ }
+}
+
+void GLES2Implementation::BindAttribLocation(
+ GLuint program, GLuint index, const char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindAttribLocation("
+ << program << ", " << index << ", " << name << ")");
+ SetBucketAsString(kResultBucketId, name);
+ helper_->BindAttribLocationBucket(program, index, kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+ CheckGLError();
+}
+
+void GLES2Implementation::BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindUniformLocationCHROMIUM("
+ << program << ", " << location << ", " << name << ")");
+ SetBucketAsString(kResultBucketId, name);
+ helper_->BindUniformLocationCHROMIUMBucket(
+ program, location, kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+ CheckGLError();
+}
+
+void GLES2Implementation::GetVertexAttribPointerv(
+ GLuint index, GLenum pname, void** ptr) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribPointer("
+ << index << ", " << GLES2Util::GetStringVertexPointer(pname) << ", "
+ << static_cast<void*>(ptr) << ")");
+ GPU_CLIENT_LOG_CODE_BLOCK(int32 num_results = 1);
+ if (!vertex_array_object_manager_->GetAttribPointer(index, pname, ptr)) {
+ TRACE_EVENT0("gpu", "GLES2::GetVertexAttribPointerv");
+ typedef cmds::GetVertexAttribPointerv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetVertexAttribPointerv(
+ index, pname, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(ptr);
+ GPU_CLIENT_LOG_CODE_BLOCK(num_results = result->GetNumResults());
+ }
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < num_results; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << ptr[i]);
+ }
+ });
+ CheckGLError();
+}
+
+bool GLES2Implementation::DeleteProgramHelper(GLuint program) {
+ if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
+ this, 1, &program, &GLES2Implementation::DeleteProgramStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteProgram", "id not created by this context.");
+ return false;
+ }
+ if (program == current_program_) {
+ current_program_ = 0;
+ }
+ return true;
+}
+
+void GLES2Implementation::DeleteProgramStub(
+ GLsizei n, const GLuint* programs) {
+ GPU_DCHECK_EQ(1, n);
+ share_group_->program_info_manager()->DeleteInfo(programs[0]);
+ helper_->DeleteProgram(programs[0]);
+}
+
+bool GLES2Implementation::DeleteShaderHelper(GLuint shader) {
+ if (!GetIdHandler(id_namespaces::kProgramsAndShaders)->FreeIds(
+ this, 1, &shader, &GLES2Implementation::DeleteShaderStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteShader", "id not created by this context.");
+ return false;
+ }
+ return true;
+}
+
+void GLES2Implementation::DeleteShaderStub(
+ GLsizei n, const GLuint* shaders) {
+ GPU_DCHECK_EQ(1, n);
+ share_group_->program_info_manager()->DeleteInfo(shaders[0]);
+ helper_->DeleteShader(shaders[0]);
+}
+
+
+GLint GLES2Implementation::GetAttribLocationHelper(
+ GLuint program, const char* name) {
+ typedef cmds::GetAttribLocationBucket::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return -1;
+ }
+ *result = -1;
+ SetBucketAsCString(kResultBucketId, name);
+ helper_->GetAttribLocationBucket(
+ program, kResultBucketId, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ helper_->SetBucketSize(kResultBucketId, 0);
+ return *result;
+}
+
+GLint GLES2Implementation::GetAttribLocation(
+ GLuint program, const char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttribLocation(" << program
+ << ", " << name << ")");
+ TRACE_EVENT0("gpu", "GLES2::GetAttribLocation");
+ GLint loc = share_group_->program_info_manager()->GetAttribLocation(
+ this, program, name);
+ GPU_CLIENT_LOG("returned " << loc);
+ CheckGLError();
+ return loc;
+}
+
+GLint GLES2Implementation::GetUniformLocationHelper(
+ GLuint program, const char* name) {
+ typedef cmds::GetUniformLocationBucket::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return -1;
+ }
+ *result = -1;
+ SetBucketAsCString(kResultBucketId, name);
+ helper_->GetUniformLocationBucket(program, kResultBucketId,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ helper_->SetBucketSize(kResultBucketId, 0);
+ return *result;
+}
+
+GLint GLES2Implementation::GetUniformLocation(
+ GLuint program, const char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformLocation(" << program
+ << ", " << name << ")");
+ TRACE_EVENT0("gpu", "GLES2::GetUniformLocation");
+ GLint loc = share_group_->program_info_manager()->GetUniformLocation(
+ this, program, name);
+ GPU_CLIENT_LOG("returned " << loc);
+ CheckGLError();
+ return loc;
+}
+
+void GLES2Implementation::UseProgram(GLuint program) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUseProgram(" << program << ")");
+ if (current_program_ != program) {
+ current_program_ = program;
+ helper_->UseProgram(program);
+ }
+ CheckGLError();
+}
+
+bool GLES2Implementation::GetProgramivHelper(
+ GLuint program, GLenum pname, GLint* params) {
+ bool got_value = share_group_->program_info_manager()->GetProgramiv(
+ this, program, pname, params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ if (got_value) {
+ GPU_CLIENT_LOG(" 0: " << *params);
+ }
+ });
+ return got_value;
+}
+
+void GLES2Implementation::LinkProgram(GLuint program) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLinkProgram(" << program << ")");
+ helper_->LinkProgram(program);
+ share_group_->program_info_manager()->CreateInfo(program);
+ CheckGLError();
+}
+
+void GLES2Implementation::ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderBinary(" << n << ", "
+ << static_cast<const void*>(shaders) << ", "
+ << GLES2Util::GetStringEnum(binaryformat) << ", "
+ << static_cast<const void*>(binary) << ", "
+ << length << ")");
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glShaderBinary", "n < 0.");
+ return;
+ }
+ if (length < 0) {
+ SetGLError(GL_INVALID_VALUE, "glShaderBinary", "length < 0.");
+ return;
+ }
+ // TODO(gman): ShaderBinary should use buckets.
+ unsigned int shader_id_size = n * sizeof(*shaders);
+ ScopedTransferBufferArray<GLint> buffer(
+ shader_id_size + length, helper_, transfer_buffer_);
+ if (!buffer.valid() || buffer.num_elements() != shader_id_size + length) {
+ SetGLError(GL_OUT_OF_MEMORY, "glShaderBinary", "out of memory.");
+ return;
+ }
+ void* shader_ids = buffer.elements();
+ void* shader_data = buffer.elements() + shader_id_size;
+ memcpy(shader_ids, shaders, shader_id_size);
+ memcpy(shader_data, binary, length);
+ helper_->ShaderBinary(
+ n,
+ buffer.shm_id(),
+ buffer.offset(),
+ binaryformat,
+ buffer.shm_id(),
+ buffer.offset() + shader_id_size,
+ length);
+ CheckGLError();
+}
+
+void GLES2Implementation::PixelStorei(GLenum pname, GLint param) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPixelStorei("
+ << GLES2Util::GetStringPixelStore(pname) << ", "
+ << param << ")");
+ switch (pname) {
+ case GL_PACK_ALIGNMENT:
+ pack_alignment_ = param;
+ break;
+ case GL_UNPACK_ALIGNMENT:
+ unpack_alignment_ = param;
+ break;
+ case GL_UNPACK_ROW_LENGTH:
+ unpack_row_length_ = param;
+ return;
+ case GL_UNPACK_SKIP_ROWS:
+ unpack_skip_rows_ = param;
+ return;
+ case GL_UNPACK_SKIP_PIXELS:
+ unpack_skip_pixels_ = param;
+ return;
+ case GL_UNPACK_FLIP_Y_CHROMIUM:
+ unpack_flip_y_ = (param != 0);
+ break;
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
+ pack_reverse_row_order_ =
+ IsAnglePackReverseRowOrderAvailable() ? (param != 0) : false;
+ break;
+ default:
+ break;
+ }
+ helper_->PixelStorei(pname, param);
+ CheckGLError();
+}
+
+
+void GLES2Implementation::VertexAttribPointer(
+ GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribPointer("
+ << index << ", "
+ << size << ", "
+ << GLES2Util::GetStringVertexAttribType(type) << ", "
+ << GLES2Util::GetStringBool(normalized) << ", "
+ << stride << ", "
+ << static_cast<const void*>(ptr) << ")");
+ // Record the info on the client side.
+ if (!vertex_array_object_manager_->SetAttribPointer(
+ bound_array_buffer_id_, index, size, type, normalized, stride, ptr)) {
+ SetGLError(GL_INVALID_OPERATION, "glVertexAttribPointer",
+ "client side arrays are not allowed in vertex array objects.");
+ return;
+ }
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ if (bound_array_buffer_id_ != 0) {
+ // Only report NON client side buffers to the service.
+ helper_->VertexAttribPointer(index, size, type, normalized, stride,
+ ToGLuint(ptr));
+ }
+#else // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ helper_->VertexAttribPointer(index, size, type, normalized, stride,
+ ToGLuint(ptr));
+#endif // !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttribDivisorANGLE(
+ GLuint index, GLuint divisor) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttribDivisorANGLE("
+ << index << ", "
+ << divisor << ") ");
+ // Record the info on the client side.
+ vertex_array_object_manager_->SetAttribDivisor(index, divisor);
+ helper_->VertexAttribDivisorANGLE(index, divisor);
+ CheckGLError();
+}
+
+void GLES2Implementation::ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* source, const GLint* length) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glShaderSource("
+ << shader << ", " << count << ", "
+ << static_cast<const void*>(source) << ", "
+ << static_cast<const void*>(length) << ")");
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ if (source[ii]) {
+ if (length && length[ii] >= 0) {
+ std::string str(source[ii], length[ii]);
+ GPU_CLIENT_LOG(" " << ii << ": ---\n" << str << "\n---");
+ } else {
+ GPU_CLIENT_LOG(" " << ii << ": ---\n" << source[ii] << "\n---");
+ }
+ } else {
+ GPU_CLIENT_LOG(" " << ii << ": NULL");
+ }
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glShaderSource", "count < 0");
+ return;
+ }
+ if (shader == 0) {
+ SetGLError(GL_INVALID_VALUE, "glShaderSource", "shader == 0");
+ return;
+ }
+
+ // Compute the total size.
+ uint32 total_size = 1;
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ if (source[ii]) {
+ total_size += (length && length[ii] >= 0) ?
+ static_cast<size_t>(length[ii]) : strlen(source[ii]);
+ }
+ }
+
+ // Concatenate all the strings in to a bucket on the service.
+ helper_->SetBucketSize(kResultBucketId, total_size);
+ uint32 offset = 0;
+ for (GLsizei ii = 0; ii <= count; ++ii) {
+ const char* src = ii < count ? source[ii] : "";
+ if (src) {
+ uint32 size = ii < count ?
+ (length ? static_cast<size_t>(length[ii]) : strlen(src)) : 1;
+ while (size) {
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
+ if (!buffer.valid()) {
+ return;
+ }
+ memcpy(buffer.address(), src, buffer.size());
+ helper_->SetBucketData(kResultBucketId, offset, buffer.size(),
+ buffer.shm_id(), buffer.offset());
+ offset += buffer.size();
+ src += buffer.size();
+ size -= buffer.size();
+ }
+ }
+ }
+
+ GPU_DCHECK_EQ(total_size, offset);
+
+ helper_->ShaderSourceBucket(shader, kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+ CheckGLError();
+}
+
+void GLES2Implementation::BufferDataHelper(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ if (size < 0) {
+ SetGLError(GL_INVALID_VALUE, "glBufferData", "size < 0");
+ return;
+ }
+
+ GLuint buffer_id;
+ if (GetBoundPixelTransferBuffer(target, "glBufferData", &buffer_id)) {
+ if (!buffer_id) {
+ return;
+ }
+
+ BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
+ if (buffer) {
+ // Free buffer memory, pending the passage of a token.
+ buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
+
+ // Remove old buffer.
+ buffer_tracker_->RemoveBuffer(buffer_id);
+ }
+
+ // Create new buffer.
+ buffer = buffer_tracker_->CreateBuffer(buffer_id, size);
+ GPU_DCHECK(buffer);
+ if (buffer->address() && data)
+ memcpy(buffer->address(), data, size);
+ return;
+ }
+
+ if (size == 0) {
+ return;
+ }
+
+ // If there is no data just send BufferData
+ if (!data) {
+ helper_->BufferData(target, size, 0, 0, usage);
+ return;
+ }
+
+ // See if we can send all at once.
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
+ if (!buffer.valid()) {
+ return;
+ }
+
+ if (buffer.size() >= static_cast<unsigned int>(size)) {
+ memcpy(buffer.address(), data, size);
+ helper_->BufferData(
+ target,
+ size,
+ buffer.shm_id(),
+ buffer.offset(),
+ usage);
+ return;
+ }
+
+ // Make the buffer with BufferData then send via BufferSubData
+ helper_->BufferData(target, size, 0, 0, usage);
+ BufferSubDataHelperImpl(target, 0, size, data, &buffer);
+ CheckGLError();
+}
+
+void GLES2Implementation::BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferData("
+ << GLES2Util::GetStringBufferTarget(target) << ", "
+ << size << ", "
+ << static_cast<const void*>(data) << ", "
+ << GLES2Util::GetStringBufferUsage(usage) << ")");
+ BufferDataHelper(target, size, data, usage);
+ CheckGLError();
+}
+
+void GLES2Implementation::BufferSubDataHelper(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ if (size == 0) {
+ return;
+ }
+
+ if (size < 0) {
+ SetGLError(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
+ return;
+ }
+
+ GLuint buffer_id;
+ if (GetBoundPixelTransferBuffer(target, "glBufferSubData", &buffer_id)) {
+ if (!buffer_id) {
+ return;
+ }
+ BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
+ if (!buffer) {
+ SetGLError(GL_INVALID_VALUE, "glBufferSubData", "unknown buffer");
+ return;
+ }
+
+ int32 end = 0;
+ int32 buffer_size = buffer->size();
+ if (!SafeAddInt32(offset, size, &end) || end > buffer_size) {
+ SetGLError(GL_INVALID_VALUE, "glBufferSubData", "out of range");
+ return;
+ }
+
+ if (buffer->address() && data)
+ memcpy(static_cast<uint8*>(buffer->address()) + offset, data, size);
+ return;
+ }
+
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
+ BufferSubDataHelperImpl(target, offset, size, data, &buffer);
+}
+
+void GLES2Implementation::BufferSubDataHelperImpl(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
+ ScopedTransferBufferPtr* buffer) {
+ GPU_DCHECK(buffer);
+ GPU_DCHECK_GT(size, 0);
+
+ const int8* source = static_cast<const int8*>(data);
+ while (size) {
+ if (!buffer->valid() || buffer->size() == 0) {
+ buffer->Reset(size);
+ if (!buffer->valid()) {
+ return;
+ }
+ }
+ memcpy(buffer->address(), source, buffer->size());
+ helper_->BufferSubData(
+ target, offset, buffer->size(), buffer->shm_id(), buffer->offset());
+ offset += buffer->size();
+ source += buffer->size();
+ size -= buffer->size();
+ buffer->Release();
+ }
+}
+
+void GLES2Implementation::BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBufferSubData("
+ << GLES2Util::GetStringBufferTarget(target) << ", "
+ << offset << ", " << size << ", "
+ << static_cast<const void*>(data) << ")");
+ BufferSubDataHelper(target, offset, size, data);
+ CheckGLError();
+}
+
+bool GLES2Implementation::GetBoundPixelTransferBuffer(
+ GLenum target,
+ const char* function_name,
+ GLuint* buffer_id) {
+ *buffer_id = 0;
+
+ switch (target) {
+ case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
+ *buffer_id = bound_pixel_pack_transfer_buffer_id_;
+ break;
+ case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
+ *buffer_id = bound_pixel_unpack_transfer_buffer_id_;
+ break;
+ default:
+ // Unknown target
+ return false;
+ }
+ if (!*buffer_id) {
+ SetGLError(GL_INVALID_OPERATION, function_name, "no buffer bound");
+ }
+ return true;
+}
+
+BufferTracker::Buffer*
+GLES2Implementation::GetBoundPixelUnpackTransferBufferIfValid(
+ GLuint buffer_id,
+ const char* function_name,
+ GLuint offset, GLsizei size)
+{
+ DCHECK(buffer_id);
+ BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
+ if (!buffer) {
+ SetGLError(GL_INVALID_OPERATION, function_name, "invalid buffer");
+ return NULL;
+ }
+ if (buffer->mapped()) {
+ SetGLError(GL_INVALID_OPERATION, function_name, "buffer mapped");
+ return NULL;
+ }
+ if ((buffer->size() - offset) < static_cast<GLuint>(size)) {
+ SetGLError(GL_INVALID_VALUE, function_name, "unpack size to large");
+ return NULL;
+ }
+ return buffer;
+}
+
+void GLES2Implementation::CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei image_size, const void* data) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexImage2D("
+ << GLES2Util::GetStringTextureTarget(target) << ", "
+ << level << ", "
+ << GLES2Util::GetStringCompressedTextureFormat(internalformat) << ", "
+ << width << ", " << height << ", " << border << ", "
+ << image_size << ", "
+ << static_cast<const void*>(data) << ")");
+ if (width < 0 || height < 0 || level < 0) {
+ SetGLError(GL_INVALID_VALUE, "glCompressedTexImage2D", "dimension < 0");
+ return;
+ }
+ if (height == 0 || width == 0) {
+ return;
+ }
+ // If there's a pixel unpack buffer bound use it when issuing
+ // CompressedTexImage2D.
+ if (bound_pixel_unpack_transfer_buffer_id_) {
+ GLuint offset = ToGLuint(data);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_unpack_transfer_buffer_id_,
+ "glCompressedTexImage2D", offset, image_size);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->CompressedTexImage2D(
+ target, level, internalformat, width, height, border, image_size,
+ buffer->shm_id(), buffer->shm_offset() + offset);
+ buffer->set_transfer_ready_token(helper_->InsertToken());
+ }
+ return;
+ }
+ SetBucketContents(kResultBucketId, data, image_size);
+ helper_->CompressedTexImage2DBucket(
+ target, level, internalformat, width, height, border, kResultBucketId);
+ // Free the bucket. This is not required but it does free up the memory.
+ // and we don't have to wait for the result so from the client's perspective
+ // it's cheap.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ CheckGLError();
+}
+
+void GLES2Implementation::CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei image_size, const void* data) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompressedTexSubImage2D("
+ << GLES2Util::GetStringTextureTarget(target) << ", "
+ << level << ", "
+ << xoffset << ", " << yoffset << ", "
+ << width << ", " << height << ", "
+ << GLES2Util::GetStringCompressedTextureFormat(format) << ", "
+ << image_size << ", "
+ << static_cast<const void*>(data) << ")");
+ if (width < 0 || height < 0 || level < 0) {
+ SetGLError(GL_INVALID_VALUE, "glCompressedTexSubImage2D", "dimension < 0");
+ return;
+ }
+ // If there's a pixel unpack buffer bound use it when issuing
+ // CompressedTexSubImage2D.
+ if (bound_pixel_unpack_transfer_buffer_id_) {
+ GLuint offset = ToGLuint(data);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_unpack_transfer_buffer_id_,
+ "glCompressedTexSubImage2D", offset, image_size);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->CompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, image_size,
+ buffer->shm_id(), buffer->shm_offset() + offset);
+ buffer->set_transfer_ready_token(helper_->InsertToken());
+ CheckGLError();
+ }
+ return;
+ }
+ SetBucketContents(kResultBucketId, data, image_size);
+ helper_->CompressedTexSubImage2DBucket(
+ target, level, xoffset, yoffset, width, height, format, kResultBucketId);
+ // Free the bucket. This is not required but it does free up the memory.
+ // and we don't have to wait for the result so from the client's perspective
+ // it's cheap.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ CheckGLError();
+}
+
+namespace {
+
+void CopyRectToBuffer(
+ const void* pixels,
+ uint32 height,
+ uint32 unpadded_row_size,
+ uint32 pixels_padded_row_size,
+ bool flip_y,
+ void* buffer,
+ uint32 buffer_padded_row_size) {
+ const int8* source = static_cast<const int8*>(pixels);
+ int8* dest = static_cast<int8*>(buffer);
+ if (flip_y || pixels_padded_row_size != buffer_padded_row_size) {
+ if (flip_y) {
+ dest += buffer_padded_row_size * (height - 1);
+ }
+ // the last row is copied unpadded at the end
+ for (; height > 1; --height) {
+ memcpy(dest, source, buffer_padded_row_size);
+ if (flip_y) {
+ dest -= buffer_padded_row_size;
+ } else {
+ dest += buffer_padded_row_size;
+ }
+ source += pixels_padded_row_size;
+ }
+ memcpy(dest, source, unpadded_row_size);
+ } else {
+ uint32 size = (height - 1) * pixels_padded_row_size + unpadded_row_size;
+ memcpy(dest, source, size);
+ }
+}
+
+} // anonymous namespace
+
+void GLES2Implementation::TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
+ << GLES2Util::GetStringTextureTarget(target) << ", "
+ << level << ", "
+ << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
+ << width << ", " << height << ", " << border << ", "
+ << GLES2Util::GetStringTextureFormat(format) << ", "
+ << GLES2Util::GetStringPixelType(type) << ", "
+ << static_cast<const void*>(pixels) << ")");
+ if (level < 0 || height < 0 || width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
+ return;
+ }
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, unpack_alignment_, &size,
+ &unpadded_row_size, &padded_row_size)) {
+ SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
+ return;
+ }
+
+ // If there's a pixel unpack buffer bound use it when issuing TexImage2D.
+ if (bound_pixel_unpack_transfer_buffer_id_) {
+ GLuint offset = ToGLuint(pixels);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_unpack_transfer_buffer_id_,
+ "glTexImage2D", offset, size);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->TexImage2D(
+ target, level, internalformat, width, height, border, format, type,
+ buffer->shm_id(), buffer->shm_offset() + offset);
+ buffer->set_transfer_ready_token(helper_->InsertToken());
+ CheckGLError();
+ }
+ return;
+ }
+
+ // If there's no data just issue TexImage2D
+ if (!pixels) {
+ helper_->TexImage2D(
+ target, level, internalformat, width, height, border, format, type,
+ 0, 0);
+ CheckGLError();
+ return;
+ }
+
+ // compute the advance bytes per row for the src pixels
+ uint32 src_padded_row_size;
+ if (unpack_row_length_ > 0) {
+ if (!GLES2Util::ComputeImagePaddedRowSize(
+ unpack_row_length_, format, type, unpack_alignment_,
+ &src_padded_row_size)) {
+ SetGLError(
+ GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
+ return;
+ }
+ } else {
+ src_padded_row_size = padded_row_size;
+ }
+
+ // advance pixels pointer past the skip rows and skip pixels
+ pixels = reinterpret_cast<const int8*>(pixels) +
+ unpack_skip_rows_ * src_padded_row_size;
+ if (unpack_skip_pixels_) {
+ uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
+ pixels = reinterpret_cast<const int8*>(pixels) +
+ unpack_skip_pixels_ * group_size;
+ }
+
+ // Check if we can send it all at once.
+ ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_);
+ if (!buffer.valid()) {
+ return;
+ }
+
+ if (buffer.size() >= size) {
+ CopyRectToBuffer(
+ pixels, height, unpadded_row_size, src_padded_row_size, unpack_flip_y_,
+ buffer.address(), padded_row_size);
+ helper_->TexImage2D(
+ target, level, internalformat, width, height, border, format, type,
+ buffer.shm_id(), buffer.offset());
+ CheckGLError();
+ return;
+ }
+
+ // No, so send it using TexSubImage2D.
+ helper_->TexImage2D(
+ target, level, internalformat, width, height, border, format, type,
+ 0, 0);
+ TexSubImage2DImpl(
+ target, level, 0, 0, width, height, format, type, unpadded_row_size,
+ pixels, src_padded_row_size, GL_TRUE, &buffer, padded_row_size);
+ CheckGLError();
+}
+
+void GLES2Implementation::TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexSubImage2D("
+ << GLES2Util::GetStringTextureTarget(target) << ", "
+ << level << ", "
+ << xoffset << ", " << yoffset << ", "
+ << width << ", " << height << ", "
+ << GLES2Util::GetStringTextureFormat(format) << ", "
+ << GLES2Util::GetStringPixelType(type) << ", "
+ << static_cast<const void*>(pixels) << ")");
+
+ if (level < 0 || height < 0 || width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0");
+ return;
+ }
+ if (height == 0 || width == 0) {
+ return;
+ }
+
+ uint32 temp_size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, unpack_alignment_, &temp_size,
+ &unpadded_row_size, &padded_row_size)) {
+ SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large");
+ return;
+ }
+
+ // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D.
+ if (bound_pixel_unpack_transfer_buffer_id_) {
+ GLuint offset = ToGLuint(pixels);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_unpack_transfer_buffer_id_,
+ "glTexSubImage2D", offset, temp_size);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->TexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type,
+ buffer->shm_id(), buffer->shm_offset() + offset, false);
+ buffer->set_transfer_ready_token(helper_->InsertToken());
+ CheckGLError();
+ }
+ return;
+ }
+
+ // compute the advance bytes per row for the src pixels
+ uint32 src_padded_row_size;
+ if (unpack_row_length_ > 0) {
+ if (!GLES2Util::ComputeImagePaddedRowSize(
+ unpack_row_length_, format, type, unpack_alignment_,
+ &src_padded_row_size)) {
+ SetGLError(
+ GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large");
+ return;
+ }
+ } else {
+ src_padded_row_size = padded_row_size;
+ }
+
+ // advance pixels pointer past the skip rows and skip pixels
+ pixels = reinterpret_cast<const int8*>(pixels) +
+ unpack_skip_rows_ * src_padded_row_size;
+ if (unpack_skip_pixels_) {
+ uint32 group_size = GLES2Util::ComputeImageGroupSize(format, type);
+ pixels = reinterpret_cast<const int8*>(pixels) +
+ unpack_skip_pixels_ * group_size;
+ }
+
+ ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_);
+ TexSubImage2DImpl(
+ target, level, xoffset, yoffset, width, height, format, type,
+ unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer,
+ padded_row_size);
+ CheckGLError();
+}
+
+static GLint ComputeNumRowsThatFitInBuffer(
+ GLsizeiptr padded_row_size, GLsizeiptr unpadded_row_size,
+ unsigned int size) {
+ GPU_DCHECK_GE(unpadded_row_size, 0);
+ if (padded_row_size == 0) {
+ return 1;
+ }
+ GLint num_rows = size / padded_row_size;
+ return num_rows + (size - num_rows * padded_row_size) / unpadded_row_size;
+}
+
+void GLES2Implementation::TexSubImage2DImpl(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
+ const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
+ ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size) {
+ GPU_DCHECK(buffer);
+ GPU_DCHECK_GE(level, 0);
+ GPU_DCHECK_GT(height, 0);
+ GPU_DCHECK_GT(width, 0);
+
+ const int8* source = reinterpret_cast<const int8*>(pixels);
+ GLint original_yoffset = yoffset;
+ // Transfer by rows.
+ while (height) {
+ unsigned int desired_size =
+ buffer_padded_row_size * (height - 1) + unpadded_row_size;
+ if (!buffer->valid() || buffer->size() == 0) {
+ buffer->Reset(desired_size);
+ if (!buffer->valid()) {
+ return;
+ }
+ }
+
+ GLint num_rows = ComputeNumRowsThatFitInBuffer(
+ buffer_padded_row_size, unpadded_row_size, buffer->size());
+ num_rows = std::min(num_rows, height);
+ CopyRectToBuffer(
+ source, num_rows, unpadded_row_size, pixels_padded_row_size,
+ unpack_flip_y_, buffer->address(), buffer_padded_row_size);
+ GLint y = unpack_flip_y_ ? original_yoffset + height - num_rows : yoffset;
+ helper_->TexSubImage2D(
+ target, level, xoffset, y, width, num_rows, format, type,
+ buffer->shm_id(), buffer->offset(), internal);
+ buffer->Release();
+ yoffset += num_rows;
+ source += num_rows * pixels_padded_row_size;
+ height -= num_rows;
+ }
+}
+
+bool GLES2Implementation::GetActiveAttribHelper(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ // Clear the bucket so if the command fails nothing will be in it.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ typedef cmds::GetActiveAttrib::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return false;
+ }
+ // Set as failed so if the command fails we'll recover.
+ result->success = false;
+ helper_->GetActiveAttrib(program, index, kResultBucketId,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ if (result->success) {
+ if (size) {
+ *size = result->size;
+ }
+ if (type) {
+ *type = result->type;
+ }
+ if (length || name) {
+ std::vector<int8> str;
+ GetBucketContents(kResultBucketId, &str);
+ GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
+ std::max(static_cast<size_t>(0),
+ str.size() - 1));
+ if (length) {
+ *length = max_size;
+ }
+ if (name && bufsize > 0) {
+ memcpy(name, &str[0], max_size);
+ name[max_size] = '\0';
+ }
+ }
+ }
+ return result->success != 0;
+}
+
+void GLES2Implementation::GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveAttrib("
+ << program << ", " << index << ", " << bufsize << ", "
+ << static_cast<const void*>(length) << ", "
+ << static_cast<const void*>(size) << ", "
+ << static_cast<const void*>(type) << ", "
+ << static_cast<const void*>(name) << ", ");
+ if (bufsize < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGetActiveAttrib", "bufsize < 0");
+ return;
+ }
+ TRACE_EVENT0("gpu", "GLES2::GetActiveAttrib");
+ bool success = share_group_->program_info_manager()->GetActiveAttrib(
+ this, program, index, bufsize, length, size, type, name);
+ if (success) {
+ if (size) {
+ GPU_CLIENT_LOG(" size: " << *size);
+ }
+ if (type) {
+ GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
+ }
+ if (name) {
+ GPU_CLIENT_LOG(" name: " << name);
+ }
+ }
+ CheckGLError();
+}
+
+bool GLES2Implementation::GetActiveUniformHelper(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ // Clear the bucket so if the command fails nothing will be in it.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ typedef cmds::GetActiveUniform::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return false;
+ }
+ // Set as failed so if the command fails we'll recover.
+ result->success = false;
+ helper_->GetActiveUniform(program, index, kResultBucketId,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ if (result->success) {
+ if (size) {
+ *size = result->size;
+ }
+ if (type) {
+ *type = result->type;
+ }
+ if (length || name) {
+ std::vector<int8> str;
+ GetBucketContents(kResultBucketId, &str);
+ GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
+ std::max(static_cast<size_t>(0),
+ str.size() - 1));
+ if (length) {
+ *length = max_size;
+ }
+ if (name && bufsize > 0) {
+ memcpy(name, &str[0], max_size);
+ name[max_size] = '\0';
+ }
+ }
+ }
+ return result->success != 0;
+}
+
+void GLES2Implementation::GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetActiveUniform("
+ << program << ", " << index << ", " << bufsize << ", "
+ << static_cast<const void*>(length) << ", "
+ << static_cast<const void*>(size) << ", "
+ << static_cast<const void*>(type) << ", "
+ << static_cast<const void*>(name) << ", ");
+ if (bufsize < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGetActiveUniform", "bufsize < 0");
+ return;
+ }
+ TRACE_EVENT0("gpu", "GLES2::GetActiveUniform");
+ bool success = share_group_->program_info_manager()->GetActiveUniform(
+ this, program, index, bufsize, length, size, type, name);
+ if (success) {
+ if (size) {
+ GPU_CLIENT_LOG(" size: " << *size);
+ }
+ if (type) {
+ GPU_CLIENT_LOG(" type: " << GLES2Util::GetStringEnum(*type));
+ }
+ if (name) {
+ GPU_CLIENT_LOG(" name: " << name);
+ }
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetAttachedShaders("
+ << program << ", " << maxcount << ", "
+ << static_cast<const void*>(count) << ", "
+ << static_cast<const void*>(shaders) << ", ");
+ if (maxcount < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGetAttachedShaders", "maxcount < 0");
+ return;
+ }
+ TRACE_EVENT0("gpu", "GLES2::GetAttachedShaders");
+ typedef cmds::GetAttachedShaders::Result Result;
+ uint32 size = Result::ComputeSize(maxcount);
+ Result* result = static_cast<Result*>(transfer_buffer_->Alloc(size));
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetAttachedShaders(
+ program,
+ transfer_buffer_->GetShmId(),
+ transfer_buffer_->GetOffset(result),
+ size);
+ int32 token = helper_->InsertToken();
+ WaitForCmd();
+ if (count) {
+ *count = result->GetNumResults();
+ }
+ result->CopyResult(shaders);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ transfer_buffer_->FreePendingToken(result, token);
+ CheckGLError();
+}
+
+void GLES2Implementation::GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderPrecisionFormat("
+ << GLES2Util::GetStringShaderType(shadertype) << ", "
+ << GLES2Util::GetStringShaderPrecision(precisiontype) << ", "
+ << static_cast<const void*>(range) << ", "
+ << static_cast<const void*>(precision) << ", ");
+ TRACE_EVENT0("gpu", "GLES2::GetShaderPrecisionFormat");
+ typedef cmds::GetShaderPrecisionFormat::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+
+ GLStaticState::ShaderPrecisionKey key(shadertype, precisiontype);
+ GLStaticState::ShaderPrecisionMap::iterator i =
+ static_state_.shader_precisions.find(key);
+ if (i != static_state_.shader_precisions.end()) {
+ *result = i->second;
+ } else {
+ result->success = false;
+ helper_->GetShaderPrecisionFormat(
+ shadertype, precisiontype, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ if (result->success)
+ static_state_.shader_precisions[key] = *result;
+ }
+
+ if (result->success) {
+ if (range) {
+ range[0] = result->min_range;
+ range[1] = result->max_range;
+ GPU_CLIENT_LOG(" min_range: " << range[0]);
+ GPU_CLIENT_LOG(" min_range: " << range[1]);
+ }
+ if (precision) {
+ precision[0] = result->precision;
+ GPU_CLIENT_LOG(" min_range: " << precision[0]);
+ }
+ }
+ CheckGLError();
+}
+
+const GLubyte* GLES2Implementation::GetStringHelper(GLenum name) {
+ const char* result = NULL;
+ // Clears the bucket so if the command fails nothing will be in it.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetString(name, kResultBucketId);
+ std::string str;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ // Adds extensions implemented on client side only.
+ switch (name) {
+ case GL_EXTENSIONS:
+ str += std::string(str.empty() ? "" : " ") +
+ "GL_CHROMIUM_flipy "
+ "GL_CHROMIUM_map_sub "
+ "GL_CHROMIUM_shallow_flush "
+ "GL_EXT_unpack_subimage";
+ if (image_factory_ != NULL) {
+ // The first space character is intentional.
+ str += " GL_CHROMIUM_map_image";
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Because of WebGL the extensions can change. We have to cache each unique
+ // result since we don't know when the client will stop referring to a
+ // previous one it queries.
+ GLStringMap::iterator it = gl_strings_.find(name);
+ if (it == gl_strings_.end()) {
+ std::set<std::string> strings;
+ std::pair<GLStringMap::iterator, bool> insert_result =
+ gl_strings_.insert(std::make_pair(name, strings));
+ GPU_DCHECK(insert_result.second);
+ it = insert_result.first;
+ }
+ std::set<std::string>& string_set = it->second;
+ std::set<std::string>::const_iterator sit = string_set.find(str);
+ if (sit != string_set.end()) {
+ result = sit->c_str();
+ } else {
+ std::pair<std::set<std::string>::const_iterator, bool> insert_result =
+ string_set.insert(str);
+ GPU_DCHECK(insert_result.second);
+ result = insert_result.first->c_str();
+ }
+ }
+ return reinterpret_cast<const GLubyte*>(result);
+}
+
+const GLubyte* GLES2Implementation::GetString(GLenum name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetString("
+ << GLES2Util::GetStringStringType(name) << ")");
+ TRACE_EVENT0("gpu", "GLES2::GetString");
+ const GLubyte* result = GetStringHelper(name);
+ GPU_CLIENT_LOG(" returned " << reinterpret_cast<const char*>(result));
+ CheckGLError();
+ return result;
+}
+
+void GLES2Implementation::GetUniformfv(
+ GLuint program, GLint location, GLfloat* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformfv("
+ << program << ", " << location << ", "
+ << static_cast<const void*>(params) << ")");
+ TRACE_EVENT0("gpu", "GLES2::GetUniformfv");
+ typedef cmds::GetUniformfv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetUniformfv(
+ program, location, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::GetUniformiv(
+ GLuint program, GLint location, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetUniformiv("
+ << program << ", " << location << ", "
+ << static_cast<const void*>(params) << ")");
+ TRACE_EVENT0("gpu", "GLES2::GetUniformiv");
+ typedef cmds::GetUniformiv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetUniformiv(
+ program, location, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GetResultAs<cmds::GetUniformfv::Result*>()->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::ReadPixels(
+ GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, void* pixels) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReadPixels("
+ << xoffset << ", " << yoffset << ", "
+ << width << ", " << height << ", "
+ << GLES2Util::GetStringReadPixelFormat(format) << ", "
+ << GLES2Util::GetStringPixelType(type) << ", "
+ << static_cast<const void*>(pixels) << ")");
+ if (width < 0 || height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
+ return;
+ }
+ if (width == 0 || height == 0) {
+ return;
+ }
+
+ // glReadPixel pads the size of each row of pixels by an amount specified by
+ // glPixelStorei. So, we have to take that into account both in the fact that
+ // the pixels returned from the ReadPixel command will include that padding
+ // and that when we copy the results to the user's buffer we need to not
+ // write those padding bytes but leave them as they are.
+
+ TRACE_EVENT0("gpu", "GLES2::ReadPixels");
+ typedef cmds::ReadPixels::Result Result;
+
+ int8* dest = reinterpret_cast<int8*>(pixels);
+ uint32 temp_size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, 2, format, type, pack_alignment_, &temp_size, &unpadded_row_size,
+ &padded_row_size)) {
+ SetGLError(GL_INVALID_VALUE, "glReadPixels", "size too large.");
+ return;
+ }
+
+ if (bound_pixel_pack_transfer_buffer_id_) {
+ GLuint offset = ToGLuint(pixels);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_pack_transfer_buffer_id_,
+ "glReadPixels", offset, padded_row_size * height);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->ReadPixels(xoffset, yoffset, width, height, format, type,
+ buffer->shm_id(), buffer->shm_offset(),
+ 0, 0, true);
+ CheckGLError();
+ }
+ return;
+ }
+
+ if (!pixels) {
+ SetGLError(GL_INVALID_OPERATION, "glReadPixels", "pixels = NULL");
+ return;
+ }
+
+ // Transfer by rows.
+ // The max rows we can transfer.
+ while (height) {
+ GLsizei desired_size = padded_row_size * height - 1 + unpadded_row_size;
+ ScopedTransferBufferPtr buffer(desired_size, helper_, transfer_buffer_);
+ if (!buffer.valid()) {
+ return;
+ }
+ GLint num_rows = ComputeNumRowsThatFitInBuffer(
+ padded_row_size, unpadded_row_size, buffer.size());
+ num_rows = std::min(num_rows, height);
+ // NOTE: We must look up the address of the result area AFTER allocation
+ // of the transfer buffer since the transfer buffer may be reallocated.
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ *result = 0; // mark as failed.
+ helper_->ReadPixels(
+ xoffset, yoffset, width, num_rows, format, type,
+ buffer.shm_id(), buffer.offset(),
+ GetResultShmId(), GetResultShmOffset(),
+ false);
+ WaitForCmd();
+ if (*result != 0) {
+ // when doing a y-flip we have to iterate through top-to-bottom chunks
+ // of the dst. The service side handles reversing the rows within a
+ // chunk.
+ int8* rows_dst;
+ if (pack_reverse_row_order_) {
+ rows_dst = dest + (height - num_rows) * padded_row_size;
+ } else {
+ rows_dst = dest;
+ }
+ // We have to copy 1 row at a time to avoid writing pad bytes.
+ const int8* src = static_cast<const int8*>(buffer.address());
+ for (GLint yy = 0; yy < num_rows; ++yy) {
+ memcpy(rows_dst, src, unpadded_row_size);
+ rows_dst += padded_row_size;
+ src += padded_row_size;
+ }
+ if (!pack_reverse_row_order_) {
+ dest = rows_dst;
+ }
+ }
+ // If it was not marked as successful exit.
+ if (*result == 0) {
+ return;
+ }
+ yoffset += num_rows;
+ height -= num_rows;
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::ActiveTexture(GLenum texture) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
+ << GLES2Util::GetStringEnum(texture) << ")");
+ GLuint texture_index = texture - GL_TEXTURE0;
+ if (texture_index >= static_cast<GLuint>(
+ static_state_.int_state.max_combined_texture_image_units)) {
+ SetGLErrorInvalidEnum(
+ "glActiveTexture", texture, "texture");
+ return;
+ }
+
+ active_texture_unit_ = texture_index;
+ helper_->ActiveTexture(texture);
+ CheckGLError();
+}
+
+void GLES2Implementation::GenBuffersHelper(
+ GLsizei /* n */, const GLuint* /* buffers */) {
+}
+
+void GLES2Implementation::GenFramebuffersHelper(
+ GLsizei /* n */, const GLuint* /* framebuffers */) {
+}
+
+void GLES2Implementation::GenRenderbuffersHelper(
+ GLsizei /* n */, const GLuint* /* renderbuffers */) {
+}
+
+void GLES2Implementation::GenTexturesHelper(
+ GLsizei /* n */, const GLuint* /* textures */) {
+}
+
+void GLES2Implementation::GenVertexArraysOESHelper(
+ GLsizei n, const GLuint* arrays) {
+ vertex_array_object_manager_->GenVertexArrays(n, arrays);
+}
+
+void GLES2Implementation::GenQueriesEXTHelper(
+ GLsizei /* n */, const GLuint* /* queries */) {
+}
+
+// NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
+// generates a new resource. On newer versions of OpenGL they don't. The code
+// related to binding below will need to change if we switch to the new OpenGL
+// model. Specifically it assumes a bind will succeed which is always true in
+// the old model but possibly not true in the new model if another context has
+// deleted the resource.
+
+bool GLES2Implementation::BindBufferHelper(
+ GLenum target, GLuint buffer) {
+ // TODO(gman): See note #1 above.
+ bool changed = false;
+ switch (target) {
+ case GL_ARRAY_BUFFER:
+ if (bound_array_buffer_id_ != buffer) {
+ bound_array_buffer_id_ = buffer;
+ changed = true;
+ }
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ changed = vertex_array_object_manager_->BindElementArray(buffer);
+ break;
+ case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
+ bound_pixel_pack_transfer_buffer_id_ = buffer;
+ break;
+ case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
+ bound_pixel_unpack_transfer_buffer_id_ = buffer;
+ break;
+ default:
+ changed = true;
+ break;
+ }
+ // TODO(gman): There's a bug here. If the target is invalid the ID will not be
+ // used even though it's marked it as used here.
+ GetIdHandler(id_namespaces::kBuffers)->MarkAsUsedForBind(buffer);
+ return changed;
+}
+
+bool GLES2Implementation::BindFramebufferHelper(
+ GLenum target, GLuint framebuffer) {
+ // TODO(gman): See note #1 above.
+ bool changed = false;
+ switch (target) {
+ case GL_FRAMEBUFFER:
+ if (bound_framebuffer_ != framebuffer ||
+ bound_read_framebuffer_ != framebuffer) {
+ bound_framebuffer_ = framebuffer;
+ bound_read_framebuffer_ = framebuffer;
+ changed = true;
+ }
+ break;
+ case GL_READ_FRAMEBUFFER:
+ if (!IsChromiumFramebufferMultisampleAvailable()) {
+ SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
+ return false;
+ }
+ if (bound_read_framebuffer_ != framebuffer) {
+ bound_read_framebuffer_ = framebuffer;
+ changed = true;
+ }
+ break;
+ case GL_DRAW_FRAMEBUFFER:
+ if (!IsChromiumFramebufferMultisampleAvailable()) {
+ SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
+ return false;
+ }
+ if (bound_framebuffer_ != framebuffer) {
+ bound_framebuffer_ = framebuffer;
+ changed = true;
+ }
+ break;
+ default:
+ SetGLErrorInvalidEnum("glBindFramebuffer", target, "target");
+ return false;
+ }
+ GetIdHandler(id_namespaces::kFramebuffers)->MarkAsUsedForBind(framebuffer);
+ return changed;
+}
+
+bool GLES2Implementation::BindRenderbufferHelper(
+ GLenum target, GLuint renderbuffer) {
+ // TODO(gman): See note #1 above.
+ bool changed = false;
+ switch (target) {
+ case GL_RENDERBUFFER:
+ if (bound_renderbuffer_ != renderbuffer) {
+ bound_renderbuffer_ = renderbuffer;
+ changed = true;
+ }
+ break;
+ default:
+ changed = true;
+ break;
+ }
+ // TODO(gman): There's a bug here. If the target is invalid the ID will not be
+ // used even though it's marked it as used here.
+ GetIdHandler(id_namespaces::kRenderbuffers)->MarkAsUsedForBind(renderbuffer);
+ return changed;
+}
+
+bool GLES2Implementation::BindTextureHelper(GLenum target, GLuint texture) {
+ // TODO(gman): See note #1 above.
+ // TODO(gman): Change this to false once we figure out why it's failing
+ // on daisy.
+ bool changed = true;
+ TextureUnit& unit = texture_units_[active_texture_unit_];
+ switch (target) {
+ case GL_TEXTURE_2D:
+ if (unit.bound_texture_2d != texture) {
+ unit.bound_texture_2d = texture;
+ changed = true;
+ }
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ if (unit.bound_texture_cube_map != texture) {
+ unit.bound_texture_cube_map = texture;
+ changed = true;
+ }
+ break;
+ default:
+ changed = true;
+ break;
+ }
+ // TODO(gman): There's a bug here. If the target is invalid the ID will not be
+ // used. even though it's marked it as used here.
+ GetIdHandler(id_namespaces::kTextures)->MarkAsUsedForBind(texture);
+ return changed;
+}
+
+bool GLES2Implementation::BindVertexArrayHelper(GLuint array) {
+ // TODO(gman): See note #1 above.
+ bool changed = false;
+ if (!vertex_array_object_manager_->BindVertexArray(array, &changed)) {
+ SetGLError(
+ GL_INVALID_OPERATION, "glBindVertexArrayOES",
+ "id was not generated with glGenVertexArrayOES");
+ }
+ // Unlike other BindXXXHelpers we don't call MarkAsUsedForBind
+ // because unlike other resources VertexArrayObject ids must
+ // be generated by GenVertexArrays. A random id to Bind will not
+ // generate a new object.
+ return changed;
+}
+
+bool GLES2Implementation::IsBufferReservedId(GLuint id) {
+ return vertex_array_object_manager_->IsReservedId(id);
+}
+
+void GLES2Implementation::DeleteBuffersHelper(
+ GLsizei n, const GLuint* buffers) {
+ if (!GetIdHandler(id_namespaces::kBuffers)->FreeIds(
+ this, n, buffers, &GLES2Implementation::DeleteBuffersStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteBuffers", "id not created by this context.");
+ return;
+ }
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (buffers[ii] == bound_array_buffer_id_) {
+ bound_array_buffer_id_ = 0;
+ }
+ vertex_array_object_manager_->UnbindBuffer(buffers[ii]);
+ BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffers[ii]);
+ if (buffer) {
+ // Free buffer memory, pending the passage of a token.
+ buffer_tracker_->FreePendingToken(buffer, helper_->InsertToken());
+ // Remove buffer.
+ buffer_tracker_->RemoveBuffer(buffers[ii]);
+ }
+ if (buffers[ii] == bound_pixel_unpack_transfer_buffer_id_) {
+ bound_pixel_unpack_transfer_buffer_id_ = 0;
+ }
+ }
+}
+
+void GLES2Implementation::DeleteBuffersStub(
+ GLsizei n, const GLuint* buffers) {
+ helper_->DeleteBuffersImmediate(n, buffers);
+}
+
+
+void GLES2Implementation::DeleteFramebuffersHelper(
+ GLsizei n, const GLuint* framebuffers) {
+ if (!GetIdHandler(id_namespaces::kFramebuffers)->FreeIds(
+ this, n, framebuffers, &GLES2Implementation::DeleteFramebuffersStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteFramebuffers", "id not created by this context.");
+ return;
+ }
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (framebuffers[ii] == bound_framebuffer_) {
+ bound_framebuffer_ = 0;
+ }
+ if (framebuffers[ii] == bound_read_framebuffer_) {
+ bound_read_framebuffer_ = 0;
+ }
+ }
+}
+
+void GLES2Implementation::DeleteFramebuffersStub(
+ GLsizei n, const GLuint* framebuffers) {
+ helper_->DeleteFramebuffersImmediate(n, framebuffers);
+}
+
+void GLES2Implementation::DeleteRenderbuffersHelper(
+ GLsizei n, const GLuint* renderbuffers) {
+ if (!GetIdHandler(id_namespaces::kRenderbuffers)->FreeIds(
+ this, n, renderbuffers, &GLES2Implementation::DeleteRenderbuffersStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteRenderbuffers", "id not created by this context.");
+ return;
+ }
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (renderbuffers[ii] == bound_renderbuffer_) {
+ bound_renderbuffer_ = 0;
+ }
+ }
+}
+
+void GLES2Implementation::DeleteRenderbuffersStub(
+ GLsizei n, const GLuint* renderbuffers) {
+ helper_->DeleteRenderbuffersImmediate(n, renderbuffers);
+}
+
+void GLES2Implementation::DeleteTexturesHelper(
+ GLsizei n, const GLuint* textures) {
+ if (!GetIdHandler(id_namespaces::kTextures)->FreeIds(
+ this, n, textures, &GLES2Implementation::DeleteTexturesStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteTextures", "id not created by this context.");
+ return;
+ }
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ for (GLint tt = 0;
+ tt < static_state_.int_state.max_combined_texture_image_units;
+ ++tt) {
+ TextureUnit& unit = texture_units_[tt];
+ if (textures[ii] == unit.bound_texture_2d) {
+ unit.bound_texture_2d = 0;
+ }
+ if (textures[ii] == unit.bound_texture_cube_map) {
+ unit.bound_texture_cube_map = 0;
+ }
+ }
+ }
+}
+
+void GLES2Implementation::DeleteVertexArraysOESHelper(
+ GLsizei n, const GLuint* arrays) {
+ vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
+ if (!GetIdHandler(id_namespaces::kVertexArrays)->FreeIds(
+ this, n, arrays, &GLES2Implementation::DeleteVertexArraysOESStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteVertexArraysOES", "id not created by this context.");
+ return;
+ }
+}
+
+void GLES2Implementation::DeleteVertexArraysOESStub(
+ GLsizei n, const GLuint* arrays) {
+ helper_->DeleteVertexArraysOESImmediate(n, arrays);
+}
+
+void GLES2Implementation::DeleteTexturesStub(
+ GLsizei n, const GLuint* textures) {
+ helper_->DeleteTexturesImmediate(n, textures);
+}
+
+void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG(
+ "[" << GetLogPrefix() << "] glDisableVertexAttribArray(" << index << ")");
+ vertex_array_object_manager_->SetAttribEnable(index, false);
+ helper_->DisableVertexAttribArray(index);
+ CheckGLError();
+}
+
+void GLES2Implementation::EnableVertexAttribArray(GLuint index) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableVertexAttribArray("
+ << index << ")");
+ vertex_array_object_manager_->SetAttribEnable(index, true);
+ helper_->EnableVertexAttribArray(index);
+ CheckGLError();
+}
+
+void GLES2Implementation::DrawArrays(GLenum mode, GLint first, GLsizei count) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArrays("
+ << GLES2Util::GetStringDrawMode(mode) << ", "
+ << first << ", " << count << ")");
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawArrays", "count < 0");
+ return;
+ }
+ bool simulated = false;
+ if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
+ "glDrawArrays", this, helper_, first + count, 0, &simulated)) {
+ return;
+ }
+ helper_->DrawArrays(mode, first, count);
+ RestoreArrayBuffer(simulated);
+ CheckGLError();
+}
+
+void GLES2Implementation::GetVertexAttribfv(
+ GLuint index, GLenum pname, GLfloat* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribfv("
+ << index << ", "
+ << GLES2Util::GetStringVertexAttribute(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+ uint32 value = 0;
+ if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
+ *params = static_cast<float>(value);
+ return;
+ }
+ TRACE_EVENT0("gpu", "GLES2::GetVertexAttribfv");
+ typedef cmds::GetVertexAttribfv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetVertexAttribfv(
+ index, pname, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::GetVertexAttribiv(
+ GLuint index, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetVertexAttribiv("
+ << index << ", "
+ << GLES2Util::GetStringVertexAttribute(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+ uint32 value = 0;
+ if (vertex_array_object_manager_->GetVertexAttrib(index, pname, &value)) {
+ *params = value;
+ return;
+ }
+ TRACE_EVENT0("gpu", "GLES2::GetVertexAttribiv");
+ typedef cmds::GetVertexAttribiv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetVertexAttribiv(
+ index, pname, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+
+GLboolean GLES2Implementation::EnableFeatureCHROMIUM(
+ const char* feature) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glEnableFeatureCHROMIUM("
+ << feature << ")");
+ TRACE_EVENT0("gpu", "GLES2::EnableFeatureCHROMIUM");
+ typedef cmds::EnableFeatureCHROMIUM::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return false;
+ }
+ *result = 0;
+ SetBucketAsCString(kResultBucketId, feature);
+ helper_->EnableFeatureCHROMIUM(
+ kResultBucketId, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ helper_->SetBucketSize(kResultBucketId, 0);
+ GPU_CLIENT_LOG(" returned " << GLES2Util::GetStringBool(*result));
+ return *result;
+}
+
+void* GLES2Implementation::MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferSubDataCHROMIUM("
+ << target << ", " << offset << ", " << size << ", "
+ << GLES2Util::GetStringEnum(access) << ")");
+ // NOTE: target is NOT checked because the service will check it
+ // and we don't know what targets are valid.
+ if (access != GL_WRITE_ONLY) {
+ SetGLErrorInvalidEnum(
+ "glMapBufferSubDataCHROMIUM", access, "access");
+ return NULL;
+ }
+ if (offset < 0 || size < 0) {
+ SetGLError(GL_INVALID_VALUE, "glMapBufferSubDataCHROMIUM", "bad range");
+ return NULL;
+ }
+ int32 shm_id;
+ unsigned int shm_offset;
+ void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
+ if (!mem) {
+ SetGLError(GL_OUT_OF_MEMORY, "glMapBufferSubDataCHROMIUM", "out of memory");
+ return NULL;
+ }
+
+ std::pair<MappedBufferMap::iterator, bool> result =
+ mapped_buffers_.insert(std::make_pair(
+ mem,
+ MappedBuffer(
+ access, shm_id, mem, shm_offset, target, offset, size)));
+ GPU_DCHECK(result.second);
+ GPU_CLIENT_LOG(" returned " << mem);
+ return mem;
+}
+
+void GLES2Implementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG(
+ "[" << GetLogPrefix() << "] glUnmapBufferSubDataCHROMIUM(" << mem << ")");
+ MappedBufferMap::iterator it = mapped_buffers_.find(mem);
+ if (it == mapped_buffers_.end()) {
+ SetGLError(
+ GL_INVALID_VALUE, "UnmapBufferSubDataCHROMIUM", "buffer not mapped");
+ return;
+ }
+ const MappedBuffer& mb = it->second;
+ helper_->BufferSubData(
+ mb.target, mb.offset, mb.size, mb.shm_id, mb.shm_offset);
+ mapped_memory_->FreePendingToken(mb.shm_memory, helper_->InsertToken());
+ mapped_buffers_.erase(it);
+ CheckGLError();
+}
+
+void* GLES2Implementation::MapTexSubImage2DCHROMIUM(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ GLenum access) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapTexSubImage2DCHROMIUM("
+ << target << ", " << level << ", "
+ << xoffset << ", " << yoffset << ", "
+ << width << ", " << height << ", "
+ << GLES2Util::GetStringTextureFormat(format) << ", "
+ << GLES2Util::GetStringPixelType(type) << ", "
+ << GLES2Util::GetStringEnum(access) << ")");
+ if (access != GL_WRITE_ONLY) {
+ SetGLErrorInvalidEnum(
+ "glMapTexSubImage2DCHROMIUM", access, "access");
+ return NULL;
+ }
+ // NOTE: target is NOT checked because the service will check it
+ // and we don't know what targets are valid.
+ if (level < 0 || xoffset < 0 || yoffset < 0 || width < 0 || height < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "bad dimensions");
+ return NULL;
+ }
+ uint32 size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, unpack_alignment_, &size, NULL, NULL)) {
+ SetGLError(
+ GL_INVALID_VALUE, "glMapTexSubImage2DCHROMIUM", "image size too large");
+ return NULL;
+ }
+ int32 shm_id;
+ unsigned int shm_offset;
+ void* mem = mapped_memory_->Alloc(size, &shm_id, &shm_offset);
+ if (!mem) {
+ SetGLError(GL_OUT_OF_MEMORY, "glMapTexSubImage2DCHROMIUM", "out of memory");
+ return NULL;
+ }
+
+ std::pair<MappedTextureMap::iterator, bool> result =
+ mapped_textures_.insert(std::make_pair(
+ mem,
+ MappedTexture(
+ access, shm_id, mem, shm_offset,
+ target, level, xoffset, yoffset, width, height, format, type)));
+ GPU_DCHECK(result.second);
+ GPU_CLIENT_LOG(" returned " << mem);
+ return mem;
+}
+
+void GLES2Implementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG(
+ "[" << GetLogPrefix() << "] glUnmapTexSubImage2DCHROMIUM(" << mem << ")");
+ MappedTextureMap::iterator it = mapped_textures_.find(mem);
+ if (it == mapped_textures_.end()) {
+ SetGLError(
+ GL_INVALID_VALUE, "UnmapTexSubImage2DCHROMIUM", "texture not mapped");
+ return;
+ }
+ const MappedTexture& mt = it->second;
+ helper_->TexSubImage2D(
+ mt.target, mt.level, mt.xoffset, mt.yoffset, mt.width, mt.height,
+ mt.format, mt.type, mt.shm_id, mt.shm_offset, GL_FALSE);
+ mapped_memory_->FreePendingToken(mt.shm_memory, helper_->InsertToken());
+ mapped_textures_.erase(it);
+ CheckGLError();
+}
+
+void GLES2Implementation::ResizeCHROMIUM(GLuint width, GLuint height,
+ float scale_factor) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glResizeCHROMIUM("
+ << width << ", " << height << ", " << scale_factor << ")");
+ helper_->ResizeCHROMIUM(width, height, scale_factor);
+ CheckGLError();
+}
+
+const GLchar* GLES2Implementation::GetRequestableExtensionsCHROMIUM() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] glGetRequestableExtensionsCHROMIUM()");
+ TRACE_EVENT0("gpu",
+ "GLES2Implementation::GetRequestableExtensionsCHROMIUM()");
+ const char* result = NULL;
+ // Clear the bucket so if the command fails nothing will be in it.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetRequestableExtensionsCHROMIUM(kResultBucketId);
+ std::string str;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ // The set of requestable extensions shrinks as we enable
+ // them. Because we don't know when the client will stop referring
+ // to a previous one it queries (see GetString) we need to cache
+ // the unique results.
+ std::set<std::string>::const_iterator sit =
+ requestable_extensions_set_.find(str);
+ if (sit != requestable_extensions_set_.end()) {
+ result = sit->c_str();
+ } else {
+ std::pair<std::set<std::string>::const_iterator, bool> insert_result =
+ requestable_extensions_set_.insert(str);
+ GPU_DCHECK(insert_result.second);
+ result = insert_result.first->c_str();
+ }
+ }
+ GPU_CLIENT_LOG(" returned " << result);
+ return reinterpret_cast<const GLchar*>(result);
+}
+
+// TODO(gman): Remove this command. It's here for WebGL but is incompatible
+// with VirtualGL contexts.
+void GLES2Implementation::RequestExtensionCHROMIUM(const char* extension) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRequestExtensionCHROMIUM("
+ << extension << ")");
+ SetBucketAsCString(kResultBucketId, extension);
+ helper_->RequestExtensionCHROMIUM(kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+
+ struct ExtensionCheck {
+ const char* extension;
+ ExtensionStatus* status;
+ };
+ const ExtensionCheck checks[] = {
+ {
+ "GL_ANGLE_pack_reverse_row_order",
+ &angle_pack_reverse_row_order_status_,
+ },
+ {
+ "GL_CHROMIUM_framebuffer_multisample",
+ &chromium_framebuffer_multisample_,
+ },
+ };
+ const size_t kNumChecks = sizeof(checks)/sizeof(checks[0]);
+ for (size_t ii = 0; ii < kNumChecks; ++ii) {
+ const ExtensionCheck& check = checks[ii];
+ if (*check.status == kUnavailableExtensionStatus &&
+ !strcmp(extension, check.extension)) {
+ *check.status = kUnknownExtensionStatus;
+ }
+ }
+}
+
+void GLES2Implementation::RateLimitOffscreenContextCHROMIUM() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRateLimitOffscreenCHROMIUM()");
+ // Wait if this would add too many rate limit tokens.
+ if (rate_limit_tokens_.size() == kMaxSwapBuffers) {
+ helper_->WaitForToken(rate_limit_tokens_.front());
+ rate_limit_tokens_.pop();
+ }
+ rate_limit_tokens_.push(helper_->InsertToken());
+}
+
+void GLES2Implementation::GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
+ << static_cast<const void*>(pnames) << ", "
+ << count << ", " << results << ", "
+ << size << ")");
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLuint i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(
+ " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
+ }
+ });
+
+ GetMultipleIntegervState state(pnames, count, results, size);
+ if (!GetMultipleIntegervSetup(&state)) {
+ return;
+ }
+ state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
+ if (!state.buffer) {
+ SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
+ "Transfer buffer allocation failed.");
+ return;
+ }
+ GetMultipleIntegervRequest(&state);
+ WaitForCmd();
+ GetMultipleIntegervOnCompleted(&state);
+
+ GPU_CLIENT_LOG(" returned");
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int i = 0; i < state.num_results; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
+ }
+ });
+
+ // TODO(gman): We should be able to free without a token.
+ transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
+ CheckGLError();
+}
+
+bool GLES2Implementation::GetMultipleIntegervSetup(
+ GetMultipleIntegervState* state) {
+ state->num_results = 0;
+ for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
+ int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
+ if (!num) {
+ SetGLErrorInvalidEnum(
+ "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
+ return false;
+ }
+ state->num_results += num;
+ }
+ if (static_cast<size_t>(state->results_size) !=
+ state->num_results * sizeof(GLint)) {
+ SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
+ return false;
+ }
+ for (int ii = 0; ii < state->num_results; ++ii) {
+ if (state->results[ii] != 0) {
+ SetGLError(GL_INVALID_VALUE,
+ "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
+ return false;
+ }
+ }
+ state->transfer_buffer_size_needed =
+ state->pnames_count * sizeof(state->pnames[0]) +
+ state->num_results * sizeof(state->results[0]);
+ return true;
+}
+
+void GLES2Implementation::GetMultipleIntegervRequest(
+ GetMultipleIntegervState* state) {
+ GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
+ state->results_buffer = pnames_buffer + state->pnames_count;
+ memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
+ memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
+ helper_->GetMultipleIntegervCHROMIUM(
+ transfer_buffer_->GetShmId(),
+ transfer_buffer_->GetOffset(pnames_buffer),
+ state->pnames_count,
+ transfer_buffer_->GetShmId(),
+ transfer_buffer_->GetOffset(state->results_buffer),
+ state->results_size);
+}
+
+void GLES2Implementation::GetMultipleIntegervOnCompleted(
+ GetMultipleIntegervState* state) {
+ memcpy(state->results, state->results_buffer, state->results_size);;
+}
+
+void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
+ GetAllShaderPrecisionFormatsState* state) {
+ state->transfer_buffer_size_needed =
+ state->precision_params_count *
+ sizeof(cmds::GetShaderPrecisionFormat::Result);
+}
+
+void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
+ GetAllShaderPrecisionFormatsState* state) {
+ typedef cmds::GetShaderPrecisionFormat::Result Result;
+ Result* result = static_cast<Result*>(state->results_buffer);
+
+ for (int i = 0; i < state->precision_params_count; i++) {
+ result->success = false;
+ helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
+ state->precision_params[i][1],
+ transfer_buffer_->GetShmId(),
+ transfer_buffer_->GetOffset(result));
+ result++;
+ }
+}
+
+void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
+ GetAllShaderPrecisionFormatsState* state) {
+ typedef cmds::GetShaderPrecisionFormat::Result Result;
+ Result* result = static_cast<Result*>(state->results_buffer);
+
+ for (int i = 0; i < state->precision_params_count; i++) {
+ if (result->success) {
+ const GLStaticState::ShaderPrecisionKey key(
+ state->precision_params[i][0], state->precision_params[i][1]);
+ static_state_.shader_precisions[key] = *result;
+ }
+ result++;
+ }
+}
+
+void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
+ GLuint program, std::vector<int8>* result) {
+ GPU_DCHECK(result);
+ // Clear the bucket so if the command fails nothing will be in it.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
+ GetBucketContents(kResultBucketId, result);
+}
+
+void GLES2Implementation::GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ if (bufsize < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "bufsize less than 0.");
+ return;
+ }
+ if (size == NULL) {
+ SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM", "size is null.");
+ return;
+ }
+ // Make sure they've set size to 0 else the value will be undefined on
+ // lost context.
+ GPU_DCHECK(*size == 0);
+ std::vector<int8> result;
+ GetProgramInfoCHROMIUMHelper(program, &result);
+ if (result.empty()) {
+ return;
+ }
+ *size = result.size();
+ if (!info) {
+ return;
+ }
+ if (static_cast<size_t>(bufsize) < result.size()) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glProgramInfoCHROMIUM", "bufsize is too small for result.");
+ return;
+ }
+ memcpy(info, &result[0], result.size());
+}
+
+GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
+ << texture << ")");
+ TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
+ typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_ZERO;
+ }
+ *result = GL_ZERO;
+
+ helper_->CreateStreamTextureCHROMIUM(texture,
+ GetResultShmId(),
+ GetResultShmOffset());
+ WaitForCmd();
+ GLuint result_value = *result;
+ CheckGLError();
+ return result_value;
+}
+
+void GLES2Implementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] DestroyStreamTextureCHROMIUM("
+ << texture << ")");
+ TRACE_EVENT0("gpu", "GLES2::DestroyStreamTextureCHROMIUM");
+ helper_->DestroyStreamTextureCHROMIUM(texture);
+ CheckGLError();
+}
+
+void GLES2Implementation::PostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] PostSubBufferCHROMIUM("
+ << x << ", " << y << ", " << width << ", " << height << ")");
+ TRACE_EVENT2("gpu", "GLES2::PostSubBufferCHROMIUM",
+ "width", width, "height", height);
+
+ // Same flow control as GLES2Implementation::SwapBuffers (see comments there).
+ swap_buffers_tokens_.push(helper_->InsertToken());
+ helper_->PostSubBufferCHROMIUM(x, y, width, height);
+ helper_->CommandBufferHelper::Flush();
+ if (swap_buffers_tokens_.size() > kMaxSwapBuffers + 1) {
+ helper_->WaitForToken(swap_buffers_tokens_.front());
+ swap_buffers_tokens_.pop();
+ }
+}
+
+void GLES2Implementation::DeleteQueriesEXTHelper(
+ GLsizei n, const GLuint* queries) {
+ // TODO(gman): Remove this as queries are not shared resources.
+ if (!GetIdHandler(id_namespaces::kQueries)->FreeIds(
+ this, n, queries, &GLES2Implementation::DeleteQueriesStub)) {
+ SetGLError(
+ GL_INVALID_VALUE,
+ "glDeleteTextures", "id not created by this context.");
+ return;
+ }
+
+ for (GLsizei ii = 0; ii < n; ++ii)
+ query_tracker_->RemoveQuery(queries[ii]);
+
+ helper_->DeleteQueriesEXTImmediate(n, queries);
+}
+
+// TODO(gman): Remove this. Queries are not shared resources.
+void GLES2Implementation::DeleteQueriesStub(
+ GLsizei /* n */, const GLuint* /* queries */) {
+}
+
+GLboolean GLES2Implementation::IsQueryEXT(GLuint id) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] IsQueryEXT(" << id << ")");
+
+ // TODO(gman): To be spec compliant IDs from other contexts sharing
+ // resources need to return true here even though you can't share
+ // queries across contexts?
+ return query_tracker_->GetQuery(id) != NULL;
+}
+
+void GLES2Implementation::BeginQueryEXT(GLenum target, GLuint id) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] BeginQueryEXT("
+ << GLES2Util::GetStringQueryTarget(target)
+ << ", " << id << ")");
+
+ // if any outstanding queries INV_OP
+ if (current_query_) {
+ SetGLError(
+ GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
+ return;
+ }
+
+ // id = 0 INV_OP
+ if (id == 0) {
+ SetGLError(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
+ return;
+ }
+
+ // TODO(gman) if id not GENned INV_OPERATION
+
+ // if id does not have an object
+ QueryTracker::Query* query = query_tracker_->GetQuery(id);
+ if (!query) {
+ query = query_tracker_->CreateQuery(id, target);
+ if (!query) {
+ MustBeContextLost();
+ return;
+ }
+ } else if (query->target() != target) {
+ SetGLError(
+ GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
+ return;
+ }
+
+ current_query_ = query;
+
+ query->Begin(this);
+ CheckGLError();
+}
+
+void GLES2Implementation::EndQueryEXT(GLenum target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] EndQueryEXT("
+ << GLES2Util::GetStringQueryTarget(target) << ")");
+ // Don't do anything if the context is lost.
+ if (helper_->IsContextLost()) {
+ return;
+ }
+
+ if (!current_query_) {
+ SetGLError(GL_INVALID_OPERATION, "glEndQueryEXT", "no active query");
+ return;
+ }
+
+ if (current_query_->target() != target) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glEndQueryEXT", "target does not match active query");
+ return;
+ }
+
+ current_query_->End(this);
+ current_query_ = NULL;
+ CheckGLError();
+}
+
+void GLES2Implementation::GetQueryivEXT(
+ GLenum target, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT("
+ << GLES2Util::GetStringQueryTarget(target) << ", "
+ << GLES2Util::GetStringQueryParameter(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+
+ if (pname != GL_CURRENT_QUERY_EXT) {
+ SetGLErrorInvalidEnum("glGetQueryivEXT", pname, "pname");
+ return;
+ }
+ *params = (current_query_ && current_query_->target() == target) ?
+ current_query_->id() : 0;
+ GPU_CLIENT_LOG(" " << *params);
+ CheckGLError();
+}
+
+void GLES2Implementation::GetQueryObjectuivEXT(
+ GLuint id, GLenum pname, GLuint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] GetQueryivEXT(" << id << ", "
+ << GLES2Util::GetStringQueryObjectParameter(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+
+ QueryTracker::Query* query = query_tracker_->GetQuery(id);
+ if (!query) {
+ SetGLError(GL_INVALID_OPERATION, "glQueryObjectuivEXT", "unknown query id");
+ return;
+ }
+
+ if (query == current_query_) {
+ SetGLError(
+ GL_INVALID_OPERATION,
+ "glQueryObjectuivEXT", "query active. Did you to call glEndQueryEXT?");
+ return;
+ }
+
+ if (query->NeverUsed()) {
+ SetGLError(
+ GL_INVALID_OPERATION,
+ "glQueryObjectuivEXT", "Never used. Did you call glBeginQueryEXT?");
+ return;
+ }
+
+ switch (pname) {
+ case GL_QUERY_RESULT_EXT:
+ if (!query->CheckResultsAvailable(helper_)) {
+ helper_->WaitForToken(query->token());
+ if (!query->CheckResultsAvailable(helper_)) {
+ // TODO(gman): Speed this up.
+ WaitForCmd();
+ GPU_CHECK(query->CheckResultsAvailable(helper_));
+ }
+ }
+ *params = query->GetResult();
+ break;
+ case GL_QUERY_RESULT_AVAILABLE_EXT:
+ *params = query->CheckResultsAvailable(helper_);
+ break;
+ default:
+ SetGLErrorInvalidEnum("glQueryObjectuivEXT", pname, "pname");
+ break;
+ }
+ GPU_CLIENT_LOG(" " << *params);
+ CheckGLError();
+}
+
+void GLES2Implementation::DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawArraysInstancedANGLE("
+ << GLES2Util::GetStringDrawMode(mode) << ", "
+ << first << ", " << count << ", " << primcount << ")");
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "count < 0");
+ return;
+ }
+ if (primcount < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawArraysInstancedANGLE", "primcount < 0");
+ return;
+ }
+ if (primcount == 0) {
+ return;
+ }
+ bool simulated = false;
+ if (!vertex_array_object_manager_->SetupSimulatedClientSideBuffers(
+ "glDrawArraysInstancedANGLE", this, helper_, first + count, primcount,
+ &simulated)) {
+ return;
+ }
+ helper_->DrawArraysInstancedANGLE(mode, first, count, primcount);
+ RestoreArrayBuffer(simulated);
+ CheckGLError();
+}
+
+void GLES2Implementation::DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawElementsInstancedANGLE("
+ << GLES2Util::GetStringDrawMode(mode) << ", "
+ << count << ", "
+ << GLES2Util::GetStringIndexType(type) << ", "
+ << static_cast<const void*>(indices) << ", "
+ << primcount << ")");
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE,
+ "glDrawElementsInstancedANGLE", "count less than 0.");
+ return;
+ }
+ if (count == 0) {
+ return;
+ }
+ if (primcount < 0) {
+ SetGLError(GL_INVALID_VALUE,
+ "glDrawElementsInstancedANGLE", "primcount < 0");
+ return;
+ }
+ if (primcount == 0) {
+ return;
+ }
+ GLuint offset = 0;
+ bool simulated = false;
+ if (!vertex_array_object_manager_->SetupSimulatedIndexAndClientSideBuffers(
+ "glDrawElementsInstancedANGLE", this, helper_, count, type, primcount,
+ indices, &offset, &simulated)) {
+ return;
+ }
+ helper_->DrawElementsInstancedANGLE(mode, count, type, offset, primcount);
+ RestoreElementAndArrayBuffers(simulated);
+ CheckGLError();
+}
+
+void GLES2Implementation::GenMailboxCHROMIUM(
+ GLbyte* mailbox) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenMailboxCHROMIUM("
+ << static_cast<const void*>(mailbox) << ")");
+ TRACE_EVENT0("gpu", "GLES2::GenMailboxCHROMIUM");
+
+ helper_->GenMailboxCHROMIUM(kResultBucketId);
+
+ std::vector<GLbyte> result;
+ GetBucketContents(kResultBucketId, &result);
+
+ std::copy(result.begin(), result.end(), mailbox);
+ CheckGLError();
+}
+
+void GLES2Implementation::PushGroupMarkerEXT(
+ GLsizei length, const GLchar* marker) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPushGroupMarkerEXT("
+ << length << ", " << marker << ")");
+ if (!marker) {
+ marker = "";
+ }
+ SetBucketAsString(
+ kResultBucketId,
+ (length ? std::string(marker, length) : std::string(marker)));
+ helper_->PushGroupMarkerEXT(kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+ debug_marker_manager_.PushGroup(
+ length ? std::string(marker, length) : std::string(marker));
+}
+
+void GLES2Implementation::InsertEventMarkerEXT(
+ GLsizei length, const GLchar* marker) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertEventMarkerEXT("
+ << length << ", " << marker << ")");
+ if (!marker) {
+ marker = "";
+ }
+ SetBucketAsString(
+ kResultBucketId,
+ (length ? std::string(marker, length) : std::string(marker)));
+ helper_->InsertEventMarkerEXT(kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+ debug_marker_manager_.SetMarker(
+ length ? std::string(marker, length) : std::string(marker));
+}
+
+void GLES2Implementation::PopGroupMarkerEXT() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPopGroupMarkerEXT()");
+ helper_->PopGroupMarkerEXT();
+ debug_marker_manager_.PopGroup();
+}
+
+void GLES2Implementation::TraceBeginCHROMIUM(const char* name) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceBeginCHROMIUM("
+ << name << ")");
+ if (current_trace_name_.get()) {
+ SetGLError(GL_INVALID_OPERATION, "glTraceBeginCHROMIUM",
+ "trace already running");
+ return;
+ }
+ TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", name, this);
+ SetBucketAsCString(kResultBucketId, name);
+ helper_->TraceBeginCHROMIUM(kResultBucketId);
+ helper_->SetBucketSize(kResultBucketId, 0);
+ current_trace_name_.reset(new std::string(name));
+}
+
+void GLES2Implementation::TraceEndCHROMIUM() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTraceEndCHROMIUM(" << ")");
+ if (!current_trace_name_.get()) {
+ SetGLError(GL_INVALID_OPERATION, "glTraceEndCHROMIUM",
+ "missing begin trace");
+ return;
+ }
+ helper_->TraceEndCHROMIUM();
+ TRACE_EVENT_COPY_ASYNC_END0("gpu", current_trace_name_->c_str(), this);
+ current_trace_name_.reset();
+}
+
+void* GLES2Implementation::MapBufferCHROMIUM(GLuint target, GLenum access) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapBufferCHROMIUM("
+ << target << ", " << GLES2Util::GetStringEnum(access) << ")");
+ switch (target) {
+ case GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM:
+ if (access != GL_READ_ONLY) {
+ SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
+ return NULL;
+ }
+ break;
+ case GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM:
+ if (access != GL_WRITE_ONLY) {
+ SetGLError(GL_INVALID_ENUM, "glMapBufferCHROMIUM", "bad access mode");
+ return NULL;
+ }
+ break;
+ default:
+ SetGLError(
+ GL_INVALID_ENUM, "glMapBufferCHROMIUM", "invalid target");
+ return NULL;
+ }
+ GLuint buffer_id;
+ GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id);
+ if (!buffer_id) {
+ return NULL;
+ }
+ BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
+ if (!buffer) {
+ SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "invalid buffer");
+ return NULL;
+ }
+ if (buffer->mapped()) {
+ SetGLError(GL_INVALID_OPERATION, "glMapBufferCHROMIUM", "already mapped");
+ return NULL;
+ }
+ // Here we wait for previous transfer operations to be finished.
+ // TODO(hubbe): AsyncTex(Sub)Image2dCHROMIUM does not currently work
+ // with this method of synchronization. Until this is fixed,
+ // MapBufferCHROMIUM will not block even if the transfer is not ready
+ // for these calls.
+ if (buffer->transfer_ready_token()) {
+ helper_->WaitForToken(buffer->transfer_ready_token());
+ buffer->set_transfer_ready_token(0);
+ }
+ buffer->set_mapped(true);
+
+ GPU_CLIENT_LOG(" returned " << buffer->address());
+ CheckGLError();
+ return buffer->address();
+}
+
+GLboolean GLES2Implementation::UnmapBufferCHROMIUM(GLuint target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG(
+ "[" << GetLogPrefix() << "] glUnmapBufferCHROMIUM(" << target << ")");
+ GLuint buffer_id;
+ if (!GetBoundPixelTransferBuffer(target, "glMapBufferCHROMIUM", &buffer_id)) {
+ SetGLError(GL_INVALID_ENUM, "glUnmapBufferCHROMIUM", "invalid target");
+ }
+ if (!buffer_id) {
+ return false;
+ }
+ BufferTracker::Buffer* buffer = buffer_tracker_->GetBuffer(buffer_id);
+ if (!buffer) {
+ SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "invalid buffer");
+ return false;
+ }
+ if (!buffer->mapped()) {
+ SetGLError(GL_INVALID_OPERATION, "glUnmapBufferCHROMIUM", "not mapped");
+ return false;
+ }
+ buffer->set_mapped(false);
+ CheckGLError();
+ return true;
+}
+
+void GLES2Implementation::AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImage2D("
+ << GLES2Util::GetStringTextureTarget(target) << ", "
+ << level << ", "
+ << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", "
+ << width << ", " << height << ", " << border << ", "
+ << GLES2Util::GetStringTextureFormat(format) << ", "
+ << GLES2Util::GetStringPixelType(type) << ", "
+ << static_cast<const void*>(pixels) << ")");
+ if (level < 0 || height < 0 || width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexImage2D", "dimension < 0");
+ return;
+ }
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, unpack_alignment_, &size,
+ &unpadded_row_size, &padded_row_size)) {
+ SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large");
+ return;
+ }
+
+ // If there's no data/buffer just issue the AsyncTexImage2D
+ if (!pixels && !bound_pixel_unpack_transfer_buffer_id_) {
+ helper_->AsyncTexImage2DCHROMIUM(
+ target, level, internalformat, width, height, border, format, type,
+ 0, 0);
+ return;
+ }
+
+ // Otherwise, async uploads require a transfer buffer to be bound.
+ // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
+ // the buffer before the transfer is finished. (Currently such
+ // synchronization has to be handled manually.)
+ GLuint offset = ToGLuint(pixels);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_unpack_transfer_buffer_id_,
+ "glAsyncTexImage2DCHROMIUM", offset, size);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->AsyncTexImage2DCHROMIUM(
+ target, level, internalformat, width, height, border, format, type,
+ buffer->shm_id(), buffer->shm_offset() + offset);
+ }
+}
+
+void GLES2Implementation::AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAsyncTexSubImage2DCHROMIUM("
+ << GLES2Util::GetStringTextureTarget(target) << ", "
+ << level << ", "
+ << xoffset << ", " << yoffset << ", "
+ << width << ", " << height << ", "
+ << GLES2Util::GetStringTextureFormat(format) << ", "
+ << GLES2Util::GetStringPixelType(type) << ", "
+ << static_cast<const void*>(pixels) << ")");
+ if (level < 0 || height < 0 || width < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "dimension < 0");
+ return;
+ }
+
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, unpack_alignment_, &size,
+ &unpadded_row_size, &padded_row_size)) {
+ SetGLError(
+ GL_INVALID_VALUE, "glAsyncTexSubImage2DCHROMIUM", "size to large");
+ return;
+ }
+
+ // Async uploads require a transfer buffer to be bound.
+ // TODO(hubbe): Make MapBufferCHROMIUM block if someone tries to re-use
+ // the buffer before the transfer is finished. (Currently such
+ // synchronization has to be handled manually.)
+ GLuint offset = ToGLuint(pixels);
+ BufferTracker::Buffer* buffer = GetBoundPixelUnpackTransferBufferIfValid(
+ bound_pixel_unpack_transfer_buffer_id_,
+ "glAsyncTexSubImage2DCHROMIUM", offset, size);
+ if (buffer && buffer->shm_id() != -1) {
+ helper_->AsyncTexSubImage2DCHROMIUM(
+ target, level, xoffset, yoffset, width, height, format, type,
+ buffer->shm_id(), buffer->shm_offset() + offset);
+ }
+}
+
+void GLES2Implementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitAsyncTexImage2DCHROMIUM("
+ << GLES2Util::GetStringTextureTarget(target) << ")");
+ helper_->WaitAsyncTexImage2DCHROMIUM(target);
+ CheckGLError();
+}
+
+GLuint GLES2Implementation::InsertSyncPointCHROMIUM() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInsertSyncPointCHROMIUM");
+ return helper_->InsertSyncPointCHROMIUM();
+}
+
+GLuint GLES2Implementation::CreateImageCHROMIUMHelper(
+ GLsizei width, GLsizei height, GLenum internalformat) {
+ if (width <= 0) {
+ SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "width <= 0");
+ return 0;
+ }
+
+ if (height <= 0) {
+ SetGLError(GL_INVALID_VALUE, "glCreateImageCHROMIUM", "height <= 0");
+ return 0;
+ }
+ // Flush the command stream to ensure ordering in case the newly
+ // returned image_id has recently been in use with a different buffer.
+ helper_->CommandBufferHelper::Flush();
+
+ // Create new buffer.
+ GLuint buffer_id = gpu_memory_buffer_tracker_->CreateBuffer(
+ width, height, internalformat);
+ if (buffer_id == 0) {
+ SetGLError(GL_OUT_OF_MEMORY, "glCreateImageCHROMIUM", "out of GPU memory.");
+ return 0;
+ }
+ return buffer_id;
+}
+
+GLuint GLES2Implementation::CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateImageCHROMIUM("
+ << width << ", "
+ << height << ", "
+ << GLES2Util::GetStringTextureInternalFormat(internalformat) << ")");
+ GLuint image_id = CreateImageCHROMIUMHelper(width, height, internalformat);
+ CheckGLError();
+ return image_id;
+}
+
+void GLES2Implementation::DestroyImageCHROMIUMHelper(GLuint image_id) {
+ gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
+ image_id);
+ if (!gpu_buffer) {
+ SetGLError(GL_INVALID_OPERATION, "glDestroyImageCHROMIUM", "invalid image");
+ return;
+ }
+
+ // Flush the command stream to make sure all pending commands
+ // that may refer to the image_id are executed on the service side.
+ helper_->CommandBufferHelper::Flush();
+ gpu_memory_buffer_tracker_->RemoveBuffer(image_id);
+}
+
+void GLES2Implementation::DestroyImageCHROMIUM(GLuint image_id) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDestroyImageCHROMIUM("
+ << image_id << ")");
+ DestroyImageCHROMIUMHelper(image_id);
+ CheckGLError();
+}
+
+void GLES2Implementation::UnmapImageCHROMIUMHelper(GLuint image_id) {
+ gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
+ image_id);
+ if (!gpu_buffer) {
+ SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "invalid image");
+ return;
+ }
+
+ if (!gpu_buffer->IsMapped()) {
+ SetGLError(GL_INVALID_OPERATION, "glUnmapImageCHROMIUM", "not mapped");
+ return;
+ }
+ gpu_buffer->Unmap();
+}
+
+void GLES2Implementation::UnmapImageCHROMIUM(GLuint image_id) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUnmapImageCHROMIUM("
+ << image_id << ")");
+
+ UnmapImageCHROMIUMHelper(image_id);
+ CheckGLError();
+}
+
+void* GLES2Implementation::MapImageCHROMIUMHelper(GLuint image_id,
+ GLenum access) {
+ gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
+ image_id);
+ if (!gpu_buffer) {
+ SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "invalid image");
+ return NULL;
+ }
+ gfx::GpuMemoryBuffer::AccessMode mode;
+ switch(access) {
+ case GL_WRITE_ONLY:
+ mode = gfx::GpuMemoryBuffer::WRITE_ONLY;
+ break;
+ case GL_READ_ONLY:
+ mode = gfx::GpuMemoryBuffer::READ_ONLY;
+ break;
+ case GL_READ_WRITE:
+ mode = gfx::GpuMemoryBuffer::READ_WRITE;
+ break;
+ default:
+ SetGLError(GL_INVALID_ENUM, "glMapImageCHROMIUM",
+ "invalid GPU access mode");
+ return NULL;
+ }
+
+ if (gpu_buffer->IsMapped()) {
+ SetGLError(GL_INVALID_OPERATION, "glMapImageCHROMIUM", "already mapped");
+ return NULL;
+ }
+
+ void* mapped_buffer = NULL;
+ gpu_buffer->Map(mode, &mapped_buffer);
+ return mapped_buffer;
+}
+
+void* GLES2Implementation::MapImageCHROMIUM(
+ GLuint image_id, GLenum access) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glMapImageCHROMIUM("
+ << image_id << ", "
+ << GLES2Util::GetStringEnum(access) << ")");
+
+ void* mapped = MapImageCHROMIUMHelper(image_id, access);
+ CheckGLError();
+ return mapped;
+}
+
+void GLES2Implementation::GetImageParameterivCHROMIUMHelper(
+ GLuint image_id, GLenum pname, GLint* params) {
+ if (pname != GL_IMAGE_ROWBYTES_CHROMIUM) {
+ SetGLError(GL_INVALID_ENUM, "glGetImageParameterivCHROMIUM",
+ "invalid parameter");
+ return;
+ }
+
+ gfx::GpuMemoryBuffer* gpu_buffer = gpu_memory_buffer_tracker_->GetBuffer(
+ image_id);
+ if (!gpu_buffer) {
+ SetGLError(GL_INVALID_OPERATION, "glGetImageParameterivCHROMIUM",
+ "invalid image");
+ return;
+ }
+
+ *params = gpu_buffer->GetStride();
+}
+
+void GLES2Implementation::GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glImageParameterivCHROMIUM("
+ << image_id << ", "
+ << GLES2Util::GetStringBufferParameter(pname) << ", "
+ << static_cast<const void*>(params) << ")");
+ GetImageParameterivCHROMIUMHelper(image_id, pname, params);
+ CheckGLError();
+}
+
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/client/gles2_implementation_impl_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation.h b/chromium/gpu/command_buffer/client/gles2_implementation.h
new file mode 100644
index 00000000000..c2bf49f41fc
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_implementation.h
@@ -0,0 +1,712 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_H_
+
+#include <GLES2/gl2.h>
+
+#include <map>
+#include <queue>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/buffer_tracker.h"
+#include "gpu/command_buffer/client/client_context_state.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
+#include "gpu/command_buffer/client/image_factory.h"
+#include "gpu/command_buffer/client/query_tracker.h"
+#include "gpu/command_buffer/client/ref_counted.h"
+#include "gpu/command_buffer/client/ring_buffer.h"
+#include "gpu/command_buffer/client/share_group.h"
+#include "gpu/command_buffer/common/compiler_specific.h"
+#include "gpu/command_buffer/common/debug_marker_manager.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+
+#if !defined(NDEBUG) && !defined(__native_client__) && !defined(GLES2_CONFORMANCE_TESTS) // NOLINT
+ #if defined(GLES2_INLINE_OPTIMIZATION)
+ // TODO(gman): Replace with macros that work with inline optmization.
+ #define GPU_CLIENT_SINGLE_THREAD_CHECK()
+ #define GPU_CLIENT_LOG(args)
+ #define GPU_CLIENT_LOG_CODE_BLOCK(code)
+ #define GPU_CLIENT_DCHECK_CODE_BLOCK(code)
+ #else
+ #include "base/logging.h"
+ #define GPU_CLIENT_SINGLE_THREAD_CHECK() SingleThreadChecker checker(this);
+ #define GPU_CLIENT_LOG(args) DLOG_IF(INFO, debug_) << args;
+ #define GPU_CLIENT_LOG_CODE_BLOCK(code) code
+ #define GPU_CLIENT_DCHECK_CODE_BLOCK(code) code
+ #define GPU_CLIENT_DEBUG
+ #endif
+#else
+ #define GPU_CLIENT_SINGLE_THREAD_CHECK()
+ #define GPU_CLIENT_LOG(args)
+ #define GPU_CLIENT_LOG_CODE_BLOCK(code)
+ #define GPU_CLIENT_DCHECK_CODE_BLOCK(code)
+#endif
+
+#if defined(GPU_CLIENT_DEBUG)
+ // Set to 1 to have the client fail when a GL error is generated.
+ // This helps find bugs in the renderer since the debugger stops on the error.
+# if 0
+# define GL_CLIENT_FAIL_GL_ERRORS
+# endif
+#endif
+
+// Check that destination pointers point to initialized memory.
+// When the context is lost, calling GL function has no effect so if destination
+// pointers point to initialized memory it can often lead to crash bugs. eg.
+//
+// GLsizei len;
+// glGetShaderSource(shader, max_size, &len, buffer);
+// std::string src(buffer, buffer + len); // len can be uninitialized here!!!
+//
+// Because this check is not official GL this check happens only on Chrome code,
+// not Pepper.
+//
+// If it was up to us we'd just always write to the destination but the OpenGL
+// spec defines the behavior of OpenGL functions, not us. :-(
+#if defined(__native_client__) || defined(GLES2_CONFORMANCE_TESTS)
+ #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v)
+ #define GPU_CLIENT_DCHECK(v)
+#elif defined(GPU_DCHECK)
+ #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v) GPU_DCHECK(v)
+ #define GPU_CLIENT_DCHECK(v) GPU_DCHECK(v)
+#elif defined(DCHECK)
+ #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v) DCHECK(v)
+ #define GPU_CLIENT_DCHECK(v) DCHECK(v)
+#else
+ #define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(v) ASSERT(v)
+ #define GPU_CLIENT_DCHECK(v) ASSERT(v)
+#endif
+
+#define GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(type, ptr) \
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(ptr && \
+ (ptr[0] == static_cast<type>(0) || ptr[0] == static_cast<type>(-1)));
+
+#define GPU_CLIENT_VALIDATE_DESTINATION_OPTIONAL_INITALIZATION(type, ptr) \
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION_ASSERT(!ptr || \
+ (ptr[0] == static_cast<type>(0) || ptr[0] == static_cast<type>(-1)));
+
+struct GLUniformDefinitionCHROMIUM;
+
+namespace gpu {
+
+class MappedMemoryManager;
+class ScopedTransferBufferPtr;
+class TransferBufferInterface;
+
+namespace gles2 {
+
+class ImageFactory;
+class VertexArrayObjectManager;
+
+// This class emulates GLES2 over command buffers. It can be used by a client
+// program so that the program does not need deal with shared memory and command
+// buffer management. See gl2_lib.h. Note that there is a performance gain to
+// be had by changing your code to use command buffers directly by using the
+// GLES2CmdHelper but that entails changing your code to use and deal with
+// shared memory and synchronization issues.
+class GLES2_IMPL_EXPORT GLES2Implementation : public GLES2Interface {
+ public:
+ class ErrorMessageCallback {
+ public:
+ virtual ~ErrorMessageCallback() { }
+ virtual void OnErrorMessage(const char* msg, int id) = 0;
+ };
+
+ // Stores GL state that never changes.
+ struct GLES2_IMPL_EXPORT GLStaticState {
+ GLStaticState();
+ ~GLStaticState();
+
+ struct GLES2_IMPL_EXPORT IntState {
+ IntState();
+ GLint max_combined_texture_image_units;
+ GLint max_cube_map_texture_size;
+ GLint max_fragment_uniform_vectors;
+ GLint max_renderbuffer_size;
+ GLint max_texture_image_units;
+ GLint max_texture_size;
+ GLint max_varying_vectors;
+ GLint max_vertex_attribs;
+ GLint max_vertex_texture_image_units;
+ GLint max_vertex_uniform_vectors;
+ GLint num_compressed_texture_formats;
+ GLint num_shader_binary_formats;
+ };
+ IntState int_state;
+
+ typedef std::pair<GLenum,GLenum> ShaderPrecisionKey;
+ typedef std::map<ShaderPrecisionKey,
+ cmds::GetShaderPrecisionFormat::Result>
+ ShaderPrecisionMap;
+ ShaderPrecisionMap shader_precisions;
+ };
+
+ // The maxiumum result size from simple GL get commands.
+ static const size_t kMaxSizeOfSimpleResult = 16 * sizeof(uint32); // NOLINT.
+
+ // used for testing only. If more things are reseved add them here.
+ static const unsigned int kStartingOffset = kMaxSizeOfSimpleResult;
+
+ // Size in bytes to issue async flush for transfer buffer.
+ static const unsigned int kSizeToFlush = 256 * 1024;
+
+ // The bucket used for results. Public for testing only.
+ static const uint32 kResultBucketId = 1;
+
+ // Alignment of allocations.
+ static const unsigned int kAlignment = 4;
+
+ // GL names for the buffers used to emulate client side buffers.
+ static const GLuint kClientSideArrayId = 0xFEDCBA98u;
+ static const GLuint kClientSideElementArrayId = 0xFEDCBA99u;
+
+ // Number of swap buffers allowed before waiting.
+ static const size_t kMaxSwapBuffers = 2;
+
+ GLES2Implementation(
+ GLES2CmdHelper* helper,
+ ShareGroup* share_group,
+ TransferBufferInterface* transfer_buffer,
+ bool bind_generates_resource,
+ ImageFactory* image_factory);
+
+ virtual ~GLES2Implementation();
+
+ bool Initialize(
+ unsigned int starting_transfer_buffer_size,
+ unsigned int min_transfer_buffer_size,
+ unsigned int max_transfer_buffer_size);
+
+ // The GLES2CmdHelper being used by this GLES2Implementation. You can use
+ // this to issue cmds at a lower level for certain kinds of optimization.
+ GLES2CmdHelper* helper() const;
+
+ // Gets client side generated errors.
+ GLenum GetClientSideGLError();
+
+ // Include the auto-generated part of this class. We split this because
+ // it means we can easily edit the non-auto generated parts right here in
+ // this file instead of having to edit some template or the code generator.
+ #include "gpu/command_buffer/client/gles2_implementation_autogen.h"
+
+ virtual void DisableVertexAttribArray(GLuint index) OVERRIDE;
+ virtual void EnableVertexAttribArray(GLuint index) OVERRIDE;
+ virtual void GetVertexAttribfv(
+ GLuint index, GLenum pname, GLfloat* params) OVERRIDE;
+ virtual void GetVertexAttribiv(
+ GLuint index, GLenum pname, GLint* params) OVERRIDE;
+
+ void GetProgramInfoCHROMIUMHelper(GLuint program, std::vector<int8>* result);
+ GLint GetAttribLocationHelper(GLuint program, const char* name);
+ GLint GetUniformLocationHelper(GLuint program, const char* name);
+ bool GetActiveAttribHelper(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name);
+ bool GetActiveUniformHelper(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name);
+
+ void SetSharedMemoryChunkSizeMultiple(unsigned int multiple);
+
+ void FreeUnusedSharedMemory();
+ void FreeEverything();
+
+ void SetErrorMessageCallback(ErrorMessageCallback* callback) {
+ error_message_callback_ = callback;
+ }
+
+ ShareGroup* share_group() const {
+ return share_group_.get();
+ }
+
+ private:
+ friend class GLES2ImplementationTest;
+ friend class VertexArrayObjectManager;
+
+ // Used to track whether an extension is available
+ enum ExtensionStatus {
+ kAvailableExtensionStatus,
+ kUnavailableExtensionStatus,
+ kUnknownExtensionStatus
+ };
+
+ // Base class for mapped resources.
+ struct MappedResource {
+ MappedResource(GLenum _access, int _shm_id, void* mem, unsigned int offset)
+ : access(_access),
+ shm_id(_shm_id),
+ shm_memory(mem),
+ shm_offset(offset) {
+ }
+
+ // access mode. Currently only GL_WRITE_ONLY is valid
+ GLenum access;
+
+ // Shared memory ID for buffer.
+ int shm_id;
+
+ // Address of shared memory
+ void* shm_memory;
+
+ // Offset of shared memory
+ unsigned int shm_offset;
+ };
+
+ // Used to track mapped textures.
+ struct MappedTexture : public MappedResource {
+ MappedTexture(
+ GLenum access,
+ int shm_id,
+ void* shm_mem,
+ unsigned int shm_offset,
+ GLenum _target,
+ GLint _level,
+ GLint _xoffset,
+ GLint _yoffset,
+ GLsizei _width,
+ GLsizei _height,
+ GLenum _format,
+ GLenum _type)
+ : MappedResource(access, shm_id, shm_mem, shm_offset),
+ target(_target),
+ level(_level),
+ xoffset(_xoffset),
+ yoffset(_yoffset),
+ width(_width),
+ height(_height),
+ format(_format),
+ type(_type) {
+ }
+
+ // These match the arguments to TexSubImage2D.
+ GLenum target;
+ GLint level;
+ GLint xoffset;
+ GLint yoffset;
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+ };
+
+ // Used to track mapped buffers.
+ struct MappedBuffer : public MappedResource {
+ MappedBuffer(
+ GLenum access,
+ int shm_id,
+ void* shm_mem,
+ unsigned int shm_offset,
+ GLenum _target,
+ GLintptr _offset,
+ GLsizeiptr _size)
+ : MappedResource(access, shm_id, shm_mem, shm_offset),
+ target(_target),
+ offset(_offset),
+ size(_size) {
+ }
+
+ // These match the arguments to BufferSubData.
+ GLenum target;
+ GLintptr offset;
+ GLsizeiptr size;
+ };
+
+ struct TextureUnit {
+ TextureUnit()
+ : bound_texture_2d(0),
+ bound_texture_cube_map(0) {
+ }
+
+ // texture currently bound to this unit's GL_TEXTURE_2D with glBindTexture
+ GLuint bound_texture_2d;
+
+ // texture currently bound to this unit's GL_TEXTURE_CUBE_MAP with
+ // glBindTexture
+ GLuint bound_texture_cube_map;
+ };
+
+ // Checks for single threaded access.
+ class SingleThreadChecker {
+ public:
+ SingleThreadChecker(GLES2Implementation* gles2_implementation);
+ ~SingleThreadChecker();
+
+ private:
+ GLES2Implementation* gles2_implementation_;
+ };
+
+ // Gets the value of the result.
+ template <typename T>
+ T GetResultAs() {
+ return static_cast<T>(GetResultBuffer());
+ }
+
+ void* GetResultBuffer();
+ int32 GetResultShmId();
+ uint32 GetResultShmOffset();
+
+ bool QueryAndCacheStaticState();
+
+ // Helpers used to batch synchronous GetIntergerv calls with other
+ // synchronous calls.
+ struct GetMultipleIntegervState {
+ GetMultipleIntegervState(const GLenum* pnames, GLuint pnames_count,
+ GLint* results, GLsizeiptr results_size)
+ : pnames(pnames),
+ pnames_count(pnames_count),
+ results(results),
+ results_size(results_size)
+ { }
+ // inputs
+ const GLenum* pnames;
+ GLuint pnames_count;
+ // outputs
+ GLint* results;
+ GLsizeiptr results_size;
+ // transfer buffer
+ int num_results;
+ int transfer_buffer_size_needed;
+ void* buffer;
+ void* results_buffer;
+ };
+ bool GetMultipleIntegervSetup(
+ GetMultipleIntegervState* state);
+ void GetMultipleIntegervRequest(
+ GetMultipleIntegervState* state);
+ void GetMultipleIntegervOnCompleted(
+ GetMultipleIntegervState* state);
+
+ // Helpers used to batch synchronous GetShaderPrecision calls with other
+ // synchronous calls.
+ struct GetAllShaderPrecisionFormatsState {
+ GetAllShaderPrecisionFormatsState(
+ const GLenum (*precision_params)[2],
+ int precision_params_count)
+ : precision_params(precision_params),
+ precision_params_count(precision_params_count)
+ { }
+ const GLenum (*precision_params)[2];
+ int precision_params_count;
+ int transfer_buffer_size_needed;
+ void* results_buffer;
+ };
+ void GetAllShaderPrecisionFormatsSetup(
+ GetAllShaderPrecisionFormatsState* state);
+ void GetAllShaderPrecisionFormatsRequest(
+ GetAllShaderPrecisionFormatsState* state);
+ void GetAllShaderPrecisionFormatsOnCompleted(
+ GetAllShaderPrecisionFormatsState* state);
+
+ // Lazily determines if GL_ANGLE_pack_reverse_row_order is available
+ bool IsAnglePackReverseRowOrderAvailable();
+ bool IsChromiumFramebufferMultisampleAvailable();
+
+ bool IsExtensionAvailableHelper(
+ const char* extension, ExtensionStatus* status);
+
+ // Gets the GLError through our wrapper.
+ GLenum GetGLError();
+
+ // Sets our wrapper for the GLError.
+ void SetGLError(GLenum error, const char* function_name, const char* msg);
+ void SetGLErrorInvalidEnum(
+ const char* function_name, GLenum value, const char* label);
+
+ // Returns the last error and clears it. Useful for debugging.
+ const std::string& GetLastError() {
+ return last_error_;
+ }
+
+ // Waits for all commands to execute.
+ void WaitForCmd();
+
+ // TODO(gman): These bucket functions really seem like they belong in
+ // CommandBufferHelper (or maybe BucketHelper?). Unfortunately they need
+ // a transfer buffer to function which is currently managed by this class.
+
+ // Gets the contents of a bucket.
+ bool GetBucketContents(uint32 bucket_id, std::vector<int8>* data);
+
+ // Sets the contents of a bucket.
+ void SetBucketContents(uint32 bucket_id, const void* data, size_t size);
+
+ // Sets the contents of a bucket as a string.
+ void SetBucketAsCString(uint32 bucket_id, const char* str);
+
+ // Gets the contents of a bucket as a string. Returns false if there is no
+ // string available which is a separate case from the empty string.
+ bool GetBucketAsString(uint32 bucket_id, std::string* str);
+
+ // Sets the contents of a bucket as a string.
+ void SetBucketAsString(uint32 bucket_id, const std::string& str);
+
+ // Returns true if id is reserved.
+ bool IsBufferReservedId(GLuint id);
+ bool IsFramebufferReservedId(GLuint id) { return false; }
+ bool IsRenderbufferReservedId(GLuint id) { return false; }
+ bool IsTextureReservedId(GLuint id) { return false; }
+ bool IsVertexArrayReservedId(GLuint id) { return false; }
+
+ bool BindBufferHelper(GLenum target, GLuint texture);
+ bool BindFramebufferHelper(GLenum target, GLuint texture);
+ bool BindRenderbufferHelper(GLenum target, GLuint texture);
+ bool BindTextureHelper(GLenum target, GLuint texture);
+ bool BindVertexArrayHelper(GLuint array);
+
+ void GenBuffersHelper(GLsizei n, const GLuint* buffers);
+ void GenFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
+ void GenRenderbuffersHelper(GLsizei n, const GLuint* renderbuffers);
+ void GenTexturesHelper(GLsizei n, const GLuint* textures);
+ void GenVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
+ void GenQueriesEXTHelper(GLsizei n, const GLuint* queries);
+
+ void DeleteBuffersHelper(GLsizei n, const GLuint* buffers);
+ void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
+ void DeleteRenderbuffersHelper(GLsizei n, const GLuint* renderbuffers);
+ void DeleteTexturesHelper(GLsizei n, const GLuint* textures);
+ bool DeleteProgramHelper(GLuint program);
+ bool DeleteShaderHelper(GLuint shader);
+ void DeleteQueriesEXTHelper(GLsizei n, const GLuint* queries);
+ void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
+
+ void DeleteBuffersStub(GLsizei n, const GLuint* buffers);
+ void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers);
+ void DeleteRenderbuffersStub(GLsizei n, const GLuint* renderbuffers);
+ void DeleteTexturesStub(GLsizei n, const GLuint* textures);
+ void DeleteProgramStub(GLsizei n, const GLuint* programs);
+ void DeleteShaderStub(GLsizei n, const GLuint* shaders);
+ // TODO(gman): Remove this as queries are not shared.
+ void DeleteQueriesStub(GLsizei n, const GLuint* queries);
+ void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays);
+
+ void BufferDataHelper(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage);
+ void BufferSubDataHelper(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data);
+ void BufferSubDataHelperImpl(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data,
+ ScopedTransferBufferPtr* buffer);
+
+ GLuint CreateImageCHROMIUMHelper(
+ GLsizei width, GLsizei height, GLenum internalformat);
+ void DestroyImageCHROMIUMHelper(GLuint image_id);
+ void* MapImageCHROMIUMHelper(GLuint image_id, GLenum access);
+ void UnmapImageCHROMIUMHelper(GLuint image_id);
+ void GetImageParameterivCHROMIUMHelper(
+ GLuint image_id, GLenum pname, GLint* params);
+
+ // Helper for GetVertexAttrib
+ bool GetVertexAttribHelper(GLuint index, GLenum pname, uint32* param);
+
+ GLuint GetMaxValueInBufferCHROMIUMHelper(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset);
+
+ void RestoreElementAndArrayBuffers(bool restore);
+ void RestoreArrayBuffer(bool restrore);
+
+ // The pixels pointer should already account for unpack skip rows and skip
+ // pixels.
+ void TexSubImage2DImpl(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, uint32 unpadded_row_size,
+ const void* pixels, uint32 pixels_padded_row_size, GLboolean internal,
+ ScopedTransferBufferPtr* buffer, uint32 buffer_padded_row_size);
+
+ // Helpers for query functions.
+ bool GetHelper(GLenum pname, GLint* params);
+ bool GetBooleanvHelper(GLenum pname, GLboolean* params);
+ bool GetBufferParameterivHelper(GLenum target, GLenum pname, GLint* params);
+ bool GetFloatvHelper(GLenum pname, GLfloat* params);
+ bool GetFramebufferAttachmentParameterivHelper(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params);
+ bool GetIntegervHelper(GLenum pname, GLint* params);
+ bool GetProgramivHelper(GLuint program, GLenum pname, GLint* params);
+ bool GetRenderbufferParameterivHelper(
+ GLenum target, GLenum pname, GLint* params);
+ bool GetShaderivHelper(GLuint shader, GLenum pname, GLint* params);
+ bool GetTexParameterfvHelper(GLenum target, GLenum pname, GLfloat* params);
+ bool GetTexParameterivHelper(GLenum target, GLenum pname, GLint* params);
+ const GLubyte* GetStringHelper(GLenum name);
+
+ bool IsExtensionAvailable(const char* ext);
+
+ // Caches certain capabilties state. Return true if cached.
+ bool SetCapabilityState(GLenum cap, bool enabled);
+
+ IdHandlerInterface* GetIdHandler(int id_namespace) const;
+
+ void FinishHelper();
+
+ // Asserts that the context is lost.
+ // NOTE: This is an expensive call and should only be called
+ // for error checking.
+ bool MustBeContextLost();
+
+ bool GetBoundPixelTransferBuffer(
+ GLenum target, const char* function_name, GLuint* buffer_id);
+ BufferTracker::Buffer* GetBoundPixelUnpackTransferBufferIfValid(
+ GLuint buffer_id,
+ const char* function_name, GLuint offset, GLsizei size);
+
+ const std::string& GetLogPrefix() const;
+
+#if defined(GL_CLIENT_FAIL_GL_ERRORS)
+ void CheckGLError();
+ void FailGLError(GLenum error);
+#else
+ void CheckGLError() { }
+ void FailGLError(GLenum /* error */) { }
+#endif
+
+ GLES2Util util_;
+ GLES2CmdHelper* helper_;
+ TransferBufferInterface* transfer_buffer_;
+ std::string last_error_;
+ DebugMarkerManager debug_marker_manager_;
+ std::string this_in_hex_;
+
+ std::queue<int32> swap_buffers_tokens_;
+ std::queue<int32> rate_limit_tokens_;
+
+ ExtensionStatus angle_pack_reverse_row_order_status_;
+ ExtensionStatus chromium_framebuffer_multisample_;
+
+ GLStaticState static_state_;
+ ClientContextState state_;
+
+ // pack alignment as last set by glPixelStorei
+ GLint pack_alignment_;
+
+ // unpack alignment as last set by glPixelStorei
+ GLint unpack_alignment_;
+
+ // unpack yflip as last set by glPixelstorei
+ bool unpack_flip_y_;
+
+ // unpack row length as last set by glPixelStorei
+ GLint unpack_row_length_;
+
+ // unpack skip rows as last set by glPixelStorei
+ GLint unpack_skip_rows_;
+
+ // unpack skip pixels as last set by glPixelStorei
+ GLint unpack_skip_pixels_;
+
+ // pack reverse row order as last set by glPixelstorei
+ bool pack_reverse_row_order_;
+
+ scoped_ptr<TextureUnit[]> texture_units_;
+
+ // 0 to gl_state_.max_combined_texture_image_units.
+ GLuint active_texture_unit_;
+
+ GLuint bound_framebuffer_;
+ GLuint bound_read_framebuffer_;
+ GLuint bound_renderbuffer_;
+
+ // The program in use by glUseProgram
+ GLuint current_program_;
+
+ // The currently bound array buffer.
+ GLuint bound_array_buffer_id_;
+
+ // The currently bound pixel transfer buffers.
+ GLuint bound_pixel_pack_transfer_buffer_id_;
+ GLuint bound_pixel_unpack_transfer_buffer_id_;
+
+ // Client side management for vertex array objects. Needed to correctly
+ // track client side arrays.
+ scoped_ptr<VertexArrayObjectManager> vertex_array_object_manager_;
+
+ GLuint reserved_ids_[2];
+
+ // Current GL error bits.
+ uint32 error_bits_;
+
+ // Whether or not to print debugging info.
+ bool debug_;
+
+ // Used to check for single threaded access.
+ int use_count_;
+
+ // Map of GLenum to Strings for glGetString. We need to cache these because
+ // the pointer passed back to the client has to remain valid for eternity.
+ typedef std::map<uint32, std::set<std::string> > GLStringMap;
+ GLStringMap gl_strings_;
+
+ // Similar cache for glGetRequestableExtensionsCHROMIUM. We don't
+ // have an enum for this so handle it separately.
+ std::set<std::string> requestable_extensions_set_;
+
+ typedef std::map<const void*, MappedBuffer> MappedBufferMap;
+ MappedBufferMap mapped_buffers_;
+
+ typedef std::map<const void*, MappedTexture> MappedTextureMap;
+ MappedTextureMap mapped_textures_;
+
+ scoped_ptr<MappedMemoryManager> mapped_memory_;
+
+ scoped_refptr<ShareGroup> share_group_;
+
+ scoped_ptr<QueryTracker> query_tracker_;
+ QueryTracker::Query* current_query_;
+
+ scoped_ptr<BufferTracker> buffer_tracker_;
+
+ scoped_ptr<GpuMemoryBufferTracker> gpu_memory_buffer_tracker_;
+
+ ErrorMessageCallback* error_message_callback_;
+
+ scoped_ptr<std::string> current_trace_name_;
+
+ ImageFactory* image_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLES2Implementation);
+};
+
+inline bool GLES2Implementation::GetBufferParameterivHelper(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+ return false;
+}
+
+inline bool GLES2Implementation::GetFramebufferAttachmentParameterivHelper(
+ GLenum /* target */,
+ GLenum /* attachment */,
+ GLenum /* pname */,
+ GLint* /* params */) {
+ return false;
+}
+
+inline bool GLES2Implementation::GetRenderbufferParameterivHelper(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+ return false;
+}
+
+inline bool GLES2Implementation::GetShaderivHelper(
+ GLuint /* shader */, GLenum /* pname */, GLint* /* params */) {
+ return false;
+}
+
+inline bool GLES2Implementation::GetTexParameterfvHelper(
+ GLenum /* target */, GLenum /* pname */, GLfloat* /* params */) {
+ return false;
+}
+
+inline bool GLES2Implementation::GetTexParameterivHelper(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+ return false;
+}
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation_autogen.h b/chromium/gpu/command_buffer/client/gles2_implementation_autogen.h
new file mode 100644
index 00000000000..c4ed4996dba
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -0,0 +1,555 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_implementation.h to declare the
+// GL api functions.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
+
+virtual void ActiveTexture(GLenum texture) OVERRIDE;
+
+virtual void AttachShader(GLuint program, GLuint shader) OVERRIDE;
+
+virtual void BindAttribLocation(
+ GLuint program, GLuint index, const char* name) OVERRIDE;
+
+virtual void BindBuffer(GLenum target, GLuint buffer) OVERRIDE;
+
+virtual void BindFramebuffer(GLenum target, GLuint framebuffer) OVERRIDE;
+
+virtual void BindRenderbuffer(GLenum target, GLuint renderbuffer) OVERRIDE;
+
+virtual void BindTexture(GLenum target, GLuint texture) OVERRIDE;
+
+virtual void BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) OVERRIDE;
+
+virtual void BlendEquation(GLenum mode) OVERRIDE;
+
+virtual void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) OVERRIDE;
+
+virtual void BlendFunc(GLenum sfactor, GLenum dfactor) OVERRIDE;
+
+virtual void BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) OVERRIDE;
+
+virtual void BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) OVERRIDE;
+
+virtual void BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size,
+ const void* data) OVERRIDE;
+
+virtual GLenum CheckFramebufferStatus(GLenum target) OVERRIDE;
+
+virtual void Clear(GLbitfield mask) OVERRIDE;
+
+virtual void ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) OVERRIDE;
+
+virtual void ClearDepthf(GLclampf depth) OVERRIDE;
+
+virtual void ClearStencil(GLint s) OVERRIDE;
+
+virtual void ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) OVERRIDE;
+
+virtual void CompileShader(GLuint shader) OVERRIDE;
+
+virtual void CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize,
+ const void* data) OVERRIDE;
+
+virtual void CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize,
+ const void* data) OVERRIDE;
+
+virtual void CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) OVERRIDE;
+
+virtual void CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) OVERRIDE;
+
+virtual GLuint CreateProgram() OVERRIDE;
+
+virtual GLuint CreateShader(GLenum type) OVERRIDE;
+
+virtual void CullFace(GLenum mode) OVERRIDE;
+
+virtual void DeleteBuffers(GLsizei n, const GLuint* buffers) OVERRIDE;
+
+virtual void DeleteFramebuffers(
+ GLsizei n, const GLuint* framebuffers) OVERRIDE;
+
+virtual void DeleteProgram(GLuint program) OVERRIDE;
+
+virtual void DeleteRenderbuffers(
+ GLsizei n, const GLuint* renderbuffers) OVERRIDE;
+
+virtual void DeleteShader(GLuint shader) OVERRIDE;
+
+virtual void DeleteTextures(GLsizei n, const GLuint* textures) OVERRIDE;
+
+virtual void DepthFunc(GLenum func) OVERRIDE;
+
+virtual void DepthMask(GLboolean flag) OVERRIDE;
+
+virtual void DepthRangef(GLclampf zNear, GLclampf zFar) OVERRIDE;
+
+virtual void DetachShader(GLuint program, GLuint shader) OVERRIDE;
+
+virtual void Disable(GLenum cap) OVERRIDE;
+
+virtual void DrawArrays(GLenum mode, GLint first, GLsizei count) OVERRIDE;
+
+virtual void DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) OVERRIDE;
+
+virtual void Enable(GLenum cap) OVERRIDE;
+
+virtual void Finish() OVERRIDE;
+
+virtual void Flush() OVERRIDE;
+
+virtual void FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) OVERRIDE;
+
+virtual void FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) OVERRIDE;
+
+virtual void FrontFace(GLenum mode) OVERRIDE;
+
+virtual void GenBuffers(GLsizei n, GLuint* buffers) OVERRIDE;
+
+virtual void GenerateMipmap(GLenum target) OVERRIDE;
+
+virtual void GenFramebuffers(GLsizei n, GLuint* framebuffers) OVERRIDE;
+
+virtual void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) OVERRIDE;
+
+virtual void GenTextures(GLsizei n, GLuint* textures) OVERRIDE;
+
+virtual void GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) OVERRIDE;
+
+virtual void GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) OVERRIDE;
+
+virtual void GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count,
+ GLuint* shaders) OVERRIDE;
+
+virtual GLint GetAttribLocation(GLuint program, const char* name) OVERRIDE;
+
+virtual void GetBooleanv(GLenum pname, GLboolean* params) OVERRIDE;
+
+virtual void GetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+
+virtual GLenum GetError() OVERRIDE;
+
+virtual void GetFloatv(GLenum pname, GLfloat* params) OVERRIDE;
+
+virtual void GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetIntegerv(GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetProgramiv(
+ GLuint program, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) OVERRIDE;
+
+virtual void GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetShaderiv(GLuint shader, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) OVERRIDE;
+
+virtual void GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range,
+ GLint* precision) OVERRIDE;
+
+virtual void GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) OVERRIDE;
+
+virtual const GLubyte* GetString(GLenum name) OVERRIDE;
+
+virtual void GetTexParameterfv(
+ GLenum target, GLenum pname, GLfloat* params) OVERRIDE;
+
+virtual void GetTexParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetUniformfv(
+ GLuint program, GLint location, GLfloat* params) OVERRIDE;
+
+virtual void GetUniformiv(
+ GLuint program, GLint location, GLint* params) OVERRIDE;
+
+virtual GLint GetUniformLocation(GLuint program, const char* name) OVERRIDE;
+
+virtual void GetVertexAttribPointerv(
+ GLuint index, GLenum pname, void** pointer) OVERRIDE;
+
+virtual void Hint(GLenum target, GLenum mode) OVERRIDE;
+
+virtual GLboolean IsBuffer(GLuint buffer) OVERRIDE;
+
+virtual GLboolean IsEnabled(GLenum cap) OVERRIDE;
+
+virtual GLboolean IsFramebuffer(GLuint framebuffer) OVERRIDE;
+
+virtual GLboolean IsProgram(GLuint program) OVERRIDE;
+
+virtual GLboolean IsRenderbuffer(GLuint renderbuffer) OVERRIDE;
+
+virtual GLboolean IsShader(GLuint shader) OVERRIDE;
+
+virtual GLboolean IsTexture(GLuint texture) OVERRIDE;
+
+virtual void LineWidth(GLfloat width) OVERRIDE;
+
+virtual void LinkProgram(GLuint program) OVERRIDE;
+
+virtual void PixelStorei(GLenum pname, GLint param) OVERRIDE;
+
+virtual void PolygonOffset(GLfloat factor, GLfloat units) OVERRIDE;
+
+virtual void ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ void* pixels) OVERRIDE;
+
+virtual void ReleaseShaderCompiler() OVERRIDE;
+
+virtual void RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width,
+ GLsizei height) OVERRIDE;
+
+virtual void SampleCoverage(GLclampf value, GLboolean invert) OVERRIDE;
+
+virtual void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) OVERRIDE;
+
+virtual void ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) OVERRIDE;
+
+virtual void ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* str,
+ const GLint* length) OVERRIDE;
+
+virtual void ShallowFinishCHROMIUM() OVERRIDE;
+
+virtual void ShallowFlushCHROMIUM() OVERRIDE;
+
+virtual void StencilFunc(GLenum func, GLint ref, GLuint mask) OVERRIDE;
+
+virtual void StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) OVERRIDE;
+
+virtual void StencilMask(GLuint mask) OVERRIDE;
+
+virtual void StencilMaskSeparate(GLenum face, GLuint mask) OVERRIDE;
+
+virtual void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) OVERRIDE;
+
+virtual void StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) OVERRIDE;
+
+virtual void TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) OVERRIDE;
+
+virtual void TexParameterf(
+ GLenum target, GLenum pname, GLfloat param) OVERRIDE;
+
+virtual void TexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) OVERRIDE;
+
+virtual void TexParameteri(GLenum target, GLenum pname, GLint param) OVERRIDE;
+
+virtual void TexParameteriv(
+ GLenum target, GLenum pname, const GLint* params) OVERRIDE;
+
+virtual void TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) OVERRIDE;
+
+virtual void Uniform1f(GLint location, GLfloat x) OVERRIDE;
+
+virtual void Uniform1fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+
+virtual void Uniform1i(GLint location, GLint x) OVERRIDE;
+
+virtual void Uniform1iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+
+virtual void Uniform2f(GLint location, GLfloat x, GLfloat y) OVERRIDE;
+
+virtual void Uniform2fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+
+virtual void Uniform2i(GLint location, GLint x, GLint y) OVERRIDE;
+
+virtual void Uniform2iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+
+virtual void Uniform3f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z) OVERRIDE;
+
+virtual void Uniform3fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+
+virtual void Uniform3i(GLint location, GLint x, GLint y, GLint z) OVERRIDE;
+
+virtual void Uniform3iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+
+virtual void Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) OVERRIDE;
+
+virtual void Uniform4fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+
+virtual void Uniform4i(
+ GLint location, GLint x, GLint y, GLint z, GLint w) OVERRIDE;
+
+virtual void Uniform4iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+
+virtual void UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+
+virtual void UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+
+virtual void UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+
+virtual void UseProgram(GLuint program) OVERRIDE;
+
+virtual void ValidateProgram(GLuint program) OVERRIDE;
+
+virtual void VertexAttrib1f(GLuint indx, GLfloat x) OVERRIDE;
+
+virtual void VertexAttrib1fv(GLuint indx, const GLfloat* values) OVERRIDE;
+
+virtual void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) OVERRIDE;
+
+virtual void VertexAttrib2fv(GLuint indx, const GLfloat* values) OVERRIDE;
+
+virtual void VertexAttrib3f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z) OVERRIDE;
+
+virtual void VertexAttrib3fv(GLuint indx, const GLfloat* values) OVERRIDE;
+
+virtual void VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) OVERRIDE;
+
+virtual void VertexAttrib4fv(GLuint indx, const GLfloat* values) OVERRIDE;
+
+virtual void VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) OVERRIDE;
+
+virtual void Viewport(
+ GLint x, GLint y, GLsizei width, GLsizei height) OVERRIDE;
+
+virtual void BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
+ GLenum filter) OVERRIDE;
+
+virtual void RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) OVERRIDE;
+
+virtual void FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) OVERRIDE;
+
+virtual void TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) OVERRIDE;
+
+virtual void GenQueriesEXT(GLsizei n, GLuint* queries) OVERRIDE;
+
+virtual void DeleteQueriesEXT(GLsizei n, const GLuint* queries) OVERRIDE;
+
+virtual GLboolean IsQueryEXT(GLuint id) OVERRIDE;
+
+virtual void BeginQueryEXT(GLenum target, GLuint id) OVERRIDE;
+
+virtual void EndQueryEXT(GLenum target) OVERRIDE;
+
+virtual void GetQueryivEXT(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetQueryObjectuivEXT(
+ GLuint id, GLenum pname, GLuint* params) OVERRIDE;
+
+virtual void InsertEventMarkerEXT(
+ GLsizei length, const GLchar* marker) OVERRIDE;
+
+virtual void PushGroupMarkerEXT(GLsizei length, const GLchar* marker) OVERRIDE;
+
+virtual void PopGroupMarkerEXT() OVERRIDE;
+
+virtual void GenVertexArraysOES(GLsizei n, GLuint* arrays) OVERRIDE;
+
+virtual void DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) OVERRIDE;
+
+virtual GLboolean IsVertexArrayOES(GLuint array) OVERRIDE;
+
+virtual void BindVertexArrayOES(GLuint array) OVERRIDE;
+
+virtual void SwapBuffers() OVERRIDE;
+
+virtual GLuint GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) OVERRIDE;
+
+virtual void GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE;
+
+virtual void DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) OVERRIDE;
+
+virtual void RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) OVERRIDE;
+
+virtual GLboolean EnableFeatureCHROMIUM(const char* feature) OVERRIDE;
+
+virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) OVERRIDE;
+
+virtual GLboolean UnmapBufferCHROMIUM(GLuint target) OVERRIDE;
+
+virtual void* MapImageCHROMIUM(GLuint image_id, GLenum access) OVERRIDE;
+
+virtual void UnmapImageCHROMIUM(GLuint image_id) OVERRIDE;
+
+virtual void* MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) OVERRIDE;
+
+virtual void UnmapBufferSubDataCHROMIUM(const void* mem) OVERRIDE;
+
+virtual void* MapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access) OVERRIDE;
+
+virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) OVERRIDE;
+
+virtual void ResizeCHROMIUM(
+ GLuint width, GLuint height, GLfloat scale_factor) OVERRIDE;
+
+virtual const GLchar* GetRequestableExtensionsCHROMIUM() OVERRIDE;
+
+virtual void RequestExtensionCHROMIUM(const char* extension) OVERRIDE;
+
+virtual void RateLimitOffscreenContextCHROMIUM() OVERRIDE;
+
+virtual void GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results,
+ GLsizeiptr size) OVERRIDE;
+
+virtual void GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) OVERRIDE;
+
+virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) OVERRIDE;
+
+virtual void DestroyStreamTextureCHROMIUM(GLuint texture) OVERRIDE;
+
+virtual GLuint CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) OVERRIDE;
+
+virtual void DestroyImageCHROMIUM(GLuint image_id) OVERRIDE;
+
+virtual void GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) OVERRIDE;
+
+virtual void GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) OVERRIDE;
+
+virtual void PostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height) OVERRIDE;
+
+virtual void TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) OVERRIDE;
+
+virtual void CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) OVERRIDE;
+
+virtual void DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) OVERRIDE;
+
+virtual void DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) OVERRIDE;
+
+virtual void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) OVERRIDE;
+
+virtual void GenMailboxCHROMIUM(GLbyte* mailbox) OVERRIDE;
+
+virtual void ProduceTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) OVERRIDE;
+
+virtual void ConsumeTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) OVERRIDE;
+
+virtual void BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) OVERRIDE;
+
+virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) OVERRIDE;
+
+virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) OVERRIDE;
+
+virtual void TraceBeginCHROMIUM(const char* name) OVERRIDE;
+
+virtual void TraceEndCHROMIUM() OVERRIDE;
+
+virtual void AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* data) OVERRIDE;
+
+virtual void AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) OVERRIDE;
+
+virtual void WaitAsyncTexImage2DCHROMIUM(GLenum target) OVERRIDE;
+
+virtual void DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) OVERRIDE;
+
+virtual void LoseContextCHROMIUM(GLenum current, GLenum other) OVERRIDE;
+
+virtual GLuint InsertSyncPointCHROMIUM() OVERRIDE;
+
+virtual void WaitSyncPointCHROMIUM(GLuint sync_point) OVERRIDE;
+
+virtual void DrawBuffersEXT(GLsizei count, const GLenum* bufs) OVERRIDE;
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/chromium/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
new file mode 100644
index 00000000000..82e0ce07aa4
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -0,0 +1,1738 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_implementation.cc to define the
+// GL api functions.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_IMPL_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_IMPL_AUTOGEN_H_
+
+void GLES2Implementation::AttachShader(GLuint program, GLuint shader) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glAttachShader(" << program << ", " << shader << ")"); // NOLINT
+ helper_->AttachShader(program, shader);
+ CheckGLError();
+}
+
+void GLES2Implementation::BindBuffer(GLenum target, GLuint buffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindBuffer(" << GLES2Util::GetStringBufferTarget(target) << ", " << buffer << ")"); // NOLINT
+ if (IsBufferReservedId(buffer)) {
+ SetGLError(GL_INVALID_OPERATION, "BindBuffer", "buffer reserved id");
+ return;
+ }
+ if (BindBufferHelper(target, buffer)) {
+ helper_->BindBuffer(target, buffer);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::BindFramebuffer(GLenum target, GLuint framebuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFramebuffer(" << GLES2Util::GetStringFrameBufferTarget(target) << ", " << framebuffer << ")"); // NOLINT
+ if (IsFramebufferReservedId(framebuffer)) {
+ SetGLError(
+ GL_INVALID_OPERATION, "BindFramebuffer", "framebuffer reserved id");
+ return;
+ }
+ if (BindFramebufferHelper(target, framebuffer)) {
+ helper_->BindFramebuffer(target, framebuffer);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::BindRenderbuffer(
+ GLenum target, GLuint renderbuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindRenderbuffer(" << GLES2Util::GetStringRenderBufferTarget(target) << ", " << renderbuffer << ")"); // NOLINT
+ if (IsRenderbufferReservedId(renderbuffer)) {
+ SetGLError(
+ GL_INVALID_OPERATION, "BindRenderbuffer", "renderbuffer reserved id");
+ return;
+ }
+ if (BindRenderbufferHelper(target, renderbuffer)) {
+ helper_->BindRenderbuffer(target, renderbuffer);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::BindTexture(GLenum target, GLuint texture) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTexture(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << texture << ")"); // NOLINT
+ if (IsTextureReservedId(texture)) {
+ SetGLError(GL_INVALID_OPERATION, "BindTexture", "texture reserved id");
+ return;
+ }
+ if (BindTextureHelper(target, texture)) {
+ helper_->BindTexture(target, texture);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlendColor(" << red << ", " << green << ", " << blue << ", " << alpha << ")"); // NOLINT
+ helper_->BlendColor(red, green, blue, alpha);
+ CheckGLError();
+}
+
+void GLES2Implementation::BlendEquation(GLenum mode) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlendEquation(" << GLES2Util::GetStringEquation(mode) << ")"); // NOLINT
+ helper_->BlendEquation(mode);
+ CheckGLError();
+}
+
+void GLES2Implementation::BlendEquationSeparate(
+ GLenum modeRGB, GLenum modeAlpha) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlendEquationSeparate(" << GLES2Util::GetStringEquation(modeRGB) << ", " << GLES2Util::GetStringEquation(modeAlpha) << ")"); // NOLINT
+ helper_->BlendEquationSeparate(modeRGB, modeAlpha);
+ CheckGLError();
+}
+
+void GLES2Implementation::BlendFunc(GLenum sfactor, GLenum dfactor) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlendFunc(" << GLES2Util::GetStringSrcBlendFactor(sfactor) << ", " << GLES2Util::GetStringDstBlendFactor(dfactor) << ")"); // NOLINT
+ helper_->BlendFunc(sfactor, dfactor);
+ CheckGLError();
+}
+
+void GLES2Implementation::BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlendFuncSeparate(" << GLES2Util::GetStringSrcBlendFactor(srcRGB) << ", " << GLES2Util::GetStringDstBlendFactor(dstRGB) << ", " << GLES2Util::GetStringSrcBlendFactor(srcAlpha) << ", " << GLES2Util::GetStringDstBlendFactor(dstAlpha) << ")"); // NOLINT
+ helper_->BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ CheckGLError();
+}
+
+GLenum GLES2Implementation::CheckFramebufferStatus(GLenum target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::CheckFramebufferStatus");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCheckFramebufferStatus(" << GLES2Util::GetStringFrameBufferTarget(target) << ")"); // NOLINT
+ typedef cmds::CheckFramebufferStatus::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+ *result = 0;
+ helper_->CheckFramebufferStatus(
+ target, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLenum result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+void GLES2Implementation::Clear(GLbitfield mask) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClear(" << mask << ")");
+ helper_->Clear(mask);
+ CheckGLError();
+}
+
+void GLES2Implementation::ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClearColor(" << red << ", " << green << ", " << blue << ", " << alpha << ")"); // NOLINT
+ helper_->ClearColor(red, green, blue, alpha);
+ CheckGLError();
+}
+
+void GLES2Implementation::ClearDepthf(GLclampf depth) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClearDepthf(" << depth << ")");
+ helper_->ClearDepthf(depth);
+ CheckGLError();
+}
+
+void GLES2Implementation::ClearStencil(GLint s) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClearStencil(" << s << ")");
+ helper_->ClearStencil(s);
+ CheckGLError();
+}
+
+void GLES2Implementation::ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glColorMask(" << GLES2Util::GetStringBool(red) << ", " << GLES2Util::GetStringBool(green) << ", " << GLES2Util::GetStringBool(blue) << ", " << GLES2Util::GetStringBool(alpha) << ")"); // NOLINT
+ helper_->ColorMask(red, green, blue, alpha);
+ CheckGLError();
+}
+
+void GLES2Implementation::CompileShader(GLuint shader) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCompileShader(" << shader << ")"); // NOLINT
+ helper_->CompileShader(shader);
+ CheckGLError();
+}
+
+void GLES2Implementation::CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCopyTexImage2D(" << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", " << GLES2Util::GetStringTextureInternalFormat(internalformat) << ", " << x << ", " << y << ", " << width << ", " << height << ", " << border << ")"); // NOLINT
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glCopyTexImage2D", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glCopyTexImage2D", "height < 0");
+ return;
+ }
+ helper_->CopyTexImage2D(
+ target, level, internalformat, x, y, width, height, border);
+ CheckGLError();
+}
+
+void GLES2Implementation::CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCopyTexSubImage2D(" << GLES2Util::GetStringTextureTarget(target) << ", " << level << ", " << xoffset << ", " << yoffset << ", " << x << ", " << y << ", " << width << ", " << height << ")"); // NOLINT
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glCopyTexSubImage2D", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glCopyTexSubImage2D", "height < 0");
+ return;
+ }
+ helper_->CopyTexSubImage2D(
+ target, level, xoffset, yoffset, x, y, width, height);
+ CheckGLError();
+}
+
+GLuint GLES2Implementation::CreateProgram() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateProgram(" << ")");
+ GLuint client_id;
+ GetIdHandler(id_namespaces::kProgramsAndShaders)->
+ MakeIds(this, 0, 1, &client_id);
+ helper_->CreateProgram(client_id);
+ GPU_CLIENT_LOG("returned " << client_id);
+ CheckGLError();
+ return client_id;
+}
+
+GLuint GLES2Implementation::CreateShader(GLenum type) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCreateShader(" << GLES2Util::GetStringShaderType(type) << ")"); // NOLINT
+ GLuint client_id;
+ GetIdHandler(id_namespaces::kProgramsAndShaders)->
+ MakeIds(this, 0, 1, &client_id);
+ helper_->CreateShader(type, client_id);
+ GPU_CLIENT_LOG("returned " << client_id);
+ CheckGLError();
+ return client_id;
+}
+
+void GLES2Implementation::CullFace(GLenum mode) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCullFace(" << GLES2Util::GetStringFaceType(mode) << ")"); // NOLINT
+ helper_->CullFace(mode);
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteBuffers(GLsizei n, const GLuint* buffers) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteBuffers(" << n << ", " << static_cast<const void*>(buffers) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << buffers[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(buffers[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteBuffers", "n < 0");
+ return;
+ }
+ DeleteBuffersHelper(n, buffers);
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteFramebuffers(
+ GLsizei n, const GLuint* framebuffers) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteFramebuffers(" << n << ", " << static_cast<const void*>(framebuffers) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << framebuffers[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(framebuffers[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteFramebuffers", "n < 0");
+ return;
+ }
+ DeleteFramebuffersHelper(n, framebuffers);
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteProgram(GLuint program) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteProgram(" << program << ")"); // NOLINT
+ GPU_CLIENT_DCHECK(program != 0);
+ DeleteProgramHelper(program);
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteRenderbuffers(
+ GLsizei n, const GLuint* renderbuffers) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteRenderbuffers(" << n << ", " << static_cast<const void*>(renderbuffers) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << renderbuffers[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(renderbuffers[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteRenderbuffers", "n < 0");
+ return;
+ }
+ DeleteRenderbuffersHelper(n, renderbuffers);
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteShader(GLuint shader) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteShader(" << shader << ")");
+ GPU_CLIENT_DCHECK(shader != 0);
+ DeleteShaderHelper(shader);
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteTextures(GLsizei n, const GLuint* textures) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteTextures(" << n << ", " << static_cast<const void*>(textures) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << textures[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(textures[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteTextures", "n < 0");
+ return;
+ }
+ DeleteTexturesHelper(n, textures);
+ CheckGLError();
+}
+
+void GLES2Implementation::DepthFunc(GLenum func) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDepthFunc(" << GLES2Util::GetStringCmpFunction(func) << ")"); // NOLINT
+ helper_->DepthFunc(func);
+ CheckGLError();
+}
+
+void GLES2Implementation::DepthMask(GLboolean flag) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDepthMask(" << GLES2Util::GetStringBool(flag) << ")"); // NOLINT
+ helper_->DepthMask(flag);
+ CheckGLError();
+}
+
+void GLES2Implementation::DepthRangef(GLclampf zNear, GLclampf zFar) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDepthRangef(" << zNear << ", " << zFar << ")"); // NOLINT
+ helper_->DepthRangef(zNear, zFar);
+ CheckGLError();
+}
+
+void GLES2Implementation::DetachShader(GLuint program, GLuint shader) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDetachShader(" << program << ", " << shader << ")"); // NOLINT
+ helper_->DetachShader(program, shader);
+ CheckGLError();
+}
+
+void GLES2Implementation::FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFramebufferRenderbuffer(" << GLES2Util::GetStringFrameBufferTarget(target) << ", " << GLES2Util::GetStringAttachment(attachment) << ", " << GLES2Util::GetStringRenderBufferTarget(renderbuffertarget) << ", " << renderbuffer << ")"); // NOLINT
+ helper_->FramebufferRenderbuffer(
+ target, attachment, renderbuffertarget, renderbuffer);
+ CheckGLError();
+}
+
+void GLES2Implementation::FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFramebufferTexture2D(" << GLES2Util::GetStringFrameBufferTarget(target) << ", " << GLES2Util::GetStringAttachment(attachment) << ", " << GLES2Util::GetStringTextureTarget(textarget) << ", " << texture << ", " << level << ")"); // NOLINT
+ helper_->FramebufferTexture2D(target, attachment, textarget, texture, level);
+ CheckGLError();
+}
+
+void GLES2Implementation::FrontFace(GLenum mode) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFrontFace(" << GLES2Util::GetStringFaceMode(mode) << ")"); // NOLINT
+ helper_->FrontFace(mode);
+ CheckGLError();
+}
+
+void GLES2Implementation::GenBuffers(GLsizei n, GLuint* buffers) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenBuffers(" << n << ", " << static_cast<const void*>(buffers) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenBuffers", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kBuffers)->
+ MakeIds(this, 0, n, buffers);
+ GenBuffersHelper(n, buffers);
+ helper_->GenBuffersImmediate(n, buffers);
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << buffers[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::GenerateMipmap(GLenum target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenerateMipmap(" << GLES2Util::GetStringTextureBindTarget(target) << ")"); // NOLINT
+ helper_->GenerateMipmap(target);
+ CheckGLError();
+}
+
+void GLES2Implementation::GenFramebuffers(GLsizei n, GLuint* framebuffers) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenFramebuffers(" << n << ", " << static_cast<const void*>(framebuffers) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenFramebuffers", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kFramebuffers)->
+ MakeIds(this, 0, n, framebuffers);
+ GenFramebuffersHelper(n, framebuffers);
+ helper_->GenFramebuffersImmediate(n, framebuffers);
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << framebuffers[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::GenRenderbuffers(GLsizei n, GLuint* renderbuffers) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenRenderbuffers(" << n << ", " << static_cast<const void*>(renderbuffers) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenRenderbuffers", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kRenderbuffers)->
+ MakeIds(this, 0, n, renderbuffers);
+ GenRenderbuffersHelper(n, renderbuffers);
+ helper_->GenRenderbuffersImmediate(n, renderbuffers);
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << renderbuffers[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::GenTextures(GLsizei n, GLuint* textures) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenTextures(" << n << ", " << static_cast<const void*>(textures) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenTextures", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kTextures)->
+ MakeIds(this, 0, n, textures);
+ GenTexturesHelper(n, textures);
+ helper_->GenTexturesImmediate(n, textures);
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << textures[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::GetBooleanv(GLenum pname, GLboolean* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLboolean, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetBooleanv(" << GLES2Util::GetStringGLState(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetBooleanv");
+ if (GetBooleanvHelper(pname, params)) {
+ return;
+ }
+ typedef cmds::GetBooleanv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetBooleanv(pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetBufferParameteriv(" << GLES2Util::GetStringBufferTarget(target) << ", " << GLES2Util::GetStringBufferParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetBufferParameteriv");
+ if (GetBufferParameterivHelper(target, pname, params)) {
+ return;
+ }
+ typedef cmds::GetBufferParameteriv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetBufferParameteriv(target, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetFloatv(GLenum pname, GLfloat* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFloatv(" << GLES2Util::GetStringGLState(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetFloatv");
+ if (GetFloatvHelper(pname, params)) {
+ return;
+ }
+ typedef cmds::GetFloatv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetFloatv(pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFramebufferAttachmentParameteriv(" << GLES2Util::GetStringFrameBufferTarget(target) << ", " << GLES2Util::GetStringAttachment(attachment) << ", " << GLES2Util::GetStringFrameBufferParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetFramebufferAttachmentParameteriv"); // NOLINT
+ if (GetFramebufferAttachmentParameterivHelper(
+ target, attachment, pname, params)) {
+ return;
+ }
+ typedef cmds::GetFramebufferAttachmentParameteriv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetFramebufferAttachmentParameteriv(target, attachment, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetIntegerv(GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetIntegerv(" << GLES2Util::GetStringGLState(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetIntegerv");
+ if (GetIntegervHelper(pname, params)) {
+ return;
+ }
+ typedef cmds::GetIntegerv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetIntegerv(pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetProgramiv(
+ GLuint program, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetProgramiv(" << program << ", " << GLES2Util::GetStringProgramParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetProgramiv");
+ if (GetProgramivHelper(program, pname, params)) {
+ return;
+ }
+ typedef cmds::GetProgramiv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetProgramiv(program, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_OPTIONAL_INITALIZATION(GLsizei, length);
+ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] glGetProgramInfoLog" << "("
+ << program << ", "
+ << bufsize << ", "
+ << static_cast<void*>(length) << ", "
+ << static_cast<void*>(infolog) << ")");
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetProgramInfoLog(program, kResultBucketId);
+ std::string str;
+ GLsizei max_size = 0;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ if (bufsize > 0) {
+ max_size =
+ std::min(static_cast<size_t>(bufsize) - 1, str.size());
+ memcpy(infolog, str.c_str(), max_size);
+ infolog[max_size] = '\0';
+ GPU_CLIENT_LOG("------\n" << infolog << "\n------");
+ }
+ }
+ if (length != NULL) {
+ *length = max_size;
+ }
+ CheckGLError();
+}
+void GLES2Implementation::GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetRenderbufferParameteriv(" << GLES2Util::GetStringRenderBufferTarget(target) << ", " << GLES2Util::GetStringRenderBufferParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetRenderbufferParameteriv");
+ if (GetRenderbufferParameterivHelper(target, pname, params)) {
+ return;
+ }
+ typedef cmds::GetRenderbufferParameteriv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetRenderbufferParameteriv(target, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetShaderiv(
+ GLuint shader, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetShaderiv(" << shader << ", " << GLES2Util::GetStringShaderParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetShaderiv");
+ if (GetShaderivHelper(shader, pname, params)) {
+ return;
+ }
+ typedef cmds::GetShaderiv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetShaderiv(shader, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_OPTIONAL_INITALIZATION(GLsizei, length);
+ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] glGetShaderInfoLog" << "("
+ << shader << ", "
+ << bufsize << ", "
+ << static_cast<void*>(length) << ", "
+ << static_cast<void*>(infolog) << ")");
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetShaderInfoLog(shader, kResultBucketId);
+ std::string str;
+ GLsizei max_size = 0;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ if (bufsize > 0) {
+ max_size =
+ std::min(static_cast<size_t>(bufsize) - 1, str.size());
+ memcpy(infolog, str.c_str(), max_size);
+ infolog[max_size] = '\0';
+ GPU_CLIENT_LOG("------\n" << infolog << "\n------");
+ }
+ }
+ if (length != NULL) {
+ *length = max_size;
+ }
+ CheckGLError();
+}
+void GLES2Implementation::GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_OPTIONAL_INITALIZATION(GLsizei, length);
+ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] glGetShaderSource" << "("
+ << shader << ", "
+ << bufsize << ", "
+ << static_cast<void*>(length) << ", "
+ << static_cast<void*>(source) << ")");
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetShaderSource(shader, kResultBucketId);
+ std::string str;
+ GLsizei max_size = 0;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ if (bufsize > 0) {
+ max_size =
+ std::min(static_cast<size_t>(bufsize) - 1, str.size());
+ memcpy(source, str.c_str(), max_size);
+ source[max_size] = '\0';
+ GPU_CLIENT_LOG("------\n" << source << "\n------");
+ }
+ }
+ if (length != NULL) {
+ *length = max_size;
+ }
+ CheckGLError();
+}
+void GLES2Implementation::GetTexParameterfv(
+ GLenum target, GLenum pname, GLfloat* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTexParameterfv(" << GLES2Util::GetStringGetTexParamTarget(target) << ", " << GLES2Util::GetStringTextureParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetTexParameterfv");
+ if (GetTexParameterfvHelper(target, pname, params)) {
+ return;
+ }
+ typedef cmds::GetTexParameterfv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetTexParameterfv(target, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::GetTexParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_INITALIZATION(GLint, params);
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetTexParameteriv(" << GLES2Util::GetStringGetTexParamTarget(target) << ", " << GLES2Util::GetStringTextureParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ TRACE_EVENT0("gpu", "GLES2Implementation::GetTexParameteriv");
+ if (GetTexParameterivHelper(target, pname, params)) {
+ return;
+ }
+ typedef cmds::GetTexParameteriv::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return;
+ }
+ result->SetNumResults(0);
+ helper_->GetTexParameteriv(target, pname,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ result->CopyResult(params);
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (int32 i = 0; i < result->GetNumResults(); ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << result->GetData()[i]);
+ }
+ });
+ CheckGLError();
+}
+void GLES2Implementation::Hint(GLenum target, GLenum mode) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glHint(" << GLES2Util::GetStringHintTarget(target) << ", " << GLES2Util::GetStringHintMode(mode) << ")"); // NOLINT
+ helper_->Hint(target, mode);
+ CheckGLError();
+}
+
+GLboolean GLES2Implementation::IsBuffer(GLuint buffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsBuffer");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsBuffer(" << buffer << ")");
+ typedef cmds::IsBuffer::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsBuffer(buffer, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+GLboolean GLES2Implementation::IsFramebuffer(GLuint framebuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsFramebuffer");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsFramebuffer(" << framebuffer << ")"); // NOLINT
+ typedef cmds::IsFramebuffer::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsFramebuffer(framebuffer, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+GLboolean GLES2Implementation::IsProgram(GLuint program) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsProgram");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsProgram(" << program << ")");
+ typedef cmds::IsProgram::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsProgram(program, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+GLboolean GLES2Implementation::IsRenderbuffer(GLuint renderbuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsRenderbuffer");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsRenderbuffer(" << renderbuffer << ")"); // NOLINT
+ typedef cmds::IsRenderbuffer::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsRenderbuffer(
+ renderbuffer, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+GLboolean GLES2Implementation::IsShader(GLuint shader) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsShader");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsShader(" << shader << ")");
+ typedef cmds::IsShader::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsShader(shader, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+GLboolean GLES2Implementation::IsTexture(GLuint texture) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsTexture");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsTexture(" << texture << ")");
+ typedef cmds::IsTexture::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsTexture(texture, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+void GLES2Implementation::LineWidth(GLfloat width) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLineWidth(" << width << ")");
+ helper_->LineWidth(width);
+ CheckGLError();
+}
+
+void GLES2Implementation::PolygonOffset(GLfloat factor, GLfloat units) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glPolygonOffset(" << factor << ", " << units << ")"); // NOLINT
+ helper_->PolygonOffset(factor, units);
+ CheckGLError();
+}
+
+void GLES2Implementation::ReleaseShaderCompiler() {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReleaseShaderCompiler(" << ")");
+ helper_->ReleaseShaderCompiler();
+ CheckGLError();
+}
+
+void GLES2Implementation::RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRenderbufferStorage(" << GLES2Util::GetStringRenderBufferTarget(target) << ", " << GLES2Util::GetStringRenderBufferFormat(internalformat) << ", " << width << ", " << height << ")"); // NOLINT
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glRenderbufferStorage", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glRenderbufferStorage", "height < 0");
+ return;
+ }
+ helper_->RenderbufferStorage(target, internalformat, width, height);
+ CheckGLError();
+}
+
+void GLES2Implementation::SampleCoverage(GLclampf value, GLboolean invert) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSampleCoverage(" << value << ", " << GLES2Util::GetStringBool(invert) << ")"); // NOLINT
+ helper_->SampleCoverage(value, invert);
+ CheckGLError();
+}
+
+void GLES2Implementation::Scissor(
+ GLint x, GLint y, GLsizei width, GLsizei height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glScissor(" << x << ", " << y << ", " << width << ", " << height << ")"); // NOLINT
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glScissor", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glScissor", "height < 0");
+ return;
+ }
+ helper_->Scissor(x, y, width, height);
+ CheckGLError();
+}
+
+void GLES2Implementation::StencilFunc(GLenum func, GLint ref, GLuint mask) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilFunc(" << GLES2Util::GetStringCmpFunction(func) << ", " << ref << ", " << mask << ")"); // NOLINT
+ helper_->StencilFunc(func, ref, mask);
+ CheckGLError();
+}
+
+void GLES2Implementation::StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilFuncSeparate(" << GLES2Util::GetStringFaceType(face) << ", " << GLES2Util::GetStringCmpFunction(func) << ", " << ref << ", " << mask << ")"); // NOLINT
+ helper_->StencilFuncSeparate(face, func, ref, mask);
+ CheckGLError();
+}
+
+void GLES2Implementation::StencilMask(GLuint mask) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilMask(" << mask << ")");
+ helper_->StencilMask(mask);
+ CheckGLError();
+}
+
+void GLES2Implementation::StencilMaskSeparate(GLenum face, GLuint mask) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilMaskSeparate(" << GLES2Util::GetStringFaceType(face) << ", " << mask << ")"); // NOLINT
+ helper_->StencilMaskSeparate(face, mask);
+ CheckGLError();
+}
+
+void GLES2Implementation::StencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilOp(" << GLES2Util::GetStringStencilOp(fail) << ", " << GLES2Util::GetStringStencilOp(zfail) << ", " << GLES2Util::GetStringStencilOp(zpass) << ")"); // NOLINT
+ helper_->StencilOp(fail, zfail, zpass);
+ CheckGLError();
+}
+
+void GLES2Implementation::StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glStencilOpSeparate(" << GLES2Util::GetStringFaceType(face) << ", " << GLES2Util::GetStringStencilOp(fail) << ", " << GLES2Util::GetStringStencilOp(zfail) << ", " << GLES2Util::GetStringStencilOp(zpass) << ")"); // NOLINT
+ helper_->StencilOpSeparate(face, fail, zfail, zpass);
+ CheckGLError();
+}
+
+void GLES2Implementation::TexParameterf(
+ GLenum target, GLenum pname, GLfloat param) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexParameterf(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << GLES2Util::GetStringTextureParameter(pname) << ", " << param << ")"); // NOLINT
+ helper_->TexParameterf(target, pname, param);
+ CheckGLError();
+}
+
+void GLES2Implementation::TexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexParameterfv(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << GLES2Util::GetStringTextureParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << params[0]);
+ helper_->TexParameterfvImmediate(target, pname, params);
+ CheckGLError();
+}
+
+void GLES2Implementation::TexParameteri(
+ GLenum target, GLenum pname, GLint param) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexParameteri(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << GLES2Util::GetStringTextureParameter(pname) << ", " << param << ")"); // NOLINT
+ helper_->TexParameteri(target, pname, param);
+ CheckGLError();
+}
+
+void GLES2Implementation::TexParameteriv(
+ GLenum target, GLenum pname, const GLint* params) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexParameteriv(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << GLES2Util::GetStringTextureParameter(pname) << ", " << static_cast<const void*>(params) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << params[0]);
+ helper_->TexParameterivImmediate(target, pname, params);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform1f(GLint location, GLfloat x) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform1f(" << location << ", " << x << ")"); // NOLINT
+ helper_->Uniform1f(location, x);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform1fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform1fv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 1]);
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform1fv", "count < 0");
+ return;
+ }
+ helper_->Uniform1fvImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform1i(GLint location, GLint x) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform1i(" << location << ", " << x << ")"); // NOLINT
+ helper_->Uniform1i(location, x);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform1iv(
+ GLint location, GLsizei count, const GLint* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform1iv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 1]);
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform1iv", "count < 0");
+ return;
+ }
+ helper_->Uniform1ivImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform2f(GLint location, GLfloat x, GLfloat y) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform2f(" << location << ", " << x << ", " << y << ")"); // NOLINT
+ helper_->Uniform2f(location, x, y);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform2fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform2fv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 2] << ", " << v[1 + i * 2]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform2fv", "count < 0");
+ return;
+ }
+ helper_->Uniform2fvImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform2i(GLint location, GLint x, GLint y) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform2i(" << location << ", " << x << ", " << y << ")"); // NOLINT
+ helper_->Uniform2i(location, x, y);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform2iv(
+ GLint location, GLsizei count, const GLint* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform2iv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 2] << ", " << v[1 + i * 2]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform2iv", "count < 0");
+ return;
+ }
+ helper_->Uniform2ivImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform3f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform3f(" << location << ", " << x << ", " << y << ", " << z << ")"); // NOLINT
+ helper_->Uniform3f(location, x, y, z);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform3fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform3fv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 3] << ", " << v[1 + i * 3] << ", " << v[2 + i * 3]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform3fv", "count < 0");
+ return;
+ }
+ helper_->Uniform3fvImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform3i(
+ GLint location, GLint x, GLint y, GLint z) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform3i(" << location << ", " << x << ", " << y << ", " << z << ")"); // NOLINT
+ helper_->Uniform3i(location, x, y, z);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform3iv(
+ GLint location, GLsizei count, const GLint* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform3iv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 3] << ", " << v[1 + i * 3] << ", " << v[2 + i * 3]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform3iv", "count < 0");
+ return;
+ }
+ helper_->Uniform3ivImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform4f(" << location << ", " << x << ", " << y << ", " << z << ", " << w << ")"); // NOLINT
+ helper_->Uniform4f(location, x, y, z, w);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform4fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform4fv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 4] << ", " << v[1 + i * 4] << ", " << v[2 + i * 4] << ", " << v[3 + i * 4]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform4fv", "count < 0");
+ return;
+ }
+ helper_->Uniform4fvImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform4i(
+ GLint location, GLint x, GLint y, GLint z, GLint w) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform4i(" << location << ", " << x << ", " << y << ", " << z << ", " << w << ")"); // NOLINT
+ helper_->Uniform4i(location, x, y, z, w);
+ CheckGLError();
+}
+
+void GLES2Implementation::Uniform4iv(
+ GLint location, GLsizei count, const GLint* v) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniform4iv(" << location << ", " << count << ", " << static_cast<const void*>(v) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << v[0 + i * 4] << ", " << v[1 + i * 4] << ", " << v[2 + i * 4] << ", " << v[3 + i * 4]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniform4iv", "count < 0");
+ return;
+ }
+ helper_->Uniform4ivImmediate(location, count, v);
+ CheckGLError();
+}
+
+void GLES2Implementation::UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformMatrix2fv(" << location << ", " << count << ", " << GLES2Util::GetStringBool(transpose) << ", " << static_cast<const void*>(value) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << value[0 + i * 4] << ", " << value[1 + i * 4] << ", " << value[2 + i * 4] << ", " << value[3 + i * 4]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniformMatrix2fv", "count < 0");
+ return;
+ }
+ helper_->UniformMatrix2fvImmediate(location, count, transpose, value);
+ CheckGLError();
+}
+
+void GLES2Implementation::UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformMatrix3fv(" << location << ", " << count << ", " << GLES2Util::GetStringBool(transpose) << ", " << static_cast<const void*>(value) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << value[0 + i * 9] << ", " << value[1 + i * 9] << ", " << value[2 + i * 9] << ", " << value[3 + i * 9] << ", " << value[4 + i * 9] << ", " << value[5 + i * 9] << ", " << value[6 + i * 9] << ", " << value[7 + i * 9] << ", " << value[8 + i * 9]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniformMatrix3fv", "count < 0");
+ return;
+ }
+ helper_->UniformMatrix3fvImmediate(location, count, transpose, value);
+ CheckGLError();
+}
+
+void GLES2Implementation::UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glUniformMatrix4fv(" << location << ", " << count << ", " << GLES2Util::GetStringBool(transpose) << ", " << static_cast<const void*>(value) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << value[0 + i * 16] << ", " << value[1 + i * 16] << ", " << value[2 + i * 16] << ", " << value[3 + i * 16] << ", " << value[4 + i * 16] << ", " << value[5 + i * 16] << ", " << value[6 + i * 16] << ", " << value[7 + i * 16] << ", " << value[8 + i * 16] << ", " << value[9 + i * 16] << ", " << value[10 + i * 16] << ", " << value[11 + i * 16] << ", " << value[12 + i * 16] << ", " << value[13 + i * 16] << ", " << value[14 + i * 16] << ", " << value[15 + i * 16]); // NOLINT
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glUniformMatrix4fv", "count < 0");
+ return;
+ }
+ helper_->UniformMatrix4fvImmediate(location, count, transpose, value);
+ CheckGLError();
+}
+
+void GLES2Implementation::ValidateProgram(GLuint program) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glValidateProgram(" << program << ")"); // NOLINT
+ helper_->ValidateProgram(program);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib1f(GLuint indx, GLfloat x) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib1f(" << indx << ", " << x << ")"); // NOLINT
+ helper_->VertexAttrib1f(indx, x);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib1fv(GLuint indx, const GLfloat* values) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib1fv(" << indx << ", " << static_cast<const void*>(values) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << values[0]);
+ helper_->VertexAttrib1fvImmediate(indx, values);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib2f(" << indx << ", " << x << ", " << y << ")"); // NOLINT
+ helper_->VertexAttrib2f(indx, x, y);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib2fv(GLuint indx, const GLfloat* values) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib2fv(" << indx << ", " << static_cast<const void*>(values) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << values[0] << ", " << values[1]);
+ helper_->VertexAttrib2fvImmediate(indx, values);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib3f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib3f(" << indx << ", " << x << ", " << y << ", " << z << ")"); // NOLINT
+ helper_->VertexAttrib3f(indx, x, y, z);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib3fv(GLuint indx, const GLfloat* values) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib3fv(" << indx << ", " << static_cast<const void*>(values) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << values[0] << ", " << values[1] << ", " << values[2]); // NOLINT
+ helper_->VertexAttrib3fvImmediate(indx, values);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib4f(" << indx << ", " << x << ", " << y << ", " << z << ", " << w << ")"); // NOLINT
+ helper_->VertexAttrib4f(indx, x, y, z, w);
+ CheckGLError();
+}
+
+void GLES2Implementation::VertexAttrib4fv(GLuint indx, const GLfloat* values) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glVertexAttrib4fv(" << indx << ", " << static_cast<const void*>(values) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << values[0] << ", " << values[1] << ", " << values[2] << ", " << values[3]); // NOLINT
+ helper_->VertexAttrib4fvImmediate(indx, values);
+ CheckGLError();
+}
+
+void GLES2Implementation::Viewport(
+ GLint x, GLint y, GLsizei width, GLsizei height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glViewport(" << x << ", " << y << ", " << width << ", " << height << ")"); // NOLINT
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glViewport", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glViewport", "height < 0");
+ return;
+ }
+ helper_->Viewport(x, y, width, height);
+ CheckGLError();
+}
+
+void GLES2Implementation::BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBlitFramebufferEXT(" << srcX0 << ", " << srcY0 << ", " << srcX1 << ", " << srcY1 << ", " << dstX0 << ", " << dstY0 << ", " << dstX1 << ", " << dstY1 << ", " << mask << ", " << GLES2Util::GetStringBlitFilter(filter) << ")"); // NOLINT
+ helper_->BlitFramebufferEXT(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ CheckGLError();
+}
+
+void GLES2Implementation::RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glRenderbufferStorageMultisampleEXT(" << GLES2Util::GetStringRenderBufferTarget(target) << ", " << samples << ", " << GLES2Util::GetStringRenderBufferFormat(internalformat) << ", " << width << ", " << height << ")"); // NOLINT
+ if (samples < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glRenderbufferStorageMultisampleEXT", "samples < 0");
+ return;
+ }
+ if (width < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glRenderbufferStorageMultisampleEXT", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glRenderbufferStorageMultisampleEXT", "height < 0");
+ return;
+ }
+ helper_->RenderbufferStorageMultisampleEXT(
+ target, samples, internalformat, width, height);
+ CheckGLError();
+}
+
+void GLES2Implementation::FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glFramebufferTexture2DMultisampleEXT(" << GLES2Util::GetStringFrameBufferTarget(target) << ", " << GLES2Util::GetStringAttachment(attachment) << ", " << GLES2Util::GetStringTextureTarget(textarget) << ", " << texture << ", " << level << ", " << samples << ")"); // NOLINT
+ if (samples < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glFramebufferTexture2DMultisampleEXT", "samples < 0"); // NOLINT
+ return;
+ }
+ helper_->FramebufferTexture2DMultisampleEXT(
+ target, attachment, textarget, texture, level, samples);
+ CheckGLError();
+}
+
+void GLES2Implementation::TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexStorage2DEXT(" << GLES2Util::GetStringTextureTarget(target) << ", " << levels << ", " << GLES2Util::GetStringTextureInternalFormatStorage(internalFormat) << ", " << width << ", " << height << ")"); // NOLINT
+ if (levels < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexStorage2DEXT", "levels < 0");
+ return;
+ }
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexStorage2DEXT", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexStorage2DEXT", "height < 0");
+ return;
+ }
+ helper_->TexStorage2DEXT(target, levels, internalFormat, width, height);
+ CheckGLError();
+}
+
+void GLES2Implementation::GenQueriesEXT(GLsizei n, GLuint* queries) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenQueriesEXT(" << n << ", " << static_cast<const void*>(queries) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenQueriesEXT", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kQueries)->
+ MakeIds(this, 0, n, queries);
+ GenQueriesEXTHelper(n, queries);
+ helper_->GenQueriesEXTImmediate(n, queries);
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << queries[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteQueriesEXT(GLsizei n, const GLuint* queries) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteQueriesEXT(" << n << ", " << static_cast<const void*>(queries) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << queries[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(queries[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteQueriesEXT", "n < 0");
+ return;
+ }
+ DeleteQueriesEXTHelper(n, queries);
+ CheckGLError();
+}
+
+void GLES2Implementation::GenVertexArraysOES(GLsizei n, GLuint* arrays) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenVertexArraysOES(" << n << ", " << static_cast<const void*>(arrays) << ")"); // NOLINT
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenVertexArraysOES", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kVertexArrays)->
+ MakeIds(this, 0, n, arrays);
+ GenVertexArraysOESHelper(n, arrays);
+ helper_->GenVertexArraysOESImmediate(n, arrays);
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << arrays[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteVertexArraysOES(
+ GLsizei n, const GLuint* arrays) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteVertexArraysOES(" << n << ", " << static_cast<const void*>(arrays) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << arrays[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_DCHECK(arrays[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteVertexArraysOES", "n < 0");
+ return;
+ }
+ DeleteVertexArraysOESHelper(n, arrays);
+ CheckGLError();
+}
+
+GLboolean GLES2Implementation::IsVertexArrayOES(GLuint array) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsVertexArrayOES");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsVertexArrayOES(" << array << ")"); // NOLINT
+ typedef cmds::IsVertexArrayOES::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsVertexArrayOES(array, GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+void GLES2Implementation::BindVertexArrayOES(GLuint array) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindVertexArrayOES(" << array << ")"); // NOLINT
+ if (IsVertexArrayReservedId(array)) {
+ SetGLError(
+ GL_INVALID_OPERATION, "BindVertexArrayOES", "array reserved id");
+ return;
+ }
+ if (BindVertexArrayHelper(array)) {
+ helper_->BindVertexArrayOES(array);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_VALIDATE_DESTINATION_OPTIONAL_INITALIZATION(GLsizei, length);
+ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] glGetTranslatedShaderSourceANGLE" << "("
+ << shader << ", "
+ << bufsize << ", "
+ << static_cast<void*>(length) << ", "
+ << static_cast<void*>(source) << ")");
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetTranslatedShaderSourceANGLE(shader, kResultBucketId);
+ std::string str;
+ GLsizei max_size = 0;
+ if (GetBucketAsString(kResultBucketId, &str)) {
+ if (bufsize > 0) {
+ max_size =
+ std::min(static_cast<size_t>(bufsize) - 1, str.size());
+ memcpy(source, str.c_str(), max_size);
+ source[max_size] = '\0';
+ GPU_CLIENT_LOG("------\n" << source << "\n------");
+ }
+ }
+ if (length != NULL) {
+ *length = max_size;
+ }
+ CheckGLError();
+}
+void GLES2Implementation::TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glTexImageIOSurface2DCHROMIUM(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << width << ", " << height << ", " << ioSurfaceId << ", " << plane << ")"); // NOLINT
+ if (width < 0) {
+ SetGLError(GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM", "width < 0");
+ return;
+ }
+ if (height < 0) {
+ SetGLError(
+ GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM", "height < 0");
+ return;
+ }
+ helper_->TexImageIOSurface2DCHROMIUM(
+ target, width, height, ioSurfaceId, plane);
+ CheckGLError();
+}
+
+void GLES2Implementation::CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glCopyTextureCHROMIUM(" << GLES2Util::GetStringEnum(target) << ", " << GLES2Util::GetStringEnum(source_id) << ", " << GLES2Util::GetStringEnum(dest_id) << ", " << level << ", " << internalformat << ", " << GLES2Util::GetStringPixelType(dest_type) << ")"); // NOLINT
+ helper_->CopyTextureCHROMIUM(
+ target, source_id, dest_id, level, internalformat, dest_type);
+ CheckGLError();
+}
+
+void GLES2Implementation::ProduceTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glProduceTextureCHROMIUM(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << static_cast<const void*>(mailbox) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << mailbox[0] << ", " << mailbox[1] << ", " << mailbox[2] << ", " << mailbox[3] << ", " << mailbox[4] << ", " << mailbox[5] << ", " << mailbox[6] << ", " << mailbox[7] << ", " << mailbox[8] << ", " << mailbox[9] << ", " << mailbox[10] << ", " << mailbox[11] << ", " << mailbox[12] << ", " << mailbox[13] << ", " << mailbox[14] << ", " << mailbox[15] << ", " << mailbox[16] << ", " << mailbox[17] << ", " << mailbox[18] << ", " << mailbox[19] << ", " << mailbox[20] << ", " << mailbox[21] << ", " << mailbox[22] << ", " << mailbox[23] << ", " << mailbox[24] << ", " << mailbox[25] << ", " << mailbox[26] << ", " << mailbox[27] << ", " << mailbox[28] << ", " << mailbox[29] << ", " << mailbox[30] << ", " << mailbox[31] << ", " << mailbox[32] << ", " << mailbox[33] << ", " << mailbox[34] << ", " << mailbox[35] << ", " << mailbox[36] << ", " << mailbox[37] << ", " << mailbox[38] << ", " << mailbox[39] << ", " << mailbox[40] << ", " << mailbox[41] << ", " << mailbox[42] << ", " << mailbox[43] << ", " << mailbox[44] << ", " << mailbox[45] << ", " << mailbox[46] << ", " << mailbox[47] << ", " << mailbox[48] << ", " << mailbox[49] << ", " << mailbox[50] << ", " << mailbox[51] << ", " << mailbox[52] << ", " << mailbox[53] << ", " << mailbox[54] << ", " << mailbox[55] << ", " << mailbox[56] << ", " << mailbox[57] << ", " << mailbox[58] << ", " << mailbox[59] << ", " << mailbox[60] << ", " << mailbox[61] << ", " << mailbox[62] << ", " << mailbox[63]); // NOLINT
+ helper_->ProduceTextureCHROMIUMImmediate(target, mailbox);
+ CheckGLError();
+}
+
+void GLES2Implementation::ConsumeTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glConsumeTextureCHROMIUM(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << static_cast<const void*>(mailbox) << ")"); // NOLINT
+ GPU_CLIENT_LOG("values: " << mailbox[0] << ", " << mailbox[1] << ", " << mailbox[2] << ", " << mailbox[3] << ", " << mailbox[4] << ", " << mailbox[5] << ", " << mailbox[6] << ", " << mailbox[7] << ", " << mailbox[8] << ", " << mailbox[9] << ", " << mailbox[10] << ", " << mailbox[11] << ", " << mailbox[12] << ", " << mailbox[13] << ", " << mailbox[14] << ", " << mailbox[15] << ", " << mailbox[16] << ", " << mailbox[17] << ", " << mailbox[18] << ", " << mailbox[19] << ", " << mailbox[20] << ", " << mailbox[21] << ", " << mailbox[22] << ", " << mailbox[23] << ", " << mailbox[24] << ", " << mailbox[25] << ", " << mailbox[26] << ", " << mailbox[27] << ", " << mailbox[28] << ", " << mailbox[29] << ", " << mailbox[30] << ", " << mailbox[31] << ", " << mailbox[32] << ", " << mailbox[33] << ", " << mailbox[34] << ", " << mailbox[35] << ", " << mailbox[36] << ", " << mailbox[37] << ", " << mailbox[38] << ", " << mailbox[39] << ", " << mailbox[40] << ", " << mailbox[41] << ", " << mailbox[42] << ", " << mailbox[43] << ", " << mailbox[44] << ", " << mailbox[45] << ", " << mailbox[46] << ", " << mailbox[47] << ", " << mailbox[48] << ", " << mailbox[49] << ", " << mailbox[50] << ", " << mailbox[51] << ", " << mailbox[52] << ", " << mailbox[53] << ", " << mailbox[54] << ", " << mailbox[55] << ", " << mailbox[56] << ", " << mailbox[57] << ", " << mailbox[58] << ", " << mailbox[59] << ", " << mailbox[60] << ", " << mailbox[61] << ", " << mailbox[62] << ", " << mailbox[63]); // NOLINT
+ helper_->ConsumeTextureCHROMIUMImmediate(target, mailbox);
+ CheckGLError();
+}
+
+void GLES2Implementation::BindTexImage2DCHROMIUM(
+ GLenum target, GLint imageId) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTexImage2DCHROMIUM(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << imageId << ")"); // NOLINT
+ helper_->BindTexImage2DCHROMIUM(target, imageId);
+ CheckGLError();
+}
+
+void GLES2Implementation::ReleaseTexImage2DCHROMIUM(
+ GLenum target, GLint imageId) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glReleaseTexImage2DCHROMIUM(" << GLES2Util::GetStringTextureBindTarget(target) << ", " << imageId << ")"); // NOLINT
+ helper_->ReleaseTexImage2DCHROMIUM(target, imageId);
+ CheckGLError();
+}
+
+void GLES2Implementation::DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDiscardFramebufferEXT(" << GLES2Util::GetStringEnum(target) << ", " << count << ", " << static_cast<const void*>(attachments) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << attachments[0 + i * 1]);
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDiscardFramebufferEXT", "count < 0");
+ return;
+ }
+ helper_->DiscardFramebufferEXTImmediate(target, count, attachments);
+ CheckGLError();
+}
+
+void GLES2Implementation::LoseContextCHROMIUM(GLenum current, GLenum other) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glLoseContextCHROMIUM(" << GLES2Util::GetStringEnum(current) << ", " << GLES2Util::GetStringEnum(other) << ")"); // NOLINT
+ helper_->LoseContextCHROMIUM(current, other);
+ CheckGLError();
+}
+
+void GLES2Implementation::WaitSyncPointCHROMIUM(GLuint sync_point) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSyncPointCHROMIUM(" << sync_point << ")"); // NOLINT
+ helper_->WaitSyncPointCHROMIUM(sync_point);
+ CheckGLError();
+}
+
+void GLES2Implementation::DrawBuffersEXT(GLsizei count, const GLenum* bufs) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDrawBuffersEXT(" << count << ", " << static_cast<const void*>(bufs) << ")"); // NOLINT
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < count; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << bufs[0 + i * 1]);
+ }
+ });
+ if (count < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDrawBuffersEXT", "count < 0");
+ return;
+ }
+ helper_->DrawBuffersEXTImmediate(count, bufs);
+ CheckGLError();
+}
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_IMPL_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc b/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc
new file mode 100644
index 00000000000..e58907c8b27
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -0,0 +1,2876 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for GLES2Implementation.
+
+#include "gpu/command_buffer/client/gles2_implementation.h"
+
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+#include "gpu/command_buffer/client/client_test_helper.h"
+#include "gpu/command_buffer/client/program_info_manager.h"
+#include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+#if !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+#define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
+#endif
+
+using testing::_;
+using testing::AtLeast;
+using testing::AnyNumber;
+using testing::DoAll;
+using testing::InSequence;
+using testing::Invoke;
+using testing::Mock;
+using testing::Sequence;
+using testing::StrictMock;
+using testing::Truly;
+using testing::Return;
+
+namespace gpu {
+namespace gles2 {
+
+ACTION_P2(SetMemory, dst, obj) {
+ memcpy(dst, &obj, sizeof(obj));
+}
+
+ACTION_P3(SetMemoryFromArray, dst, array, size) {
+ memcpy(dst, array, size);
+}
+
+// Used to help set the transfer buffer result to SizedResult of a single value.
+template <typename T>
+class SizedResultHelper {
+ public:
+ explicit SizedResultHelper(T result)
+ : size_(sizeof(result)),
+ result_(result) {
+ }
+
+ private:
+ uint32 size_;
+ T result_;
+};
+
+// Struct to make it easy to pass a vec4 worth of floats.
+struct FourFloats {
+ FourFloats(float _x, float _y, float _z, float _w)
+ : x(_x),
+ y(_y),
+ z(_z),
+ w(_w) {
+ }
+
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+#pragma pack(push, 1)
+// Struct that holds 7 characters.
+struct Str7 {
+ char str[7];
+};
+#pragma pack(pop)
+
+class MockTransferBuffer : public TransferBufferInterface {
+ public:
+ struct ExpectedMemoryInfo {
+ uint32 offset;
+ int32 id;
+ uint8* ptr;
+ };
+
+ MockTransferBuffer(
+ CommandBuffer* command_buffer,
+ unsigned int size,
+ unsigned int result_size,
+ unsigned int alignment)
+ : command_buffer_(command_buffer),
+ size_(size),
+ result_size_(result_size),
+ alignment_(alignment),
+ actual_buffer_index_(0),
+ expected_buffer_index_(0),
+ last_alloc_(NULL),
+ expected_offset_(result_size),
+ actual_offset_(result_size) {
+ // We have to allocate the buffers here because
+ // we need to know their address before GLES2Implementation::Initialize
+ // is called.
+ for (int ii = 0; ii < kNumBuffers; ++ii) {
+ buffers_[ii] = command_buffer_->CreateTransferBuffer(
+ size_ + ii * alignment_,
+ &buffer_ids_[ii]);
+ EXPECT_NE(-1, buffer_ids_[ii]);
+ }
+ }
+
+ virtual ~MockTransferBuffer() { }
+
+ virtual bool Initialize(
+ unsigned int starting_buffer_size,
+ unsigned int result_size,
+ unsigned int /* min_buffer_size */,
+ unsigned int /* max_buffer_size */,
+ unsigned int alignment,
+ unsigned int size_to_flush) OVERRIDE;
+ virtual int GetShmId() OVERRIDE;
+ virtual void* GetResultBuffer() OVERRIDE;
+ virtual int GetResultOffset() OVERRIDE;
+ virtual void Free() OVERRIDE;
+ virtual bool HaveBuffer() const OVERRIDE;
+ virtual void* AllocUpTo(
+ unsigned int size, unsigned int* size_allocated) OVERRIDE;
+ virtual void* Alloc(unsigned int size) OVERRIDE;
+ virtual RingBuffer::Offset GetOffset(void* pointer) const OVERRIDE;
+ virtual void FreePendingToken(void* p, unsigned int /* token */) OVERRIDE;
+
+ size_t MaxTransferBufferSize() {
+ return size_ - result_size_;
+ }
+
+ unsigned int RoundToAlignment(unsigned int size) {
+ return (size + alignment_ - 1) & ~(alignment_ - 1);
+ }
+
+ bool InSync() {
+ return expected_buffer_index_ == actual_buffer_index_ &&
+ expected_offset_ == actual_offset_;
+ }
+
+ ExpectedMemoryInfo GetExpectedMemory(size_t size) {
+ ExpectedMemoryInfo mem;
+ mem.offset = AllocateExpectedTransferBuffer(size);
+ mem.id = GetExpectedTransferBufferId();
+ mem.ptr = static_cast<uint8*>(
+ GetExpectedTransferAddressFromOffset(mem.offset, size));
+ return mem;
+ }
+
+ ExpectedMemoryInfo GetExpectedResultMemory(size_t size) {
+ ExpectedMemoryInfo mem;
+ mem.offset = GetExpectedResultBufferOffset();
+ mem.id = GetExpectedResultBufferId();
+ mem.ptr = static_cast<uint8*>(
+ GetExpectedTransferAddressFromOffset(mem.offset, size));
+ return mem;
+ }
+
+ private:
+ static const int kNumBuffers = 2;
+
+ uint8* actual_buffer() const {
+ return static_cast<uint8*>(buffers_[actual_buffer_index_].ptr);
+ }
+
+ uint8* expected_buffer() const {
+ return static_cast<uint8*>(buffers_[expected_buffer_index_].ptr);
+ }
+
+ uint32 AllocateExpectedTransferBuffer(size_t size) {
+ EXPECT_LE(size, MaxTransferBufferSize());
+
+ // Toggle which buffer we get each time to simulate the buffer being
+ // reallocated.
+ expected_buffer_index_ = (expected_buffer_index_ + 1) % kNumBuffers;
+
+ if (expected_offset_ + size > size_) {
+ expected_offset_ = result_size_;
+ }
+ uint32 offset = expected_offset_;
+ expected_offset_ += RoundToAlignment(size);
+
+ // Make sure each buffer has a different offset.
+ return offset + expected_buffer_index_ * alignment_;
+ }
+
+ void* GetExpectedTransferAddressFromOffset(uint32 offset, size_t size) {
+ EXPECT_GE(offset, expected_buffer_index_ * alignment_);
+ EXPECT_LE(offset + size, size_ + expected_buffer_index_ * alignment_);
+ return expected_buffer() + offset;
+ }
+
+ int GetExpectedResultBufferId() {
+ return buffer_ids_[expected_buffer_index_];
+ }
+
+ uint32 GetExpectedResultBufferOffset() {
+ return expected_buffer_index_ * alignment_;
+ }
+
+ int GetExpectedTransferBufferId() {
+ return buffer_ids_[expected_buffer_index_];
+ }
+
+ CommandBuffer* command_buffer_;
+ size_t size_;
+ size_t result_size_;
+ uint32 alignment_;
+ int buffer_ids_[kNumBuffers];
+ gpu::Buffer buffers_[kNumBuffers];
+ int actual_buffer_index_;
+ int expected_buffer_index_;
+ void* last_alloc_;
+ uint32 expected_offset_;
+ uint32 actual_offset_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockTransferBuffer);
+};
+
+bool MockTransferBuffer::Initialize(
+ unsigned int starting_buffer_size,
+ unsigned int result_size,
+ unsigned int /* min_buffer_size */,
+ unsigned int /* max_buffer_size */,
+ unsigned int alignment,
+ unsigned int /* size_to_flush */) {
+ // Just check they match.
+ return size_ == starting_buffer_size &&
+ result_size_ == result_size &&
+ alignment_ == alignment;
+};
+
+int MockTransferBuffer::GetShmId() {
+ return buffer_ids_[actual_buffer_index_];
+}
+
+void* MockTransferBuffer::GetResultBuffer() {
+ return actual_buffer() + actual_buffer_index_ * alignment_;
+}
+
+int MockTransferBuffer::GetResultOffset() {
+ return actual_buffer_index_ * alignment_;
+}
+
+void MockTransferBuffer::Free() {
+ GPU_NOTREACHED();
+}
+
+bool MockTransferBuffer::HaveBuffer() const {
+ return true;
+}
+
+void* MockTransferBuffer::AllocUpTo(
+ unsigned int size, unsigned int* size_allocated) {
+ EXPECT_TRUE(size_allocated != NULL);
+ EXPECT_TRUE(last_alloc_ == NULL);
+
+ // Toggle which buffer we get each time to simulate the buffer being
+ // reallocated.
+ actual_buffer_index_ = (actual_buffer_index_ + 1) % kNumBuffers;
+
+ size = std::min(static_cast<size_t>(size), MaxTransferBufferSize());
+ if (actual_offset_ + size > size_) {
+ actual_offset_ = result_size_;
+ }
+ uint32 offset = actual_offset_;
+ actual_offset_ += RoundToAlignment(size);
+ *size_allocated = size;
+
+ // Make sure each buffer has a different offset.
+ last_alloc_ = actual_buffer() + offset + actual_buffer_index_ * alignment_;
+ return last_alloc_;
+}
+
+void* MockTransferBuffer::Alloc(unsigned int size) {
+ EXPECT_LE(size, MaxTransferBufferSize());
+ unsigned int temp = 0;
+ void* p = AllocUpTo(size, &temp);
+ EXPECT_EQ(temp, size);
+ return p;
+}
+
+RingBuffer::Offset MockTransferBuffer::GetOffset(void* pointer) const {
+ // Make sure each buffer has a different offset.
+ return static_cast<uint8*>(pointer) - actual_buffer();
+}
+
+void MockTransferBuffer::FreePendingToken(void* p, unsigned int /* token */) {
+ EXPECT_EQ(last_alloc_, p);
+ last_alloc_ = NULL;
+}
+
+class GLES2ImplementationTest : public testing::Test {
+ protected:
+ static const uint8 kInitialValue = 0xBD;
+ static const int32 kNumCommandEntries = 500;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+ static const size_t kTransferBufferSize = 512;
+
+ static const GLint kMaxCombinedTextureImageUnits = 8;
+ static const GLint kMaxCubeMapTextureSize = 64;
+ static const GLint kMaxFragmentUniformVectors = 16;
+ static const GLint kMaxRenderbufferSize = 64;
+ static const GLint kMaxTextureImageUnits = 8;
+ static const GLint kMaxTextureSize = 128;
+ static const GLint kMaxVaryingVectors = 8;
+ static const GLint kMaxVertexAttribs = 8;
+ static const GLint kMaxVertexTextureImageUnits = 0;
+ static const GLint kMaxVertexUniformVectors = 128;
+ static const GLint kNumCompressedTextureFormats = 0;
+ static const GLint kNumShaderBinaryFormats = 0;
+ static const GLuint kStartId = 1024;
+ static const GLuint kBuffersStartId =
+ GLES2Implementation::kClientSideArrayId + 2;
+ static const GLuint kFramebuffersStartId = 1;
+ static const GLuint kProgramsAndShadersStartId = 1;
+ static const GLuint kRenderbuffersStartId = 1;
+ static const GLuint kTexturesStartId = 1;
+ static const GLuint kQueriesStartId = 1;
+ static const GLuint kVertexArraysStartId = 1;
+
+ typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
+
+ GLES2ImplementationTest()
+ : commands_(NULL),
+ token_(0) {
+ }
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ bool NoCommandsWritten() {
+ Buffer ring_buffer = helper_->get_ring_buffer();
+ const uint8* cmds = reinterpret_cast<const uint8*>(ring_buffer.ptr);
+ const uint8* end = cmds + ring_buffer.size;
+ for (; cmds < end; ++cmds) {
+ if (*cmds != kInitialValue) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ QueryTracker::Query* GetQuery(GLuint id) {
+ return gl_->query_tracker_->GetQuery(id);
+ }
+
+ void Initialize(bool bind_generates_resource) {
+ command_buffer_.reset(new StrictMock<MockClientCommandBuffer>());
+ ASSERT_TRUE(command_buffer_->Initialize());
+
+ transfer_buffer_.reset(new MockTransferBuffer(
+ command_buffer(),
+ kTransferBufferSize,
+ GLES2Implementation::kStartingOffset,
+ GLES2Implementation::kAlignment));
+
+ helper_.reset(new GLES2CmdHelper(command_buffer()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+
+ GLES2Implementation::GLStaticState state;
+ GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
+ int_state.max_combined_texture_image_units = kMaxCombinedTextureImageUnits;
+ int_state.max_cube_map_texture_size = kMaxCubeMapTextureSize;
+ int_state.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
+ int_state.max_renderbuffer_size = kMaxRenderbufferSize;
+ int_state.max_texture_image_units = kMaxTextureImageUnits;
+ int_state.max_texture_size = kMaxTextureSize;
+ int_state.max_varying_vectors = kMaxVaryingVectors;
+ int_state.max_vertex_attribs = kMaxVertexAttribs;
+ int_state.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
+ int_state.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
+ int_state.num_compressed_texture_formats = kNumCompressedTextureFormats;
+ int_state.num_shader_binary_formats = kNumShaderBinaryFormats;
+
+ // This just happens to work for now because IntState has 1 GLint per state.
+ // If IntState gets more complicated this code will need to get more
+ // complicated.
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(
+ sizeof(GLES2Implementation::GLStaticState::IntState) * 2 +
+ sizeof(cmds::GetShaderPrecisionFormat::Result) * 12);
+
+ {
+ InSequence sequence;
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(mem1.ptr + sizeof(int_state), int_state))
+ .RetiresOnSaturation();
+ GetNextToken(); // eat the token that starting up will use.
+
+ gl_.reset(new GLES2Implementation(
+ helper_.get(),
+ NULL,
+ transfer_buffer_.get(),
+ bind_generates_resource,
+ NULL));
+ ASSERT_TRUE(gl_->Initialize(
+ kTransferBufferSize,
+ kTransferBufferSize,
+ kTransferBufferSize));
+ }
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .Times(1)
+ .RetiresOnSaturation();
+ helper_->CommandBufferHelper::Finish();
+ ::testing::Mock::VerifyAndClearExpectations(gl_.get());
+
+ Buffer ring_buffer = helper_->get_ring_buffer();
+ commands_ = static_cast<CommandBufferEntry*>(ring_buffer.ptr) +
+ command_buffer()->GetState().put_offset;
+ ClearCommands();
+ EXPECT_TRUE(transfer_buffer_->InSync());
+
+ ::testing::Mock::VerifyAndClearExpectations(command_buffer());
+ }
+
+ MockClientCommandBuffer* command_buffer() const {
+ return command_buffer_.get();
+ }
+
+ int GetNextToken() {
+ return ++token_;
+ }
+
+ const void* GetPut() {
+ return helper_->GetSpace(0);
+ }
+
+ void ClearCommands() {
+ Buffer ring_buffer = helper_->get_ring_buffer();
+ memset(ring_buffer.ptr, kInitialValue, ring_buffer.size);
+ }
+
+ size_t MaxTransferBufferSize() {
+ return transfer_buffer_->MaxTransferBufferSize();
+ }
+
+ ExpectedMemoryInfo GetExpectedMemory(size_t size) {
+ return transfer_buffer_->GetExpectedMemory(size);
+ }
+
+ ExpectedMemoryInfo GetExpectedResultMemory(size_t size) {
+ return transfer_buffer_->GetExpectedResultMemory(size);
+ }
+
+ // Sets the ProgramInfoManager. The manager will be owned
+ // by the ShareGroup.
+ void SetProgramInfoManager(ProgramInfoManager* manager) {
+ gl_->share_group()->set_program_info_manager(manager);
+ }
+
+ int CheckError() {
+ ExpectedMemoryInfo result =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+ return gl_->GetError();
+ }
+
+ bool GetBucketContents(uint32 bucket_id, std::vector<int8>* data) {
+ return gl_->GetBucketContents(bucket_id, data);
+ }
+
+ Sequence sequence_;
+ scoped_ptr<MockClientCommandBuffer> command_buffer_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MockTransferBuffer> transfer_buffer_;
+ scoped_ptr<GLES2Implementation> gl_;
+ CommandBufferEntry* commands_;
+ int token_;
+};
+
+void GLES2ImplementationTest::SetUp() {
+ Initialize(true);
+}
+
+void GLES2ImplementationTest::TearDown() {
+ Mock::VerifyAndClear(gl_.get());
+ EXPECT_CALL(*command_buffer(), OnFlush()).Times(AnyNumber());
+ // For command buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(AtLeast(1));
+ gl_.reset();
+}
+
+class GLES2ImplementationStrictSharedTest : public GLES2ImplementationTest {
+ protected:
+ virtual void SetUp() OVERRIDE;
+};
+
+void GLES2ImplementationStrictSharedTest::SetUp() {
+ Initialize(false);
+}
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const uint8 GLES2ImplementationTest::kInitialValue;
+const int32 GLES2ImplementationTest::kNumCommandEntries;
+const int32 GLES2ImplementationTest::kCommandBufferSizeBytes;
+const size_t GLES2ImplementationTest::kTransferBufferSize;
+const GLint GLES2ImplementationTest::kMaxCombinedTextureImageUnits;
+const GLint GLES2ImplementationTest::kMaxCubeMapTextureSize;
+const GLint GLES2ImplementationTest::kMaxFragmentUniformVectors;
+const GLint GLES2ImplementationTest::kMaxRenderbufferSize;
+const GLint GLES2ImplementationTest::kMaxTextureImageUnits;
+const GLint GLES2ImplementationTest::kMaxTextureSize;
+const GLint GLES2ImplementationTest::kMaxVaryingVectors;
+const GLint GLES2ImplementationTest::kMaxVertexAttribs;
+const GLint GLES2ImplementationTest::kMaxVertexTextureImageUnits;
+const GLint GLES2ImplementationTest::kMaxVertexUniformVectors;
+const GLint GLES2ImplementationTest::kNumCompressedTextureFormats;
+const GLint GLES2ImplementationTest::kNumShaderBinaryFormats;
+const GLuint GLES2ImplementationTest::kStartId;
+const GLuint GLES2ImplementationTest::kBuffersStartId;
+const GLuint GLES2ImplementationTest::kFramebuffersStartId;
+const GLuint GLES2ImplementationTest::kProgramsAndShadersStartId;
+const GLuint GLES2ImplementationTest::kRenderbuffersStartId;
+const GLuint GLES2ImplementationTest::kTexturesStartId;
+const GLuint GLES2ImplementationTest::kQueriesStartId;
+const GLuint GLES2ImplementationTest::kVertexArraysStartId;
+#endif
+
+TEST_F(GLES2ImplementationTest, Basic) {
+ EXPECT_TRUE(gl_->share_group() != NULL);
+}
+
+TEST_F(GLES2ImplementationTest, GetBucketContents) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const uint32 kTestSize = MaxTransferBufferSize() + 32;
+
+ scoped_ptr<uint8[]> buf(new uint8 [kTestSize]);
+ uint8* expected_data = buf.get();
+ for (uint32 ii = 0; ii < kTestSize; ++ii) {
+ expected_data[ii] = ii * 3;
+ }
+
+ struct Cmds {
+ cmd::GetBucketStart get_bucket_start;
+ cmd::SetToken set_token1;
+ cmd::GetBucketData get_bucket_data;
+ cmd::SetToken set_token2;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(sizeof(uint32));
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(
+ kTestSize - MaxTransferBufferSize());
+
+ Cmds expected;
+ expected.get_bucket_start.Init(
+ kBucketId, result1.id, result1.offset,
+ MaxTransferBufferSize(), mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.get_bucket_data.Init(
+ kBucketId, MaxTransferBufferSize(),
+ kTestSize - MaxTransferBufferSize(), mem2.id, mem2.offset);
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ expected.set_token2.Init(GetNextToken());
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(DoAll(
+ SetMemory(result1.ptr, kTestSize),
+ SetMemoryFromArray(
+ mem1.ptr, expected_data, MaxTransferBufferSize())))
+ .WillOnce(SetMemoryFromArray(
+ mem2.ptr, expected_data + MaxTransferBufferSize(),
+ kTestSize - MaxTransferBufferSize()))
+ .RetiresOnSaturation();
+
+ std::vector<int8> data;
+ GetBucketContents(kBucketId, &data);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ ASSERT_EQ(kTestSize, data.size());
+ EXPECT_EQ(0, memcmp(expected_data, &data[0], data.size()));
+}
+
+TEST_F(GLES2ImplementationTest, GetShaderPrecisionFormat) {
+ struct Cmds {
+ cmds::GetShaderPrecisionFormat cmd;
+ };
+ typedef cmds::GetShaderPrecisionFormat::Result Result;
+
+ // The first call for mediump should trigger a command buffer request.
+ GLint range1[2] = {0, 0};
+ GLint precision1 = 0;
+ Cmds expected1;
+ ExpectedMemoryInfo client_result1 = GetExpectedResultMemory(4);
+ expected1.cmd.Init(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
+ client_result1.id, client_result1.offset);
+ Result server_result1 = {true, 14, 14, 10};
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(client_result1.ptr, server_result1))
+ .RetiresOnSaturation();
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
+ range1, &precision1);
+ const void* commands2 = GetPut();
+ EXPECT_NE(commands_, commands2);
+ EXPECT_EQ(0, memcmp(&expected1, commands_, sizeof(expected1)));
+ EXPECT_EQ(range1[0], 14);
+ EXPECT_EQ(range1[1], 14);
+ EXPECT_EQ(precision1, 10);
+
+ // The second call for mediump should use the cached value and avoid
+ // triggering a command buffer request, so we do not expect a call to
+ // OnFlush() here. We do expect the results to be correct though.
+ GLint range2[2] = {0, 0};
+ GLint precision2 = 0;
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
+ range2, &precision2);
+ const void* commands3 = GetPut();
+ EXPECT_EQ(commands2, commands3);
+ EXPECT_EQ(range2[0], 14);
+ EXPECT_EQ(range2[1], 14);
+ EXPECT_EQ(precision2, 10);
+
+ // If we then make a request for highp, we should get another command
+ // buffer request since it hasn't been cached yet.
+ GLint range3[2] = {0, 0};
+ GLint precision3 = 0;
+ Cmds expected3;
+ ExpectedMemoryInfo result3 = GetExpectedResultMemory(4);
+ expected3.cmd.Init(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
+ result3.id, result3.offset);
+ Result result3_source = {true, 62, 62, 16};
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result3.ptr, result3_source))
+ .RetiresOnSaturation();
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
+ range3, &precision3);
+ const void* commands4 = GetPut();
+ EXPECT_NE(commands3, commands4);
+ EXPECT_EQ(0, memcmp(&expected3, commands3, sizeof(expected3)));
+ EXPECT_EQ(range3[0], 62);
+ EXPECT_EQ(range3[1], 62);
+ EXPECT_EQ(precision3, 16);
+}
+
+TEST_F(GLES2ImplementationTest, ShaderSource) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const GLuint kShaderId = 456;
+ const char* kString1 = "foobar";
+ const char* kString2 = "barfoo";
+ const size_t kString1Size = strlen(kString1);
+ const size_t kString2Size = strlen(kString2);
+ const size_t kString3Size = 1; // Want the NULL;
+ const size_t kSourceSize = kString1Size + kString2Size + kString3Size;
+ const size_t kPaddedString1Size =
+ transfer_buffer_->RoundToAlignment(kString1Size);
+ const size_t kPaddedString2Size =
+ transfer_buffer_->RoundToAlignment(kString2Size);
+ const size_t kPaddedString3Size =
+ transfer_buffer_->RoundToAlignment(kString3Size);
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size;
+ cmd::SetBucketData set_bucket_data1;
+ cmd::SetToken set_token1;
+ cmd::SetBucketData set_bucket_data2;
+ cmd::SetToken set_token2;
+ cmd::SetBucketData set_bucket_data3;
+ cmd::SetToken set_token3;
+ cmds::ShaderSourceBucket shader_source_bucket;
+ cmd::SetBucketSize clear_bucket_size;
+ };
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kPaddedString1Size);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kPaddedString2Size);
+ ExpectedMemoryInfo mem3 = GetExpectedMemory(kPaddedString3Size);
+
+ Cmds expected;
+ expected.set_bucket_size.Init(kBucketId, kSourceSize);
+ expected.set_bucket_data1.Init(
+ kBucketId, 0, kString1Size, mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_data2.Init(
+ kBucketId, kString1Size, kString2Size, mem2.id, mem2.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_bucket_data3.Init(
+ kBucketId, kString1Size + kString2Size,
+ kString3Size, mem3.id, mem3.offset);
+ expected.set_token3.Init(GetNextToken());
+ expected.shader_source_bucket.Init(kShaderId, kBucketId);
+ expected.clear_bucket_size.Init(kBucketId, 0);
+ const char* strings[] = {
+ kString1,
+ kString2,
+ };
+ gl_->ShaderSource(kShaderId, 2, strings, NULL);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, GetShaderSource) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const GLuint kShaderId = 456;
+ const Str7 kString = {"foobar"};
+ const char kBad = 0x12;
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ cmds::GetShaderSource get_shader_source;
+ cmd::GetBucketStart get_bucket_start;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(sizeof(uint32));
+
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_shader_source.Init(kShaderId, kBucketId);
+ expected.get_bucket_start.Init(
+ kBucketId, result1.id, result1.offset,
+ MaxTransferBufferSize(), mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ char buf[sizeof(kString) + 1];
+ memset(buf, kBad, sizeof(buf));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(DoAll(SetMemory(result1.ptr, uint32(sizeof(kString))),
+ SetMemory(mem1.ptr, kString)))
+ .RetiresOnSaturation();
+
+ GLsizei length = 0;
+ gl_->GetShaderSource(kShaderId, sizeof(buf), &length, buf);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(sizeof(kString) - 1, static_cast<size_t>(length));
+ EXPECT_STREQ(kString.str, buf);
+ EXPECT_EQ(buf[sizeof(kString)], kBad);
+}
+
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+
+TEST_F(GLES2ImplementationTest, DrawArraysClientSideBuffers) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable1;
+ cmds::EnableVertexAttribArray enable2;
+ cmds::BindBuffer bind_to_emu;
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::VertexAttribPointer set_pointer1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ cmds::VertexAttribPointer set_pointer2;
+ cmds::DrawArrays draw;
+ cmds::BindBuffer restore;
+ };
+ const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId;
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLint kFirst = 1;
+ const GLsizei kCount = 2;
+ const GLsizei kSize1 =
+ arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]);
+ const GLsizei kSize2 =
+ arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]);
+ const GLsizei kEmuOffset1 = 0;
+ const GLsizei kEmuOffset2 = kSize1;
+ const GLsizei kTotalSize = kSize1 + kSize2;
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize1);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize2);
+
+ Cmds expected;
+ expected.enable1.Init(kAttribIndex1);
+ expected.enable2.Init(kAttribIndex2);
+ expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId);
+ expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_pointer1.Init(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1);
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem2.id, mem2.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_pointer2.Init(
+ kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, 0, kEmuOffset2);
+ expected.draw.Init(GL_POINTS, kFirst, kCount);
+ expected.restore.Init(GL_ARRAY_BUFFER, 0);
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->VertexAttribPointer(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(
+ kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->DrawArrays(GL_POINTS, kFirst, kCount);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawArraysInstancedANGLEClientSideBuffers) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable1;
+ cmds::EnableVertexAttribArray enable2;
+ cmds::VertexAttribDivisorANGLE divisor;
+ cmds::BindBuffer bind_to_emu;
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::VertexAttribPointer set_pointer1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ cmds::VertexAttribPointer set_pointer2;
+ cmds::DrawArraysInstancedANGLE draw;
+ cmds::BindBuffer restore;
+ };
+ const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId;
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLint kFirst = 1;
+ const GLsizei kCount = 2;
+ const GLuint kDivisor = 1;
+ const GLsizei kSize1 =
+ arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]);
+ const GLsizei kSize2 =
+ 1 * kNumComponents2 * sizeof(verts[0][0]);
+ const GLsizei kEmuOffset1 = 0;
+ const GLsizei kEmuOffset2 = kSize1;
+ const GLsizei kTotalSize = kSize1 + kSize2;
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize1);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize2);
+
+ Cmds expected;
+ expected.enable1.Init(kAttribIndex1);
+ expected.enable2.Init(kAttribIndex2);
+ expected.divisor.Init(kAttribIndex2, kDivisor);
+ expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId);
+ expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_pointer1.Init(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1);
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem2.id, mem2.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_pointer2.Init(
+ kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, 0, kEmuOffset2);
+ expected.draw.Init(GL_POINTS, kFirst, kCount, 1);
+ expected.restore.Init(GL_ARRAY_BUFFER, 0);
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->VertexAttribPointer(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(
+ kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribDivisorANGLE(kAttribIndex2, kDivisor);
+ gl_->DrawArraysInstancedANGLE(GL_POINTS, kFirst, kCount, 1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawElementsClientSideBuffers) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ static const uint16 indices[] = {
+ 1, 2,
+ };
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable1;
+ cmds::EnableVertexAttribArray enable2;
+ cmds::BindBuffer bind_to_index_emu;
+ cmds::BufferData set_index_size;
+ cmds::BufferSubData copy_data0;
+ cmd::SetToken set_token0;
+ cmds::BindBuffer bind_to_emu;
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::VertexAttribPointer set_pointer1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ cmds::VertexAttribPointer set_pointer2;
+ cmds::DrawElements draw;
+ cmds::BindBuffer restore;
+ cmds::BindBuffer restore_element;
+ };
+ const GLsizei kIndexSize = sizeof(indices);
+ const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId;
+ const GLuint kEmuIndexBufferId =
+ GLES2Implementation::kClientSideElementArrayId;
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLsizei kCount = 2;
+ const GLsizei kSize1 =
+ arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]);
+ const GLsizei kSize2 =
+ arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]);
+ const GLsizei kEmuOffset1 = 0;
+ const GLsizei kEmuOffset2 = kSize1;
+ const GLsizei kTotalSize = kSize1 + kSize2;
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kIndexSize);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1);
+ ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2);
+
+ Cmds expected;
+ expected.enable1.Init(kAttribIndex1);
+ expected.enable2.Init(kAttribIndex2);
+ expected.bind_to_index_emu.Init(GL_ELEMENT_ARRAY_BUFFER, kEmuIndexBufferId);
+ expected.set_index_size.Init(
+ GL_ELEMENT_ARRAY_BUFFER, kIndexSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data0.Init(
+ GL_ELEMENT_ARRAY_BUFFER, 0, kIndexSize, mem1.id, mem1.offset);
+ expected.set_token0.Init(GetNextToken());
+ expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId);
+ expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_pointer1.Init(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1);
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_pointer2.Init(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, 0, kEmuOffset2);
+ expected.draw.Init(GL_POINTS, kCount, GL_UNSIGNED_SHORT, 0);
+ expected.restore.Init(GL_ARRAY_BUFFER, 0);
+ expected.restore_element.Init(GL_ELEMENT_ARRAY_BUFFER, 0);
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->DrawElements(GL_POINTS, kCount, GL_UNSIGNED_SHORT, indices);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawElementsClientSideBuffersIndexUint) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ static const uint32 indices[] = {
+ 1, 2,
+ };
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable1;
+ cmds::EnableVertexAttribArray enable2;
+ cmds::BindBuffer bind_to_index_emu;
+ cmds::BufferData set_index_size;
+ cmds::BufferSubData copy_data0;
+ cmd::SetToken set_token0;
+ cmds::BindBuffer bind_to_emu;
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::VertexAttribPointer set_pointer1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ cmds::VertexAttribPointer set_pointer2;
+ cmds::DrawElements draw;
+ cmds::BindBuffer restore;
+ cmds::BindBuffer restore_element;
+ };
+ const GLsizei kIndexSize = sizeof(indices);
+ const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId;
+ const GLuint kEmuIndexBufferId =
+ GLES2Implementation::kClientSideElementArrayId;
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLsizei kCount = 2;
+ const GLsizei kSize1 =
+ arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]);
+ const GLsizei kSize2 =
+ arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]);
+ const GLsizei kEmuOffset1 = 0;
+ const GLsizei kEmuOffset2 = kSize1;
+ const GLsizei kTotalSize = kSize1 + kSize2;
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kIndexSize);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1);
+ ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2);
+
+ Cmds expected;
+ expected.enable1.Init(kAttribIndex1);
+ expected.enable2.Init(kAttribIndex2);
+ expected.bind_to_index_emu.Init(GL_ELEMENT_ARRAY_BUFFER, kEmuIndexBufferId);
+ expected.set_index_size.Init(
+ GL_ELEMENT_ARRAY_BUFFER, kIndexSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data0.Init(
+ GL_ELEMENT_ARRAY_BUFFER, 0, kIndexSize, mem1.id, mem1.offset);
+ expected.set_token0.Init(GetNextToken());
+ expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId);
+ expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_pointer1.Init(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1);
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_pointer2.Init(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, 0, kEmuOffset2);
+ expected.draw.Init(GL_POINTS, kCount, GL_UNSIGNED_INT, 0);
+ expected.restore.Init(GL_ARRAY_BUFFER, 0);
+ expected.restore_element.Init(GL_ELEMENT_ARRAY_BUFFER, 0);
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->DrawElements(GL_POINTS, kCount, GL_UNSIGNED_INT, indices);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawElementsClientSideBuffersInvalidIndexUint) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ static const uint32 indices[] = {
+ 1, 0x90000000
+ };
+
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLsizei kCount = 2;
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .Times(1)
+ .RetiresOnSaturation();
+
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->DrawElements(GL_POINTS, kCount, GL_UNSIGNED_INT, indices);
+
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), gl_->GetError());
+}
+
+TEST_F(GLES2ImplementationTest,
+ DrawElementsClientSideBuffersServiceSideIndices) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable1;
+ cmds::EnableVertexAttribArray enable2;
+ cmds::BindBuffer bind_to_index;
+ cmds::GetMaxValueInBufferCHROMIUM get_max;
+ cmds::BindBuffer bind_to_emu;
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::VertexAttribPointer set_pointer1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ cmds::VertexAttribPointer set_pointer2;
+ cmds::DrawElements draw;
+ cmds::BindBuffer restore;
+ };
+ const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId;
+ const GLuint kClientIndexBufferId = 0x789;
+ const GLuint kIndexOffset = 0x40;
+ const GLuint kMaxIndex = 2;
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLsizei kCount = 2;
+ const GLsizei kSize1 =
+ arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]);
+ const GLsizei kSize2 =
+ arraysize(verts) * kNumComponents2 * sizeof(verts[0][0]);
+ const GLsizei kEmuOffset1 = 0;
+ const GLsizei kEmuOffset2 = kSize1;
+ const GLsizei kTotalSize = kSize1 + kSize2;
+
+ ExpectedMemoryInfo mem1 = GetExpectedResultMemory(sizeof(uint32));
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1);
+ ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2);
+
+
+ Cmds expected;
+ expected.enable1.Init(kAttribIndex1);
+ expected.enable2.Init(kAttribIndex2);
+ expected.bind_to_index.Init(GL_ELEMENT_ARRAY_BUFFER, kClientIndexBufferId);
+ expected.get_max.Init(kClientIndexBufferId, kCount, GL_UNSIGNED_SHORT,
+ kIndexOffset, mem1.id, mem1.offset);
+ expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId);
+ expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_pointer1.Init(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, 0, kEmuOffset1);
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_pointer2.Init(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, 0, kEmuOffset2);
+ expected.draw.Init(GL_POINTS, kCount, GL_UNSIGNED_SHORT, kIndexOffset);
+ expected.restore.Init(GL_ARRAY_BUFFER, 0);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(mem1.ptr,kMaxIndex))
+ .RetiresOnSaturation();
+
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, kClientIndexBufferId);
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->DrawElements(GL_POINTS, kCount, GL_UNSIGNED_SHORT,
+ reinterpret_cast<const void*>(kIndexOffset));
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawElementsInstancedANGLEClientSideBuffers) {
+ static const float verts[][4] = {
+ { 12.0f, 23.0f, 34.0f, 45.0f, },
+ { 56.0f, 67.0f, 78.0f, 89.0f, },
+ { 13.0f, 24.0f, 35.0f, 46.0f, },
+ };
+ static const uint16 indices[] = {
+ 1, 2,
+ };
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable1;
+ cmds::EnableVertexAttribArray enable2;
+ cmds::VertexAttribDivisorANGLE divisor;
+ cmds::BindBuffer bind_to_index_emu;
+ cmds::BufferData set_index_size;
+ cmds::BufferSubData copy_data0;
+ cmd::SetToken set_token0;
+ cmds::BindBuffer bind_to_emu;
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::VertexAttribPointer set_pointer1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ cmds::VertexAttribPointer set_pointer2;
+ cmds::DrawElementsInstancedANGLE draw;
+ cmds::BindBuffer restore;
+ cmds::BindBuffer restore_element;
+ };
+ const GLsizei kIndexSize = sizeof(indices);
+ const GLuint kEmuBufferId = GLES2Implementation::kClientSideArrayId;
+ const GLuint kEmuIndexBufferId =
+ GLES2Implementation::kClientSideElementArrayId;
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kClientStride = sizeof(verts[0]);
+ const GLsizei kCount = 2;
+ const GLsizei kSize1 =
+ arraysize(verts) * kNumComponents1 * sizeof(verts[0][0]);
+ const GLsizei kSize2 =
+ 1 * kNumComponents2 * sizeof(verts[0][0]);
+ const GLuint kDivisor = 1;
+ const GLsizei kEmuOffset1 = 0;
+ const GLsizei kEmuOffset2 = kSize1;
+ const GLsizei kTotalSize = kSize1 + kSize2;
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kIndexSize);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kSize1);
+ ExpectedMemoryInfo mem3 = GetExpectedMemory(kSize2);
+
+ Cmds expected;
+ expected.enable1.Init(kAttribIndex1);
+ expected.enable2.Init(kAttribIndex2);
+ expected.divisor.Init(kAttribIndex2, kDivisor);
+ expected.bind_to_index_emu.Init(GL_ELEMENT_ARRAY_BUFFER, kEmuIndexBufferId);
+ expected.set_index_size.Init(
+ GL_ELEMENT_ARRAY_BUFFER, kIndexSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data0.Init(
+ GL_ELEMENT_ARRAY_BUFFER, 0, kIndexSize, mem1.id, mem1.offset);
+ expected.set_token0.Init(GetNextToken());
+ expected.bind_to_emu.Init(GL_ARRAY_BUFFER, kEmuBufferId);
+ expected.set_size.Init(GL_ARRAY_BUFFER, kTotalSize, 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, kEmuOffset1, kSize1, mem2.id, mem2.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_pointer1.Init(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, 0, kEmuOffset1);
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kEmuOffset2, kSize2, mem3.id, mem3.offset);
+ expected.set_token2.Init(GetNextToken());
+ expected.set_pointer2.Init(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, 0, kEmuOffset2);
+ expected.draw.Init(GL_POINTS, kCount, GL_UNSIGNED_SHORT, 0, 1);
+ expected.restore.Init(GL_ARRAY_BUFFER, 0);
+ expected.restore_element.Init(GL_ELEMENT_ARRAY_BUFFER, 0);
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ gl_->EnableVertexAttribArray(kAttribIndex2);
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kClientStride, verts);
+ gl_->VertexAttribDivisorANGLE(kAttribIndex2, kDivisor);
+ gl_->DrawElementsInstancedANGLE(
+ GL_POINTS, kCount, GL_UNSIGNED_SHORT, indices, 1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, GetVertexBufferPointerv) {
+ static const float verts[1] = { 0.0f, };
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kStride1 = 12;
+ const GLsizei kStride2 = 0;
+ const GLuint kBufferId = 0x123;
+ const GLint kOffset2 = 0x456;
+
+ // It's all cached on the client side so no get commands are issued.
+ struct Cmds {
+ cmds::BindBuffer bind;
+ cmds::VertexAttribPointer set_pointer;
+ };
+
+ Cmds expected;
+ expected.bind.Init(GL_ARRAY_BUFFER, kBufferId);
+ expected.set_pointer.Init(kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE,
+ kStride2, kOffset2);
+
+ // Set one client side buffer.
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kStride1, verts);
+ // Set one VBO
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kStride2,
+ reinterpret_cast<const void*>(kOffset2));
+ // now get them both.
+ void* ptr1 = NULL;
+ void* ptr2 = NULL;
+
+ gl_->GetVertexAttribPointerv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr1);
+ gl_->GetVertexAttribPointerv(
+ kAttribIndex2, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr2);
+
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(static_cast<const void*>(&verts) == ptr1);
+ EXPECT_TRUE(ptr2 == reinterpret_cast<void*>(kOffset2));
+}
+
+TEST_F(GLES2ImplementationTest, GetVertexAttrib) {
+ static const float verts[1] = { 0.0f, };
+ const GLuint kAttribIndex1 = 1;
+ const GLuint kAttribIndex2 = 3;
+ const GLint kNumComponents1 = 3;
+ const GLint kNumComponents2 = 2;
+ const GLsizei kStride1 = 12;
+ const GLsizei kStride2 = 0;
+ const GLuint kBufferId = 0x123;
+ const GLint kOffset2 = 0x456;
+
+ // Only one set and one get because the client side buffer's info is stored
+ // on the client side.
+ struct Cmds {
+ cmds::EnableVertexAttribArray enable;
+ cmds::BindBuffer bind;
+ cmds::VertexAttribPointer set_pointer;
+ cmds::GetVertexAttribfv get2; // for getting the value from attrib1
+ };
+
+ ExpectedMemoryInfo mem2 = GetExpectedResultMemory(16);
+
+ Cmds expected;
+ expected.enable.Init(kAttribIndex1);
+ expected.bind.Init(GL_ARRAY_BUFFER, kBufferId);
+ expected.set_pointer.Init(kAttribIndex2, kNumComponents2, GL_FLOAT, GL_FALSE,
+ kStride2, kOffset2);
+ expected.get2.Init(kAttribIndex1,
+ GL_CURRENT_VERTEX_ATTRIB,
+ mem2.id, mem2.offset);
+
+ FourFloats current_attrib(1.2f, 3.4f, 5.6f, 7.8f);
+
+ // One call to flush to wait for last call to GetVertexAttribiv
+ // as others are all cached.
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(
+ mem2.ptr, SizedResultHelper<FourFloats>(current_attrib)))
+ .RetiresOnSaturation();
+
+ gl_->EnableVertexAttribArray(kAttribIndex1);
+ // Set one client side buffer.
+ gl_->VertexAttribPointer(kAttribIndex1, kNumComponents1,
+ GL_FLOAT, GL_FALSE, kStride1, verts);
+ // Set one VBO
+ gl_->BindBuffer(GL_ARRAY_BUFFER, kBufferId);
+ gl_->VertexAttribPointer(kAttribIndex2, kNumComponents2,
+ GL_FLOAT, GL_FALSE, kStride2,
+ reinterpret_cast<const void*>(kOffset2));
+ // first get the service side once to see that we make a command
+ GLint buffer_id = 0;
+ GLint enabled = 0;
+ GLint size = 0;
+ GLint stride = 0;
+ GLint type = 0;
+ GLint normalized = 1;
+ float current[4] = { 0.0f, };
+
+ gl_->GetVertexAttribiv(
+ kAttribIndex2, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &buffer_id);
+ EXPECT_EQ(kBufferId, static_cast<GLuint>(buffer_id));
+ gl_->GetVertexAttribiv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &buffer_id);
+ gl_->GetVertexAttribiv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &enabled);
+ gl_->GetVertexAttribiv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_SIZE, &size);
+ gl_->GetVertexAttribiv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_STRIDE, &stride);
+ gl_->GetVertexAttribiv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_TYPE, &type);
+ gl_->GetVertexAttribiv(
+ kAttribIndex1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &normalized);
+ gl_->GetVertexAttribfv(
+ kAttribIndex1, GL_CURRENT_VERTEX_ATTRIB, &current[0]);
+
+ EXPECT_EQ(0, buffer_id);
+ EXPECT_EQ(GL_TRUE, enabled);
+ EXPECT_EQ(kNumComponents1, size);
+ EXPECT_EQ(kStride1, stride);
+ EXPECT_EQ(GL_FLOAT, type);
+ EXPECT_EQ(GL_FALSE, normalized);
+ EXPECT_EQ(0, memcmp(&current_attrib, &current, sizeof(current_attrib)));
+
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ReservedIds) {
+ // Only the get error command should be issued.
+ struct Cmds {
+ cmds::GetError get;
+ };
+ Cmds expected;
+
+ ExpectedMemoryInfo mem1 = GetExpectedResultMemory(
+ sizeof(cmds::GetError::Result));
+
+ expected.get.Init(mem1.id, mem1.offset);
+
+ // One call to flush to wait for GetError
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(mem1.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ gl_->BindBuffer(
+ GL_ARRAY_BUFFER,
+ GLES2Implementation::kClientSideArrayId);
+ gl_->BindBuffer(
+ GL_ARRAY_BUFFER,
+ GLES2Implementation::kClientSideElementArrayId);
+ GLenum err = gl_->GetError();
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), err);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+
+TEST_F(GLES2ImplementationTest, ReadPixels2Reads) {
+ struct Cmds {
+ cmds::ReadPixels read1;
+ cmd::SetToken set_token1;
+ cmds::ReadPixels read2;
+ cmd::SetToken set_token2;
+ };
+ const GLint kBytesPerPixel = 4;
+ const GLint kWidth =
+ (kTransferBufferSize - GLES2Implementation::kStartingOffset) /
+ kBytesPerPixel;
+ const GLint kHeight = 2;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+
+ ExpectedMemoryInfo mem1 =
+ GetExpectedMemory(kWidth * kHeight / 2 * kBytesPerPixel);
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::ReadPixels::Result));
+ ExpectedMemoryInfo mem2 =
+ GetExpectedMemory(kWidth * kHeight / 2 * kBytesPerPixel);
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::ReadPixels::Result));
+
+ Cmds expected;
+ expected.read1.Init(
+ 0, 0, kWidth, kHeight / 2, kFormat, kType,
+ mem1.id, mem1.offset, result1.id, result1.offset,
+ false);
+ expected.set_token1.Init(GetNextToken());
+ expected.read2.Init(
+ 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
+ mem2.id, mem2.offset, result2.id, result2.offset, false);
+ expected.set_token2.Init(GetNextToken());
+ scoped_ptr<int8[]> buffer(new int8[kWidth * kHeight * kBytesPerPixel]);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, static_cast<uint32>(1)))
+ .WillOnce(SetMemory(result2.ptr, static_cast<uint32>(1)))
+ .RetiresOnSaturation();
+
+ gl_->ReadPixels(0, 0, kWidth, kHeight, kFormat, kType, buffer.get());
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ReadPixelsBadFormatType) {
+ struct Cmds {
+ cmds::ReadPixels read;
+ cmd::SetToken set_token;
+ };
+ const GLint kBytesPerPixel = 4;
+ const GLint kWidth = 2;
+ const GLint kHeight = 2;
+ const GLenum kFormat = 0;
+ const GLenum kType = 0;
+
+ ExpectedMemoryInfo mem1 =
+ GetExpectedMemory(kWidth * kHeight * kBytesPerPixel);
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::ReadPixels::Result));
+
+ Cmds expected;
+ expected.read.Init(
+ 0, 0, kWidth, kHeight, kFormat, kType,
+ mem1.id, mem1.offset, result1.id, result1.offset, false);
+ expected.set_token.Init(GetNextToken());
+ scoped_ptr<int8[]> buffer(new int8[kWidth * kHeight * kBytesPerPixel]);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .Times(1)
+ .RetiresOnSaturation();
+
+ gl_->ReadPixels(0, 0, kWidth, kHeight, kFormat, kType, buffer.get());
+}
+
+TEST_F(GLES2ImplementationTest, FreeUnusedSharedMemory) {
+ struct Cmds {
+ cmds::BufferSubData buf;
+ cmd::SetToken set_token;
+ };
+ const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER;
+ const GLintptr kOffset = 15;
+ const GLsizeiptr kSize = 16;
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kSize);
+
+ Cmds expected;
+ expected.buf.Init(
+ kTarget, kOffset, kSize, mem1.id, mem1.offset);
+ expected.set_token.Init(GetNextToken());
+
+ void* mem = gl_->MapBufferSubDataCHROMIUM(
+ kTarget, kOffset, kSize, GL_WRITE_ONLY);
+ ASSERT_TRUE(mem != NULL);
+ gl_->UnmapBufferSubDataCHROMIUM(mem);
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ gl_->FreeUnusedSharedMemory();
+}
+
+TEST_F(GLES2ImplementationTest, MapUnmapBufferSubDataCHROMIUM) {
+ struct Cmds {
+ cmds::BufferSubData buf;
+ cmd::SetToken set_token;
+ };
+ const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER;
+ const GLintptr kOffset = 15;
+ const GLsizeiptr kSize = 16;
+
+ uint32 offset = 0;
+ Cmds expected;
+ expected.buf.Init(
+ kTarget, kOffset, kSize,
+ command_buffer()->GetNextFreeTransferBufferId(), offset);
+ expected.set_token.Init(GetNextToken());
+
+ void* mem = gl_->MapBufferSubDataCHROMIUM(
+ kTarget, kOffset, kSize, GL_WRITE_ONLY);
+ ASSERT_TRUE(mem != NULL);
+ gl_->UnmapBufferSubDataCHROMIUM(mem);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, MapUnmapBufferSubDataCHROMIUMBadArgs) {
+ const GLenum kTarget = GL_ELEMENT_ARRAY_BUFFER;
+ const GLintptr kOffset = 15;
+ const GLsizeiptr kSize = 16;
+
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result3 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result4 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ // Calls to flush to wait for GetError
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ void* mem;
+ mem = gl_->MapBufferSubDataCHROMIUM(kTarget, -1, kSize, GL_WRITE_ONLY);
+ ASSERT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapBufferSubDataCHROMIUM(kTarget, kOffset, -1, GL_WRITE_ONLY);
+ ASSERT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapBufferSubDataCHROMIUM(kTarget, kOffset, kSize, GL_READ_ONLY);
+ ASSERT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
+ const char* kPtr = "something";
+ gl_->UnmapBufferSubDataCHROMIUM(kPtr);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+}
+
+TEST_F(GLES2ImplementationTest, MapUnmapTexSubImage2DCHROMIUM) {
+ struct Cmds {
+ cmds::TexSubImage2D tex;
+ cmd::SetToken set_token;
+ };
+ const GLint kLevel = 1;
+ const GLint kXOffset = 2;
+ const GLint kYOffset = 3;
+ const GLint kWidth = 4;
+ const GLint kHeight = 5;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+
+ uint32 offset = 0;
+ Cmds expected;
+ expected.tex.Init(
+ GL_TEXTURE_2D, kLevel, kXOffset, kYOffset, kWidth, kHeight, kFormat,
+ kType,
+ command_buffer()->GetNextFreeTransferBufferId(), offset, GL_FALSE);
+ expected.set_token.Init(GetNextToken());
+
+ void* mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ kLevel,
+ kXOffset,
+ kYOffset,
+ kWidth,
+ kHeight,
+ kFormat,
+ kType,
+ GL_WRITE_ONLY);
+ ASSERT_TRUE(mem != NULL);
+ gl_->UnmapTexSubImage2DCHROMIUM(mem);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, MapUnmapTexSubImage2DCHROMIUMBadArgs) {
+ const GLint kLevel = 1;
+ const GLint kXOffset = 2;
+ const GLint kYOffset = 3;
+ const GLint kWidth = 4;
+ const GLint kHeight = 5;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result3 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result4 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result5 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result6 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result7 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ // Calls to flush to wait for GetError
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result5.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result6.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result7.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ void* mem;
+ mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ -1,
+ kXOffset,
+ kYOffset,
+ kWidth,
+ kHeight,
+ kFormat,
+ kType,
+ GL_WRITE_ONLY);
+ EXPECT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ kLevel,
+ -1,
+ kYOffset,
+ kWidth,
+ kHeight,
+ kFormat,
+ kType,
+ GL_WRITE_ONLY);
+ EXPECT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ kLevel,
+ kXOffset,
+ -1,
+ kWidth,
+ kHeight,
+ kFormat,
+ kType,
+ GL_WRITE_ONLY);
+ EXPECT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ kLevel,
+ kXOffset,
+ kYOffset,
+ -1,
+ kHeight,
+ kFormat,
+ kType,
+ GL_WRITE_ONLY);
+ EXPECT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ kLevel,
+ kXOffset,
+ kYOffset,
+ kWidth,
+ -1,
+ kFormat,
+ kType,
+ GL_WRITE_ONLY);
+ EXPECT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ mem = gl_->MapTexSubImage2DCHROMIUM(
+ GL_TEXTURE_2D,
+ kLevel,
+ kXOffset,
+ kYOffset,
+ kWidth,
+ kHeight,
+ kFormat,
+ kType,
+ GL_READ_ONLY);
+ EXPECT_TRUE(mem == NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
+ const char* kPtr = "something";
+ gl_->UnmapTexSubImage2DCHROMIUM(kPtr);
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+}
+
+TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMValidArgs) {
+ const GLenum pnames[] = {
+ GL_DEPTH_WRITEMASK,
+ GL_COLOR_WRITEMASK,
+ GL_STENCIL_WRITEMASK,
+ };
+ const GLint num_results = 6;
+ GLint results[num_results + 1];
+ struct Cmds {
+ cmds::GetMultipleIntegervCHROMIUM get_multiple;
+ cmd::SetToken set_token;
+ };
+ const GLsizei kNumPnames = arraysize(pnames);
+ const GLsizeiptr kResultsSize = num_results * sizeof(results[0]);
+ const size_t kPNamesSize = kNumPnames * sizeof(pnames[0]);
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kPNamesSize + kResultsSize);
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(
+ sizeof(cmds::GetError::Result));
+
+ const uint32 kPnamesOffset = mem1.offset;
+ const uint32 kResultsOffset = mem1.offset + kPNamesSize;
+ Cmds expected;
+ expected.get_multiple.Init(
+ mem1.id, kPnamesOffset, kNumPnames,
+ mem1.id, kResultsOffset, kResultsSize);
+ expected.set_token.Init(GetNextToken());
+
+ const GLint kSentinel = 0x12345678;
+ memset(results, 0, sizeof(results));
+ results[num_results] = kSentinel;
+ const GLint returned_results[] = {
+ 1, 0, 1, 0, 1, -1,
+ };
+ // One call to flush to wait for results
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemoryFromArray(mem1.ptr + kPNamesSize,
+ returned_results, sizeof(returned_results)))
+ .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ gl_->GetMultipleIntegervCHROMIUM(
+ &pnames[0], kNumPnames, &results[0], kResultsSize);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(0, memcmp(&returned_results, results, sizeof(returned_results)));
+ EXPECT_EQ(kSentinel, results[num_results]);
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+}
+
+TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMBadArgs) {
+ GLenum pnames[] = {
+ GL_DEPTH_WRITEMASK,
+ GL_COLOR_WRITEMASK,
+ GL_STENCIL_WRITEMASK,
+ };
+ const GLint num_results = 6;
+ GLint results[num_results + 1];
+ const GLsizei kNumPnames = arraysize(pnames);
+ const GLsizeiptr kResultsSize = num_results * sizeof(results[0]);
+
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result3 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result4 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ // Calls to flush to wait for GetError
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ const GLint kSentinel = 0x12345678;
+ memset(results, 0, sizeof(results));
+ results[num_results] = kSentinel;
+ // try bad size.
+ gl_->GetMultipleIntegervCHROMIUM(
+ &pnames[0], kNumPnames, &results[0], kResultsSize + 1);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ EXPECT_EQ(0, results[0]);
+ EXPECT_EQ(kSentinel, results[num_results]);
+ // try bad size.
+ ClearCommands();
+ gl_->GetMultipleIntegervCHROMIUM(
+ &pnames[0], kNumPnames, &results[0], kResultsSize - 1);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ EXPECT_EQ(0, results[0]);
+ EXPECT_EQ(kSentinel, results[num_results]);
+ // try uncleared results.
+ ClearCommands();
+ results[2] = 1;
+ gl_->GetMultipleIntegervCHROMIUM(
+ &pnames[0], kNumPnames, &results[0], kResultsSize);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ EXPECT_EQ(0, results[0]);
+ EXPECT_EQ(kSentinel, results[num_results]);
+ // try bad enum results.
+ ClearCommands();
+ results[2] = 0;
+ pnames[1] = GL_TRUE;
+ gl_->GetMultipleIntegervCHROMIUM(
+ &pnames[0], kNumPnames, &results[0], kResultsSize);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
+ EXPECT_EQ(0, results[0]);
+ EXPECT_EQ(kSentinel, results[num_results]);
+}
+
+TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const GLuint kProgramId = 123;
+ const char kBad = 0x12;
+ GLsizei size = 0;
+ const Str7 kString = {"foobar"};
+ char buf[20];
+
+ ExpectedMemoryInfo mem1 =
+ GetExpectedMemory(MaxTransferBufferSize());
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ memset(buf, kBad, sizeof(buf));
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(DoAll(SetMemory(result1.ptr, uint32(sizeof(kString))),
+ SetMemory(mem1.ptr, kString)))
+ .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ cmds::GetProgramInfoCHROMIUM get_program_info;
+ cmd::GetBucketStart get_bucket_start;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_program_info.Init(kProgramId, kBucketId);
+ expected.get_bucket_start.Init(
+ kBucketId, result1.id, result1.offset,
+ MaxTransferBufferSize(), mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), &size, &buf);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+ EXPECT_EQ(sizeof(kString), static_cast<size_t>(size));
+ EXPECT_STREQ(kString.str, buf);
+ EXPECT_EQ(buf[sizeof(kString)], kBad);
+}
+
+TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMBadArgs) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const GLuint kProgramId = 123;
+ GLsizei size = 0;
+ const Str7 kString = {"foobar"};
+ char buf[20];
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result3 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+ ExpectedMemoryInfo result4 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(DoAll(SetMemory(result1.ptr, uint32(sizeof(kString))),
+ SetMemory(mem1.ptr, kString)))
+ .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ // try bufsize not big enough.
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ cmds::GetProgramInfoCHROMIUM get_program_info;
+ cmd::GetBucketStart get_bucket_start;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_program_info.Init(kProgramId, kBucketId);
+ expected.get_bucket_start.Init(
+ kBucketId, result1.id, result1.offset,
+ MaxTransferBufferSize(), mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ gl_->GetProgramInfoCHROMIUM(kProgramId, 6, &size, &buf);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), gl_->GetError());
+ ClearCommands();
+
+ // try bad bufsize
+ gl_->GetProgramInfoCHROMIUM(kProgramId, -1, &size, &buf);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ ClearCommands();
+ // try no size ptr.
+ gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), NULL, &buf);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+}
+
+// Test that things are cached
+TEST_F(GLES2ImplementationTest, GetIntegerCacheRead) {
+ struct PNameValue {
+ GLenum pname;
+ GLint expected;
+ };
+ const PNameValue pairs[] = {
+ { GL_ACTIVE_TEXTURE, GL_TEXTURE0, },
+ { GL_TEXTURE_BINDING_2D, 0, },
+ { GL_TEXTURE_BINDING_CUBE_MAP, 0, },
+ { GL_FRAMEBUFFER_BINDING, 0, },
+ { GL_RENDERBUFFER_BINDING, 0, },
+ { GL_ARRAY_BUFFER_BINDING, 0, },
+ { GL_ELEMENT_ARRAY_BUFFER_BINDING, 0, },
+ { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kMaxCombinedTextureImageUnits, },
+ { GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMaxCubeMapTextureSize, },
+ { GL_MAX_FRAGMENT_UNIFORM_VECTORS, kMaxFragmentUniformVectors, },
+ { GL_MAX_RENDERBUFFER_SIZE, kMaxRenderbufferSize, },
+ { GL_MAX_TEXTURE_IMAGE_UNITS, kMaxTextureImageUnits, },
+ { GL_MAX_TEXTURE_SIZE, kMaxTextureSize, },
+ { GL_MAX_VARYING_VECTORS, kMaxVaryingVectors, },
+ { GL_MAX_VERTEX_ATTRIBS, kMaxVertexAttribs, },
+ { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMaxVertexTextureImageUnits, },
+ { GL_MAX_VERTEX_UNIFORM_VECTORS, kMaxVertexUniformVectors, },
+ { GL_NUM_COMPRESSED_TEXTURE_FORMATS, kNumCompressedTextureFormats, },
+ { GL_NUM_SHADER_BINARY_FORMATS, kNumShaderBinaryFormats, },
+ };
+ size_t num_pairs = sizeof(pairs) / sizeof(pairs[0]);
+ for (size_t ii = 0; ii < num_pairs; ++ii) {
+ const PNameValue& pv = pairs[ii];
+ GLint v = -1;
+ gl_->GetIntegerv(pv.pname, &v);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(pv.expected, v);
+ }
+
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+}
+
+TEST_F(GLES2ImplementationTest, GetIntegerCacheWrite) {
+ struct PNameValue {
+ GLenum pname;
+ GLint expected;
+ };
+ gl_->ActiveTexture(GL_TEXTURE4);
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 2);
+ gl_->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 3);
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 4);
+ gl_->BindRenderbuffer(GL_RENDERBUFFER, 5);
+ gl_->BindTexture(GL_TEXTURE_2D, 6);
+ gl_->BindTexture(GL_TEXTURE_CUBE_MAP, 7);
+
+ const PNameValue pairs[] = {
+ { GL_ACTIVE_TEXTURE, GL_TEXTURE4, },
+ { GL_ARRAY_BUFFER_BINDING, 2, },
+ { GL_ELEMENT_ARRAY_BUFFER_BINDING, 3, },
+ { GL_FRAMEBUFFER_BINDING, 4, },
+ { GL_RENDERBUFFER_BINDING, 5, },
+ { GL_TEXTURE_BINDING_2D, 6, },
+ { GL_TEXTURE_BINDING_CUBE_MAP, 7, },
+ };
+ size_t num_pairs = sizeof(pairs) / sizeof(pairs[0]);
+ for (size_t ii = 0; ii < num_pairs; ++ii) {
+ const PNameValue& pv = pairs[ii];
+ GLint v = -1;
+ gl_->GetIntegerv(pv.pname, &v);
+ EXPECT_EQ(pv.expected, v);
+ }
+
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+}
+
+static bool CheckRect(
+ int width, int height, GLenum format, GLenum type, int alignment,
+ bool flip_y, const uint8* r1, const uint8* r2) {
+ uint32 size = 0;
+ uint32 unpadded_row_size = 0;
+ uint32 padded_row_size = 0;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, alignment, &size, &unpadded_row_size,
+ &padded_row_size)) {
+ return false;
+ }
+
+ int r2_stride = flip_y ?
+ -static_cast<int>(padded_row_size) :
+ static_cast<int>(padded_row_size);
+ r2 = flip_y ? (r2 + (height - 1) * padded_row_size) : r2;
+
+ for (int y = 0; y < height; ++y) {
+ if (memcmp(r1, r2, unpadded_row_size) != 0) {
+ return false;
+ }
+ r1 += padded_row_size;
+ r2 += r2_stride;
+ }
+ return true;
+}
+
+ACTION_P8(CheckRectAction, width, height, format, type, alignment, flip_y,
+ r1, r2) {
+ EXPECT_TRUE(CheckRect(
+ width, height, format, type, alignment, flip_y, r1, r2));
+}
+
+// Test TexImage2D with and without flip_y
+TEST_F(GLES2ImplementationTest, TexImage2D) {
+ struct Cmds {
+ cmds::TexImage2D tex_image_2d;
+ cmd::SetToken set_token;
+ };
+ struct Cmds2 {
+ cmds::TexImage2D tex_image_2d;
+ cmd::SetToken set_token;
+ };
+ const GLenum kTarget = GL_TEXTURE_2D;
+ const GLint kLevel = 0;
+ const GLenum kFormat = GL_RGB;
+ const GLsizei kWidth = 3;
+ const GLsizei kHeight = 4;
+ const GLint kBorder = 0;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLint kPixelStoreUnpackAlignment = 4;
+ static uint8 pixels[] = {
+ 11, 12, 13, 13, 14, 15, 15, 16, 17, 101, 102, 103,
+ 21, 22, 23, 23, 24, 25, 25, 26, 27, 201, 202, 203,
+ 31, 32, 33, 33, 34, 35, 35, 36, 37, 123, 124, 125,
+ 41, 42, 43, 43, 44, 45, 45, 46, 47,
+ };
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(sizeof(pixels));
+
+ Cmds expected;
+ expected.tex_image_2d.Init(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ mem1.id, mem1.offset);
+ expected.set_token.Init(GetNextToken());
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ pixels);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(CheckRect(
+ kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, false,
+ pixels, mem1.ptr));
+
+ ClearCommands();
+ gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE);
+
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(sizeof(pixels));
+ Cmds2 expected2;
+ expected2.tex_image_2d.Init(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ mem2.id, mem2.offset);
+ expected2.set_token.Init(GetNextToken());
+ const void* commands2 = GetPut();
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ pixels);
+ EXPECT_EQ(0, memcmp(&expected2, commands2, sizeof(expected2)));
+ EXPECT_TRUE(CheckRect(
+ kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment, true,
+ pixels, mem2.ptr));
+}
+
+// Test TexImage2D with 2 writes
+TEST_F(GLES2ImplementationTest, TexImage2D2Writes) {
+ struct Cmds {
+ cmds::TexImage2D tex_image_2d;
+ cmds::TexSubImage2D tex_sub_image_2d1;
+ cmd::SetToken set_token1;
+ cmds::TexSubImage2D tex_sub_image_2d2;
+ cmd::SetToken set_token2;
+ };
+ const GLenum kTarget = GL_TEXTURE_2D;
+ const GLint kLevel = 0;
+ const GLenum kFormat = GL_RGB;
+ const GLint kBorder = 0;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLint kPixelStoreUnpackAlignment = 4;
+ const GLsizei kWidth = 3;
+
+ uint32 size = 0;
+ uint32 unpadded_row_size = 0;
+ uint32 padded_row_size = 0;
+ ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment,
+ &size, &unpadded_row_size, &padded_row_size));
+ const GLsizei kHeight = (MaxTransferBufferSize() / padded_row_size) * 2;
+ ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, kFormat, kType, kPixelStoreUnpackAlignment,
+ &size, NULL, NULL));
+ uint32 half_size = 0;
+ ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment,
+ &half_size, NULL, NULL));
+
+ scoped_ptr<uint8[]> pixels(new uint8[size]);
+ for (uint32 ii = 0; ii < size; ++ii) {
+ pixels[ii] = static_cast<uint8>(ii);
+ }
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(half_size);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(half_size);
+
+ Cmds expected;
+ expected.tex_image_2d.Init(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ 0, 0);
+ expected.tex_sub_image_2d1.Init(
+ kTarget, kLevel, 0, 0, kWidth, kHeight / 2, kFormat, kType,
+ mem1.id, mem1.offset, true);
+ expected.set_token1.Init(GetNextToken());
+ expected.tex_sub_image_2d2.Init(
+ kTarget, kLevel, 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
+ mem2.id, mem2.offset, true);
+ expected.set_token2.Init(GetNextToken());
+
+ // TODO(gman): Make it possible to run this test
+ // EXPECT_CALL(*command_buffer(), OnFlush())
+ // .WillOnce(CheckRectAction(
+ // kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment,
+ // false, pixels.get(),
+ // GetExpectedTransferAddressFromOffsetAs<uint8>(offset1, half_size)))
+ // .RetiresOnSaturation();
+
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ pixels.get());
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(CheckRect(
+ kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, false,
+ pixels.get() + kHeight / 2 * padded_row_size, mem2.ptr));
+
+ ClearCommands();
+ gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE);
+ const void* commands2 = GetPut();
+ ExpectedMemoryInfo mem3 = GetExpectedMemory(half_size);
+ ExpectedMemoryInfo mem4 = GetExpectedMemory(half_size);
+ expected.tex_image_2d.Init(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ 0, 0);
+ expected.tex_sub_image_2d1.Init(
+ kTarget, kLevel, 0, kHeight / 2, kWidth, kHeight / 2, kFormat, kType,
+ mem3.id, mem3.offset, true);
+ expected.set_token1.Init(GetNextToken());
+ expected.tex_sub_image_2d2.Init(
+ kTarget, kLevel, 0, 0, kWidth, kHeight / 2, kFormat, kType,
+ mem4.id, mem4.offset, true);
+ expected.set_token2.Init(GetNextToken());
+
+ // TODO(gman): Make it possible to run this test
+ // EXPECT_CALL(*command_buffer(), OnFlush())
+ // .WillOnce(CheckRectAction(
+ // kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment,
+ // true, pixels.get(),
+ // GetExpectedTransferAddressFromOffsetAs<uint8>(offset3, half_size)))
+ // .RetiresOnSaturation();
+
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kWidth, kHeight, kBorder, kFormat, kType,
+ pixels.get());
+ EXPECT_EQ(0, memcmp(&expected, commands2, sizeof(expected)));
+ EXPECT_TRUE(CheckRect(
+ kWidth, kHeight / 2, kFormat, kType, kPixelStoreUnpackAlignment, true,
+ pixels.get() + kHeight / 2 * padded_row_size, mem4.ptr));
+}
+
+// Test TexSubImage2D with GL_PACK_FLIP_Y set and partial multirow transfers
+TEST_F(GLES2ImplementationTest, TexSubImage2DFlipY) {
+ const GLsizei kTextureWidth = MaxTransferBufferSize() / 4;
+ const GLsizei kTextureHeight = 7;
+ const GLsizei kSubImageWidth = MaxTransferBufferSize() / 8;
+ const GLsizei kSubImageHeight = 4;
+ const GLint kSubImageXOffset = 1;
+ const GLint kSubImageYOffset = 2;
+ const GLenum kFormat = GL_RGBA;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLenum kTarget = GL_TEXTURE_2D;
+ const GLint kLevel = 0;
+ const GLint kBorder = 0;
+ const GLint kPixelStoreUnpackAlignment = 4;
+
+ struct Cmds {
+ cmds::PixelStorei pixel_store_i1;
+ cmds::TexImage2D tex_image_2d;
+ cmds::PixelStorei pixel_store_i2;
+ cmds::TexSubImage2D tex_sub_image_2d1;
+ cmd::SetToken set_token1;
+ cmds::TexSubImage2D tex_sub_image_2d2;
+ cmd::SetToken set_token2;
+ };
+
+ uint32 sub_2_high_size = 0;
+ ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kSubImageWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment,
+ &sub_2_high_size, NULL, NULL));
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(sub_2_high_size);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(sub_2_high_size);
+
+ Cmds expected;
+ expected.pixel_store_i1.Init(GL_UNPACK_ALIGNMENT, kPixelStoreUnpackAlignment);
+ expected.tex_image_2d.Init(
+ kTarget, kLevel, kFormat, kTextureWidth, kTextureHeight, kBorder, kFormat,
+ kType, 0, 0);
+ expected.pixel_store_i2.Init(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE);
+ expected.tex_sub_image_2d1.Init(kTarget, kLevel, kSubImageXOffset,
+ kSubImageYOffset + 2, kSubImageWidth, 2, kFormat, kType,
+ mem1.id, mem1.offset, false);
+ expected.set_token1.Init(GetNextToken());
+ expected.tex_sub_image_2d2.Init(kTarget, kLevel, kSubImageXOffset,
+ kSubImageYOffset, kSubImageWidth , 2, kFormat, kType,
+ mem2.id, mem2.offset, false);
+ expected.set_token2.Init(GetNextToken());
+
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, kPixelStoreUnpackAlignment);
+ gl_->TexImage2D(
+ kTarget, kLevel, kFormat, kTextureWidth, kTextureHeight, kBorder, kFormat,
+ kType, NULL);
+ gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, GL_TRUE);
+ scoped_ptr<uint32[]> pixels(new uint32[kSubImageWidth * kSubImageHeight]);
+ for (int y = 0; y < kSubImageHeight; ++y) {
+ for (int x = 0; x < kSubImageWidth; ++x) {
+ pixels.get()[kSubImageWidth * y + x] = x | (y << 16);
+ }
+ }
+ gl_->TexSubImage2D(
+ GL_TEXTURE_2D, 0, kSubImageXOffset, kSubImageYOffset, kSubImageWidth,
+ kSubImageHeight, GL_RGBA, GL_UNSIGNED_BYTE, pixels.get());
+
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(CheckRect(
+ kSubImageWidth, 2, kFormat, kType, kPixelStoreUnpackAlignment, true,
+ reinterpret_cast<uint8*>(pixels.get() + 2 * kSubImageWidth),
+ mem2.ptr));
+}
+
+TEST_F(GLES2ImplementationTest, SubImageUnpack) {
+ static const GLint unpack_alignments[] = { 1, 2, 4, 8 };
+
+ static const GLenum kFormat = GL_RGB;
+ static const GLenum kType = GL_UNSIGNED_BYTE;
+ static const GLint kLevel = 0;
+ static const GLint kBorder = 0;
+ // We're testing using the unpack params to pull a subimage out of a larger
+ // source of pixels. Here we specify the subimage by its border rows /
+ // columns.
+ static const GLint kSrcWidth = 33;
+ static const GLint kSrcSubImageX0 = 11;
+ static const GLint kSrcSubImageX1 = 20;
+ static const GLint kSrcSubImageY0 = 18;
+ static const GLint kSrcSubImageY1 = 23;
+ static const GLint kSrcSubImageWidth = kSrcSubImageX1 - kSrcSubImageX0;
+ static const GLint kSrcSubImageHeight = kSrcSubImageY1 - kSrcSubImageY0;
+
+ // these are only used in the texsubimage tests
+ static const GLint kTexWidth = 1023;
+ static const GLint kTexHeight = 511;
+ static const GLint kTexSubXOffset = 419;
+ static const GLint kTexSubYOffset = 103;
+
+ struct {
+ cmds::PixelStorei pixel_store_i;
+ cmds::PixelStorei pixel_store_i2;
+ cmds::TexImage2D tex_image_2d;
+ } texImageExpected;
+
+ struct {
+ cmds::PixelStorei pixel_store_i;
+ cmds::PixelStorei pixel_store_i2;
+ cmds::TexImage2D tex_image_2d;
+ cmds::TexSubImage2D tex_sub_image_2d;
+ } texSubImageExpected;
+
+ uint32 src_size;
+ ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kSrcWidth, kSrcSubImageY1, kFormat, kType, 8, &src_size, NULL, NULL));
+ scoped_ptr<uint8[]> src_pixels;
+ src_pixels.reset(new uint8[src_size]);
+ for (size_t i = 0; i < src_size; ++i) {
+ src_pixels[i] = static_cast<int8>(i);
+ }
+
+ for (int sub = 0; sub < 2; ++sub) {
+ for (int flip_y = 0; flip_y < 2; ++flip_y) {
+ for (size_t a = 0; a < arraysize(unpack_alignments); ++a) {
+ GLint alignment = unpack_alignments[a];
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ ASSERT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kSrcSubImageWidth, kSrcSubImageHeight, kFormat, kType, alignment,
+ &size, &unpadded_row_size, &padded_row_size));
+ ASSERT_TRUE(size <= MaxTransferBufferSize());
+ ExpectedMemoryInfo mem = GetExpectedMemory(size);
+
+ const void* commands = GetPut();
+ gl_->PixelStorei(GL_UNPACK_ALIGNMENT, alignment);
+ gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, kSrcWidth);
+ gl_->PixelStorei(GL_UNPACK_SKIP_PIXELS, kSrcSubImageX0);
+ gl_->PixelStorei(GL_UNPACK_SKIP_ROWS, kSrcSubImageY0);
+ gl_->PixelStorei(GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
+ if (sub) {
+ gl_->TexImage2D(
+ GL_TEXTURE_2D, kLevel, kFormat, kTexWidth, kTexHeight, kBorder,
+ kFormat, kType, NULL);
+ gl_->TexSubImage2D(
+ GL_TEXTURE_2D, kLevel, kTexSubXOffset, kTexSubYOffset,
+ kSrcSubImageWidth, kSrcSubImageHeight, kFormat, kType,
+ src_pixels.get());
+ texSubImageExpected.pixel_store_i.Init(
+ GL_UNPACK_ALIGNMENT, alignment);
+ texSubImageExpected.pixel_store_i2.Init(
+ GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
+ texSubImageExpected.tex_image_2d.Init(
+ GL_TEXTURE_2D, kLevel, kFormat, kTexWidth, kTexHeight, kBorder,
+ kFormat, kType, 0, 0);
+ texSubImageExpected.tex_sub_image_2d.Init(
+ GL_TEXTURE_2D, kLevel, kTexSubXOffset, kTexSubYOffset,
+ kSrcSubImageWidth, kSrcSubImageHeight, kFormat, kType, mem.id,
+ mem.offset, GL_FALSE);
+ EXPECT_EQ(0, memcmp(
+ &texSubImageExpected, commands, sizeof(texSubImageExpected)));
+ } else {
+ gl_->TexImage2D(
+ GL_TEXTURE_2D, kLevel, kFormat,
+ kSrcSubImageWidth, kSrcSubImageHeight, kBorder, kFormat, kType,
+ src_pixels.get());
+ texImageExpected.pixel_store_i.Init(GL_UNPACK_ALIGNMENT, alignment);
+ texImageExpected.pixel_store_i2.Init(
+ GL_UNPACK_FLIP_Y_CHROMIUM, flip_y);
+ texImageExpected.tex_image_2d.Init(
+ GL_TEXTURE_2D, kLevel, kFormat, kSrcSubImageWidth,
+ kSrcSubImageHeight, kBorder, kFormat, kType, mem.id, mem.offset);
+ EXPECT_EQ(0, memcmp(
+ &texImageExpected, commands, sizeof(texImageExpected)));
+ }
+ uint32 src_padded_row_size;
+ ASSERT_TRUE(GLES2Util::ComputeImagePaddedRowSize(
+ kSrcWidth, kFormat, kType, alignment, &src_padded_row_size));
+ uint32 bytes_per_group = GLES2Util::ComputeImageGroupSize(
+ kFormat, kType);
+ for (int y = 0; y < kSrcSubImageHeight; ++y) {
+ GLint src_sub_y = flip_y ? kSrcSubImageHeight - y - 1 : y;
+ const uint8* src_row = src_pixels.get() +
+ (kSrcSubImageY0 + src_sub_y) * src_padded_row_size +
+ bytes_per_group * kSrcSubImageX0;
+ const uint8* dst_row = mem.ptr + y * padded_row_size;
+ EXPECT_EQ(0, memcmp(src_row, dst_row, unpadded_row_size));
+ }
+ ClearCommands();
+ }
+ }
+ }
+}
+
+// Binds can not be cached with bind_generates_resource = false because
+// our id might not be valid. More specifically if you bind on contextA then
+// delete on contextB the resource is still bound on contextA but GetInterger
+// won't return an id.
+TEST_F(GLES2ImplementationStrictSharedTest, BindsNotCached) {
+ struct PNameValue {
+ GLenum pname;
+ GLint expected;
+ };
+ const PNameValue pairs[] = {
+ { GL_TEXTURE_BINDING_2D, 1, },
+ { GL_TEXTURE_BINDING_CUBE_MAP, 2, },
+ { GL_FRAMEBUFFER_BINDING, 3, },
+ { GL_RENDERBUFFER_BINDING, 4, },
+ { GL_ARRAY_BUFFER_BINDING, 5, },
+ { GL_ELEMENT_ARRAY_BUFFER_BINDING, 6, },
+ };
+ size_t num_pairs = sizeof(pairs) / sizeof(pairs[0]);
+ for (size_t ii = 0; ii < num_pairs; ++ii) {
+ const PNameValue& pv = pairs[ii];
+ GLint v = -1;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::GetIntegerv::Result));
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr,
+ SizedResultHelper<GLuint>(pv.expected)))
+ .RetiresOnSaturation();
+ gl_->GetIntegerv(pv.pname, &v);
+ EXPECT_EQ(pv.expected, v);
+ }
+}
+
+TEST_F(GLES2ImplementationTest, CreateStreamTextureCHROMIUM) {
+ const GLuint kTextureId = 123;
+ const GLuint kResult = 456;
+
+ struct Cmds {
+ cmds::CreateStreamTextureCHROMIUM create_stream;
+ };
+
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(
+ sizeof(cmds::CreateStreamTextureCHROMIUM::Result));
+ ExpectedMemoryInfo result2 =
+ GetExpectedResultMemory(sizeof(cmds::GetError::Result));
+
+ Cmds expected;
+ expected.create_stream.Init(kTextureId, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, kResult))
+ .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ GLuint handle = gl_->CreateStreamTextureCHROMIUM(kTextureId);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(handle, kResult);
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+}
+
+TEST_F(GLES2ImplementationTest, GetString) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const Str7 kString = {"foobar"};
+ // GL_CHROMIUM_map_sub GL_CHROMIUM_flipy are hard coded into
+ // GLES2Implementation.
+ const char* expected_str =
+ "foobar "
+ "GL_CHROMIUM_flipy "
+ "GL_CHROMIUM_map_sub "
+ "GL_CHROMIUM_shallow_flush "
+ "GL_EXT_unpack_subimage";
+ const char kBad = 0x12;
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ cmds::GetString get_string;
+ cmd::GetBucketStart get_bucket_start;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_string.Init(GL_EXTENSIONS, kBucketId);
+ expected.get_bucket_start.Init(
+ kBucketId, result1.id, result1.offset,
+ MaxTransferBufferSize(), mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ char buf[sizeof(kString) + 1];
+ memset(buf, kBad, sizeof(buf));
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(DoAll(SetMemory(result1.ptr, uint32(sizeof(kString))),
+ SetMemory(mem1.ptr, kString)))
+ .RetiresOnSaturation();
+
+ const GLubyte* result = gl_->GetString(GL_EXTENSIONS);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_STREQ(expected_str, reinterpret_cast<const char*>(result));
+}
+
+TEST_F(GLES2ImplementationTest, PixelStoreiGLPackReverseRowOrderANGLE) {
+ const uint32 kBucketId = GLES2Implementation::kResultBucketId;
+ const Str7 kString = {"foobar"};
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ cmds::GetString get_string;
+ cmd::GetBucketStart get_bucket_start;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ cmds::PixelStorei pixel_store;
+ };
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(MaxTransferBufferSize());
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmd::GetBucketStart::Result));
+
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_string.Init(GL_EXTENSIONS, kBucketId);
+ expected.get_bucket_start.Init(
+ kBucketId, result1.id, result1.offset,
+ MaxTransferBufferSize(), mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ expected.pixel_store.Init(GL_PACK_REVERSE_ROW_ORDER_ANGLE, 1);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(DoAll(SetMemory(result1.ptr, uint32(sizeof(kString))),
+ SetMemory(mem1.ptr, kString)))
+ .RetiresOnSaturation();
+
+ gl_->PixelStorei(GL_PACK_REVERSE_ROW_ORDER_ANGLE, 1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CreateProgram) {
+ struct Cmds {
+ cmds::CreateProgram cmd;
+ };
+
+ Cmds expected;
+ expected.cmd.Init(kProgramsAndShadersStartId);
+ GLuint id = gl_->CreateProgram();
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kProgramsAndShadersStartId, id);
+}
+
+TEST_F(GLES2ImplementationTest, BufferDataLargerThanTransferBuffer) {
+ struct Cmds {
+ cmds::BufferData set_size;
+ cmds::BufferSubData copy_data1;
+ cmd::SetToken set_token1;
+ cmds::BufferSubData copy_data2;
+ cmd::SetToken set_token2;
+ };
+ const unsigned kUsableSize =
+ kTransferBufferSize - GLES2Implementation::kStartingOffset;
+ uint8 buf[kUsableSize * 2] = { 0, };
+
+ ExpectedMemoryInfo mem1 = GetExpectedMemory(kUsableSize);
+ ExpectedMemoryInfo mem2 = GetExpectedMemory(kUsableSize);
+
+ Cmds expected;
+ expected.set_size.Init(
+ GL_ARRAY_BUFFER, arraysize(buf), 0, 0, GL_DYNAMIC_DRAW);
+ expected.copy_data1.Init(
+ GL_ARRAY_BUFFER, 0, kUsableSize, mem1.id, mem1.offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.copy_data2.Init(
+ GL_ARRAY_BUFFER, kUsableSize, kUsableSize, mem2.id, mem2.offset);
+ expected.set_token2.Init(GetNextToken());
+ gl_->BufferData(GL_ARRAY_BUFFER, arraysize(buf), buf, GL_DYNAMIC_DRAW);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CapabilitiesAreCached) {
+ static const GLenum kStates[] = {
+ GL_DITHER,
+ GL_BLEND,
+ GL_CULL_FACE,
+ GL_DEPTH_TEST,
+ GL_POLYGON_OFFSET_FILL,
+ GL_SAMPLE_ALPHA_TO_COVERAGE,
+ GL_SAMPLE_COVERAGE,
+ GL_SCISSOR_TEST,
+ GL_STENCIL_TEST,
+ };
+ struct Cmds {
+ cmds::Enable enable_cmd;
+ };
+ Cmds expected;
+
+ for (size_t ii = 0; ii < arraysize(kStates); ++ii) {
+ GLenum state = kStates[ii];
+ expected.enable_cmd.Init(state);
+ GLboolean result = gl_->IsEnabled(state);
+ EXPECT_EQ(static_cast<GLboolean>(ii == 0), result);
+ EXPECT_TRUE(NoCommandsWritten());
+ const void* commands = GetPut();
+ if (!result) {
+ gl_->Enable(state);
+ EXPECT_EQ(0, memcmp(&expected, commands, sizeof(expected)));
+ }
+ ClearCommands();
+ result = gl_->IsEnabled(state);
+ EXPECT_TRUE(result);
+ EXPECT_TRUE(NoCommandsWritten());
+ }
+}
+
+TEST_F(GLES2ImplementationTest, BindVertexArrayOES) {
+ GLuint id = 0;
+ gl_->GenVertexArraysOES(1, &id);
+ ClearCommands();
+
+ struct Cmds {
+ cmds::BindVertexArrayOES cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(id);
+
+ const void* commands = GetPut();
+ gl_->BindVertexArrayOES(id);
+ EXPECT_EQ(0, memcmp(&expected, commands, sizeof(expected)));
+ ClearCommands();
+ gl_->BindVertexArrayOES(id);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, BeginEndQueryEXT) {
+ // Test GetQueryivEXT returns 0 if no current query.
+ GLint param = -1;
+ gl_->GetQueryivEXT(GL_ANY_SAMPLES_PASSED_EXT, GL_CURRENT_QUERY_EXT, &param);
+ EXPECT_EQ(0, param);
+
+ GLuint expected_ids[2] = { 1, 2 }; // These must match what's actually genned.
+ struct GenCmds {
+ cmds::GenQueriesEXTImmediate gen;
+ GLuint data[2];
+ };
+ GenCmds expected_gen_cmds;
+ expected_gen_cmds.gen.Init(arraysize(expected_ids), &expected_ids[0]);
+ GLuint ids[arraysize(expected_ids)] = { 0, };
+ gl_->GenQueriesEXT(arraysize(expected_ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(
+ &expected_gen_cmds, commands_, sizeof(expected_gen_cmds)));
+ GLuint id1 = ids[0];
+ GLuint id2 = ids[1];
+ ClearCommands();
+
+ // Test BeginQueryEXT fails if id = 0.
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, 0);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test BeginQueryEXT fails if id not GENed.
+ // TODO(gman):
+
+ // Test BeginQueryEXT inserts command.
+ struct BeginCmds {
+ cmds::BeginQueryEXT begin_query;
+ };
+ BeginCmds expected_begin_cmds;
+ const void* commands = GetPut();
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
+ QueryTracker::Query* query = GetQuery(id1);
+ ASSERT_TRUE(query != NULL);
+ expected_begin_cmds.begin_query.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, id1, query->shm_id(), query->shm_offset());
+ EXPECT_EQ(0, memcmp(
+ &expected_begin_cmds, commands, sizeof(expected_begin_cmds)));
+ ClearCommands();
+
+ // Test GetQueryivEXT returns id.
+ param = -1;
+ gl_->GetQueryivEXT(GL_ANY_SAMPLES_PASSED_EXT, GL_CURRENT_QUERY_EXT, &param);
+ EXPECT_EQ(id1, static_cast<GLuint>(param));
+ gl_->GetQueryivEXT(
+ GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, GL_CURRENT_QUERY_EXT, &param);
+ EXPECT_EQ(0, param);
+
+ // Test BeginQueryEXT fails if between Begin/End.
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id2);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test EndQueryEXT fails if target not same as current query.
+ ClearCommands();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test EndQueryEXT sends command
+ struct EndCmds {
+ cmds::EndQueryEXT end_query;
+ };
+ EndCmds expected_end_cmds;
+ expected_end_cmds.end_query.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, query->submit_count());
+ commands = GetPut();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ EXPECT_EQ(0, memcmp(
+ &expected_end_cmds, commands, sizeof(expected_end_cmds)));
+
+ // Test EndQueryEXT fails if no current query.
+ ClearCommands();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test 2nd Begin/End increments count.
+ uint32 old_submit_count = query->submit_count();
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, id1);
+ EXPECT_NE(old_submit_count, query->submit_count());
+ expected_end_cmds.end_query.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, query->submit_count());
+ commands = GetPut();
+ gl_->EndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);
+ EXPECT_EQ(0, memcmp(
+ &expected_end_cmds, commands, sizeof(expected_end_cmds)));
+
+ // Test BeginQueryEXT fails if target changed.
+ ClearCommands();
+ gl_->BeginQueryEXT(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, id1);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test GetQueryObjectuivEXT fails if unused id
+ GLuint available = 0xBDu;
+ ClearCommands();
+ gl_->GetQueryObjectuivEXT(id2, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0xBDu, available);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test GetQueryObjectuivEXT fails if bad id
+ ClearCommands();
+ gl_->GetQueryObjectuivEXT(4567, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0xBDu, available);
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ // Test GetQueryObjectuivEXT CheckResultsAvailable
+ ClearCommands();
+ gl_->GetQueryObjectuivEXT(id1, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0u, available);
+}
+
+TEST_F(GLES2ImplementationTest, ErrorQuery) {
+ GLuint id = 0;
+ gl_->GenQueriesEXT(1, &id);
+ ClearCommands();
+
+ // Test BeginQueryEXT does NOT insert commands.
+ gl_->BeginQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM, id);
+ EXPECT_TRUE(NoCommandsWritten());
+ QueryTracker::Query* query = GetQuery(id);
+ ASSERT_TRUE(query != NULL);
+
+ // Test EndQueryEXT sends both begin and end command
+ struct EndCmds {
+ cmds::BeginQueryEXT begin_query;
+ cmds::EndQueryEXT end_query;
+ };
+ EndCmds expected_end_cmds;
+ expected_end_cmds.begin_query.Init(
+ GL_GET_ERROR_QUERY_CHROMIUM, id, query->shm_id(), query->shm_offset());
+ expected_end_cmds.end_query.Init(
+ GL_GET_ERROR_QUERY_CHROMIUM, query->submit_count());
+ const void* commands = GetPut();
+ gl_->EndQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM);
+ EXPECT_EQ(0, memcmp(
+ &expected_end_cmds, commands, sizeof(expected_end_cmds)));
+ ClearCommands();
+
+ // Check result is not yet available.
+ GLuint available = 0xBDu;
+ gl_->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(0u, available);
+
+ // Test no commands are sent if there is a client side error.
+
+ // Generate a client side error
+ gl_->ActiveTexture(GL_TEXTURE0 - 1);
+
+ gl_->BeginQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM, id);
+ gl_->EndQueryEXT(GL_GET_ERROR_QUERY_CHROMIUM);
+ EXPECT_TRUE(NoCommandsWritten());
+
+ // Check result is available.
+ gl_->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_NE(0u, available);
+
+ // Check result.
+ GLuint result = 0xBDu;
+ gl_->GetQueryObjectuivEXT(id, GL_QUERY_RESULT_EXT, &result);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLuint>(GL_INVALID_ENUM), result);
+}
+
+#if !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+TEST_F(GLES2ImplementationTest, VertexArrays) {
+ const GLuint kAttribIndex1 = 1;
+ const GLint kNumComponents1 = 3;
+ const GLsizei kClientStride = 12;
+
+ GLuint id = 0;
+ gl_->GenVertexArraysOES(1, &id);
+ ClearCommands();
+
+ gl_->BindVertexArrayOES(id);
+
+ // Test that VertexAttribPointer cannot be called with a bound buffer of 0
+ // unless the offset is NULL
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 0);
+
+ gl_->VertexAttribPointer(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride,
+ reinterpret_cast<const void*>(4));
+ EXPECT_EQ(GL_INVALID_OPERATION, CheckError());
+
+ gl_->VertexAttribPointer(
+ kAttribIndex1, kNumComponents1, GL_FLOAT, GL_FALSE, kClientStride, NULL);
+ EXPECT_EQ(GL_NO_ERROR, CheckError());
+}
+#endif
+
+TEST_F(GLES2ImplementationTest, Disable) {
+ struct Cmds {
+ cmds::Disable cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_DITHER); // Note: DITHER defaults to enabled.
+
+ gl_->Disable(GL_DITHER);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ // Check it's cached and not called again.
+ ClearCommands();
+ gl_->Disable(GL_DITHER);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, Enable) {
+ struct Cmds {
+ cmds::Enable cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_BLEND); // Note: BLEND defaults to disabled.
+
+ gl_->Enable(GL_BLEND);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ // Check it's cached and not called again.
+ ClearCommands();
+ gl_->Enable(GL_BLEND);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+
+#include "gpu/command_buffer/client/gles2_implementation_unittest_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/chromium/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
new file mode 100644
index 00000000000..a1ea5873a36
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -0,0 +1,1853 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_implementation.h to declare the
+// GL api functions.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_
+
+
+TEST_F(GLES2ImplementationTest, AttachShader) {
+ struct Cmds {
+ cmds::AttachShader cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->AttachShader(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for BindAttribLocation
+
+TEST_F(GLES2ImplementationTest, BindBuffer) {
+ struct Cmds {
+ cmds::BindBuffer cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_ARRAY_BUFFER, 2);
+
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ ClearCommands();
+ gl_->BindBuffer(GL_ARRAY_BUFFER, 2);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, BindFramebuffer) {
+ struct Cmds {
+ cmds::BindFramebuffer cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRAMEBUFFER, 2);
+
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ ClearCommands();
+ gl_->BindFramebuffer(GL_FRAMEBUFFER, 2);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, BindRenderbuffer) {
+ struct Cmds {
+ cmds::BindRenderbuffer cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_RENDERBUFFER, 2);
+
+ gl_->BindRenderbuffer(GL_RENDERBUFFER, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ ClearCommands();
+ gl_->BindRenderbuffer(GL_RENDERBUFFER, 2);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, BlendColor) {
+ struct Cmds {
+ cmds::BlendColor cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->BlendColor(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, BlendEquation) {
+ struct Cmds {
+ cmds::BlendEquation cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FUNC_SUBTRACT);
+
+ gl_->BlendEquation(GL_FUNC_SUBTRACT);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, BlendEquationSeparate) {
+ struct Cmds {
+ cmds::BlendEquationSeparate cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FUNC_SUBTRACT, GL_FUNC_ADD);
+
+ gl_->BlendEquationSeparate(GL_FUNC_SUBTRACT, GL_FUNC_ADD);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, BlendFunc) {
+ struct Cmds {
+ cmds::BlendFunc cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_ZERO, GL_ZERO);
+
+ gl_->BlendFunc(GL_ZERO, GL_ZERO);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, BlendFuncSeparate) {
+ struct Cmds {
+ cmds::BlendFuncSeparate cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO);
+
+ gl_->BlendFuncSeparate(GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CheckFramebufferStatus) {
+ struct Cmds {
+ cmds::CheckFramebufferStatus cmd;
+ };
+
+ typedef cmds::CheckFramebufferStatus::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::CheckFramebufferStatus::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->CheckFramebufferStatus(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, Clear) {
+ struct Cmds {
+ cmds::Clear cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->Clear(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ClearColor) {
+ struct Cmds {
+ cmds::ClearColor cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->ClearColor(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ClearDepthf) {
+ struct Cmds {
+ cmds::ClearDepthf cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->ClearDepthf(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ClearStencil) {
+ struct Cmds {
+ cmds::ClearStencil cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->ClearStencil(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ColorMask) {
+ struct Cmds {
+ cmds::ColorMask cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(true, true, true, true);
+
+ gl_->ColorMask(true, true, true, true);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CompileShader) {
+ struct Cmds {
+ cmds::CompileShader cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->CompileShader(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for CompressedTexImage2D
+// TODO: Implement unit test for CompressedTexSubImage2D
+
+TEST_F(GLES2ImplementationTest, CopyTexImage2D) {
+ struct Cmds {
+ cmds::CopyTexImage2D cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, 2, GL_ALPHA, 4, 5, 6, 7, 0);
+
+ gl_->CopyTexImage2D(GL_TEXTURE_2D, 2, GL_ALPHA, 4, 5, 6, 7, 0);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CopyTexSubImage2D) {
+ struct Cmds {
+ cmds::CopyTexSubImage2D cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, 2, 3, 4, 5, 6, 7, 8);
+
+ gl_->CopyTexSubImage2D(GL_TEXTURE_2D, 2, 3, 4, 5, 6, 7, 8);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CullFace) {
+ struct Cmds {
+ cmds::CullFace cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRONT);
+
+ gl_->CullFace(GL_FRONT);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DeleteBuffers) {
+ GLuint ids[2] = { kBuffersStartId, kBuffersStartId + 1 };
+ struct Cmds {
+ cmds::DeleteBuffersImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kBuffersStartId;
+ expected.data[1] = kBuffersStartId + 1;
+ gl_->DeleteBuffers(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DeleteFramebuffers) {
+ GLuint ids[2] = { kFramebuffersStartId, kFramebuffersStartId + 1 };
+ struct Cmds {
+ cmds::DeleteFramebuffersImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kFramebuffersStartId;
+ expected.data[1] = kFramebuffersStartId + 1;
+ gl_->DeleteFramebuffers(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DeleteProgram) {
+ struct Cmds {
+ cmds::DeleteProgram cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->DeleteProgram(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DeleteRenderbuffers) {
+ GLuint ids[2] = { kRenderbuffersStartId, kRenderbuffersStartId + 1 };
+ struct Cmds {
+ cmds::DeleteRenderbuffersImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kRenderbuffersStartId;
+ expected.data[1] = kRenderbuffersStartId + 1;
+ gl_->DeleteRenderbuffers(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DeleteShader) {
+ struct Cmds {
+ cmds::DeleteShader cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->DeleteShader(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DeleteTextures) {
+ GLuint ids[2] = { kTexturesStartId, kTexturesStartId + 1 };
+ struct Cmds {
+ cmds::DeleteTexturesImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kTexturesStartId;
+ expected.data[1] = kTexturesStartId + 1;
+ gl_->DeleteTextures(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DepthFunc) {
+ struct Cmds {
+ cmds::DepthFunc cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_NEVER);
+
+ gl_->DepthFunc(GL_NEVER);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DepthMask) {
+ struct Cmds {
+ cmds::DepthMask cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(true);
+
+ gl_->DepthMask(true);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DepthRangef) {
+ struct Cmds {
+ cmds::DepthRangef cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->DepthRangef(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DetachShader) {
+ struct Cmds {
+ cmds::DetachShader cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->DetachShader(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DisableVertexAttribArray) {
+ struct Cmds {
+ cmds::DisableVertexAttribArray cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->DisableVertexAttribArray(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawArrays) {
+ struct Cmds {
+ cmds::DrawArrays cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_POINTS, 2, 3);
+
+ gl_->DrawArrays(GL_POINTS, 2, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, EnableVertexAttribArray) {
+ struct Cmds {
+ cmds::EnableVertexAttribArray cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->EnableVertexAttribArray(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Flush) {
+ struct Cmds {
+ cmds::Flush cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init();
+
+ gl_->Flush();
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, FramebufferRenderbuffer) {
+ struct Cmds {
+ cmds::FramebufferRenderbuffer cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 4);
+
+ gl_->FramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, FramebufferTexture2D) {
+ struct Cmds {
+ cmds::FramebufferTexture2D cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 4, 0);
+
+ gl_->FramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 4, 0);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, FrontFace) {
+ struct Cmds {
+ cmds::FrontFace cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_CW);
+
+ gl_->FrontFace(GL_CW);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, GenBuffers) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::GenBuffersImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kBuffersStartId;
+ expected.data[1] = kBuffersStartId + 1;
+ gl_->GenBuffers(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kBuffersStartId, ids[0]);
+ EXPECT_EQ(kBuffersStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, GenerateMipmap) {
+ struct Cmds {
+ cmds::GenerateMipmap cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D);
+
+ gl_->GenerateMipmap(GL_TEXTURE_2D);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, GenFramebuffers) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::GenFramebuffersImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kFramebuffersStartId;
+ expected.data[1] = kFramebuffersStartId + 1;
+ gl_->GenFramebuffers(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kFramebuffersStartId, ids[0]);
+ EXPECT_EQ(kFramebuffersStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, GenRenderbuffers) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::GenRenderbuffersImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kRenderbuffersStartId;
+ expected.data[1] = kRenderbuffersStartId + 1;
+ gl_->GenRenderbuffers(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kRenderbuffersStartId, ids[0]);
+ EXPECT_EQ(kRenderbuffersStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, GenTextures) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::GenTexturesImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kTexturesStartId;
+ expected.data[1] = kTexturesStartId + 1;
+ gl_->GenTextures(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kTexturesStartId, ids[0]);
+ EXPECT_EQ(kTexturesStartId + 1, ids[1]);
+}
+// TODO: Implement unit test for GetActiveAttrib
+// TODO: Implement unit test for GetActiveUniform
+// TODO: Implement unit test for GetAttachedShaders
+// TODO: Implement unit test for GetAttribLocation
+
+TEST_F(GLES2ImplementationTest, GetBooleanv) {
+ struct Cmds {
+ cmds::GetBooleanv cmd;
+ };
+ typedef cmds::GetBooleanv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetBooleanv(123, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetBufferParameteriv) {
+ struct Cmds {
+ cmds::GetBufferParameteriv cmd;
+ };
+ typedef cmds::GetBufferParameteriv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, GL_BUFFER_SIZE, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetBufferParameteriv(123, GL_BUFFER_SIZE, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetFloatv) {
+ struct Cmds {
+ cmds::GetFloatv cmd;
+ };
+ typedef cmds::GetFloatv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetFloatv(123, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetFramebufferAttachmentParameteriv) {
+ struct Cmds {
+ cmds::GetFramebufferAttachmentParameteriv cmd;
+ };
+ typedef cmds::GetFramebufferAttachmentParameteriv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(
+ 123, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetFramebufferAttachmentParameteriv(
+ 123, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetIntegerv) {
+ struct Cmds {
+ cmds::GetIntegerv cmd;
+ };
+ typedef cmds::GetIntegerv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetIntegerv(123, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetProgramiv) {
+ struct Cmds {
+ cmds::GetProgramiv cmd;
+ };
+ typedef cmds::GetProgramiv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, GL_DELETE_STATUS, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetProgramiv(123, GL_DELETE_STATUS, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+// TODO: Implement unit test for GetProgramInfoLog
+
+TEST_F(GLES2ImplementationTest, GetRenderbufferParameteriv) {
+ struct Cmds {
+ cmds::GetRenderbufferParameteriv cmd;
+ };
+ typedef cmds::GetRenderbufferParameteriv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, GL_RENDERBUFFER_RED_SIZE, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetRenderbufferParameteriv(123, GL_RENDERBUFFER_RED_SIZE, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetShaderiv) {
+ struct Cmds {
+ cmds::GetShaderiv cmd;
+ };
+ typedef cmds::GetShaderiv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, GL_SHADER_TYPE, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetShaderiv(123, GL_SHADER_TYPE, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+// TODO: Implement unit test for GetShaderInfoLog
+// TODO: Implement unit test for GetShaderPrecisionFormat
+
+TEST_F(GLES2ImplementationTest, GetTexParameterfv) {
+ struct Cmds {
+ cmds::GetTexParameterfv cmd;
+ };
+ typedef cmds::GetTexParameterfv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetTexParameterfv(123, GL_TEXTURE_MAG_FILTER, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetTexParameteriv) {
+ struct Cmds {
+ cmds::GetTexParameteriv cmd;
+ };
+ typedef cmds::GetTexParameteriv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(123, GL_TEXTURE_MAG_FILTER, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetTexParameteriv(123, GL_TEXTURE_MAG_FILTER, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+// TODO: Implement unit test for GetUniformfv
+// TODO: Implement unit test for GetUniformiv
+// TODO: Implement unit test for GetUniformLocation
+
+TEST_F(GLES2ImplementationTest, GetVertexAttribfv) {
+ struct Cmds {
+ cmds::GetVertexAttribfv cmd;
+ };
+ typedef cmds::GetVertexAttribfv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(
+ 123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetVertexAttribfv(123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, GetVertexAttribiv) {
+ struct Cmds {
+ cmds::GetVertexAttribiv cmd;
+ };
+ typedef cmds::GetVertexAttribiv::Result Result;
+ Result::Type result = 0;
+ Cmds expected;
+ ExpectedMemoryInfo result1 = GetExpectedResultMemory(4);
+ expected.cmd.Init(
+ 123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, result1.id, result1.offset);
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, SizedResultHelper<Result::Type>(1)))
+ .RetiresOnSaturation();
+ gl_->GetVertexAttribiv(123, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &result);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<Result::Type>(1), result);
+}
+
+TEST_F(GLES2ImplementationTest, Hint) {
+ struct Cmds {
+ cmds::Hint cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);
+
+ gl_->Hint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, IsBuffer) {
+ struct Cmds {
+ cmds::IsBuffer cmd;
+ };
+
+ typedef cmds::IsBuffer::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsBuffer::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsBuffer(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, IsEnabled) {
+ struct Cmds {
+ cmds::IsEnabled cmd;
+ };
+
+ typedef cmds::IsEnabled::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsEnabled::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsEnabled(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, IsFramebuffer) {
+ struct Cmds {
+ cmds::IsFramebuffer cmd;
+ };
+
+ typedef cmds::IsFramebuffer::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsFramebuffer::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsFramebuffer(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, IsProgram) {
+ struct Cmds {
+ cmds::IsProgram cmd;
+ };
+
+ typedef cmds::IsProgram::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsProgram::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsProgram(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, IsRenderbuffer) {
+ struct Cmds {
+ cmds::IsRenderbuffer cmd;
+ };
+
+ typedef cmds::IsRenderbuffer::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsRenderbuffer::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsRenderbuffer(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, IsShader) {
+ struct Cmds {
+ cmds::IsShader cmd;
+ };
+
+ typedef cmds::IsShader::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsShader::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsShader(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, IsTexture) {
+ struct Cmds {
+ cmds::IsTexture cmd;
+ };
+
+ typedef cmds::IsTexture::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsTexture::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsTexture(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, LineWidth) {
+ struct Cmds {
+ cmds::LineWidth cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->LineWidth(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, LinkProgram) {
+ struct Cmds {
+ cmds::LinkProgram cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->LinkProgram(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, PixelStorei) {
+ struct Cmds {
+ cmds::PixelStorei cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_PACK_ALIGNMENT, 1);
+
+ gl_->PixelStorei(GL_PACK_ALIGNMENT, 1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, PolygonOffset) {
+ struct Cmds {
+ cmds::PolygonOffset cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->PolygonOffset(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ReleaseShaderCompiler) {
+ struct Cmds {
+ cmds::ReleaseShaderCompiler cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init();
+
+ gl_->ReleaseShaderCompiler();
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, RenderbufferStorage) {
+ struct Cmds {
+ cmds::RenderbufferStorage cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 3, 4);
+
+ gl_->RenderbufferStorage(GL_RENDERBUFFER, GL_RGBA4, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, SampleCoverage) {
+ struct Cmds {
+ cmds::SampleCoverage cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, true);
+
+ gl_->SampleCoverage(1, true);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Scissor) {
+ struct Cmds {
+ cmds::Scissor cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->Scissor(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, StencilFunc) {
+ struct Cmds {
+ cmds::StencilFunc cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_NEVER, 2, 3);
+
+ gl_->StencilFunc(GL_NEVER, 2, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, StencilFuncSeparate) {
+ struct Cmds {
+ cmds::StencilFuncSeparate cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRONT, GL_NEVER, 3, 4);
+
+ gl_->StencilFuncSeparate(GL_FRONT, GL_NEVER, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, StencilMask) {
+ struct Cmds {
+ cmds::StencilMask cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->StencilMask(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, StencilMaskSeparate) {
+ struct Cmds {
+ cmds::StencilMaskSeparate cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRONT, 2);
+
+ gl_->StencilMaskSeparate(GL_FRONT, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, StencilOp) {
+ struct Cmds {
+ cmds::StencilOp cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_KEEP, GL_INCR, GL_KEEP);
+
+ gl_->StencilOp(GL_KEEP, GL_INCR, GL_KEEP);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, StencilOpSeparate) {
+ struct Cmds {
+ cmds::StencilOpSeparate cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_FRONT, GL_INCR, GL_KEEP, GL_KEEP);
+
+ gl_->StencilOpSeparate(GL_FRONT, GL_INCR, GL_KEEP, GL_KEEP);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, TexParameterf) {
+ struct Cmds {
+ cmds::TexParameterf cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 3);
+
+ gl_->TexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, TexParameterfv) {
+ GLfloat data[1] = {0};
+ struct Cmds {
+ cmds::TexParameterfvImmediate cmd;
+ GLfloat data[1];
+ };
+
+ for (int jj = 0; jj < 1; ++jj) {
+ data[jj] = static_cast<GLfloat>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &data[0]);
+ gl_->TexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, TexParameteri) {
+ struct Cmds {
+ cmds::TexParameteri cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 3);
+
+ gl_->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, TexParameteriv) {
+ GLint data[1] = {0};
+ struct Cmds {
+ cmds::TexParameterivImmediate cmd;
+ GLint data[1];
+ };
+
+ for (int jj = 0; jj < 1; ++jj) {
+ data[jj] = static_cast<GLint>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &data[0]);
+ gl_->TexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform1f) {
+ struct Cmds {
+ cmds::Uniform1f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->Uniform1f(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform1fv) {
+ GLfloat data[2][1] = {{0}};
+ struct Cmds {
+ cmds::Uniform1fvImmediate cmd;
+ GLfloat data[2][1];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 1; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 1 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform1fv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform1i) {
+ struct Cmds {
+ cmds::Uniform1i cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->Uniform1i(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform1iv) {
+ GLint data[2][1] = {{0}};
+ struct Cmds {
+ cmds::Uniform1ivImmediate cmd;
+ GLint data[2][1];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 1; ++jj) {
+ data[ii][jj] = static_cast<GLint>(ii * 1 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform1iv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform2f) {
+ struct Cmds {
+ cmds::Uniform2f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3);
+
+ gl_->Uniform2f(1, 2, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform2fv) {
+ GLfloat data[2][2] = {{0}};
+ struct Cmds {
+ cmds::Uniform2fvImmediate cmd;
+ GLfloat data[2][2];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 2; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 2 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform2fv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform2i) {
+ struct Cmds {
+ cmds::Uniform2i cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3);
+
+ gl_->Uniform2i(1, 2, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform2iv) {
+ GLint data[2][2] = {{0}};
+ struct Cmds {
+ cmds::Uniform2ivImmediate cmd;
+ GLint data[2][2];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 2; ++jj) {
+ data[ii][jj] = static_cast<GLint>(ii * 2 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform2iv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform3f) {
+ struct Cmds {
+ cmds::Uniform3f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->Uniform3f(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform3fv) {
+ GLfloat data[2][3] = {{0}};
+ struct Cmds {
+ cmds::Uniform3fvImmediate cmd;
+ GLfloat data[2][3];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 3; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 3 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform3fv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform3i) {
+ struct Cmds {
+ cmds::Uniform3i cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->Uniform3i(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform3iv) {
+ GLint data[2][3] = {{0}};
+ struct Cmds {
+ cmds::Uniform3ivImmediate cmd;
+ GLint data[2][3];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 3; ++jj) {
+ data[ii][jj] = static_cast<GLint>(ii * 3 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform3iv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform4f) {
+ struct Cmds {
+ cmds::Uniform4f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4, 5);
+
+ gl_->Uniform4f(1, 2, 3, 4, 5);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform4fv) {
+ GLfloat data[2][4] = {{0}};
+ struct Cmds {
+ cmds::Uniform4fvImmediate cmd;
+ GLfloat data[2][4];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 4; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 4 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform4fv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform4i) {
+ struct Cmds {
+ cmds::Uniform4i cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4, 5);
+
+ gl_->Uniform4i(1, 2, 3, 4, 5);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Uniform4iv) {
+ GLint data[2][4] = {{0}};
+ struct Cmds {
+ cmds::Uniform4ivImmediate cmd;
+ GLint data[2][4];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 4; ++jj) {
+ data[ii][jj] = static_cast<GLint>(ii * 4 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->Uniform4iv(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UniformMatrix2fv) {
+ GLfloat data[2][4] = {{0}};
+ struct Cmds {
+ cmds::UniformMatrix2fvImmediate cmd;
+ GLfloat data[2][4];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 4; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 4 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, false, &data[0][0]);
+ gl_->UniformMatrix2fv(1, 2, false, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UniformMatrix3fv) {
+ GLfloat data[2][9] = {{0}};
+ struct Cmds {
+ cmds::UniformMatrix3fvImmediate cmd;
+ GLfloat data[2][9];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 9; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 9 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, false, &data[0][0]);
+ gl_->UniformMatrix3fv(1, 2, false, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UniformMatrix4fv) {
+ GLfloat data[2][16] = {{0}};
+ struct Cmds {
+ cmds::UniformMatrix4fvImmediate cmd;
+ GLfloat data[2][16];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 16; ++jj) {
+ data[ii][jj] = static_cast<GLfloat>(ii * 16 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, false, &data[0][0]);
+ gl_->UniformMatrix4fv(1, 2, false, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UseProgram) {
+ struct Cmds {
+ cmds::UseProgram cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->UseProgram(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ValidateProgram) {
+ struct Cmds {
+ cmds::ValidateProgram cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->ValidateProgram(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib1f) {
+ struct Cmds {
+ cmds::VertexAttrib1f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->VertexAttrib1f(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib1fv) {
+ GLfloat data[1] = {0};
+ struct Cmds {
+ cmds::VertexAttrib1fvImmediate cmd;
+ GLfloat data[1];
+ };
+
+ for (int jj = 0; jj < 1; ++jj) {
+ data[jj] = static_cast<GLfloat>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(1, &data[0]);
+ gl_->VertexAttrib1fv(1, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib2f) {
+ struct Cmds {
+ cmds::VertexAttrib2f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3);
+
+ gl_->VertexAttrib2f(1, 2, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib2fv) {
+ GLfloat data[2] = {0};
+ struct Cmds {
+ cmds::VertexAttrib2fvImmediate cmd;
+ GLfloat data[2];
+ };
+
+ for (int jj = 0; jj < 2; ++jj) {
+ data[jj] = static_cast<GLfloat>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(1, &data[0]);
+ gl_->VertexAttrib2fv(1, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib3f) {
+ struct Cmds {
+ cmds::VertexAttrib3f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->VertexAttrib3f(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib3fv) {
+ GLfloat data[3] = {0};
+ struct Cmds {
+ cmds::VertexAttrib3fvImmediate cmd;
+ GLfloat data[3];
+ };
+
+ for (int jj = 0; jj < 3; ++jj) {
+ data[jj] = static_cast<GLfloat>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(1, &data[0]);
+ gl_->VertexAttrib3fv(1, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib4f) {
+ struct Cmds {
+ cmds::VertexAttrib4f cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4, 5);
+
+ gl_->VertexAttrib4f(1, 2, 3, 4, 5);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttrib4fv) {
+ GLfloat data[4] = {0};
+ struct Cmds {
+ cmds::VertexAttrib4fvImmediate cmd;
+ GLfloat data[4];
+ };
+
+ for (int jj = 0; jj < 4; ++jj) {
+ data[jj] = static_cast<GLfloat>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(1, &data[0]);
+ gl_->VertexAttrib4fv(1, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, Viewport) {
+ struct Cmds {
+ cmds::Viewport cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4);
+
+ gl_->Viewport(1, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, BlitFramebufferEXT) {
+ struct Cmds {
+ cmds::BlitFramebufferEXT cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4, 5, 6, 7, 8, 9, GL_NEAREST);
+
+ gl_->BlitFramebufferEXT(1, 2, 3, 4, 5, 6, 7, 8, 9, GL_NEAREST);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, RenderbufferStorageMultisampleEXT) {
+ struct Cmds {
+ cmds::RenderbufferStorageMultisampleEXT cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_RENDERBUFFER, 2, GL_RGBA4, 4, 5);
+
+ gl_->RenderbufferStorageMultisampleEXT(GL_RENDERBUFFER, 2, GL_RGBA4, 4, 5);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, FramebufferTexture2DMultisampleEXT) {
+ struct Cmds {
+ cmds::FramebufferTexture2DMultisampleEXT cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 4, 0, 6);
+
+ gl_->FramebufferTexture2DMultisampleEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 4, 0, 6);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, TexStorage2DEXT) {
+ struct Cmds {
+ cmds::TexStorage2DEXT cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, 2, GL_RGB565, 4, 5);
+
+ gl_->TexStorage2DEXT(GL_TEXTURE_2D, 2, GL_RGB565, 4, 5);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, GenQueriesEXT) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::GenQueriesEXTImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kQueriesStartId;
+ expected.data[1] = kQueriesStartId + 1;
+ gl_->GenQueriesEXT(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kQueriesStartId, ids[0]);
+ EXPECT_EQ(kQueriesStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, DeleteQueriesEXT) {
+ GLuint ids[2] = { kQueriesStartId, kQueriesStartId + 1 };
+ struct Cmds {
+ cmds::DeleteQueriesEXTImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kQueriesStartId;
+ expected.data[1] = kQueriesStartId + 1;
+ gl_->DeleteQueriesEXT(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for BeginQueryEXT
+// TODO: Implement unit test for InsertEventMarkerEXT
+// TODO: Implement unit test for PushGroupMarkerEXT
+
+TEST_F(GLES2ImplementationTest, PopGroupMarkerEXT) {
+ struct Cmds {
+ cmds::PopGroupMarkerEXT cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init();
+
+ gl_->PopGroupMarkerEXT();
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, GenVertexArraysOES) {
+ GLuint ids[2] = { 0, };
+ struct Cmds {
+ cmds::GenVertexArraysOESImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kVertexArraysStartId;
+ expected.data[1] = kVertexArraysStartId + 1;
+ gl_->GenVertexArraysOES(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kVertexArraysStartId, ids[0]);
+ EXPECT_EQ(kVertexArraysStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, DeleteVertexArraysOES) {
+ GLuint ids[2] = { kVertexArraysStartId, kVertexArraysStartId + 1 };
+ struct Cmds {
+ cmds::DeleteVertexArraysOESImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kVertexArraysStartId;
+ expected.data[1] = kVertexArraysStartId + 1;
+ gl_->DeleteVertexArraysOES(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, IsVertexArrayOES) {
+ struct Cmds {
+ cmds::IsVertexArrayOES cmd;
+ };
+
+ typedef cmds::IsVertexArrayOES::Result Result;
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsVertexArrayOES::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsVertexArrayOES(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+// TODO: Implement unit test for GenSharedIdsCHROMIUM
+// TODO: Implement unit test for DeleteSharedIdsCHROMIUM
+// TODO: Implement unit test for RegisterSharedIdsCHROMIUM
+// TODO: Implement unit test for EnableFeatureCHROMIUM
+
+TEST_F(GLES2ImplementationTest, ResizeCHROMIUM) {
+ struct Cmds {
+ cmds::ResizeCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3);
+
+ gl_->ResizeCHROMIUM(1, 2, 3);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for GetRequestableExtensionsCHROMIUM
+
+TEST_F(GLES2ImplementationTest, DestroyStreamTextureCHROMIUM) {
+ struct Cmds {
+ cmds::DestroyStreamTextureCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->DestroyStreamTextureCHROMIUM(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for GetTranslatedShaderSourceANGLE
+
+TEST_F(GLES2ImplementationTest, TexImageIOSurface2DCHROMIUM) {
+ struct Cmds {
+ cmds::TexImageIOSurface2DCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, 2, 3, 4, 5);
+
+ gl_->TexImageIOSurface2DCHROMIUM(GL_TEXTURE_2D, 2, 3, 4, 5);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, CopyTextureCHROMIUM) {
+ struct Cmds {
+ cmds::CopyTextureCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2, 3, 4, GL_ALPHA, GL_UNSIGNED_BYTE);
+
+ gl_->CopyTextureCHROMIUM(1, 2, 3, 4, GL_ALPHA, GL_UNSIGNED_BYTE);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawArraysInstancedANGLE) {
+ struct Cmds {
+ cmds::DrawArraysInstancedANGLE cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_POINTS, 2, 3, 4);
+
+ gl_->DrawArraysInstancedANGLE(GL_POINTS, 2, 3, 4);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, VertexAttribDivisorANGLE) {
+ struct Cmds {
+ cmds::VertexAttribDivisorANGLE cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->VertexAttribDivisorANGLE(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ProduceTextureCHROMIUM) {
+ GLbyte data[64] = {0};
+ struct Cmds {
+ cmds::ProduceTextureCHROMIUMImmediate cmd;
+ GLbyte data[64];
+ };
+
+ for (int jj = 0; jj < 64; ++jj) {
+ data[jj] = static_cast<GLbyte>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, &data[0]);
+ gl_->ProduceTextureCHROMIUM(GL_TEXTURE_2D, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ConsumeTextureCHROMIUM) {
+ GLbyte data[64] = {0};
+ struct Cmds {
+ cmds::ConsumeTextureCHROMIUMImmediate cmd;
+ GLbyte data[64];
+ };
+
+ for (int jj = 0; jj < 64; ++jj) {
+ data[jj] = static_cast<GLbyte>(jj);
+ }
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, &data[0]);
+ gl_->ConsumeTextureCHROMIUM(GL_TEXTURE_2D, &data[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for BindUniformLocationCHROMIUM
+
+TEST_F(GLES2ImplementationTest, BindTexImage2DCHROMIUM) {
+ struct Cmds {
+ cmds::BindTexImage2DCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, 2);
+
+ gl_->BindTexImage2DCHROMIUM(GL_TEXTURE_2D, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, ReleaseTexImage2DCHROMIUM) {
+ struct Cmds {
+ cmds::ReleaseTexImage2DCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_TEXTURE_2D, 2);
+
+ gl_->ReleaseTexImage2DCHROMIUM(GL_TEXTURE_2D, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DiscardFramebufferEXT) {
+ GLenum data[2][1] = {{0}};
+ struct Cmds {
+ cmds::DiscardFramebufferEXTImmediate cmd;
+ GLenum data[2][1];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 2; ++ii) {
+ for (int jj = 0; jj < 1; ++jj) {
+ data[ii][jj] = static_cast<GLenum>(ii * 1 + jj);
+ }
+ }
+ expected.cmd.Init(1, 2, &data[0][0]);
+ gl_->DiscardFramebufferEXT(1, 2, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, LoseContextCHROMIUM) {
+ struct Cmds {
+ cmds::LoseContextCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, 2);
+
+ gl_->LoseContextCHROMIUM(1, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+// TODO: Implement unit test for InsertSyncPointCHROMIUM
+
+TEST_F(GLES2ImplementationTest, WaitSyncPointCHROMIUM) {
+ struct Cmds {
+ cmds::WaitSyncPointCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1);
+
+ gl_->WaitSyncPointCHROMIUM(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, DrawBuffersEXT) {
+ GLenum data[1][1] = {{0}};
+ struct Cmds {
+ cmds::DrawBuffersEXTImmediate cmd;
+ GLenum data[1][1];
+ };
+
+ Cmds expected;
+ for (int ii = 0; ii < 1; ++ii) {
+ for (int jj = 0; jj < 1; ++jj) {
+ data[ii][jj] = static_cast<GLenum>(ii * 1 + jj);
+ }
+ }
+ expected.cmd.Init(1, &data[0][0]);
+ gl_->DrawBuffersEXT(1, &data[0][0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_UNITTEST_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_interface.cc b/chromium/gpu/command_buffer/client/gles2_interface.cc
new file mode 100644
index 00000000000..a94f167eb34
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface.cc
@@ -0,0 +1,19 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace gpu {
+namespace gles2 {
+
+GLES2Interface::GLES2Interface() {
+}
+
+GLES2Interface::~GLES2Interface() {
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/gles2_interface.h b/chromium/gpu/command_buffer/client/gles2_interface.h
new file mode 100644
index 00000000000..d1659bf73f7
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_H_
+
+#include <GLES2/gl2.h>
+#include "gles2_impl_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+// This class is the interface for all client side GL functions.
+class GLES2_IMPL_EXPORT GLES2Interface {
+ public:
+ GLES2Interface();
+ virtual ~GLES2Interface();
+
+ // Include the auto-generated part of this class. We split this because
+ // it means we can easily edit the non-auto generated parts right here in
+ // this file instead of having to edit some template or the code generator.
+ #include "gpu/command_buffer/client/gles2_interface_autogen.h"
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_interface_autogen.h b/chromium/gpu/command_buffer/client/gles2_interface_autogen.h
new file mode 100644
index 00000000000..24ce83bc2f5
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -0,0 +1,323 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_interface.h to declare the
+// GL api functions.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
+
+virtual void ActiveTexture(GLenum texture) = 0;
+virtual void AttachShader(GLuint program, GLuint shader) = 0;
+virtual void BindAttribLocation(
+ GLuint program, GLuint index, const char* name) = 0;
+virtual void BindBuffer(GLenum target, GLuint buffer) = 0;
+virtual void BindFramebuffer(GLenum target, GLuint framebuffer) = 0;
+virtual void BindRenderbuffer(GLenum target, GLuint renderbuffer) = 0;
+virtual void BindTexture(GLenum target, GLuint texture) = 0;
+virtual void BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) = 0;
+virtual void BlendEquation(GLenum mode) = 0;
+virtual void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) = 0;
+virtual void BlendFunc(GLenum sfactor, GLenum dfactor) = 0;
+virtual void BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) = 0;
+virtual void BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) = 0;
+virtual void BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data) = 0;
+virtual GLenum CheckFramebufferStatus(GLenum target) = 0;
+virtual void Clear(GLbitfield mask) = 0;
+virtual void ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) = 0;
+virtual void ClearDepthf(GLclampf depth) = 0;
+virtual void ClearStencil(GLint s) = 0;
+virtual void ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) = 0;
+virtual void CompileShader(GLuint shader) = 0;
+virtual void CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize, const void* data) = 0;
+virtual void CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize, const void* data) = 0;
+virtual void CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) = 0;
+virtual void CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) = 0;
+virtual GLuint CreateProgram() = 0;
+virtual GLuint CreateShader(GLenum type) = 0;
+virtual void CullFace(GLenum mode) = 0;
+virtual void DeleteBuffers(GLsizei n, const GLuint* buffers) = 0;
+virtual void DeleteFramebuffers(GLsizei n, const GLuint* framebuffers) = 0;
+virtual void DeleteProgram(GLuint program) = 0;
+virtual void DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) = 0;
+virtual void DeleteShader(GLuint shader) = 0;
+virtual void DeleteTextures(GLsizei n, const GLuint* textures) = 0;
+virtual void DepthFunc(GLenum func) = 0;
+virtual void DepthMask(GLboolean flag) = 0;
+virtual void DepthRangef(GLclampf zNear, GLclampf zFar) = 0;
+virtual void DetachShader(GLuint program, GLuint shader) = 0;
+virtual void Disable(GLenum cap) = 0;
+virtual void DisableVertexAttribArray(GLuint index) = 0;
+virtual void DrawArrays(GLenum mode, GLint first, GLsizei count) = 0;
+virtual void DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) = 0;
+virtual void Enable(GLenum cap) = 0;
+virtual void EnableVertexAttribArray(GLuint index) = 0;
+virtual void Finish() = 0;
+virtual void Flush() = 0;
+virtual void FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) = 0;
+virtual void FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) = 0;
+virtual void FrontFace(GLenum mode) = 0;
+virtual void GenBuffers(GLsizei n, GLuint* buffers) = 0;
+virtual void GenerateMipmap(GLenum target) = 0;
+virtual void GenFramebuffers(GLsizei n, GLuint* framebuffers) = 0;
+virtual void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) = 0;
+virtual void GenTextures(GLsizei n, GLuint* textures) = 0;
+virtual void GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) = 0;
+virtual void GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) = 0;
+virtual void GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) = 0;
+virtual GLint GetAttribLocation(GLuint program, const char* name) = 0;
+virtual void GetBooleanv(GLenum pname, GLboolean* params) = 0;
+virtual void GetBufferParameteriv(GLenum target, GLenum pname, GLint* params) =
+ 0;
+virtual GLenum GetError() = 0;
+virtual void GetFloatv(GLenum pname, GLfloat* params) = 0;
+virtual void GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) = 0;
+virtual void GetIntegerv(GLenum pname, GLint* params) = 0;
+virtual void GetProgramiv(GLuint program, GLenum pname, GLint* params) = 0;
+virtual void GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) = 0;
+virtual void GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) = 0;
+virtual void GetShaderiv(GLuint shader, GLenum pname, GLint* params) = 0;
+virtual void GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) = 0;
+virtual void GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) =
+ 0;
+virtual void GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) = 0;
+virtual const GLubyte* GetString(GLenum name) = 0;
+virtual void GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) =
+ 0;
+virtual void GetTexParameteriv(GLenum target, GLenum pname, GLint* params) = 0;
+virtual void GetUniformfv(GLuint program, GLint location, GLfloat* params) = 0;
+virtual void GetUniformiv(GLuint program, GLint location, GLint* params) = 0;
+virtual GLint GetUniformLocation(GLuint program, const char* name) = 0;
+virtual void GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) =
+ 0;
+virtual void GetVertexAttribiv(GLuint index, GLenum pname, GLint* params) = 0;
+virtual void GetVertexAttribPointerv(
+ GLuint index, GLenum pname, void** pointer) = 0;
+virtual void Hint(GLenum target, GLenum mode) = 0;
+virtual GLboolean IsBuffer(GLuint buffer) = 0;
+virtual GLboolean IsEnabled(GLenum cap) = 0;
+virtual GLboolean IsFramebuffer(GLuint framebuffer) = 0;
+virtual GLboolean IsProgram(GLuint program) = 0;
+virtual GLboolean IsRenderbuffer(GLuint renderbuffer) = 0;
+virtual GLboolean IsShader(GLuint shader) = 0;
+virtual GLboolean IsTexture(GLuint texture) = 0;
+virtual void LineWidth(GLfloat width) = 0;
+virtual void LinkProgram(GLuint program) = 0;
+virtual void PixelStorei(GLenum pname, GLint param) = 0;
+virtual void PolygonOffset(GLfloat factor, GLfloat units) = 0;
+virtual void ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ void* pixels) = 0;
+virtual void ReleaseShaderCompiler() = 0;
+virtual void RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height) = 0;
+virtual void SampleCoverage(GLclampf value, GLboolean invert) = 0;
+virtual void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) = 0;
+virtual void ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) = 0;
+virtual void ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* str,
+ const GLint* length) = 0;
+virtual void ShallowFinishCHROMIUM() = 0;
+virtual void ShallowFlushCHROMIUM() = 0;
+virtual void StencilFunc(GLenum func, GLint ref, GLuint mask) = 0;
+virtual void StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) = 0;
+virtual void StencilMask(GLuint mask) = 0;
+virtual void StencilMaskSeparate(GLenum face, GLuint mask) = 0;
+virtual void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) = 0;
+virtual void StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) = 0;
+virtual void TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) = 0;
+virtual void TexParameterf(GLenum target, GLenum pname, GLfloat param) = 0;
+virtual void TexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) = 0;
+virtual void TexParameteri(GLenum target, GLenum pname, GLint param) = 0;
+virtual void TexParameteriv(GLenum target, GLenum pname, const GLint* params) =
+ 0;
+virtual void TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) = 0;
+virtual void Uniform1f(GLint location, GLfloat x) = 0;
+virtual void Uniform1fv(GLint location, GLsizei count, const GLfloat* v) = 0;
+virtual void Uniform1i(GLint location, GLint x) = 0;
+virtual void Uniform1iv(GLint location, GLsizei count, const GLint* v) = 0;
+virtual void Uniform2f(GLint location, GLfloat x, GLfloat y) = 0;
+virtual void Uniform2fv(GLint location, GLsizei count, const GLfloat* v) = 0;
+virtual void Uniform2i(GLint location, GLint x, GLint y) = 0;
+virtual void Uniform2iv(GLint location, GLsizei count, const GLint* v) = 0;
+virtual void Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) = 0;
+virtual void Uniform3fv(GLint location, GLsizei count, const GLfloat* v) = 0;
+virtual void Uniform3i(GLint location, GLint x, GLint y, GLint z) = 0;
+virtual void Uniform3iv(GLint location, GLsizei count, const GLint* v) = 0;
+virtual void Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) = 0;
+virtual void Uniform4fv(GLint location, GLsizei count, const GLfloat* v) = 0;
+virtual void Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) = 0;
+virtual void Uniform4iv(GLint location, GLsizei count, const GLint* v) = 0;
+virtual void UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) =
+ 0;
+virtual void UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) =
+ 0;
+virtual void UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) =
+ 0;
+virtual void UseProgram(GLuint program) = 0;
+virtual void ValidateProgram(GLuint program) = 0;
+virtual void VertexAttrib1f(GLuint indx, GLfloat x) = 0;
+virtual void VertexAttrib1fv(GLuint indx, const GLfloat* values) = 0;
+virtual void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) = 0;
+virtual void VertexAttrib2fv(GLuint indx, const GLfloat* values) = 0;
+virtual void VertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z) = 0;
+virtual void VertexAttrib3fv(GLuint indx, const GLfloat* values) = 0;
+virtual void VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) = 0;
+virtual void VertexAttrib4fv(GLuint indx, const GLfloat* values) = 0;
+virtual void VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) = 0;
+virtual void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) = 0;
+virtual void BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) = 0;
+virtual void RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) = 0;
+virtual void FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) = 0;
+virtual void TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) = 0;
+virtual void GenQueriesEXT(GLsizei n, GLuint* queries) = 0;
+virtual void DeleteQueriesEXT(GLsizei n, const GLuint* queries) = 0;
+virtual GLboolean IsQueryEXT(GLuint id) = 0;
+virtual void BeginQueryEXT(GLenum target, GLuint id) = 0;
+virtual void EndQueryEXT(GLenum target) = 0;
+virtual void GetQueryivEXT(GLenum target, GLenum pname, GLint* params) = 0;
+virtual void GetQueryObjectuivEXT(GLuint id, GLenum pname, GLuint* params) = 0;
+virtual void InsertEventMarkerEXT(GLsizei length, const GLchar* marker) = 0;
+virtual void PushGroupMarkerEXT(GLsizei length, const GLchar* marker) = 0;
+virtual void PopGroupMarkerEXT() = 0;
+virtual void GenVertexArraysOES(GLsizei n, GLuint* arrays) = 0;
+virtual void DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) = 0;
+virtual GLboolean IsVertexArrayOES(GLuint array) = 0;
+virtual void BindVertexArrayOES(GLuint array) = 0;
+virtual void SwapBuffers() = 0;
+virtual GLuint GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) = 0;
+virtual void GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) = 0;
+virtual void DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) = 0;
+virtual void RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) = 0;
+virtual GLboolean EnableFeatureCHROMIUM(const char* feature) = 0;
+virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) = 0;
+virtual GLboolean UnmapBufferCHROMIUM(GLuint target) = 0;
+virtual void* MapImageCHROMIUM(GLuint image_id, GLenum access) = 0;
+virtual void UnmapImageCHROMIUM(GLuint image_id) = 0;
+virtual void* MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) = 0;
+virtual void UnmapBufferSubDataCHROMIUM(const void* mem) = 0;
+virtual void* MapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access) = 0;
+virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) = 0;
+virtual void ResizeCHROMIUM(GLuint width, GLuint height, GLfloat scale_factor) =
+ 0;
+virtual const GLchar* GetRequestableExtensionsCHROMIUM() = 0;
+virtual void RequestExtensionCHROMIUM(const char* extension) = 0;
+virtual void RateLimitOffscreenContextCHROMIUM() = 0;
+virtual void GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) = 0;
+virtual void GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) = 0;
+virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) = 0;
+virtual void DestroyStreamTextureCHROMIUM(GLuint texture) = 0;
+virtual GLuint CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) = 0;
+virtual void DestroyImageCHROMIUM(GLuint image_id) = 0;
+virtual void GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) = 0;
+virtual void GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) = 0;
+virtual void PostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height) = 0;
+virtual void TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) = 0;
+virtual void CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) = 0;
+virtual void DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) = 0;
+virtual void DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) = 0;
+virtual void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) = 0;
+virtual void GenMailboxCHROMIUM(GLbyte* mailbox) = 0;
+virtual void ProduceTextureCHROMIUM(GLenum target, const GLbyte* mailbox) = 0;
+virtual void ConsumeTextureCHROMIUM(GLenum target, const GLbyte* mailbox) = 0;
+virtual void BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) = 0;
+virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
+virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
+virtual void TraceBeginCHROMIUM(const char* name) = 0;
+virtual void TraceEndCHROMIUM() = 0;
+virtual void AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* data) = 0;
+virtual void AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) = 0;
+virtual void WaitAsyncTexImage2DCHROMIUM(GLenum target) = 0;
+virtual void DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) = 0;
+virtual void LoseContextCHROMIUM(GLenum current, GLenum other) = 0;
+virtual GLuint InsertSyncPointCHROMIUM() = 0;
+virtual void WaitSyncPointCHROMIUM(GLuint sync_point) = 0;
+virtual void DrawBuffersEXT(GLsizei count, const GLenum* bufs) = 0;
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_interface_stub.cc b/chromium/gpu/command_buffer/client/gles2_interface_stub.cc
new file mode 100644
index 00000000000..3f4d7baf044
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface_stub.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gles2_interface_stub.h"
+
+namespace gpu {
+namespace gles2 {
+
+GLES2InterfaceStub::GLES2InterfaceStub() {
+}
+
+GLES2InterfaceStub::~GLES2InterfaceStub() {
+}
+
+// Include the auto-generated part of this class. We split this because
+// it means we can easily edit the non-auto generated parts right here in
+// this file instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/gles2_interface_stub.h b/chromium/gpu/command_buffer/client/gles2_interface_stub.h
new file mode 100644
index 00000000000..342fc9bad0b
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface_stub.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_H_
+
+#include "gpu/command_buffer/common/compiler_specific.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace gpu {
+namespace gles2 {
+
+// This class a stub to help with mocks for the GLES2Interface class.
+class GLES2InterfaceStub : public GLES2Interface {
+ public:
+ GLES2InterfaceStub();
+ virtual ~GLES2InterfaceStub();
+
+ // Include the auto-generated part of this class. We split this because
+ // it means we can easily edit the non-auto generated parts right here in
+ // this file instead of having to edit some template or the code generator.
+ #include "gpu/command_buffer/client/gles2_interface_stub_autogen.h"
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/chromium/gpu/command_buffer/client/gles2_interface_stub_autogen.h
new file mode 100644
index 00000000000..7650cd667ac
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_interface_stub.h.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
+
+virtual void ActiveTexture(GLenum texture) OVERRIDE;
+virtual void AttachShader(GLuint program, GLuint shader) OVERRIDE;
+virtual void BindAttribLocation(
+ GLuint program, GLuint index, const char* name) OVERRIDE;
+virtual void BindBuffer(GLenum target, GLuint buffer) OVERRIDE;
+virtual void BindFramebuffer(GLenum target, GLuint framebuffer) OVERRIDE;
+virtual void BindRenderbuffer(GLenum target, GLuint renderbuffer) OVERRIDE;
+virtual void BindTexture(GLenum target, GLuint texture) OVERRIDE;
+virtual void BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) OVERRIDE;
+virtual void BlendEquation(GLenum mode) OVERRIDE;
+virtual void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) OVERRIDE;
+virtual void BlendFunc(GLenum sfactor, GLenum dfactor) OVERRIDE;
+virtual void BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) OVERRIDE;
+virtual void BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) OVERRIDE;
+virtual void BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size,
+ const void* data) OVERRIDE;
+virtual GLenum CheckFramebufferStatus(GLenum target) OVERRIDE;
+virtual void Clear(GLbitfield mask) OVERRIDE;
+virtual void ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) OVERRIDE;
+virtual void ClearDepthf(GLclampf depth) OVERRIDE;
+virtual void ClearStencil(GLint s) OVERRIDE;
+virtual void ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) OVERRIDE;
+virtual void CompileShader(GLuint shader) OVERRIDE;
+virtual void CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize,
+ const void* data) OVERRIDE;
+virtual void CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize,
+ const void* data) OVERRIDE;
+virtual void CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) OVERRIDE;
+virtual void CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) OVERRIDE;
+virtual GLuint CreateProgram() OVERRIDE;
+virtual GLuint CreateShader(GLenum type) OVERRIDE;
+virtual void CullFace(GLenum mode) OVERRIDE;
+virtual void DeleteBuffers(GLsizei n, const GLuint* buffers) OVERRIDE;
+virtual void DeleteFramebuffers(
+ GLsizei n, const GLuint* framebuffers) OVERRIDE;
+virtual void DeleteProgram(GLuint program) OVERRIDE;
+virtual void DeleteRenderbuffers(
+ GLsizei n, const GLuint* renderbuffers) OVERRIDE;
+virtual void DeleteShader(GLuint shader) OVERRIDE;
+virtual void DeleteTextures(GLsizei n, const GLuint* textures) OVERRIDE;
+virtual void DepthFunc(GLenum func) OVERRIDE;
+virtual void DepthMask(GLboolean flag) OVERRIDE;
+virtual void DepthRangef(GLclampf zNear, GLclampf zFar) OVERRIDE;
+virtual void DetachShader(GLuint program, GLuint shader) OVERRIDE;
+virtual void Disable(GLenum cap) OVERRIDE;
+virtual void DisableVertexAttribArray(GLuint index) OVERRIDE;
+virtual void DrawArrays(GLenum mode, GLint first, GLsizei count) OVERRIDE;
+virtual void DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) OVERRIDE;
+virtual void Enable(GLenum cap) OVERRIDE;
+virtual void EnableVertexAttribArray(GLuint index) OVERRIDE;
+virtual void Finish() OVERRIDE;
+virtual void Flush() OVERRIDE;
+virtual void FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) OVERRIDE;
+virtual void FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) OVERRIDE;
+virtual void FrontFace(GLenum mode) OVERRIDE;
+virtual void GenBuffers(GLsizei n, GLuint* buffers) OVERRIDE;
+virtual void GenerateMipmap(GLenum target) OVERRIDE;
+virtual void GenFramebuffers(GLsizei n, GLuint* framebuffers) OVERRIDE;
+virtual void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) OVERRIDE;
+virtual void GenTextures(GLsizei n, GLuint* textures) OVERRIDE;
+virtual void GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) OVERRIDE;
+virtual void GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) OVERRIDE;
+virtual void GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count,
+ GLuint* shaders) OVERRIDE;
+virtual GLint GetAttribLocation(GLuint program, const char* name) OVERRIDE;
+virtual void GetBooleanv(GLenum pname, GLboolean* params) OVERRIDE;
+virtual void GetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual GLenum GetError() OVERRIDE;
+virtual void GetFloatv(GLenum pname, GLfloat* params) OVERRIDE;
+virtual void GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetIntegerv(GLenum pname, GLint* params) OVERRIDE;
+virtual void GetProgramiv(
+ GLuint program, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) OVERRIDE;
+virtual void GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetShaderiv(GLuint shader, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) OVERRIDE;
+virtual void GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range,
+ GLint* precision) OVERRIDE;
+virtual void GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) OVERRIDE;
+virtual const GLubyte* GetString(GLenum name) OVERRIDE;
+virtual void GetTexParameterfv(
+ GLenum target, GLenum pname, GLfloat* params) OVERRIDE;
+virtual void GetTexParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetUniformfv(
+ GLuint program, GLint location, GLfloat* params) OVERRIDE;
+virtual void GetUniformiv(
+ GLuint program, GLint location, GLint* params) OVERRIDE;
+virtual GLint GetUniformLocation(GLuint program, const char* name) OVERRIDE;
+virtual void GetVertexAttribfv(
+ GLuint index, GLenum pname, GLfloat* params) OVERRIDE;
+virtual void GetVertexAttribiv(
+ GLuint index, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetVertexAttribPointerv(
+ GLuint index, GLenum pname, void** pointer) OVERRIDE;
+virtual void Hint(GLenum target, GLenum mode) OVERRIDE;
+virtual GLboolean IsBuffer(GLuint buffer) OVERRIDE;
+virtual GLboolean IsEnabled(GLenum cap) OVERRIDE;
+virtual GLboolean IsFramebuffer(GLuint framebuffer) OVERRIDE;
+virtual GLboolean IsProgram(GLuint program) OVERRIDE;
+virtual GLboolean IsRenderbuffer(GLuint renderbuffer) OVERRIDE;
+virtual GLboolean IsShader(GLuint shader) OVERRIDE;
+virtual GLboolean IsTexture(GLuint texture) OVERRIDE;
+virtual void LineWidth(GLfloat width) OVERRIDE;
+virtual void LinkProgram(GLuint program) OVERRIDE;
+virtual void PixelStorei(GLenum pname, GLint param) OVERRIDE;
+virtual void PolygonOffset(GLfloat factor, GLfloat units) OVERRIDE;
+virtual void ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ void* pixels) OVERRIDE;
+virtual void ReleaseShaderCompiler() OVERRIDE;
+virtual void RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width,
+ GLsizei height) OVERRIDE;
+virtual void SampleCoverage(GLclampf value, GLboolean invert) OVERRIDE;
+virtual void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) OVERRIDE;
+virtual void ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) OVERRIDE;
+virtual void ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* str,
+ const GLint* length) OVERRIDE;
+virtual void ShallowFinishCHROMIUM() OVERRIDE;
+virtual void ShallowFlushCHROMIUM() OVERRIDE;
+virtual void StencilFunc(GLenum func, GLint ref, GLuint mask) OVERRIDE;
+virtual void StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) OVERRIDE;
+virtual void StencilMask(GLuint mask) OVERRIDE;
+virtual void StencilMaskSeparate(GLenum face, GLuint mask) OVERRIDE;
+virtual void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) OVERRIDE;
+virtual void StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) OVERRIDE;
+virtual void TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) OVERRIDE;
+virtual void TexParameterf(
+ GLenum target, GLenum pname, GLfloat param) OVERRIDE;
+virtual void TexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) OVERRIDE;
+virtual void TexParameteri(GLenum target, GLenum pname, GLint param) OVERRIDE;
+virtual void TexParameteriv(
+ GLenum target, GLenum pname, const GLint* params) OVERRIDE;
+virtual void TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) OVERRIDE;
+virtual void Uniform1f(GLint location, GLfloat x) OVERRIDE;
+virtual void Uniform1fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform1i(GLint location, GLint x) OVERRIDE;
+virtual void Uniform1iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void Uniform2f(GLint location, GLfloat x, GLfloat y) OVERRIDE;
+virtual void Uniform2fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform2i(GLint location, GLint x, GLint y) OVERRIDE;
+virtual void Uniform2iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void Uniform3f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z) OVERRIDE;
+virtual void Uniform3fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform3i(GLint location, GLint x, GLint y, GLint z) OVERRIDE;
+virtual void Uniform3iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) OVERRIDE;
+virtual void Uniform4fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform4i(
+ GLint location, GLint x, GLint y, GLint z, GLint w) OVERRIDE;
+virtual void Uniform4iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+virtual void UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+virtual void UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+virtual void UseProgram(GLuint program) OVERRIDE;
+virtual void ValidateProgram(GLuint program) OVERRIDE;
+virtual void VertexAttrib1f(GLuint indx, GLfloat x) OVERRIDE;
+virtual void VertexAttrib1fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) OVERRIDE;
+virtual void VertexAttrib2fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttrib3f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z) OVERRIDE;
+virtual void VertexAttrib3fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) OVERRIDE;
+virtual void VertexAttrib4fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) OVERRIDE;
+virtual void Viewport(
+ GLint x, GLint y, GLsizei width, GLsizei height) OVERRIDE;
+virtual void BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
+ GLenum filter) OVERRIDE;
+virtual void RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) OVERRIDE;
+virtual void FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) OVERRIDE;
+virtual void TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) OVERRIDE;
+virtual void GenQueriesEXT(GLsizei n, GLuint* queries) OVERRIDE;
+virtual void DeleteQueriesEXT(GLsizei n, const GLuint* queries) OVERRIDE;
+virtual GLboolean IsQueryEXT(GLuint id) OVERRIDE;
+virtual void BeginQueryEXT(GLenum target, GLuint id) OVERRIDE;
+virtual void EndQueryEXT(GLenum target) OVERRIDE;
+virtual void GetQueryivEXT(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetQueryObjectuivEXT(
+ GLuint id, GLenum pname, GLuint* params) OVERRIDE;
+virtual void InsertEventMarkerEXT(
+ GLsizei length, const GLchar* marker) OVERRIDE;
+virtual void PushGroupMarkerEXT(GLsizei length, const GLchar* marker) OVERRIDE;
+virtual void PopGroupMarkerEXT() OVERRIDE;
+virtual void GenVertexArraysOES(GLsizei n, GLuint* arrays) OVERRIDE;
+virtual void DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) OVERRIDE;
+virtual GLboolean IsVertexArrayOES(GLuint array) OVERRIDE;
+virtual void BindVertexArrayOES(GLuint array) OVERRIDE;
+virtual void SwapBuffers() OVERRIDE;
+virtual GLuint GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) OVERRIDE;
+virtual void GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE;
+virtual void DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) OVERRIDE;
+virtual void RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) OVERRIDE;
+virtual GLboolean EnableFeatureCHROMIUM(const char* feature) OVERRIDE;
+virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) OVERRIDE;
+virtual GLboolean UnmapBufferCHROMIUM(GLuint target) OVERRIDE;
+virtual void* MapImageCHROMIUM(GLuint image_id, GLenum access) OVERRIDE;
+virtual void UnmapImageCHROMIUM(GLuint image_id) OVERRIDE;
+virtual void* MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) OVERRIDE;
+virtual void UnmapBufferSubDataCHROMIUM(const void* mem) OVERRIDE;
+virtual void* MapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access) OVERRIDE;
+virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) OVERRIDE;
+virtual void ResizeCHROMIUM(
+ GLuint width, GLuint height, GLfloat scale_factor) OVERRIDE;
+virtual const GLchar* GetRequestableExtensionsCHROMIUM() OVERRIDE;
+virtual void RequestExtensionCHROMIUM(const char* extension) OVERRIDE;
+virtual void RateLimitOffscreenContextCHROMIUM() OVERRIDE;
+virtual void GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results,
+ GLsizeiptr size) OVERRIDE;
+virtual void GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) OVERRIDE;
+virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) OVERRIDE;
+virtual void DestroyStreamTextureCHROMIUM(GLuint texture) OVERRIDE;
+virtual GLuint CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) OVERRIDE;
+virtual void DestroyImageCHROMIUM(GLuint image_id) OVERRIDE;
+virtual void GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) OVERRIDE;
+virtual void PostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height) OVERRIDE;
+virtual void TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) OVERRIDE;
+virtual void CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) OVERRIDE;
+virtual void DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) OVERRIDE;
+virtual void DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) OVERRIDE;
+virtual void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) OVERRIDE;
+virtual void GenMailboxCHROMIUM(GLbyte* mailbox) OVERRIDE;
+virtual void ProduceTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) OVERRIDE;
+virtual void ConsumeTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) OVERRIDE;
+virtual void BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) OVERRIDE;
+virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) OVERRIDE;
+virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) OVERRIDE;
+virtual void TraceBeginCHROMIUM(const char* name) OVERRIDE;
+virtual void TraceEndCHROMIUM() OVERRIDE;
+virtual void AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* data) OVERRIDE;
+virtual void AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) OVERRIDE;
+virtual void WaitAsyncTexImage2DCHROMIUM(GLenum target) OVERRIDE;
+virtual void DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) OVERRIDE;
+virtual void LoseContextCHROMIUM(GLenum current, GLenum other) OVERRIDE;
+virtual GLuint InsertSyncPointCHROMIUM() OVERRIDE;
+virtual void WaitSyncPointCHROMIUM(GLuint sync_point) OVERRIDE;
+virtual void DrawBuffersEXT(GLsizei count, const GLenum* bufs) OVERRIDE;
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/chromium/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
new file mode 100644
index 00000000000..6778fcfbc9a
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -0,0 +1,665 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_interface_stub.cc.
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
+
+void GLES2InterfaceStub::ActiveTexture(GLenum /* texture */) {
+}
+void GLES2InterfaceStub::AttachShader(
+ GLuint /* program */, GLuint /* shader */) {
+}
+void GLES2InterfaceStub::BindAttribLocation(
+ GLuint /* program */, GLuint /* index */, const char* /* name */) {
+}
+void GLES2InterfaceStub::BindBuffer(GLenum /* target */, GLuint /* buffer */) {
+}
+void GLES2InterfaceStub::BindFramebuffer(
+ GLenum /* target */, GLuint /* framebuffer */) {
+}
+void GLES2InterfaceStub::BindRenderbuffer(
+ GLenum /* target */, GLuint /* renderbuffer */) {
+}
+void GLES2InterfaceStub::BindTexture(
+ GLenum /* target */, GLuint /* texture */) {
+}
+void GLES2InterfaceStub::BlendColor(
+ GLclampf /* red */, GLclampf /* green */, GLclampf /* blue */,
+ GLclampf /* alpha */) {
+}
+void GLES2InterfaceStub::BlendEquation(GLenum /* mode */) {
+}
+void GLES2InterfaceStub::BlendEquationSeparate(
+ GLenum /* modeRGB */, GLenum /* modeAlpha */) {
+}
+void GLES2InterfaceStub::BlendFunc(
+ GLenum /* sfactor */, GLenum /* dfactor */) {
+}
+void GLES2InterfaceStub::BlendFuncSeparate(
+ GLenum /* srcRGB */, GLenum /* dstRGB */, GLenum /* srcAlpha */,
+ GLenum /* dstAlpha */) {
+}
+void GLES2InterfaceStub::BufferData(
+ GLenum /* target */, GLsizeiptr /* size */, const void* /* data */,
+ GLenum /* usage */) {
+}
+void GLES2InterfaceStub::BufferSubData(
+ GLenum /* target */, GLintptr /* offset */, GLsizeiptr /* size */,
+ const void* /* data */) {
+}
+GLenum GLES2InterfaceStub::CheckFramebufferStatus(GLenum /* target */) {
+ return 0;
+}
+void GLES2InterfaceStub::Clear(GLbitfield /* mask */) {
+}
+void GLES2InterfaceStub::ClearColor(
+ GLclampf /* red */, GLclampf /* green */, GLclampf /* blue */,
+ GLclampf /* alpha */) {
+}
+void GLES2InterfaceStub::ClearDepthf(GLclampf /* depth */) {
+}
+void GLES2InterfaceStub::ClearStencil(GLint /* s */) {
+}
+void GLES2InterfaceStub::ColorMask(
+ GLboolean /* red */, GLboolean /* green */, GLboolean /* blue */,
+ GLboolean /* alpha */) {
+}
+void GLES2InterfaceStub::CompileShader(GLuint /* shader */) {
+}
+void GLES2InterfaceStub::CompressedTexImage2D(
+ GLenum /* target */, GLint /* level */, GLenum /* internalformat */,
+ GLsizei /* width */, GLsizei /* height */, GLint /* border */,
+ GLsizei /* imageSize */, const void* /* data */) {
+}
+void GLES2InterfaceStub::CompressedTexSubImage2D(
+ GLenum /* target */, GLint /* level */, GLint /* xoffset */,
+ GLint /* yoffset */, GLsizei /* width */, GLsizei /* height */,
+ GLenum /* format */, GLsizei /* imageSize */, const void* /* data */) {
+}
+void GLES2InterfaceStub::CopyTexImage2D(
+ GLenum /* target */, GLint /* level */, GLenum /* internalformat */,
+ GLint /* x */, GLint /* y */, GLsizei /* width */, GLsizei /* height */,
+ GLint /* border */) {
+}
+void GLES2InterfaceStub::CopyTexSubImage2D(
+ GLenum /* target */, GLint /* level */, GLint /* xoffset */,
+ GLint /* yoffset */, GLint /* x */, GLint /* y */, GLsizei /* width */,
+ GLsizei /* height */) {
+}
+GLuint GLES2InterfaceStub::CreateProgram() {
+ return 0;
+}
+GLuint GLES2InterfaceStub::CreateShader(GLenum /* type */) {
+ return 0;
+}
+void GLES2InterfaceStub::CullFace(GLenum /* mode */) {
+}
+void GLES2InterfaceStub::DeleteBuffers(
+ GLsizei /* n */, const GLuint* /* buffers */) {
+}
+void GLES2InterfaceStub::DeleteFramebuffers(
+ GLsizei /* n */, const GLuint* /* framebuffers */) {
+}
+void GLES2InterfaceStub::DeleteProgram(GLuint /* program */) {
+}
+void GLES2InterfaceStub::DeleteRenderbuffers(
+ GLsizei /* n */, const GLuint* /* renderbuffers */) {
+}
+void GLES2InterfaceStub::DeleteShader(GLuint /* shader */) {
+}
+void GLES2InterfaceStub::DeleteTextures(
+ GLsizei /* n */, const GLuint* /* textures */) {
+}
+void GLES2InterfaceStub::DepthFunc(GLenum /* func */) {
+}
+void GLES2InterfaceStub::DepthMask(GLboolean /* flag */) {
+}
+void GLES2InterfaceStub::DepthRangef(
+ GLclampf /* zNear */, GLclampf /* zFar */) {
+}
+void GLES2InterfaceStub::DetachShader(
+ GLuint /* program */, GLuint /* shader */) {
+}
+void GLES2InterfaceStub::Disable(GLenum /* cap */) {
+}
+void GLES2InterfaceStub::DisableVertexAttribArray(GLuint /* index */) {
+}
+void GLES2InterfaceStub::DrawArrays(
+ GLenum /* mode */, GLint /* first */, GLsizei /* count */) {
+}
+void GLES2InterfaceStub::DrawElements(
+ GLenum /* mode */, GLsizei /* count */, GLenum /* type */,
+ const void* /* indices */) {
+}
+void GLES2InterfaceStub::Enable(GLenum /* cap */) {
+}
+void GLES2InterfaceStub::EnableVertexAttribArray(GLuint /* index */) {
+}
+void GLES2InterfaceStub::Finish() {
+}
+void GLES2InterfaceStub::Flush() {
+}
+void GLES2InterfaceStub::FramebufferRenderbuffer(
+ GLenum /* target */, GLenum /* attachment */,
+ GLenum /* renderbuffertarget */, GLuint /* renderbuffer */) {
+}
+void GLES2InterfaceStub::FramebufferTexture2D(
+ GLenum /* target */, GLenum /* attachment */, GLenum /* textarget */,
+ GLuint /* texture */, GLint /* level */) {
+}
+void GLES2InterfaceStub::FrontFace(GLenum /* mode */) {
+}
+void GLES2InterfaceStub::GenBuffers(GLsizei /* n */, GLuint* /* buffers */) {
+}
+void GLES2InterfaceStub::GenerateMipmap(GLenum /* target */) {
+}
+void GLES2InterfaceStub::GenFramebuffers(
+ GLsizei /* n */, GLuint* /* framebuffers */) {
+}
+void GLES2InterfaceStub::GenRenderbuffers(
+ GLsizei /* n */, GLuint* /* renderbuffers */) {
+}
+void GLES2InterfaceStub::GenTextures(GLsizei /* n */, GLuint* /* textures */) {
+}
+void GLES2InterfaceStub::GetActiveAttrib(
+ GLuint /* program */, GLuint /* index */, GLsizei /* bufsize */,
+ GLsizei* /* length */, GLint* /* size */, GLenum* /* type */,
+ char* /* name */) {
+}
+void GLES2InterfaceStub::GetActiveUniform(
+ GLuint /* program */, GLuint /* index */, GLsizei /* bufsize */,
+ GLsizei* /* length */, GLint* /* size */, GLenum* /* type */,
+ char* /* name */) {
+}
+void GLES2InterfaceStub::GetAttachedShaders(
+ GLuint /* program */, GLsizei /* maxcount */, GLsizei* /* count */,
+ GLuint* /* shaders */) {
+}
+GLint GLES2InterfaceStub::GetAttribLocation(
+ GLuint /* program */, const char* /* name */) {
+ return 0;
+}
+void GLES2InterfaceStub::GetBooleanv(
+ GLenum /* pname */, GLboolean* /* params */) {
+}
+void GLES2InterfaceStub::GetBufferParameteriv(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+}
+GLenum GLES2InterfaceStub::GetError() {
+ return 0;
+}
+void GLES2InterfaceStub::GetFloatv(GLenum /* pname */, GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::GetFramebufferAttachmentParameteriv(
+ GLenum /* target */, GLenum /* attachment */, GLenum /* pname */,
+ GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetIntegerv(GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetProgramiv(
+ GLuint /* program */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetProgramInfoLog(
+ GLuint /* program */, GLsizei /* bufsize */, GLsizei* /* length */,
+ char* /* infolog */) {
+}
+void GLES2InterfaceStub::GetRenderbufferParameteriv(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetShaderiv(
+ GLuint /* shader */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetShaderInfoLog(
+ GLuint /* shader */, GLsizei /* bufsize */, GLsizei* /* length */,
+ char* /* infolog */) {
+}
+void GLES2InterfaceStub::GetShaderPrecisionFormat(
+ GLenum /* shadertype */, GLenum /* precisiontype */, GLint* /* range */,
+ GLint* /* precision */) {
+}
+void GLES2InterfaceStub::GetShaderSource(
+ GLuint /* shader */, GLsizei /* bufsize */, GLsizei* /* length */,
+ char* /* source */) {
+}
+const GLubyte* GLES2InterfaceStub::GetString(GLenum /* name */) {
+ return 0;
+}
+void GLES2InterfaceStub::GetTexParameterfv(
+ GLenum /* target */, GLenum /* pname */, GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::GetTexParameteriv(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetUniformfv(
+ GLuint /* program */, GLint /* location */, GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::GetUniformiv(
+ GLuint /* program */, GLint /* location */, GLint* /* params */) {
+}
+GLint GLES2InterfaceStub::GetUniformLocation(
+ GLuint /* program */, const char* /* name */) {
+ return 0;
+}
+void GLES2InterfaceStub::GetVertexAttribfv(
+ GLuint /* index */, GLenum /* pname */, GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::GetVertexAttribiv(
+ GLuint /* index */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetVertexAttribPointerv(
+ GLuint /* index */, GLenum /* pname */, void** /* pointer */) {
+}
+void GLES2InterfaceStub::Hint(GLenum /* target */, GLenum /* mode */) {
+}
+GLboolean GLES2InterfaceStub::IsBuffer(GLuint /* buffer */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::IsEnabled(GLenum /* cap */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::IsFramebuffer(GLuint /* framebuffer */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::IsProgram(GLuint /* program */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::IsRenderbuffer(GLuint /* renderbuffer */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::IsShader(GLuint /* shader */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::IsTexture(GLuint /* texture */) {
+ return 0;
+}
+void GLES2InterfaceStub::LineWidth(GLfloat /* width */) {
+}
+void GLES2InterfaceStub::LinkProgram(GLuint /* program */) {
+}
+void GLES2InterfaceStub::PixelStorei(GLenum /* pname */, GLint /* param */) {
+}
+void GLES2InterfaceStub::PolygonOffset(
+ GLfloat /* factor */, GLfloat /* units */) {
+}
+void GLES2InterfaceStub::ReadPixels(
+ GLint /* x */, GLint /* y */, GLsizei /* width */, GLsizei /* height */,
+ GLenum /* format */, GLenum /* type */, void* /* pixels */) {
+}
+void GLES2InterfaceStub::ReleaseShaderCompiler() {
+}
+void GLES2InterfaceStub::RenderbufferStorage(
+ GLenum /* target */, GLenum /* internalformat */, GLsizei /* width */,
+ GLsizei /* height */) {
+}
+void GLES2InterfaceStub::SampleCoverage(
+ GLclampf /* value */, GLboolean /* invert */) {
+}
+void GLES2InterfaceStub::Scissor(
+ GLint /* x */, GLint /* y */, GLsizei /* width */, GLsizei /* height */) {
+}
+void GLES2InterfaceStub::ShaderBinary(
+ GLsizei /* n */, const GLuint* /* shaders */, GLenum /* binaryformat */,
+ const void* /* binary */, GLsizei /* length */) {
+}
+void GLES2InterfaceStub::ShaderSource(
+ GLuint /* shader */, GLsizei /* count */, const GLchar* const* /* str */,
+ const GLint* /* length */) {
+}
+void GLES2InterfaceStub::ShallowFinishCHROMIUM() {
+}
+void GLES2InterfaceStub::ShallowFlushCHROMIUM() {
+}
+void GLES2InterfaceStub::StencilFunc(
+ GLenum /* func */, GLint /* ref */, GLuint /* mask */) {
+}
+void GLES2InterfaceStub::StencilFuncSeparate(
+ GLenum /* face */, GLenum /* func */, GLint /* ref */, GLuint /* mask */) {
+}
+void GLES2InterfaceStub::StencilMask(GLuint /* mask */) {
+}
+void GLES2InterfaceStub::StencilMaskSeparate(
+ GLenum /* face */, GLuint /* mask */) {
+}
+void GLES2InterfaceStub::StencilOp(
+ GLenum /* fail */, GLenum /* zfail */, GLenum /* zpass */) {
+}
+void GLES2InterfaceStub::StencilOpSeparate(
+ GLenum /* face */, GLenum /* fail */, GLenum /* zfail */,
+ GLenum /* zpass */) {
+}
+void GLES2InterfaceStub::TexImage2D(
+ GLenum /* target */, GLint /* level */, GLint /* internalformat */,
+ GLsizei /* width */, GLsizei /* height */, GLint /* border */,
+ GLenum /* format */, GLenum /* type */, const void* /* pixels */) {
+}
+void GLES2InterfaceStub::TexParameterf(
+ GLenum /* target */, GLenum /* pname */, GLfloat /* param */) {
+}
+void GLES2InterfaceStub::TexParameterfv(
+ GLenum /* target */, GLenum /* pname */, const GLfloat* /* params */) {
+}
+void GLES2InterfaceStub::TexParameteri(
+ GLenum /* target */, GLenum /* pname */, GLint /* param */) {
+}
+void GLES2InterfaceStub::TexParameteriv(
+ GLenum /* target */, GLenum /* pname */, const GLint* /* params */) {
+}
+void GLES2InterfaceStub::TexSubImage2D(
+ GLenum /* target */, GLint /* level */, GLint /* xoffset */,
+ GLint /* yoffset */, GLsizei /* width */, GLsizei /* height */,
+ GLenum /* format */, GLenum /* type */, const void* /* pixels */) {
+}
+void GLES2InterfaceStub::Uniform1f(GLint /* location */, GLfloat /* x */) {
+}
+void GLES2InterfaceStub::Uniform1fv(
+ GLint /* location */, GLsizei /* count */, const GLfloat* /* v */) {
+}
+void GLES2InterfaceStub::Uniform1i(GLint /* location */, GLint /* x */) {
+}
+void GLES2InterfaceStub::Uniform1iv(
+ GLint /* location */, GLsizei /* count */, const GLint* /* v */) {
+}
+void GLES2InterfaceStub::Uniform2f(
+ GLint /* location */, GLfloat /* x */, GLfloat /* y */) {
+}
+void GLES2InterfaceStub::Uniform2fv(
+ GLint /* location */, GLsizei /* count */, const GLfloat* /* v */) {
+}
+void GLES2InterfaceStub::Uniform2i(
+ GLint /* location */, GLint /* x */, GLint /* y */) {
+}
+void GLES2InterfaceStub::Uniform2iv(
+ GLint /* location */, GLsizei /* count */, const GLint* /* v */) {
+}
+void GLES2InterfaceStub::Uniform3f(
+ GLint /* location */, GLfloat /* x */, GLfloat /* y */, GLfloat /* z */) {
+}
+void GLES2InterfaceStub::Uniform3fv(
+ GLint /* location */, GLsizei /* count */, const GLfloat* /* v */) {
+}
+void GLES2InterfaceStub::Uniform3i(
+ GLint /* location */, GLint /* x */, GLint /* y */, GLint /* z */) {
+}
+void GLES2InterfaceStub::Uniform3iv(
+ GLint /* location */, GLsizei /* count */, const GLint* /* v */) {
+}
+void GLES2InterfaceStub::Uniform4f(
+ GLint /* location */, GLfloat /* x */, GLfloat /* y */, GLfloat /* z */,
+ GLfloat /* w */) {
+}
+void GLES2InterfaceStub::Uniform4fv(
+ GLint /* location */, GLsizei /* count */, const GLfloat* /* v */) {
+}
+void GLES2InterfaceStub::Uniform4i(
+ GLint /* location */, GLint /* x */, GLint /* y */, GLint /* z */,
+ GLint /* w */) {
+}
+void GLES2InterfaceStub::Uniform4iv(
+ GLint /* location */, GLsizei /* count */, const GLint* /* v */) {
+}
+void GLES2InterfaceStub::UniformMatrix2fv(
+ GLint /* location */, GLsizei /* count */, GLboolean /* transpose */,
+ const GLfloat* /* value */) {
+}
+void GLES2InterfaceStub::UniformMatrix3fv(
+ GLint /* location */, GLsizei /* count */, GLboolean /* transpose */,
+ const GLfloat* /* value */) {
+}
+void GLES2InterfaceStub::UniformMatrix4fv(
+ GLint /* location */, GLsizei /* count */, GLboolean /* transpose */,
+ const GLfloat* /* value */) {
+}
+void GLES2InterfaceStub::UseProgram(GLuint /* program */) {
+}
+void GLES2InterfaceStub::ValidateProgram(GLuint /* program */) {
+}
+void GLES2InterfaceStub::VertexAttrib1f(GLuint /* indx */, GLfloat /* x */) {
+}
+void GLES2InterfaceStub::VertexAttrib1fv(
+ GLuint /* indx */, const GLfloat* /* values */) {
+}
+void GLES2InterfaceStub::VertexAttrib2f(
+ GLuint /* indx */, GLfloat /* x */, GLfloat /* y */) {
+}
+void GLES2InterfaceStub::VertexAttrib2fv(
+ GLuint /* indx */, const GLfloat* /* values */) {
+}
+void GLES2InterfaceStub::VertexAttrib3f(
+ GLuint /* indx */, GLfloat /* x */, GLfloat /* y */, GLfloat /* z */) {
+}
+void GLES2InterfaceStub::VertexAttrib3fv(
+ GLuint /* indx */, const GLfloat* /* values */) {
+}
+void GLES2InterfaceStub::VertexAttrib4f(
+ GLuint /* indx */, GLfloat /* x */, GLfloat /* y */, GLfloat /* z */,
+ GLfloat /* w */) {
+}
+void GLES2InterfaceStub::VertexAttrib4fv(
+ GLuint /* indx */, const GLfloat* /* values */) {
+}
+void GLES2InterfaceStub::VertexAttribPointer(
+ GLuint /* indx */, GLint /* size */, GLenum /* type */,
+ GLboolean /* normalized */, GLsizei /* stride */, const void* /* ptr */) {
+}
+void GLES2InterfaceStub::Viewport(
+ GLint /* x */, GLint /* y */, GLsizei /* width */, GLsizei /* height */) {
+}
+void GLES2InterfaceStub::BlitFramebufferEXT(
+ GLint /* srcX0 */, GLint /* srcY0 */, GLint /* srcX1 */, GLint /* srcY1 */,
+ GLint /* dstX0 */, GLint /* dstY0 */, GLint /* dstX1 */, GLint /* dstY1 */,
+ GLbitfield /* mask */, GLenum /* filter */) {
+}
+void GLES2InterfaceStub::RenderbufferStorageMultisampleEXT(
+ GLenum /* target */, GLsizei /* samples */, GLenum /* internalformat */,
+ GLsizei /* width */, GLsizei /* height */) {
+}
+void GLES2InterfaceStub::FramebufferTexture2DMultisampleEXT(
+ GLenum /* target */, GLenum /* attachment */, GLenum /* textarget */,
+ GLuint /* texture */, GLint /* level */, GLsizei /* samples */) {
+}
+void GLES2InterfaceStub::TexStorage2DEXT(
+ GLenum /* target */, GLsizei /* levels */, GLenum /* internalFormat */,
+ GLsizei /* width */, GLsizei /* height */) {
+}
+void GLES2InterfaceStub::GenQueriesEXT(
+ GLsizei /* n */, GLuint* /* queries */) {
+}
+void GLES2InterfaceStub::DeleteQueriesEXT(
+ GLsizei /* n */, const GLuint* /* queries */) {
+}
+GLboolean GLES2InterfaceStub::IsQueryEXT(GLuint /* id */) {
+ return 0;
+}
+void GLES2InterfaceStub::BeginQueryEXT(GLenum /* target */, GLuint /* id */) {
+}
+void GLES2InterfaceStub::EndQueryEXT(GLenum /* target */) {
+}
+void GLES2InterfaceStub::GetQueryivEXT(
+ GLenum /* target */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetQueryObjectuivEXT(
+ GLuint /* id */, GLenum /* pname */, GLuint* /* params */) {
+}
+void GLES2InterfaceStub::InsertEventMarkerEXT(
+ GLsizei /* length */, const GLchar* /* marker */) {
+}
+void GLES2InterfaceStub::PushGroupMarkerEXT(
+ GLsizei /* length */, const GLchar* /* marker */) {
+}
+void GLES2InterfaceStub::PopGroupMarkerEXT() {
+}
+void GLES2InterfaceStub::GenVertexArraysOES(
+ GLsizei /* n */, GLuint* /* arrays */) {
+}
+void GLES2InterfaceStub::DeleteVertexArraysOES(
+ GLsizei /* n */, const GLuint* /* arrays */) {
+}
+GLboolean GLES2InterfaceStub::IsVertexArrayOES(GLuint /* array */) {
+ return 0;
+}
+void GLES2InterfaceStub::BindVertexArrayOES(GLuint /* array */) {
+}
+void GLES2InterfaceStub::SwapBuffers() {
+}
+GLuint GLES2InterfaceStub::GetMaxValueInBufferCHROMIUM(
+ GLuint /* buffer_id */, GLsizei /* count */, GLenum /* type */,
+ GLuint /* offset */) {
+ return 0;
+}
+void GLES2InterfaceStub::GenSharedIdsCHROMIUM(
+ GLuint /* namespace_id */, GLuint /* id_offset */, GLsizei /* n */,
+ GLuint* /* ids */) {
+}
+void GLES2InterfaceStub::DeleteSharedIdsCHROMIUM(
+ GLuint /* namespace_id */, GLsizei /* n */, const GLuint* /* ids */) {
+}
+void GLES2InterfaceStub::RegisterSharedIdsCHROMIUM(
+ GLuint /* namespace_id */, GLsizei /* n */, const GLuint* /* ids */) {
+}
+GLboolean GLES2InterfaceStub::EnableFeatureCHROMIUM(
+ const char* /* feature */) {
+ return 0;
+}
+void* GLES2InterfaceStub::MapBufferCHROMIUM(
+ GLuint /* target */, GLenum /* access */) {
+ return 0;
+}
+GLboolean GLES2InterfaceStub::UnmapBufferCHROMIUM(GLuint /* target */) {
+ return 0;
+}
+void* GLES2InterfaceStub::MapImageCHROMIUM(
+ GLuint /* image_id */, GLenum /* access */) {
+ return 0;
+}
+void GLES2InterfaceStub::UnmapImageCHROMIUM(GLuint /* image_id */) {
+}
+void* GLES2InterfaceStub::MapBufferSubDataCHROMIUM(
+ GLuint /* target */, GLintptr /* offset */, GLsizeiptr /* size */,
+ GLenum /* access */) {
+ return 0;
+}
+void GLES2InterfaceStub::UnmapBufferSubDataCHROMIUM(const void* /* mem */) {
+}
+void* GLES2InterfaceStub::MapTexSubImage2DCHROMIUM(
+ GLenum /* target */, GLint /* level */, GLint /* xoffset */,
+ GLint /* yoffset */, GLsizei /* width */, GLsizei /* height */,
+ GLenum /* format */, GLenum /* type */, GLenum /* access */) {
+ return 0;
+}
+void GLES2InterfaceStub::UnmapTexSubImage2DCHROMIUM(const void* /* mem */) {
+}
+void GLES2InterfaceStub::ResizeCHROMIUM(
+ GLuint /* width */, GLuint /* height */, GLfloat /* scale_factor */) {
+}
+const GLchar* GLES2InterfaceStub::GetRequestableExtensionsCHROMIUM() {
+ return 0;
+}
+void GLES2InterfaceStub::RequestExtensionCHROMIUM(
+ const char* /* extension */) {
+}
+void GLES2InterfaceStub::RateLimitOffscreenContextCHROMIUM() {
+}
+void GLES2InterfaceStub::GetMultipleIntegervCHROMIUM(
+ const GLenum* /* pnames */, GLuint /* count */, GLint* /* results */,
+ GLsizeiptr /* size */) {
+}
+void GLES2InterfaceStub::GetProgramInfoCHROMIUM(
+ GLuint /* program */, GLsizei /* bufsize */, GLsizei* /* size */,
+ void* /* info */) {
+}
+GLuint GLES2InterfaceStub::CreateStreamTextureCHROMIUM(GLuint /* texture */) {
+ return 0;
+}
+void GLES2InterfaceStub::DestroyStreamTextureCHROMIUM(GLuint /* texture */) {
+}
+GLuint GLES2InterfaceStub::CreateImageCHROMIUM(
+ GLsizei /* width */, GLsizei /* height */, GLenum /* internalformat */) {
+ return 0;
+}
+void GLES2InterfaceStub::DestroyImageCHROMIUM(GLuint /* image_id */) {
+}
+void GLES2InterfaceStub::GetImageParameterivCHROMIUM(
+ GLuint /* image_id */, GLenum /* pname */, GLint* /* params */) {
+}
+void GLES2InterfaceStub::GetTranslatedShaderSourceANGLE(
+ GLuint /* shader */, GLsizei /* bufsize */, GLsizei* /* length */,
+ char* /* source */) {
+}
+void GLES2InterfaceStub::PostSubBufferCHROMIUM(
+ GLint /* x */, GLint /* y */, GLint /* width */, GLint /* height */) {
+}
+void GLES2InterfaceStub::TexImageIOSurface2DCHROMIUM(
+ GLenum /* target */, GLsizei /* width */, GLsizei /* height */,
+ GLuint /* ioSurfaceId */, GLuint /* plane */) {
+}
+void GLES2InterfaceStub::CopyTextureCHROMIUM(
+ GLenum /* target */, GLenum /* source_id */, GLenum /* dest_id */,
+ GLint /* level */, GLint /* internalformat */, GLenum /* dest_type */) {
+}
+void GLES2InterfaceStub::DrawArraysInstancedANGLE(
+ GLenum /* mode */, GLint /* first */, GLsizei /* count */,
+ GLsizei /* primcount */) {
+}
+void GLES2InterfaceStub::DrawElementsInstancedANGLE(
+ GLenum /* mode */, GLsizei /* count */, GLenum /* type */,
+ const void* /* indices */, GLsizei /* primcount */) {
+}
+void GLES2InterfaceStub::VertexAttribDivisorANGLE(
+ GLuint /* index */, GLuint /* divisor */) {
+}
+void GLES2InterfaceStub::GenMailboxCHROMIUM(GLbyte* /* mailbox */) {
+}
+void GLES2InterfaceStub::ProduceTextureCHROMIUM(
+ GLenum /* target */, const GLbyte* /* mailbox */) {
+}
+void GLES2InterfaceStub::ConsumeTextureCHROMIUM(
+ GLenum /* target */, const GLbyte* /* mailbox */) {
+}
+void GLES2InterfaceStub::BindUniformLocationCHROMIUM(
+ GLuint /* program */, GLint /* location */, const char* /* name */) {
+}
+void GLES2InterfaceStub::BindTexImage2DCHROMIUM(
+ GLenum /* target */, GLint /* imageId */) {
+}
+void GLES2InterfaceStub::ReleaseTexImage2DCHROMIUM(
+ GLenum /* target */, GLint /* imageId */) {
+}
+void GLES2InterfaceStub::TraceBeginCHROMIUM(const char* /* name */) {
+}
+void GLES2InterfaceStub::TraceEndCHROMIUM() {
+}
+void GLES2InterfaceStub::AsyncTexSubImage2DCHROMIUM(
+ GLenum /* target */, GLint /* level */, GLint /* xoffset */,
+ GLint /* yoffset */, GLsizei /* width */, GLsizei /* height */,
+ GLenum /* format */, GLenum /* type */, const void* /* data */) {
+}
+void GLES2InterfaceStub::AsyncTexImage2DCHROMIUM(
+ GLenum /* target */, GLint /* level */, GLint /* internalformat */,
+ GLsizei /* width */, GLsizei /* height */, GLint /* border */,
+ GLenum /* format */, GLenum /* type */, const void* /* pixels */) {
+}
+void GLES2InterfaceStub::WaitAsyncTexImage2DCHROMIUM(GLenum /* target */) {
+}
+void GLES2InterfaceStub::DiscardFramebufferEXT(
+ GLenum /* target */, GLsizei /* count */,
+ const GLenum* /* attachments */) {
+}
+void GLES2InterfaceStub::LoseContextCHROMIUM(
+ GLenum /* current */, GLenum /* other */) {
+}
+GLuint GLES2InterfaceStub::InsertSyncPointCHROMIUM() {
+ return 0;
+}
+void GLES2InterfaceStub::WaitSyncPointCHROMIUM(GLuint /* sync_point */) {
+}
+void GLES2InterfaceStub::DrawBuffersEXT(
+ GLsizei /* count */, const GLenum* /* bufs */) {
+}
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_lib.cc b/chromium/gpu/command_buffer/client/gles2_lib.cc
new file mode 100644
index 00000000000..6c8b0ead13c
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_lib.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include <string.h>
+#include "gpu/command_buffer/common/thread_local.h"
+
+namespace gles2 {
+
+// This is defined in gles2_c_lib_autogen.h
+extern "C" {
+extern const NameToFunc g_gles2_function_table[];
+}
+
+// TODO(kbr): the use of this anonymous namespace core dumps the
+// linker on Mac OS X 10.6 when the symbol ordering file is used
+// namespace {
+static gpu::ThreadLocalKey g_gl_context_key;
+// } // namespace anonymous
+
+void Initialize() {
+ g_gl_context_key = gpu::ThreadLocalAlloc();
+}
+
+void Terminate() {
+ gpu::ThreadLocalFree(g_gl_context_key);
+ g_gl_context_key = 0;
+}
+
+gpu::gles2::GLES2Interface* GetGLContext() {
+ return static_cast<gpu::gles2::GLES2Interface*>(
+ gpu::ThreadLocalGetValue(g_gl_context_key));
+}
+
+void SetGLContext(gpu::gles2::GLES2Interface* context) {
+ gpu::ThreadLocalSetValue(g_gl_context_key, context);
+}
+
+GLES2FunctionPointer GetGLFunctionPointer(const char* name) {
+ for (const NameToFunc* named_function = g_gles2_function_table;
+ named_function->name;
+ ++named_function) {
+ if (!strcmp(name, named_function->name)) {
+ return named_function->func;
+ }
+ }
+ return NULL;
+}
+
+} // namespace gles2
+
+
+
+
diff --git a/chromium/gpu/command_buffer/client/gles2_lib.h b/chromium/gpu/command_buffer/client/gles2_lib.h
new file mode 100644
index 00000000000..b90a2d8daf3
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_lib.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// These functions emulate GLES2 over command buffers.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_LIB_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_LIB_H_
+
+#include "gpu/command_buffer/client/gles2_c_lib_export.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+
+namespace gles2 {
+
+typedef void (*GLES2FunctionPointer)(void);
+
+struct NameToFunc {
+ const char* name;
+ gles2::GLES2FunctionPointer func;
+};
+
+// Initialize the GLES2 library.
+GLES2_C_LIB_EXPORT void Initialize();
+
+// Terminate the GLES2 library.
+GLES2_C_LIB_EXPORT void Terminate();
+
+// Get the current GL context.
+GLES2_C_LIB_EXPORT gpu::gles2::GLES2Interface* GetGLContext();
+
+// Set the current GL context.
+GLES2_C_LIB_EXPORT void SetGLContext(gpu::gles2::GLES2Interface* impl);
+
+GLES2_C_LIB_EXPORT GLES2FunctionPointer GetGLFunctionPointer(const char* name);
+
+} // namespace gles2
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_LIB_H_
diff --git a/chromium/gpu/command_buffer/client/gles2_trace_implementation.cc b/chromium/gpu/command_buffer/client/gles2_trace_implementation.cc
new file mode 100644
index 00000000000..234f2432ac4
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_trace_implementation.cc
@@ -0,0 +1,25 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gles2_trace_implementation.h"
+#include "gpu/command_buffer/common/trace_event.h"
+
+namespace gpu {
+namespace gles2 {
+
+GLES2TraceImplementation::GLES2TraceImplementation(GLES2Interface* gl)
+ : gl_(gl) {
+}
+
+GLES2TraceImplementation::~GLES2TraceImplementation() {
+}
+
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/client/gles2_trace_implementation.h b/chromium/gpu/command_buffer/client/gles2_trace_implementation.h
new file mode 100644
index 00000000000..18e6a793cfe
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_trace_implementation.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_H_
+
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/common/compiler_specific.h"
+
+namespace gpu {
+namespace gles2 {
+
+// GLES2TraceImplementation is calls TRACE for every GL call.
+class GLES2_IMPL_EXPORT GLES2TraceImplementation : public GLES2Interface {
+ public:
+ explicit GLES2TraceImplementation(GLES2Interface* gl);
+ virtual ~GLES2TraceImplementation();
+
+ // Include the auto-generated part of this class. We split this because
+ // it means we can easily edit the non-auto generated parts right here in
+ // this file instead of having to edit some template or the code generator.
+ #include "gpu/command_buffer/client/gles2_trace_implementation_autogen.h"
+
+ private:
+ GLES2Interface* gl_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/chromium/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
new file mode 100644
index 00000000000..4f3ce31b88a
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -0,0 +1,354 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_trace_implementation.h
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
+
+virtual void ActiveTexture(GLenum texture) OVERRIDE;
+virtual void AttachShader(GLuint program, GLuint shader) OVERRIDE;
+virtual void BindAttribLocation(
+ GLuint program, GLuint index, const char* name) OVERRIDE;
+virtual void BindBuffer(GLenum target, GLuint buffer) OVERRIDE;
+virtual void BindFramebuffer(GLenum target, GLuint framebuffer) OVERRIDE;
+virtual void BindRenderbuffer(GLenum target, GLuint renderbuffer) OVERRIDE;
+virtual void BindTexture(GLenum target, GLuint texture) OVERRIDE;
+virtual void BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) OVERRIDE;
+virtual void BlendEquation(GLenum mode) OVERRIDE;
+virtual void BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) OVERRIDE;
+virtual void BlendFunc(GLenum sfactor, GLenum dfactor) OVERRIDE;
+virtual void BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) OVERRIDE;
+virtual void BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) OVERRIDE;
+virtual void BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size,
+ const void* data) OVERRIDE;
+virtual GLenum CheckFramebufferStatus(GLenum target) OVERRIDE;
+virtual void Clear(GLbitfield mask) OVERRIDE;
+virtual void ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) OVERRIDE;
+virtual void ClearDepthf(GLclampf depth) OVERRIDE;
+virtual void ClearStencil(GLint s) OVERRIDE;
+virtual void ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) OVERRIDE;
+virtual void CompileShader(GLuint shader) OVERRIDE;
+virtual void CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize,
+ const void* data) OVERRIDE;
+virtual void CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize,
+ const void* data) OVERRIDE;
+virtual void CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) OVERRIDE;
+virtual void CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) OVERRIDE;
+virtual GLuint CreateProgram() OVERRIDE;
+virtual GLuint CreateShader(GLenum type) OVERRIDE;
+virtual void CullFace(GLenum mode) OVERRIDE;
+virtual void DeleteBuffers(GLsizei n, const GLuint* buffers) OVERRIDE;
+virtual void DeleteFramebuffers(
+ GLsizei n, const GLuint* framebuffers) OVERRIDE;
+virtual void DeleteProgram(GLuint program) OVERRIDE;
+virtual void DeleteRenderbuffers(
+ GLsizei n, const GLuint* renderbuffers) OVERRIDE;
+virtual void DeleteShader(GLuint shader) OVERRIDE;
+virtual void DeleteTextures(GLsizei n, const GLuint* textures) OVERRIDE;
+virtual void DepthFunc(GLenum func) OVERRIDE;
+virtual void DepthMask(GLboolean flag) OVERRIDE;
+virtual void DepthRangef(GLclampf zNear, GLclampf zFar) OVERRIDE;
+virtual void DetachShader(GLuint program, GLuint shader) OVERRIDE;
+virtual void Disable(GLenum cap) OVERRIDE;
+virtual void DisableVertexAttribArray(GLuint index) OVERRIDE;
+virtual void DrawArrays(GLenum mode, GLint first, GLsizei count) OVERRIDE;
+virtual void DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) OVERRIDE;
+virtual void Enable(GLenum cap) OVERRIDE;
+virtual void EnableVertexAttribArray(GLuint index) OVERRIDE;
+virtual void Finish() OVERRIDE;
+virtual void Flush() OVERRIDE;
+virtual void FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) OVERRIDE;
+virtual void FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) OVERRIDE;
+virtual void FrontFace(GLenum mode) OVERRIDE;
+virtual void GenBuffers(GLsizei n, GLuint* buffers) OVERRIDE;
+virtual void GenerateMipmap(GLenum target) OVERRIDE;
+virtual void GenFramebuffers(GLsizei n, GLuint* framebuffers) OVERRIDE;
+virtual void GenRenderbuffers(GLsizei n, GLuint* renderbuffers) OVERRIDE;
+virtual void GenTextures(GLsizei n, GLuint* textures) OVERRIDE;
+virtual void GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) OVERRIDE;
+virtual void GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) OVERRIDE;
+virtual void GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count,
+ GLuint* shaders) OVERRIDE;
+virtual GLint GetAttribLocation(GLuint program, const char* name) OVERRIDE;
+virtual void GetBooleanv(GLenum pname, GLboolean* params) OVERRIDE;
+virtual void GetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual GLenum GetError() OVERRIDE;
+virtual void GetFloatv(GLenum pname, GLfloat* params) OVERRIDE;
+virtual void GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetIntegerv(GLenum pname, GLint* params) OVERRIDE;
+virtual void GetProgramiv(
+ GLuint program, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) OVERRIDE;
+virtual void GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetShaderiv(GLuint shader, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) OVERRIDE;
+virtual void GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range,
+ GLint* precision) OVERRIDE;
+virtual void GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) OVERRIDE;
+virtual const GLubyte* GetString(GLenum name) OVERRIDE;
+virtual void GetTexParameterfv(
+ GLenum target, GLenum pname, GLfloat* params) OVERRIDE;
+virtual void GetTexParameteriv(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetUniformfv(
+ GLuint program, GLint location, GLfloat* params) OVERRIDE;
+virtual void GetUniformiv(
+ GLuint program, GLint location, GLint* params) OVERRIDE;
+virtual GLint GetUniformLocation(GLuint program, const char* name) OVERRIDE;
+virtual void GetVertexAttribfv(
+ GLuint index, GLenum pname, GLfloat* params) OVERRIDE;
+virtual void GetVertexAttribiv(
+ GLuint index, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetVertexAttribPointerv(
+ GLuint index, GLenum pname, void** pointer) OVERRIDE;
+virtual void Hint(GLenum target, GLenum mode) OVERRIDE;
+virtual GLboolean IsBuffer(GLuint buffer) OVERRIDE;
+virtual GLboolean IsEnabled(GLenum cap) OVERRIDE;
+virtual GLboolean IsFramebuffer(GLuint framebuffer) OVERRIDE;
+virtual GLboolean IsProgram(GLuint program) OVERRIDE;
+virtual GLboolean IsRenderbuffer(GLuint renderbuffer) OVERRIDE;
+virtual GLboolean IsShader(GLuint shader) OVERRIDE;
+virtual GLboolean IsTexture(GLuint texture) OVERRIDE;
+virtual void LineWidth(GLfloat width) OVERRIDE;
+virtual void LinkProgram(GLuint program) OVERRIDE;
+virtual void PixelStorei(GLenum pname, GLint param) OVERRIDE;
+virtual void PolygonOffset(GLfloat factor, GLfloat units) OVERRIDE;
+virtual void ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ void* pixels) OVERRIDE;
+virtual void ReleaseShaderCompiler() OVERRIDE;
+virtual void RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width,
+ GLsizei height) OVERRIDE;
+virtual void SampleCoverage(GLclampf value, GLboolean invert) OVERRIDE;
+virtual void Scissor(GLint x, GLint y, GLsizei width, GLsizei height) OVERRIDE;
+virtual void ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) OVERRIDE;
+virtual void ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* str,
+ const GLint* length) OVERRIDE;
+virtual void ShallowFinishCHROMIUM() OVERRIDE;
+virtual void ShallowFlushCHROMIUM() OVERRIDE;
+virtual void StencilFunc(GLenum func, GLint ref, GLuint mask) OVERRIDE;
+virtual void StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) OVERRIDE;
+virtual void StencilMask(GLuint mask) OVERRIDE;
+virtual void StencilMaskSeparate(GLenum face, GLuint mask) OVERRIDE;
+virtual void StencilOp(GLenum fail, GLenum zfail, GLenum zpass) OVERRIDE;
+virtual void StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) OVERRIDE;
+virtual void TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) OVERRIDE;
+virtual void TexParameterf(
+ GLenum target, GLenum pname, GLfloat param) OVERRIDE;
+virtual void TexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) OVERRIDE;
+virtual void TexParameteri(GLenum target, GLenum pname, GLint param) OVERRIDE;
+virtual void TexParameteriv(
+ GLenum target, GLenum pname, const GLint* params) OVERRIDE;
+virtual void TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) OVERRIDE;
+virtual void Uniform1f(GLint location, GLfloat x) OVERRIDE;
+virtual void Uniform1fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform1i(GLint location, GLint x) OVERRIDE;
+virtual void Uniform1iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void Uniform2f(GLint location, GLfloat x, GLfloat y) OVERRIDE;
+virtual void Uniform2fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform2i(GLint location, GLint x, GLint y) OVERRIDE;
+virtual void Uniform2iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void Uniform3f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z) OVERRIDE;
+virtual void Uniform3fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform3i(GLint location, GLint x, GLint y, GLint z) OVERRIDE;
+virtual void Uniform3iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) OVERRIDE;
+virtual void Uniform4fv(
+ GLint location, GLsizei count, const GLfloat* v) OVERRIDE;
+virtual void Uniform4i(
+ GLint location, GLint x, GLint y, GLint z, GLint w) OVERRIDE;
+virtual void Uniform4iv(
+ GLint location, GLsizei count, const GLint* v) OVERRIDE;
+virtual void UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+virtual void UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+virtual void UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) OVERRIDE;
+virtual void UseProgram(GLuint program) OVERRIDE;
+virtual void ValidateProgram(GLuint program) OVERRIDE;
+virtual void VertexAttrib1f(GLuint indx, GLfloat x) OVERRIDE;
+virtual void VertexAttrib1fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttrib2f(GLuint indx, GLfloat x, GLfloat y) OVERRIDE;
+virtual void VertexAttrib2fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttrib3f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z) OVERRIDE;
+virtual void VertexAttrib3fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) OVERRIDE;
+virtual void VertexAttrib4fv(GLuint indx, const GLfloat* values) OVERRIDE;
+virtual void VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) OVERRIDE;
+virtual void Viewport(
+ GLint x, GLint y, GLsizei width, GLsizei height) OVERRIDE;
+virtual void BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask,
+ GLenum filter) OVERRIDE;
+virtual void RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) OVERRIDE;
+virtual void FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) OVERRIDE;
+virtual void TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) OVERRIDE;
+virtual void GenQueriesEXT(GLsizei n, GLuint* queries) OVERRIDE;
+virtual void DeleteQueriesEXT(GLsizei n, const GLuint* queries) OVERRIDE;
+virtual GLboolean IsQueryEXT(GLuint id) OVERRIDE;
+virtual void BeginQueryEXT(GLenum target, GLuint id) OVERRIDE;
+virtual void EndQueryEXT(GLenum target) OVERRIDE;
+virtual void GetQueryivEXT(
+ GLenum target, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetQueryObjectuivEXT(
+ GLuint id, GLenum pname, GLuint* params) OVERRIDE;
+virtual void InsertEventMarkerEXT(
+ GLsizei length, const GLchar* marker) OVERRIDE;
+virtual void PushGroupMarkerEXT(GLsizei length, const GLchar* marker) OVERRIDE;
+virtual void PopGroupMarkerEXT() OVERRIDE;
+virtual void GenVertexArraysOES(GLsizei n, GLuint* arrays) OVERRIDE;
+virtual void DeleteVertexArraysOES(GLsizei n, const GLuint* arrays) OVERRIDE;
+virtual GLboolean IsVertexArrayOES(GLuint array) OVERRIDE;
+virtual void BindVertexArrayOES(GLuint array) OVERRIDE;
+virtual void SwapBuffers() OVERRIDE;
+virtual GLuint GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) OVERRIDE;
+virtual void GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE;
+virtual void DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) OVERRIDE;
+virtual void RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) OVERRIDE;
+virtual GLboolean EnableFeatureCHROMIUM(const char* feature) OVERRIDE;
+virtual void* MapBufferCHROMIUM(GLuint target, GLenum access) OVERRIDE;
+virtual GLboolean UnmapBufferCHROMIUM(GLuint target) OVERRIDE;
+virtual void* MapImageCHROMIUM(GLuint image_id, GLenum access) OVERRIDE;
+virtual void UnmapImageCHROMIUM(GLuint image_id) OVERRIDE;
+virtual void* MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) OVERRIDE;
+virtual void UnmapBufferSubDataCHROMIUM(const void* mem) OVERRIDE;
+virtual void* MapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access) OVERRIDE;
+virtual void UnmapTexSubImage2DCHROMIUM(const void* mem) OVERRIDE;
+virtual void ResizeCHROMIUM(
+ GLuint width, GLuint height, GLfloat scale_factor) OVERRIDE;
+virtual const GLchar* GetRequestableExtensionsCHROMIUM() OVERRIDE;
+virtual void RequestExtensionCHROMIUM(const char* extension) OVERRIDE;
+virtual void RateLimitOffscreenContextCHROMIUM() OVERRIDE;
+virtual void GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results,
+ GLsizeiptr size) OVERRIDE;
+virtual void GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) OVERRIDE;
+virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) OVERRIDE;
+virtual void DestroyStreamTextureCHROMIUM(GLuint texture) OVERRIDE;
+virtual GLuint CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) OVERRIDE;
+virtual void DestroyImageCHROMIUM(GLuint image_id) OVERRIDE;
+virtual void GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) OVERRIDE;
+virtual void GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) OVERRIDE;
+virtual void PostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height) OVERRIDE;
+virtual void TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) OVERRIDE;
+virtual void CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) OVERRIDE;
+virtual void DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) OVERRIDE;
+virtual void DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) OVERRIDE;
+virtual void VertexAttribDivisorANGLE(GLuint index, GLuint divisor) OVERRIDE;
+virtual void GenMailboxCHROMIUM(GLbyte* mailbox) OVERRIDE;
+virtual void ProduceTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) OVERRIDE;
+virtual void ConsumeTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) OVERRIDE;
+virtual void BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) OVERRIDE;
+virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) OVERRIDE;
+virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) OVERRIDE;
+virtual void TraceBeginCHROMIUM(const char* name) OVERRIDE;
+virtual void TraceEndCHROMIUM() OVERRIDE;
+virtual void AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* data) OVERRIDE;
+virtual void AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) OVERRIDE;
+virtual void WaitAsyncTexImage2DCHROMIUM(GLenum target) OVERRIDE;
+virtual void DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) OVERRIDE;
+virtual void LoseContextCHROMIUM(GLenum current, GLenum other) OVERRIDE;
+virtual GLuint InsertSyncPointCHROMIUM() OVERRIDE;
+virtual void WaitSyncPointCHROMIUM(GLuint sync_point) OVERRIDE;
+virtual void DrawBuffersEXT(GLsizei count, const GLenum* bufs) OVERRIDE;
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/chromium/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
new file mode 100644
index 00000000000..1a2604a3974
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -0,0 +1,1233 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file is included by gles2_trace_implementation.cc
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
+
+void GLES2TraceImplementation::ActiveTexture(GLenum texture) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ActiveTexture");
+ gl_->ActiveTexture(texture);
+}
+
+void GLES2TraceImplementation::AttachShader(GLuint program, GLuint shader) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::AttachShader");
+ gl_->AttachShader(program, shader);
+}
+
+void GLES2TraceImplementation::BindAttribLocation(
+ GLuint program, GLuint index, const char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindAttribLocation");
+ gl_->BindAttribLocation(program, index, name);
+}
+
+void GLES2TraceImplementation::BindBuffer(GLenum target, GLuint buffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindBuffer");
+ gl_->BindBuffer(target, buffer);
+}
+
+void GLES2TraceImplementation::BindFramebuffer(
+ GLenum target, GLuint framebuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindFramebuffer");
+ gl_->BindFramebuffer(target, framebuffer);
+}
+
+void GLES2TraceImplementation::BindRenderbuffer(
+ GLenum target, GLuint renderbuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindRenderbuffer");
+ gl_->BindRenderbuffer(target, renderbuffer);
+}
+
+void GLES2TraceImplementation::BindTexture(GLenum target, GLuint texture) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTexture");
+ gl_->BindTexture(target, texture);
+}
+
+void GLES2TraceImplementation::BlendColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlendColor");
+ gl_->BlendColor(red, green, blue, alpha);
+}
+
+void GLES2TraceImplementation::BlendEquation(GLenum mode) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlendEquation");
+ gl_->BlendEquation(mode);
+}
+
+void GLES2TraceImplementation::BlendEquationSeparate(
+ GLenum modeRGB, GLenum modeAlpha) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlendEquationSeparate");
+ gl_->BlendEquationSeparate(modeRGB, modeAlpha);
+}
+
+void GLES2TraceImplementation::BlendFunc(GLenum sfactor, GLenum dfactor) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlendFunc");
+ gl_->BlendFunc(sfactor, dfactor);
+}
+
+void GLES2TraceImplementation::BlendFuncSeparate(
+ GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlendFuncSeparate");
+ gl_->BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+void GLES2TraceImplementation::BufferData(
+ GLenum target, GLsizeiptr size, const void* data, GLenum usage) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BufferData");
+ gl_->BufferData(target, size, data, usage);
+}
+
+void GLES2TraceImplementation::BufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const void* data) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BufferSubData");
+ gl_->BufferSubData(target, offset, size, data);
+}
+
+GLenum GLES2TraceImplementation::CheckFramebufferStatus(GLenum target) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CheckFramebufferStatus");
+ return gl_->CheckFramebufferStatus(target);
+}
+
+void GLES2TraceImplementation::Clear(GLbitfield mask) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Clear");
+ gl_->Clear(mask);
+}
+
+void GLES2TraceImplementation::ClearColor(
+ GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ClearColor");
+ gl_->ClearColor(red, green, blue, alpha);
+}
+
+void GLES2TraceImplementation::ClearDepthf(GLclampf depth) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ClearDepthf");
+ gl_->ClearDepthf(depth);
+}
+
+void GLES2TraceImplementation::ClearStencil(GLint s) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ClearStencil");
+ gl_->ClearStencil(s);
+}
+
+void GLES2TraceImplementation::ColorMask(
+ GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ColorMask");
+ gl_->ColorMask(red, green, blue, alpha);
+}
+
+void GLES2TraceImplementation::CompileShader(GLuint shader) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CompileShader");
+ gl_->CompileShader(shader);
+}
+
+void GLES2TraceImplementation::CompressedTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLsizei width,
+ GLsizei height, GLint border, GLsizei imageSize, const void* data) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CompressedTexImage2D");
+ gl_->CompressedTexImage2D(
+ target, level, internalformat, width, height, border, imageSize, data);
+}
+
+void GLES2TraceImplementation::CompressedTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLsizei imageSize, const void* data) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CompressedTexSubImage2D");
+ gl_->CompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+}
+
+void GLES2TraceImplementation::CopyTexImage2D(
+ GLenum target, GLint level, GLenum internalformat, GLint x, GLint y,
+ GLsizei width, GLsizei height, GLint border) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CopyTexImage2D");
+ gl_->CopyTexImage2D(
+ target, level, internalformat, x, y, width, height, border);
+}
+
+void GLES2TraceImplementation::CopyTexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y,
+ GLsizei width, GLsizei height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CopyTexSubImage2D");
+ gl_->CopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+}
+
+GLuint GLES2TraceImplementation::CreateProgram() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CreateProgram");
+ return gl_->CreateProgram();
+}
+
+GLuint GLES2TraceImplementation::CreateShader(GLenum type) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CreateShader");
+ return gl_->CreateShader(type);
+}
+
+void GLES2TraceImplementation::CullFace(GLenum mode) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CullFace");
+ gl_->CullFace(mode);
+}
+
+void GLES2TraceImplementation::DeleteBuffers(
+ GLsizei n, const GLuint* buffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteBuffers");
+ gl_->DeleteBuffers(n, buffers);
+}
+
+void GLES2TraceImplementation::DeleteFramebuffers(
+ GLsizei n, const GLuint* framebuffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteFramebuffers");
+ gl_->DeleteFramebuffers(n, framebuffers);
+}
+
+void GLES2TraceImplementation::DeleteProgram(GLuint program) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteProgram");
+ gl_->DeleteProgram(program);
+}
+
+void GLES2TraceImplementation::DeleteRenderbuffers(
+ GLsizei n, const GLuint* renderbuffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteRenderbuffers");
+ gl_->DeleteRenderbuffers(n, renderbuffers);
+}
+
+void GLES2TraceImplementation::DeleteShader(GLuint shader) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteShader");
+ gl_->DeleteShader(shader);
+}
+
+void GLES2TraceImplementation::DeleteTextures(
+ GLsizei n, const GLuint* textures) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteTextures");
+ gl_->DeleteTextures(n, textures);
+}
+
+void GLES2TraceImplementation::DepthFunc(GLenum func) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DepthFunc");
+ gl_->DepthFunc(func);
+}
+
+void GLES2TraceImplementation::DepthMask(GLboolean flag) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DepthMask");
+ gl_->DepthMask(flag);
+}
+
+void GLES2TraceImplementation::DepthRangef(GLclampf zNear, GLclampf zFar) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DepthRangef");
+ gl_->DepthRangef(zNear, zFar);
+}
+
+void GLES2TraceImplementation::DetachShader(GLuint program, GLuint shader) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DetachShader");
+ gl_->DetachShader(program, shader);
+}
+
+void GLES2TraceImplementation::Disable(GLenum cap) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Disable");
+ gl_->Disable(cap);
+}
+
+void GLES2TraceImplementation::DisableVertexAttribArray(GLuint index) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DisableVertexAttribArray");
+ gl_->DisableVertexAttribArray(index);
+}
+
+void GLES2TraceImplementation::DrawArrays(
+ GLenum mode, GLint first, GLsizei count) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DrawArrays");
+ gl_->DrawArrays(mode, first, count);
+}
+
+void GLES2TraceImplementation::DrawElements(
+ GLenum mode, GLsizei count, GLenum type, const void* indices) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DrawElements");
+ gl_->DrawElements(mode, count, type, indices);
+}
+
+void GLES2TraceImplementation::Enable(GLenum cap) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Enable");
+ gl_->Enable(cap);
+}
+
+void GLES2TraceImplementation::EnableVertexAttribArray(GLuint index) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EnableVertexAttribArray");
+ gl_->EnableVertexAttribArray(index);
+}
+
+void GLES2TraceImplementation::Finish() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Finish");
+ gl_->Finish();
+}
+
+void GLES2TraceImplementation::Flush() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Flush");
+ gl_->Flush();
+}
+
+void GLES2TraceImplementation::FramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::FramebufferRenderbuffer");
+ gl_->FramebufferRenderbuffer(
+ target, attachment, renderbuffertarget, renderbuffer);
+}
+
+void GLES2TraceImplementation::FramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::FramebufferTexture2D");
+ gl_->FramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+void GLES2TraceImplementation::FrontFace(GLenum mode) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::FrontFace");
+ gl_->FrontFace(mode);
+}
+
+void GLES2TraceImplementation::GenBuffers(GLsizei n, GLuint* buffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenBuffers");
+ gl_->GenBuffers(n, buffers);
+}
+
+void GLES2TraceImplementation::GenerateMipmap(GLenum target) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenerateMipmap");
+ gl_->GenerateMipmap(target);
+}
+
+void GLES2TraceImplementation::GenFramebuffers(
+ GLsizei n, GLuint* framebuffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenFramebuffers");
+ gl_->GenFramebuffers(n, framebuffers);
+}
+
+void GLES2TraceImplementation::GenRenderbuffers(
+ GLsizei n, GLuint* renderbuffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenRenderbuffers");
+ gl_->GenRenderbuffers(n, renderbuffers);
+}
+
+void GLES2TraceImplementation::GenTextures(GLsizei n, GLuint* textures) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenTextures");
+ gl_->GenTextures(n, textures);
+}
+
+void GLES2TraceImplementation::GetActiveAttrib(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetActiveAttrib");
+ gl_->GetActiveAttrib(program, index, bufsize, length, size, type, name);
+}
+
+void GLES2TraceImplementation::GetActiveUniform(
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size,
+ GLenum* type, char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetActiveUniform");
+ gl_->GetActiveUniform(program, index, bufsize, length, size, type, name);
+}
+
+void GLES2TraceImplementation::GetAttachedShaders(
+ GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetAttachedShaders");
+ gl_->GetAttachedShaders(program, maxcount, count, shaders);
+}
+
+GLint GLES2TraceImplementation::GetAttribLocation(
+ GLuint program, const char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetAttribLocation");
+ return gl_->GetAttribLocation(program, name);
+}
+
+void GLES2TraceImplementation::GetBooleanv(GLenum pname, GLboolean* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetBooleanv");
+ gl_->GetBooleanv(pname, params);
+}
+
+void GLES2TraceImplementation::GetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetBufferParameteriv");
+ gl_->GetBufferParameteriv(target, pname, params);
+}
+
+GLenum GLES2TraceImplementation::GetError() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetError");
+ return gl_->GetError();
+}
+
+void GLES2TraceImplementation::GetFloatv(GLenum pname, GLfloat* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetFloatv");
+ gl_->GetFloatv(pname, params);
+}
+
+void GLES2TraceImplementation::GetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetFramebufferAttachmentParameteriv"); // NOLINT
+ gl_->GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+}
+
+void GLES2TraceImplementation::GetIntegerv(GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetIntegerv");
+ gl_->GetIntegerv(pname, params);
+}
+
+void GLES2TraceImplementation::GetProgramiv(
+ GLuint program, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetProgramiv");
+ gl_->GetProgramiv(program, pname, params);
+}
+
+void GLES2TraceImplementation::GetProgramInfoLog(
+ GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetProgramInfoLog");
+ gl_->GetProgramInfoLog(program, bufsize, length, infolog);
+}
+
+void GLES2TraceImplementation::GetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetRenderbufferParameteriv"); // NOLINT
+ gl_->GetRenderbufferParameteriv(target, pname, params);
+}
+
+void GLES2TraceImplementation::GetShaderiv(
+ GLuint shader, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetShaderiv");
+ gl_->GetShaderiv(shader, pname, params);
+}
+
+void GLES2TraceImplementation::GetShaderInfoLog(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetShaderInfoLog");
+ gl_->GetShaderInfoLog(shader, bufsize, length, infolog);
+}
+
+void GLES2TraceImplementation::GetShaderPrecisionFormat(
+ GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetShaderPrecisionFormat");
+ gl_->GetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
+}
+
+void GLES2TraceImplementation::GetShaderSource(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetShaderSource");
+ gl_->GetShaderSource(shader, bufsize, length, source);
+}
+
+const GLubyte* GLES2TraceImplementation::GetString(GLenum name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetString");
+ return gl_->GetString(name);
+}
+
+void GLES2TraceImplementation::GetTexParameterfv(
+ GLenum target, GLenum pname, GLfloat* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetTexParameterfv");
+ gl_->GetTexParameterfv(target, pname, params);
+}
+
+void GLES2TraceImplementation::GetTexParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetTexParameteriv");
+ gl_->GetTexParameteriv(target, pname, params);
+}
+
+void GLES2TraceImplementation::GetUniformfv(
+ GLuint program, GLint location, GLfloat* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformfv");
+ gl_->GetUniformfv(program, location, params);
+}
+
+void GLES2TraceImplementation::GetUniformiv(
+ GLuint program, GLint location, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformiv");
+ gl_->GetUniformiv(program, location, params);
+}
+
+GLint GLES2TraceImplementation::GetUniformLocation(
+ GLuint program, const char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetUniformLocation");
+ return gl_->GetUniformLocation(program, name);
+}
+
+void GLES2TraceImplementation::GetVertexAttribfv(
+ GLuint index, GLenum pname, GLfloat* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetVertexAttribfv");
+ gl_->GetVertexAttribfv(index, pname, params);
+}
+
+void GLES2TraceImplementation::GetVertexAttribiv(
+ GLuint index, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetVertexAttribiv");
+ gl_->GetVertexAttribiv(index, pname, params);
+}
+
+void GLES2TraceImplementation::GetVertexAttribPointerv(
+ GLuint index, GLenum pname, void** pointer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetVertexAttribPointerv");
+ gl_->GetVertexAttribPointerv(index, pname, pointer);
+}
+
+void GLES2TraceImplementation::Hint(GLenum target, GLenum mode) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Hint");
+ gl_->Hint(target, mode);
+}
+
+GLboolean GLES2TraceImplementation::IsBuffer(GLuint buffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsBuffer");
+ return gl_->IsBuffer(buffer);
+}
+
+GLboolean GLES2TraceImplementation::IsEnabled(GLenum cap) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsEnabled");
+ return gl_->IsEnabled(cap);
+}
+
+GLboolean GLES2TraceImplementation::IsFramebuffer(GLuint framebuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsFramebuffer");
+ return gl_->IsFramebuffer(framebuffer);
+}
+
+GLboolean GLES2TraceImplementation::IsProgram(GLuint program) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsProgram");
+ return gl_->IsProgram(program);
+}
+
+GLboolean GLES2TraceImplementation::IsRenderbuffer(GLuint renderbuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsRenderbuffer");
+ return gl_->IsRenderbuffer(renderbuffer);
+}
+
+GLboolean GLES2TraceImplementation::IsShader(GLuint shader) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsShader");
+ return gl_->IsShader(shader);
+}
+
+GLboolean GLES2TraceImplementation::IsTexture(GLuint texture) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsTexture");
+ return gl_->IsTexture(texture);
+}
+
+void GLES2TraceImplementation::LineWidth(GLfloat width) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::LineWidth");
+ gl_->LineWidth(width);
+}
+
+void GLES2TraceImplementation::LinkProgram(GLuint program) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::LinkProgram");
+ gl_->LinkProgram(program);
+}
+
+void GLES2TraceImplementation::PixelStorei(GLenum pname, GLint param) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PixelStorei");
+ gl_->PixelStorei(pname, param);
+}
+
+void GLES2TraceImplementation::PolygonOffset(GLfloat factor, GLfloat units) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PolygonOffset");
+ gl_->PolygonOffset(factor, units);
+}
+
+void GLES2TraceImplementation::ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type,
+ void* pixels) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ReadPixels");
+ gl_->ReadPixels(x, y, width, height, format, type, pixels);
+}
+
+void GLES2TraceImplementation::ReleaseShaderCompiler() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ReleaseShaderCompiler");
+ gl_->ReleaseShaderCompiler();
+}
+
+void GLES2TraceImplementation::RenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::RenderbufferStorage");
+ gl_->RenderbufferStorage(target, internalformat, width, height);
+}
+
+void GLES2TraceImplementation::SampleCoverage(
+ GLclampf value, GLboolean invert) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SampleCoverage");
+ gl_->SampleCoverage(value, invert);
+}
+
+void GLES2TraceImplementation::Scissor(
+ GLint x, GLint y, GLsizei width, GLsizei height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Scissor");
+ gl_->Scissor(x, y, width, height);
+}
+
+void GLES2TraceImplementation::ShaderBinary(
+ GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary,
+ GLsizei length) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ShaderBinary");
+ gl_->ShaderBinary(n, shaders, binaryformat, binary, length);
+}
+
+void GLES2TraceImplementation::ShaderSource(
+ GLuint shader, GLsizei count, const GLchar* const* str,
+ const GLint* length) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ShaderSource");
+ gl_->ShaderSource(shader, count, str, length);
+}
+
+void GLES2TraceImplementation::ShallowFinishCHROMIUM() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ShallowFinishCHROMIUM");
+ gl_->ShallowFinishCHROMIUM();
+}
+
+void GLES2TraceImplementation::ShallowFlushCHROMIUM() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ShallowFlushCHROMIUM");
+ gl_->ShallowFlushCHROMIUM();
+}
+
+void GLES2TraceImplementation::StencilFunc(
+ GLenum func, GLint ref, GLuint mask) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilFunc");
+ gl_->StencilFunc(func, ref, mask);
+}
+
+void GLES2TraceImplementation::StencilFuncSeparate(
+ GLenum face, GLenum func, GLint ref, GLuint mask) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilFuncSeparate");
+ gl_->StencilFuncSeparate(face, func, ref, mask);
+}
+
+void GLES2TraceImplementation::StencilMask(GLuint mask) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilMask");
+ gl_->StencilMask(mask);
+}
+
+void GLES2TraceImplementation::StencilMaskSeparate(GLenum face, GLuint mask) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilMaskSeparate");
+ gl_->StencilMaskSeparate(face, mask);
+}
+
+void GLES2TraceImplementation::StencilOp(
+ GLenum fail, GLenum zfail, GLenum zpass) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilOp");
+ gl_->StencilOp(fail, zfail, zpass);
+}
+
+void GLES2TraceImplementation::StencilOpSeparate(
+ GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::StencilOpSeparate");
+ gl_->StencilOpSeparate(face, fail, zfail, zpass);
+}
+
+void GLES2TraceImplementation::TexImage2D(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexImage2D");
+ gl_->TexImage2D(
+ target, level, internalformat, width, height, border, format, type,
+ pixels);
+}
+
+void GLES2TraceImplementation::TexParameterf(
+ GLenum target, GLenum pname, GLfloat param) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexParameterf");
+ gl_->TexParameterf(target, pname, param);
+}
+
+void GLES2TraceImplementation::TexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexParameterfv");
+ gl_->TexParameterfv(target, pname, params);
+}
+
+void GLES2TraceImplementation::TexParameteri(
+ GLenum target, GLenum pname, GLint param) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexParameteri");
+ gl_->TexParameteri(target, pname, param);
+}
+
+void GLES2TraceImplementation::TexParameteriv(
+ GLenum target, GLenum pname, const GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexParameteriv");
+ gl_->TexParameteriv(target, pname, params);
+}
+
+void GLES2TraceImplementation::TexSubImage2D(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* pixels) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexSubImage2D");
+ gl_->TexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+void GLES2TraceImplementation::Uniform1f(GLint location, GLfloat x) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform1f");
+ gl_->Uniform1f(location, x);
+}
+
+void GLES2TraceImplementation::Uniform1fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform1fv");
+ gl_->Uniform1fv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform1i(GLint location, GLint x) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform1i");
+ gl_->Uniform1i(location, x);
+}
+
+void GLES2TraceImplementation::Uniform1iv(
+ GLint location, GLsizei count, const GLint* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform1iv");
+ gl_->Uniform1iv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform2f(
+ GLint location, GLfloat x, GLfloat y) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform2f");
+ gl_->Uniform2f(location, x, y);
+}
+
+void GLES2TraceImplementation::Uniform2fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform2fv");
+ gl_->Uniform2fv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform2i(GLint location, GLint x, GLint y) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform2i");
+ gl_->Uniform2i(location, x, y);
+}
+
+void GLES2TraceImplementation::Uniform2iv(
+ GLint location, GLsizei count, const GLint* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform2iv");
+ gl_->Uniform2iv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform3f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform3f");
+ gl_->Uniform3f(location, x, y, z);
+}
+
+void GLES2TraceImplementation::Uniform3fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform3fv");
+ gl_->Uniform3fv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform3i(
+ GLint location, GLint x, GLint y, GLint z) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform3i");
+ gl_->Uniform3i(location, x, y, z);
+}
+
+void GLES2TraceImplementation::Uniform3iv(
+ GLint location, GLsizei count, const GLint* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform3iv");
+ gl_->Uniform3iv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform4f(
+ GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform4f");
+ gl_->Uniform4f(location, x, y, z, w);
+}
+
+void GLES2TraceImplementation::Uniform4fv(
+ GLint location, GLsizei count, const GLfloat* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform4fv");
+ gl_->Uniform4fv(location, count, v);
+}
+
+void GLES2TraceImplementation::Uniform4i(
+ GLint location, GLint x, GLint y, GLint z, GLint w) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform4i");
+ gl_->Uniform4i(location, x, y, z, w);
+}
+
+void GLES2TraceImplementation::Uniform4iv(
+ GLint location, GLsizei count, const GLint* v) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Uniform4iv");
+ gl_->Uniform4iv(location, count, v);
+}
+
+void GLES2TraceImplementation::UniformMatrix2fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UniformMatrix2fv");
+ gl_->UniformMatrix2fv(location, count, transpose, value);
+}
+
+void GLES2TraceImplementation::UniformMatrix3fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UniformMatrix3fv");
+ gl_->UniformMatrix3fv(location, count, transpose, value);
+}
+
+void GLES2TraceImplementation::UniformMatrix4fv(
+ GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UniformMatrix4fv");
+ gl_->UniformMatrix4fv(location, count, transpose, value);
+}
+
+void GLES2TraceImplementation::UseProgram(GLuint program) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UseProgram");
+ gl_->UseProgram(program);
+}
+
+void GLES2TraceImplementation::ValidateProgram(GLuint program) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ValidateProgram");
+ gl_->ValidateProgram(program);
+}
+
+void GLES2TraceImplementation::VertexAttrib1f(GLuint indx, GLfloat x) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib1f");
+ gl_->VertexAttrib1f(indx, x);
+}
+
+void GLES2TraceImplementation::VertexAttrib1fv(
+ GLuint indx, const GLfloat* values) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib1fv");
+ gl_->VertexAttrib1fv(indx, values);
+}
+
+void GLES2TraceImplementation::VertexAttrib2f(
+ GLuint indx, GLfloat x, GLfloat y) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib2f");
+ gl_->VertexAttrib2f(indx, x, y);
+}
+
+void GLES2TraceImplementation::VertexAttrib2fv(
+ GLuint indx, const GLfloat* values) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib2fv");
+ gl_->VertexAttrib2fv(indx, values);
+}
+
+void GLES2TraceImplementation::VertexAttrib3f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib3f");
+ gl_->VertexAttrib3f(indx, x, y, z);
+}
+
+void GLES2TraceImplementation::VertexAttrib3fv(
+ GLuint indx, const GLfloat* values) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib3fv");
+ gl_->VertexAttrib3fv(indx, values);
+}
+
+void GLES2TraceImplementation::VertexAttrib4f(
+ GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib4f");
+ gl_->VertexAttrib4f(indx, x, y, z, w);
+}
+
+void GLES2TraceImplementation::VertexAttrib4fv(
+ GLuint indx, const GLfloat* values) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttrib4fv");
+ gl_->VertexAttrib4fv(indx, values);
+}
+
+void GLES2TraceImplementation::VertexAttribPointer(
+ GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttribPointer");
+ gl_->VertexAttribPointer(indx, size, type, normalized, stride, ptr);
+}
+
+void GLES2TraceImplementation::Viewport(
+ GLint x, GLint y, GLsizei width, GLsizei height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::Viewport");
+ gl_->Viewport(x, y, width, height);
+}
+
+void GLES2TraceImplementation::BlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0,
+ GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BlitFramebufferEXT");
+ gl_->BlitFramebufferEXT(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+}
+
+void GLES2TraceImplementation::RenderbufferStorageMultisampleEXT(
+ GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,
+ GLsizei height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::RenderbufferStorageMultisampleEXT"); // NOLINT
+ gl_->RenderbufferStorageMultisampleEXT(
+ target, samples, internalformat, width, height);
+}
+
+void GLES2TraceImplementation::FramebufferTexture2DMultisampleEXT(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level, GLsizei samples) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::FramebufferTexture2DMultisampleEXT"); // NOLINT
+ gl_->FramebufferTexture2DMultisampleEXT(
+ target, attachment, textarget, texture, level, samples);
+}
+
+void GLES2TraceImplementation::TexStorage2DEXT(
+ GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width,
+ GLsizei height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexStorage2DEXT");
+ gl_->TexStorage2DEXT(target, levels, internalFormat, width, height);
+}
+
+void GLES2TraceImplementation::GenQueriesEXT(GLsizei n, GLuint* queries) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenQueriesEXT");
+ gl_->GenQueriesEXT(n, queries);
+}
+
+void GLES2TraceImplementation::DeleteQueriesEXT(
+ GLsizei n, const GLuint* queries) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteQueriesEXT");
+ gl_->DeleteQueriesEXT(n, queries);
+}
+
+GLboolean GLES2TraceImplementation::IsQueryEXT(GLuint id) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsQueryEXT");
+ return gl_->IsQueryEXT(id);
+}
+
+void GLES2TraceImplementation::BeginQueryEXT(GLenum target, GLuint id) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BeginQueryEXT");
+ gl_->BeginQueryEXT(target, id);
+}
+
+void GLES2TraceImplementation::EndQueryEXT(GLenum target) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EndQueryEXT");
+ gl_->EndQueryEXT(target);
+}
+
+void GLES2TraceImplementation::GetQueryivEXT(
+ GLenum target, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetQueryivEXT");
+ gl_->GetQueryivEXT(target, pname, params);
+}
+
+void GLES2TraceImplementation::GetQueryObjectuivEXT(
+ GLuint id, GLenum pname, GLuint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetQueryObjectuivEXT");
+ gl_->GetQueryObjectuivEXT(id, pname, params);
+}
+
+void GLES2TraceImplementation::InsertEventMarkerEXT(
+ GLsizei length, const GLchar* marker) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::InsertEventMarkerEXT");
+ gl_->InsertEventMarkerEXT(length, marker);
+}
+
+void GLES2TraceImplementation::PushGroupMarkerEXT(
+ GLsizei length, const GLchar* marker) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PushGroupMarkerEXT");
+ gl_->PushGroupMarkerEXT(length, marker);
+}
+
+void GLES2TraceImplementation::PopGroupMarkerEXT() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PopGroupMarkerEXT");
+ gl_->PopGroupMarkerEXT();
+}
+
+void GLES2TraceImplementation::GenVertexArraysOES(GLsizei n, GLuint* arrays) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenVertexArraysOES");
+ gl_->GenVertexArraysOES(n, arrays);
+}
+
+void GLES2TraceImplementation::DeleteVertexArraysOES(
+ GLsizei n, const GLuint* arrays) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteVertexArraysOES");
+ gl_->DeleteVertexArraysOES(n, arrays);
+}
+
+GLboolean GLES2TraceImplementation::IsVertexArrayOES(GLuint array) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsVertexArrayOES");
+ return gl_->IsVertexArrayOES(array);
+}
+
+void GLES2TraceImplementation::BindVertexArrayOES(GLuint array) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindVertexArrayOES");
+ gl_->BindVertexArrayOES(array);
+}
+
+void GLES2TraceImplementation::SwapBuffers() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SwapBuffers");
+ gl_->SwapBuffers();
+}
+
+GLuint GLES2TraceImplementation::GetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetMaxValueInBufferCHROMIUM"); // NOLINT
+ return gl_->GetMaxValueInBufferCHROMIUM(buffer_id, count, type, offset);
+}
+
+void GLES2TraceImplementation::GenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenSharedIdsCHROMIUM");
+ gl_->GenSharedIdsCHROMIUM(namespace_id, id_offset, n, ids);
+}
+
+void GLES2TraceImplementation::DeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DeleteSharedIdsCHROMIUM");
+ gl_->DeleteSharedIdsCHROMIUM(namespace_id, n, ids);
+}
+
+void GLES2TraceImplementation::RegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::RegisterSharedIdsCHROMIUM");
+ gl_->RegisterSharedIdsCHROMIUM(namespace_id, n, ids);
+}
+
+GLboolean GLES2TraceImplementation::EnableFeatureCHROMIUM(
+ const char* feature) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::EnableFeatureCHROMIUM");
+ return gl_->EnableFeatureCHROMIUM(feature);
+}
+
+void* GLES2TraceImplementation::MapBufferCHROMIUM(
+ GLuint target, GLenum access) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapBufferCHROMIUM");
+ return gl_->MapBufferCHROMIUM(target, access);
+}
+
+GLboolean GLES2TraceImplementation::UnmapBufferCHROMIUM(GLuint target) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapBufferCHROMIUM");
+ return gl_->UnmapBufferCHROMIUM(target);
+}
+
+void* GLES2TraceImplementation::MapImageCHROMIUM(
+ GLuint image_id, GLenum access) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapImageCHROMIUM");
+ return gl_->MapImageCHROMIUM(image_id, access);
+}
+
+void GLES2TraceImplementation::UnmapImageCHROMIUM(GLuint image_id) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapImageCHROMIUM");
+ gl_->UnmapImageCHROMIUM(image_id);
+}
+
+void* GLES2TraceImplementation::MapBufferSubDataCHROMIUM(
+ GLuint target, GLintptr offset, GLsizeiptr size, GLenum access) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapBufferSubDataCHROMIUM");
+ return gl_->MapBufferSubDataCHROMIUM(target, offset, size, access);
+}
+
+void GLES2TraceImplementation::UnmapBufferSubDataCHROMIUM(const void* mem) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapBufferSubDataCHROMIUM"); // NOLINT
+ gl_->UnmapBufferSubDataCHROMIUM(mem);
+}
+
+void* GLES2TraceImplementation::MapTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, GLenum access) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::MapTexSubImage2DCHROMIUM");
+ return gl_->MapTexSubImage2DCHROMIUM(
+ target, level, xoffset, yoffset, width, height, format, type, access);
+}
+
+void GLES2TraceImplementation::UnmapTexSubImage2DCHROMIUM(const void* mem) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::UnmapTexSubImage2DCHROMIUM"); // NOLINT
+ gl_->UnmapTexSubImage2DCHROMIUM(mem);
+}
+
+void GLES2TraceImplementation::ResizeCHROMIUM(
+ GLuint width, GLuint height, GLfloat scale_factor) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ResizeCHROMIUM");
+ gl_->ResizeCHROMIUM(width, height, scale_factor);
+}
+
+const GLchar* GLES2TraceImplementation::GetRequestableExtensionsCHROMIUM() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetRequestableExtensionsCHROMIUM"); // NOLINT
+ return gl_->GetRequestableExtensionsCHROMIUM();
+}
+
+void GLES2TraceImplementation::RequestExtensionCHROMIUM(
+ const char* extension) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::RequestExtensionCHROMIUM");
+ gl_->RequestExtensionCHROMIUM(extension);
+}
+
+void GLES2TraceImplementation::RateLimitOffscreenContextCHROMIUM() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::RateLimitOffscreenContextCHROMIUM"); // NOLINT
+ gl_->RateLimitOffscreenContextCHROMIUM();
+}
+
+void GLES2TraceImplementation::GetMultipleIntegervCHROMIUM(
+ const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetMultipleIntegervCHROMIUM"); // NOLINT
+ gl_->GetMultipleIntegervCHROMIUM(pnames, count, results, size);
+}
+
+void GLES2TraceImplementation::GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetProgramInfoCHROMIUM");
+ gl_->GetProgramInfoCHROMIUM(program, bufsize, size, info);
+}
+
+GLuint GLES2TraceImplementation::CreateStreamTextureCHROMIUM(GLuint texture) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CreateStreamTextureCHROMIUM"); // NOLINT
+ return gl_->CreateStreamTextureCHROMIUM(texture);
+}
+
+void GLES2TraceImplementation::DestroyStreamTextureCHROMIUM(GLuint texture) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DestroyStreamTextureCHROMIUM"); // NOLINT
+ gl_->DestroyStreamTextureCHROMIUM(texture);
+}
+
+GLuint GLES2TraceImplementation::CreateImageCHROMIUM(
+ GLsizei width, GLsizei height, GLenum internalformat) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CreateImageCHROMIUM");
+ return gl_->CreateImageCHROMIUM(width, height, internalformat);
+}
+
+void GLES2TraceImplementation::DestroyImageCHROMIUM(GLuint image_id) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DestroyImageCHROMIUM");
+ gl_->DestroyImageCHROMIUM(image_id);
+}
+
+void GLES2TraceImplementation::GetImageParameterivCHROMIUM(
+ GLuint image_id, GLenum pname, GLint* params) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetImageParameterivCHROMIUM"); // NOLINT
+ gl_->GetImageParameterivCHROMIUM(image_id, pname, params);
+}
+
+void GLES2TraceImplementation::GetTranslatedShaderSourceANGLE(
+ GLuint shader, GLsizei bufsize, GLsizei* length, char* source) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetTranslatedShaderSourceANGLE"); // NOLINT
+ gl_->GetTranslatedShaderSourceANGLE(shader, bufsize, length, source);
+}
+
+void GLES2TraceImplementation::PostSubBufferCHROMIUM(
+ GLint x, GLint y, GLint width, GLint height) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::PostSubBufferCHROMIUM");
+ gl_->PostSubBufferCHROMIUM(x, y, width, height);
+}
+
+void GLES2TraceImplementation::TexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height, GLuint ioSurfaceId,
+ GLuint plane) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TexImageIOSurface2DCHROMIUM"); // NOLINT
+ gl_->TexImageIOSurface2DCHROMIUM(target, width, height, ioSurfaceId, plane);
+}
+
+void GLES2TraceImplementation::CopyTextureCHROMIUM(
+ GLenum target, GLenum source_id, GLenum dest_id, GLint level,
+ GLint internalformat, GLenum dest_type) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::CopyTextureCHROMIUM");
+ gl_->CopyTextureCHROMIUM(
+ target, source_id, dest_id, level, internalformat, dest_type);
+}
+
+void GLES2TraceImplementation::DrawArraysInstancedANGLE(
+ GLenum mode, GLint first, GLsizei count, GLsizei primcount) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DrawArraysInstancedANGLE");
+ gl_->DrawArraysInstancedANGLE(mode, first, count, primcount);
+}
+
+void GLES2TraceImplementation::DrawElementsInstancedANGLE(
+ GLenum mode, GLsizei count, GLenum type, const void* indices,
+ GLsizei primcount) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DrawElementsInstancedANGLE"); // NOLINT
+ gl_->DrawElementsInstancedANGLE(mode, count, type, indices, primcount);
+}
+
+void GLES2TraceImplementation::VertexAttribDivisorANGLE(
+ GLuint index, GLuint divisor) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::VertexAttribDivisorANGLE");
+ gl_->VertexAttribDivisorANGLE(index, divisor);
+}
+
+void GLES2TraceImplementation::GenMailboxCHROMIUM(GLbyte* mailbox) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenMailboxCHROMIUM");
+ gl_->GenMailboxCHROMIUM(mailbox);
+}
+
+void GLES2TraceImplementation::ProduceTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ProduceTextureCHROMIUM");
+ gl_->ProduceTextureCHROMIUM(target, mailbox);
+}
+
+void GLES2TraceImplementation::ConsumeTextureCHROMIUM(
+ GLenum target, const GLbyte* mailbox) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ConsumeTextureCHROMIUM");
+ gl_->ConsumeTextureCHROMIUM(target, mailbox);
+}
+
+void GLES2TraceImplementation::BindUniformLocationCHROMIUM(
+ GLuint program, GLint location, const char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindUniformLocationCHROMIUM"); // NOLINT
+ gl_->BindUniformLocationCHROMIUM(program, location, name);
+}
+
+void GLES2TraceImplementation::BindTexImage2DCHROMIUM(
+ GLenum target, GLint imageId) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTexImage2DCHROMIUM");
+ gl_->BindTexImage2DCHROMIUM(target, imageId);
+}
+
+void GLES2TraceImplementation::ReleaseTexImage2DCHROMIUM(
+ GLenum target, GLint imageId) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ReleaseTexImage2DCHROMIUM");
+ gl_->ReleaseTexImage2DCHROMIUM(target, imageId);
+}
+
+void GLES2TraceImplementation::TraceBeginCHROMIUM(const char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TraceBeginCHROMIUM");
+ gl_->TraceBeginCHROMIUM(name);
+}
+
+void GLES2TraceImplementation::TraceEndCHROMIUM() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::TraceEndCHROMIUM");
+ gl_->TraceEndCHROMIUM();
+}
+
+void GLES2TraceImplementation::AsyncTexSubImage2DCHROMIUM(
+ GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width,
+ GLsizei height, GLenum format, GLenum type, const void* data) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::AsyncTexSubImage2DCHROMIUM"); // NOLINT
+ gl_->AsyncTexSubImage2DCHROMIUM(
+ target, level, xoffset, yoffset, width, height, format, type, data);
+}
+
+void GLES2TraceImplementation::AsyncTexImage2DCHROMIUM(
+ GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::AsyncTexImage2DCHROMIUM");
+ gl_->AsyncTexImage2DCHROMIUM(
+ target, level, internalformat, width, height, border, format, type,
+ pixels);
+}
+
+void GLES2TraceImplementation::WaitAsyncTexImage2DCHROMIUM(GLenum target) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::WaitAsyncTexImage2DCHROMIUM"); // NOLINT
+ gl_->WaitAsyncTexImage2DCHROMIUM(target);
+}
+
+void GLES2TraceImplementation::DiscardFramebufferEXT(
+ GLenum target, GLsizei count, const GLenum* attachments) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DiscardFramebufferEXT");
+ gl_->DiscardFramebufferEXT(target, count, attachments);
+}
+
+void GLES2TraceImplementation::LoseContextCHROMIUM(
+ GLenum current, GLenum other) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::LoseContextCHROMIUM");
+ gl_->LoseContextCHROMIUM(current, other);
+}
+
+GLuint GLES2TraceImplementation::InsertSyncPointCHROMIUM() {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::InsertSyncPointCHROMIUM");
+ return gl_->InsertSyncPointCHROMIUM();
+}
+
+void GLES2TraceImplementation::WaitSyncPointCHROMIUM(GLuint sync_point) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::WaitSyncPointCHROMIUM");
+ gl_->WaitSyncPointCHROMIUM(sync_point);
+}
+
+void GLES2TraceImplementation::DrawBuffersEXT(
+ GLsizei count, const GLenum* bufs) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::DrawBuffersEXT");
+ gl_->DrawBuffersEXT(count, bufs);
+}
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/client/gpu_memory_buffer_factory.h b/chromium/gpu/command_buffer/client/gpu_memory_buffer_factory.h
new file mode 100644
index 00000000000..42dde409eaf
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gpu_memory_buffer_factory.h
@@ -0,0 +1,29 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_FACTORY_BUFFER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_FACTORY_BUFFER_H_
+
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
+namespace gpu {
+
+class GPU_EXPORT GpuMemoryBufferFactory {
+ public:
+ virtual gfx::GpuMemoryBuffer* CreateGpuMemoryBuffer(
+ size_t width,
+ size_t height,
+ unsigned internalformat) = 0;
+
+ protected:
+ virtual ~GpuMemoryBufferFactory() {}
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_FACTORY_H_
diff --git a/chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc b/chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
new file mode 100644
index 00000000000..c1c9b4d63c7
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/gpu_memory_buffer_tracker.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/image_factory.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace gpu {
+namespace gles2 {
+
+GpuMemoryBufferTracker::GpuMemoryBufferTracker(ImageFactory* factory)
+ : buffers_(),
+ factory_(factory) {
+}
+
+GpuMemoryBufferTracker::~GpuMemoryBufferTracker() {
+ while (!buffers_.empty()) {
+ RemoveBuffer(buffers_.begin()->first);
+ }
+}
+
+GLuint GpuMemoryBufferTracker::CreateBuffer(
+ GLsizei width, GLsizei height, GLenum internalformat) {
+ GLuint image_id = 0;
+ DCHECK(factory_);
+ scoped_ptr<gfx::GpuMemoryBuffer> buffer =
+ factory_->CreateGpuMemoryBuffer(width, height, internalformat, &image_id);
+
+ if (buffer.get() == NULL)
+ return 0;
+
+ std::pair<BufferMap::iterator, bool> result =
+ buffers_.insert(std::make_pair(image_id, buffer.release()));
+ GPU_DCHECK(result.second);
+
+ return image_id;
+}
+
+gfx::GpuMemoryBuffer* GpuMemoryBufferTracker::GetBuffer(GLuint image_id) {
+ BufferMap::iterator it = buffers_.find(image_id);
+ return (it != buffers_.end()) ? it->second : NULL;
+}
+
+void GpuMemoryBufferTracker::RemoveBuffer(GLuint image_id) {
+ BufferMap::iterator buffer_it = buffers_.find(image_id);
+ if (buffer_it != buffers_.end()) {
+ gfx::GpuMemoryBuffer* buffer = buffer_it->second;
+ buffers_.erase(buffer_it);
+ delete buffer;
+ }
+ DCHECK(factory_);
+ factory_->DeleteGpuMemoryBuffer(image_id);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.h b/chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
new file mode 100644
index 00000000000..1192b1714f0
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/gpu_memory_buffer_tracker.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
+
+#include <GLES2/gl2.h>
+
+#include "base/basictypes.h"
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/hash_tables.h"
+
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
+namespace gpu {
+namespace gles2 {
+class ImageFactory;
+
+// Tracks GPU memory buffer objects on the client side.
+class GLES2_IMPL_EXPORT GpuMemoryBufferTracker {
+ public:
+ // Ownership of |factory| remains with caller.
+ explicit GpuMemoryBufferTracker(ImageFactory* factory);
+ virtual ~GpuMemoryBufferTracker();
+
+ GLuint CreateBuffer(
+ GLsizei width, GLsizei height, GLenum internalformat);
+ gfx::GpuMemoryBuffer* GetBuffer(GLuint image_id);
+ void RemoveBuffer(GLuint image_id);
+
+ private:
+ typedef gpu::hash_map<GLuint, gfx::GpuMemoryBuffer*> BufferMap;
+ BufferMap buffers_;
+ ImageFactory* factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferTracker);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_GPU_MEMORY_BUFFER_TRACKER_H_
diff --git a/chromium/gpu/command_buffer/client/hash_tables.h b/chromium/gpu/command_buffer/client/hash_tables.h
new file mode 100644
index 00000000000..fff3098dea6
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/hash_tables.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_HASH_TABLES_H_
+#define GPU_COMMAND_BUFFER_CLIENT_HASH_TABLES_H_
+
+#if defined(__native_client__)
+#include <tr1/unordered_map>
+namespace gpu {
+template <typename key, typename value>
+struct hash_map : public std::tr1::unordered_map<key, value> {
+};
+}
+#else
+#include "base/containers/hash_tables.h"
+namespace gpu {
+template <typename key, typename value>
+struct hash_map : public base::hash_map<key, value> {
+};
+}
+#endif
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_HASH_TABLES_H_
diff --git a/chromium/gpu/command_buffer/client/image_factory.h b/chromium/gpu/command_buffer/client/image_factory.h
new file mode 100644
index 00000000000..449c8a4b74b
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/image_factory.h
@@ -0,0 +1,35 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
+#define GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
+
+#include <GLES2/gl2.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "gles2_impl_export.h"
+
+namespace gfx {
+class GpuMemoryBuffer;
+}
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2_IMPL_EXPORT ImageFactory {
+
+ public:
+ virtual ~ImageFactory() {}
+
+ // Create a GpuMemoryBuffer and makes it available to the
+ // service side by inserting it to the ImageManager.
+ virtual scoped_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
+ int width, int height, GLenum internalformat, unsigned* image_id) = 0;
+ virtual void DeleteGpuMemoryBuffer(unsigned image_id) = 0;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_IMAGE_FACTORY_H_
diff --git a/chromium/gpu/command_buffer/client/mapped_memory.cc b/chromium/gpu/command_buffer/client/mapped_memory.cc
new file mode 100644
index 00000000000..82829d48ec1
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/mapped_memory.cc
@@ -0,0 +1,110 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/mapped_memory.h"
+
+#include <algorithm>
+#include <functional>
+
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+
+namespace gpu {
+
+MemoryChunk::MemoryChunk(
+ int32 shm_id, gpu::Buffer shm, CommandBufferHelper* helper)
+ : shm_id_(shm_id),
+ shm_(shm),
+ allocator_(shm.size, helper, shm.ptr) {
+}
+
+MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper)
+ : chunk_size_multiple_(1),
+ helper_(helper) {
+}
+
+MappedMemoryManager::~MappedMemoryManager() {
+ CommandBuffer* cmd_buf = helper_->command_buffer();
+ for (MemoryChunkVector::iterator iter = chunks_.begin();
+ iter != chunks_.end(); ++iter) {
+ MemoryChunk* chunk = *iter;
+ cmd_buf->DestroyTransferBuffer(chunk->shm_id());
+ }
+}
+
+void* MappedMemoryManager::Alloc(
+ unsigned int size, int32* shm_id, unsigned int* shm_offset) {
+ GPU_DCHECK(shm_id);
+ GPU_DCHECK(shm_offset);
+ // See if any of the chucks can satisfy this request.
+ for (size_t ii = 0; ii < chunks_.size(); ++ii) {
+ MemoryChunk* chunk = chunks_[ii];
+ chunk->FreeUnused();
+ if (chunk->GetLargestFreeSizeWithoutWaiting() >= size) {
+ void* mem = chunk->Alloc(size);
+ GPU_DCHECK(mem);
+ *shm_id = chunk->shm_id();
+ *shm_offset = chunk->GetOffset(mem);
+ return mem;
+ }
+ }
+
+ // Make a new chunk to satisfy the request.
+ CommandBuffer* cmd_buf = helper_->command_buffer();
+ unsigned int chunk_size =
+ ((size + chunk_size_multiple_ - 1) / chunk_size_multiple_) *
+ chunk_size_multiple_;
+ int32 id = -1;
+ gpu::Buffer shm = cmd_buf->CreateTransferBuffer(chunk_size, &id);
+ if (id < 0)
+ return NULL;
+ MemoryChunk* mc = new MemoryChunk(id, shm, helper_);
+ chunks_.push_back(mc);
+ void* mem = mc->Alloc(size);
+ GPU_DCHECK(mem);
+ *shm_id = mc->shm_id();
+ *shm_offset = mc->GetOffset(mem);
+ return mem;
+}
+
+void MappedMemoryManager::Free(void* pointer) {
+ for (size_t ii = 0; ii < chunks_.size(); ++ii) {
+ MemoryChunk* chunk = chunks_[ii];
+ if (chunk->IsInChunk(pointer)) {
+ chunk->Free(pointer);
+ return;
+ }
+ }
+ GPU_NOTREACHED();
+}
+
+void MappedMemoryManager::FreePendingToken(void* pointer, int32 token) {
+ for (size_t ii = 0; ii < chunks_.size(); ++ii) {
+ MemoryChunk* chunk = chunks_[ii];
+ if (chunk->IsInChunk(pointer)) {
+ chunk->FreePendingToken(pointer, token);
+ return;
+ }
+ }
+ GPU_NOTREACHED();
+}
+
+void MappedMemoryManager::FreeUnused() {
+ CommandBuffer* cmd_buf = helper_->command_buffer();
+ MemoryChunkVector::iterator iter = chunks_.begin();
+ while (iter != chunks_.end()) {
+ MemoryChunk* chunk = *iter;
+ chunk->FreeUnused();
+ if (!chunk->InUse()) {
+ cmd_buf->DestroyTransferBuffer(chunk->shm_id());
+ iter = chunks_.erase(iter);
+ } else {
+ ++iter;
+ }
+ }
+}
+
+} // namespace gpu
+
+
+
diff --git a/chromium/gpu/command_buffer/client/mapped_memory.h b/chromium/gpu/command_buffer/client/mapped_memory.h
new file mode 100644
index 00000000000..ec70c430de5
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/mapped_memory.h
@@ -0,0 +1,167 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
+#define GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
+
+#include "base/memory/scoped_vector.h"
+#include "gpu/command_buffer/client/fenced_allocator.h"
+#include "gpu/command_buffer/common/buffer.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class CommandBufferHelper;
+
+// Manages a shared memory segment.
+class GPU_EXPORT MemoryChunk {
+ public:
+ MemoryChunk(int32 shm_id, gpu::Buffer shm, CommandBufferHelper* helper);
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSizeWithoutWaiting() {
+ return allocator_.GetLargestFreeSize();
+ }
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait.
+ unsigned int GetLargestFreeSizeWithWaiting() {
+ return allocator_.GetLargestFreeOrPendingSize();
+ }
+
+ // Gets the size of the chunk.
+ unsigned int GetSize() const {
+ return shm_.size;
+ }
+
+ // The shared memory id for this chunk.
+ int32 shm_id() const {
+ return shm_id_;
+ }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ void* Alloc(unsigned int size) {
+ return allocator_.Alloc(size);
+ }
+
+ // Gets the offset to a memory block given the base memory and the address.
+ // It translates NULL to FencedAllocator::kInvalidOffset.
+ unsigned int GetOffset(void* pointer) {
+ return allocator_.GetOffset(pointer);
+ }
+
+ // Frees a block of memory.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ void Free(void* pointer) {
+ allocator_.Free(pointer);
+ }
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(void* pointer, unsigned int token) {
+ allocator_.FreePendingToken(pointer, token);
+ }
+
+ // Frees any blocks who's tokens have passed.
+ void FreeUnused() {
+ allocator_.FreeUnused();
+ }
+
+ // Returns true if pointer is in the range of this block.
+ bool IsInChunk(void* pointer) const {
+ return pointer >= shm_.ptr &&
+ pointer < reinterpret_cast<const int8*>(shm_.ptr) + shm_.size;
+ }
+
+ // Returns true of any memory in this chuck is in use.
+ bool InUse() {
+ return allocator_.InUse();
+ }
+
+ private:
+ int32 shm_id_;
+ gpu::Buffer shm_;
+ FencedAllocatorWrapper allocator_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryChunk);
+};
+
+// Manages MemoryChucks.
+class GPU_EXPORT MappedMemoryManager {
+ public:
+ explicit MappedMemoryManager(CommandBufferHelper* helper);
+
+ ~MappedMemoryManager();
+
+ unsigned int chunk_size_multiple() const {
+ return chunk_size_multiple_;
+ }
+
+ void set_chunk_size_multiple(unsigned int multiple) {
+ chunk_size_multiple_ = multiple;
+ }
+
+ // Allocates a block of memory
+ // Parameters:
+ // size: size of memory to allocate.
+ // shm_id: pointer to variable to receive the shared memory id.
+ // shm_offset: pointer to variable to receive the shared memory offset.
+ // Returns:
+ // pointer to allocated block of memory. NULL if failure.
+ void* Alloc(
+ unsigned int size, int32* shm_id, unsigned int* shm_offset);
+
+ // Frees a block of memory.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ void Free(void* pointer);
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(void* pointer, int32 token);
+
+ // Free Any Shared memory that is not in use.
+ void FreeUnused();
+
+ // Used for testing
+ size_t num_chunks() {
+ return chunks_.size();
+ }
+
+ private:
+ typedef ScopedVector<MemoryChunk> MemoryChunkVector;
+
+ // size a chunk is rounded up to.
+ unsigned int chunk_size_multiple_;
+ CommandBufferHelper* helper_;
+ MemoryChunkVector chunks_;
+
+ DISALLOW_COPY_AND_ASSIGN(MappedMemoryManager);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
+
diff --git a/chromium/gpu/command_buffer/client/mapped_memory_unittest.cc b/chromium/gpu/command_buffer/client/mapped_memory_unittest.cc
new file mode 100644
index 00000000000..99e6e8d3ec2
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/mapped_memory_unittest.cc
@@ -0,0 +1,309 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/mapped_memory.h"
+
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace gpu {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+class MappedMemoryTestBase : public testing::Test {
+ protected:
+ static const unsigned int kBufferSize = 1024;
+
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
+ .WillRepeatedly(Return(error::kNoError));
+ // Forward the SetToken calls to the engine
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillRepeatedly(DoAll(Invoke(api_mock_.get(), &AsyncAPIMock::SetToken),
+ Return(error::kNoError)));
+
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ EXPECT_TRUE(manager->Initialize());
+ }
+
+ command_buffer_.reset(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ EXPECT_TRUE(command_buffer_->Initialize());
+
+ gpu_scheduler_.reset(new GpuScheduler(
+ command_buffer_.get(), api_mock_.get(), NULL));
+ command_buffer_->SetPutOffsetChangeCallback(base::Bind(
+ &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
+ command_buffer_->SetGetBufferChangeCallback(base::Bind(
+ &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+
+ api_mock_->set_engine(gpu_scheduler_.get());
+
+ helper_.reset(new CommandBufferHelper(command_buffer_.get()));
+ helper_->Initialize(kBufferSize);
+ }
+
+ int32 GetToken() {
+ return command_buffer_->GetState().token;
+ }
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool_;
+#endif
+ base::MessageLoop message_loop_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GpuScheduler> gpu_scheduler_;
+ scoped_ptr<CommandBufferHelper> helper_;
+};
+
+#ifndef _MSC_VER
+const unsigned int MappedMemoryTestBase::kBufferSize;
+#endif
+
+// Test fixture for MemoryChunk test - Creates a MemoryChunk, using a
+// CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
+// it directly, not through the RPC mechanism), making sure Noops are ignored
+// and SetToken are properly forwarded to the engine.
+class MemoryChunkTest : public MappedMemoryTestBase {
+ protected:
+ static const int32 kShmId = 123;
+ virtual void SetUp() {
+ MappedMemoryTestBase::SetUp();
+ buffer_.reset(new uint8[kBufferSize]);
+ gpu::Buffer buf;
+ buf.size = kBufferSize;
+ buf.ptr = buffer_.get();
+ chunk_.reset(new MemoryChunk(kShmId, buf, helper_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ MappedMemoryTestBase::TearDown();
+ }
+
+ scoped_ptr<MemoryChunk> chunk_;
+ scoped_ptr<uint8[]> buffer_;
+};
+
+#ifndef _MSC_VER
+const int32 MemoryChunkTest::kShmId;
+#endif
+
+TEST_F(MemoryChunkTest, Basic) {
+ const unsigned int kSize = 16;
+ EXPECT_EQ(kShmId, chunk_->shm_id());
+ EXPECT_EQ(kBufferSize, chunk_->GetLargestFreeSizeWithoutWaiting());
+ EXPECT_EQ(kBufferSize, chunk_->GetLargestFreeSizeWithWaiting());
+ EXPECT_EQ(kBufferSize, chunk_->GetSize());
+ void *pointer = chunk_->Alloc(kSize);
+ ASSERT_TRUE(pointer);
+ EXPECT_LE(buffer_.get(), static_cast<uint8 *>(pointer));
+ EXPECT_GE(kBufferSize, static_cast<uint8 *>(pointer) - buffer_.get() + kSize);
+ EXPECT_EQ(kBufferSize - kSize, chunk_->GetLargestFreeSizeWithoutWaiting());
+ EXPECT_EQ(kBufferSize - kSize, chunk_->GetLargestFreeSizeWithWaiting());
+ EXPECT_EQ(kBufferSize, chunk_->GetSize());
+
+ chunk_->Free(pointer);
+ EXPECT_EQ(kBufferSize, chunk_->GetLargestFreeSizeWithoutWaiting());
+ EXPECT_EQ(kBufferSize, chunk_->GetLargestFreeSizeWithWaiting());
+
+ uint8 *pointer_char = static_cast<uint8*>(chunk_->Alloc(kSize));
+ ASSERT_TRUE(pointer_char);
+ EXPECT_LE(buffer_.get(), pointer_char);
+ EXPECT_GE(buffer_.get() + kBufferSize, pointer_char + kSize);
+ EXPECT_EQ(kBufferSize - kSize, chunk_->GetLargestFreeSizeWithoutWaiting());
+ EXPECT_EQ(kBufferSize - kSize, chunk_->GetLargestFreeSizeWithWaiting());
+ chunk_->Free(pointer_char);
+ EXPECT_EQ(kBufferSize, chunk_->GetLargestFreeSizeWithoutWaiting());
+ EXPECT_EQ(kBufferSize, chunk_->GetLargestFreeSizeWithWaiting());
+}
+
+class MappedMemoryManagerTest : public MappedMemoryTestBase {
+ protected:
+ virtual void SetUp() {
+ MappedMemoryTestBase::SetUp();
+ manager_.reset(new MappedMemoryManager(helper_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+ manager_.reset();
+ MappedMemoryTestBase::TearDown();
+ }
+
+ scoped_ptr<MappedMemoryManager> manager_;
+};
+
+TEST_F(MappedMemoryManagerTest, Basic) {
+ const unsigned int kSize = 1024;
+ // Check we can alloc.
+ int32 id1 = -1;
+ unsigned int offset1 = 0xFFFFFFFFU;
+ void* mem1 = manager_->Alloc(kSize, &id1, &offset1);
+ ASSERT_TRUE(mem1);
+ EXPECT_NE(-1, id1);
+ EXPECT_EQ(0u, offset1);
+ // Check if we free and realloc the same size we get the same memory
+ int32 id2 = -1;
+ unsigned int offset2 = 0xFFFFFFFFU;
+ manager_->Free(mem1);
+ void* mem2 = manager_->Alloc(kSize, &id2, &offset2);
+ EXPECT_EQ(mem1, mem2);
+ EXPECT_EQ(id1, id2);
+ EXPECT_EQ(offset1, offset2);
+ // Check if we allocate again we get different shared memory
+ int32 id3 = -1;
+ unsigned int offset3 = 0xFFFFFFFFU;
+ void* mem3 = manager_->Alloc(kSize, &id3, &offset3);
+ ASSERT_TRUE(mem3 != NULL);
+ EXPECT_NE(mem2, mem3);
+ EXPECT_NE(id2, id3);
+ EXPECT_EQ(0u, offset3);
+ // Free 3 and allocate 2 half size blocks.
+ manager_->Free(mem3);
+ int32 id4 = -1;
+ int32 id5 = -1;
+ unsigned int offset4 = 0xFFFFFFFFU;
+ unsigned int offset5 = 0xFFFFFFFFU;
+ void* mem4 = manager_->Alloc(kSize / 2, &id4, &offset4);
+ void* mem5 = manager_->Alloc(kSize / 2, &id5, &offset5);
+ ASSERT_TRUE(mem4 != NULL);
+ ASSERT_TRUE(mem5 != NULL);
+ EXPECT_EQ(id3, id4);
+ EXPECT_EQ(id4, id5);
+ EXPECT_EQ(0u, offset4);
+ EXPECT_EQ(kSize / 2u, offset5);
+ manager_->Free(mem4);
+ manager_->Free(mem2);
+ manager_->Free(mem5);
+}
+
+TEST_F(MappedMemoryManagerTest, FreePendingToken) {
+ const unsigned int kSize = 128;
+ const unsigned int kAllocCount = (kBufferSize / kSize) * 2;
+ CHECK(kAllocCount * kSize == kBufferSize * 2);
+
+ // Allocate several buffers across multiple chunks.
+ void *pointers[kAllocCount];
+ for (unsigned int i = 0; i < kAllocCount; ++i) {
+ int32 id = -1;
+ unsigned int offset = 0xFFFFFFFFu;
+ pointers[i] = manager_->Alloc(kSize, &id, &offset);
+ EXPECT_TRUE(pointers[i]);
+ EXPECT_NE(id, -1);
+ EXPECT_NE(offset, 0xFFFFFFFFu);
+ }
+
+ // Free one successful allocation, pending fence.
+ int32 token = helper_.get()->InsertToken();
+ manager_->FreePendingToken(pointers[0], token);
+
+ // The way we hooked up the helper and engine, it won't process commands
+ // until it has to wait for something. Which means the token shouldn't have
+ // passed yet at this point.
+ EXPECT_GT(token, GetToken());
+ // Force it to read up to the token
+ helper_->Finish();
+ // Check that the token has indeed passed.
+ EXPECT_LE(token, GetToken());
+
+ // This allocation should use the spot just freed above.
+ int32 new_id = -1;
+ unsigned int new_offset = 0xFFFFFFFFu;
+ void* new_ptr = manager_->Alloc(kSize, &new_id, &new_offset);
+ EXPECT_TRUE(new_ptr);
+ EXPECT_EQ(new_ptr, pointers[0]);
+ EXPECT_NE(new_id, -1);
+ EXPECT_NE(new_offset, 0xFFFFFFFFu);
+
+ // Free up everything.
+ manager_->Free(new_ptr);
+ for (unsigned int i = 1; i < kAllocCount; ++i) {
+ manager_->Free(pointers[i]);
+ }
+}
+
+// Check if we don't free we don't crash.
+TEST_F(MappedMemoryManagerTest, DontFree) {
+ const unsigned int kSize = 1024;
+ // Check we can alloc.
+ int32 id1 = -1;
+ unsigned int offset1 = 0xFFFFFFFFU;
+ void* mem1 = manager_->Alloc(kSize, &id1, &offset1);
+ ASSERT_TRUE(mem1);
+}
+
+TEST_F(MappedMemoryManagerTest, FreeUnused) {
+ int32 id = -1;
+ unsigned int offset = 0xFFFFFFFFU;
+ void* m1 = manager_->Alloc(kBufferSize, &id, &offset);
+ void* m2 = manager_->Alloc(kBufferSize, &id, &offset);
+ ASSERT_TRUE(m1 != NULL);
+ ASSERT_TRUE(m2 != NULL);
+ EXPECT_EQ(2u, manager_->num_chunks());
+ manager_->FreeUnused();
+ EXPECT_EQ(2u, manager_->num_chunks());
+ manager_->Free(m2);
+ EXPECT_EQ(2u, manager_->num_chunks());
+ manager_->FreeUnused();
+ EXPECT_EQ(1u, manager_->num_chunks());
+ manager_->Free(m1);
+ EXPECT_EQ(1u, manager_->num_chunks());
+ manager_->FreeUnused();
+ EXPECT_EQ(0u, manager_->num_chunks());
+}
+
+TEST_F(MappedMemoryManagerTest, ChunkSizeMultiple) {
+ const unsigned int kSize = 1024;
+ manager_->set_chunk_size_multiple(kSize * 2);
+ // Check if we allocate less than the chunk size multiple we get
+ // chunks arounded up.
+ int32 id1 = -1;
+ unsigned int offset1 = 0xFFFFFFFFU;
+ void* mem1 = manager_->Alloc(kSize, &id1, &offset1);
+ int32 id2 = -1;
+ unsigned int offset2 = 0xFFFFFFFFU;
+ void* mem2 = manager_->Alloc(kSize, &id2, &offset2);
+ int32 id3 = -1;
+ unsigned int offset3 = 0xFFFFFFFFU;
+ void* mem3 = manager_->Alloc(kSize, &id3, &offset3);
+ ASSERT_TRUE(mem1);
+ ASSERT_TRUE(mem2);
+ ASSERT_TRUE(mem3);
+ EXPECT_NE(-1, id1);
+ EXPECT_EQ(id1, id2);
+ EXPECT_NE(id2, id3);
+ EXPECT_EQ(0u, offset1);
+ EXPECT_EQ(kSize, offset2);
+ EXPECT_EQ(0u, offset3);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/program_info_manager.cc b/chromium/gpu/command_buffer/client/program_info_manager.cc
new file mode 100644
index 00000000000..fb0c1f3f940
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/program_info_manager.cc
@@ -0,0 +1,523 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+
+#include "base/compiler_specific.h"
+#include "gpu/command_buffer/client/atomicops.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/program_info_manager.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+
+namespace gpu {
+namespace gles2 {
+
+class NonCachedProgramInfoManager : public ProgramInfoManager {
+ public:
+ NonCachedProgramInfoManager();
+ virtual ~NonCachedProgramInfoManager();
+
+ virtual void CreateInfo(GLuint program) OVERRIDE;
+
+ virtual void DeleteInfo(GLuint program) OVERRIDE;
+
+ virtual bool GetProgramiv(GLES2Implementation* gl,
+ GLuint program,
+ GLenum pname,
+ GLint* params) OVERRIDE;
+
+ virtual GLint GetAttribLocation(GLES2Implementation* gl,
+ GLuint program,
+ const char* name) OVERRIDE;
+
+ virtual GLint GetUniformLocation(GLES2Implementation* gl,
+ GLuint program,
+ const char* name) OVERRIDE;
+
+ virtual bool GetActiveAttrib(GLES2Implementation* gl,
+ GLuint program,
+ GLuint index,
+ GLsizei bufsize,
+ GLsizei* length,
+ GLint* size,
+ GLenum* type,
+ char* name) OVERRIDE;
+
+ virtual bool GetActiveUniform(GLES2Implementation* gl,
+ GLuint program,
+ GLuint index,
+ GLsizei bufsize,
+ GLsizei* length,
+ GLint* size,
+ GLenum* type,
+ char* name) OVERRIDE;
+
+};
+
+NonCachedProgramInfoManager::NonCachedProgramInfoManager() {
+}
+
+NonCachedProgramInfoManager::~NonCachedProgramInfoManager() {
+}
+
+void NonCachedProgramInfoManager::CreateInfo(GLuint /* program */) {
+}
+
+void NonCachedProgramInfoManager::DeleteInfo(GLuint /* program */) {
+}
+
+bool NonCachedProgramInfoManager::GetProgramiv(
+ GLES2Implementation* /* gl */,
+ GLuint /* program */,
+ GLenum /* pname */,
+ GLint* /* params */) {
+ return false;
+}
+
+GLint NonCachedProgramInfoManager::GetAttribLocation(
+ GLES2Implementation* gl, GLuint program, const char* name) {
+ return gl->GetAttribLocationHelper(program, name);
+}
+
+GLint NonCachedProgramInfoManager::GetUniformLocation(
+ GLES2Implementation* gl, GLuint program, const char* name) {
+ return gl->GetUniformLocationHelper(program, name);
+}
+
+bool NonCachedProgramInfoManager::GetActiveAttrib(
+ GLES2Implementation* gl,
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name) {
+ return gl->GetActiveAttribHelper(
+ program, index, bufsize, length, size, type, name);
+}
+
+bool NonCachedProgramInfoManager::GetActiveUniform(
+ GLES2Implementation* gl,
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name) {
+ return gl->GetActiveUniformHelper(
+ program, index, bufsize, length, size, type, name);
+}
+
+class CachedProgramInfoManager : public ProgramInfoManager {
+ public:
+ CachedProgramInfoManager();
+ virtual ~CachedProgramInfoManager();
+
+ virtual void CreateInfo(GLuint program) OVERRIDE;
+
+ virtual void DeleteInfo(GLuint program) OVERRIDE;
+
+ virtual bool GetProgramiv(GLES2Implementation* gl,
+ GLuint program,
+ GLenum pname,
+ GLint* params) OVERRIDE;
+
+ virtual GLint GetAttribLocation(GLES2Implementation* gl,
+ GLuint program,
+ const char* name) OVERRIDE;
+
+ virtual GLint GetUniformLocation(GLES2Implementation* gl,
+ GLuint program,
+ const char* name) OVERRIDE;
+
+ virtual bool GetActiveAttrib(GLES2Implementation* gl,
+ GLuint program,
+ GLuint index,
+ GLsizei bufsize,
+ GLsizei* length,
+ GLint* size,
+ GLenum* type,
+ char* name) OVERRIDE;
+
+ virtual bool GetActiveUniform(GLES2Implementation* gl,
+ GLuint program,
+ GLuint index,
+ GLsizei bufsize,
+ GLsizei* length,
+ GLint* size,
+ GLenum* type,
+ char* name) OVERRIDE;
+
+ private:
+ class Program {
+ public:
+ struct UniformInfo {
+ UniformInfo(GLsizei _size, GLenum _type, const std::string& _name);
+
+ GLsizei size;
+ GLenum type;
+ bool is_array;
+ std::string name;
+ std::vector<GLint> element_locations;
+ };
+ struct VertexAttrib {
+ VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
+ GLint _location)
+ : size(_size),
+ type(_type),
+ location(_location),
+ name(_name) {
+ }
+ GLsizei size;
+ GLenum type;
+ GLint location;
+ std::string name;
+ };
+
+ typedef std::vector<UniformInfo> UniformInfoVector;
+ typedef std::vector<VertexAttrib> AttribInfoVector;
+
+ Program();
+
+ const AttribInfoVector& GetAttribInfos() const {
+ return attrib_infos_;
+ }
+
+ const VertexAttrib* GetAttribInfo(GLint index) const {
+ return (static_cast<size_t>(index) < attrib_infos_.size()) ?
+ &attrib_infos_[index] : NULL;
+ }
+
+ GLint GetAttribLocation(const std::string& name) const;
+
+ const UniformInfo* GetUniformInfo(GLint index) const {
+ return (static_cast<size_t>(index) < uniform_infos_.size()) ?
+ &uniform_infos_[index] : NULL;
+ }
+
+ // Gets the location of a uniform by name.
+ GLint GetUniformLocation(const std::string& name) const;
+
+ bool GetProgramiv(GLenum pname, GLint* params);
+
+ // Updates the program info after a successful link.
+ void Update(GLES2Implementation* gl, GLuint program);
+
+ private:
+ bool cached_;
+
+ GLsizei max_attrib_name_length_;
+
+ // Attrib by index.
+ AttribInfoVector attrib_infos_;
+
+ GLsizei max_uniform_name_length_;
+
+ // Uniform info by index.
+ UniformInfoVector uniform_infos_;
+
+ // This is true if glLinkProgram was successful last time it was called.
+ bool link_status_;
+ };
+
+ Program* GetProgramInfo(GLES2Implementation* gl, GLuint program);
+
+ // TODO(gman): Switch to a faster container.
+ typedef std::map<GLuint, Program> ProgramInfoMap;
+
+ ProgramInfoMap program_infos_;
+
+ mutable Lock lock_;
+};
+
+CachedProgramInfoManager::Program::UniformInfo::UniformInfo(
+ GLsizei _size, GLenum _type, const std::string& _name)
+ : size(_size),
+ type(_type),
+ name(_name) {
+ is_array = (!name.empty() && name[name.size() - 1] == ']');
+ GPU_DCHECK(!(size > 1 && !is_array));
+}
+
+CachedProgramInfoManager::Program::Program()
+ : cached_(false),
+ max_attrib_name_length_(0),
+ max_uniform_name_length_(0),
+ link_status_(false) {
+}
+
+// TODO(gman): Add a faster lookup.
+GLint CachedProgramInfoManager::Program::GetAttribLocation(
+ const std::string& name) const {
+ for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttrib& info = attrib_infos_[ii];
+ if (info.name == name) {
+ return info.location;
+ }
+ }
+ return -1;
+}
+
+GLint CachedProgramInfoManager::Program::GetUniformLocation(
+ const std::string& name) const {
+ bool getting_array_location = false;
+ size_t open_pos = std::string::npos;
+ int index = 0;
+ if (!GLES2Util::ParseUniformName(
+ name, &open_pos, &index, &getting_array_location)) {
+ return -1;
+ }
+ for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ if (info.name == name ||
+ (info.is_array &&
+ info.name.compare(0, info.name.size() - 3, name) == 0)) {
+ return info.element_locations[0];
+ } else if (getting_array_location && info.is_array) {
+ // Look for an array specification.
+ size_t open_pos_2 = info.name.find_last_of('[');
+ if (open_pos_2 == open_pos &&
+ name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
+ if (index >= 0 && index < info.size) {
+ return info.element_locations[index];
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+bool CachedProgramInfoManager::Program::GetProgramiv(
+ GLenum pname, GLint* params) {
+ switch (pname) {
+ case GL_LINK_STATUS:
+ *params = link_status_;
+ return true;
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = attrib_infos_.size();
+ return true;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ *params = max_attrib_name_length_;
+ return true;
+ case GL_ACTIVE_UNIFORMS:
+ *params = uniform_infos_.size();
+ return true;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ *params = max_uniform_name_length_;
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+template<typename T> static T LocalGetAs(
+ const std::vector<int8>& data, uint32 offset, size_t size) {
+ const int8* p = &data[0] + offset;
+ if (offset + size > data.size()) {
+ GPU_NOTREACHED();
+ return NULL;
+ }
+ return static_cast<T>(static_cast<const void*>(p));
+}
+
+void CachedProgramInfoManager::Program::Update(
+ GLES2Implementation* gl, GLuint program) {
+ if (cached_) {
+ return;
+ }
+ std::vector<int8> result;
+ gl->GetProgramInfoCHROMIUMHelper(program, &result);
+ if (result.empty()) {
+ // This should only happen on a lost context.
+ return;
+ }
+ GPU_DCHECK_GE(result.size(), sizeof(ProgramInfoHeader));
+ const ProgramInfoHeader* header = LocalGetAs<const ProgramInfoHeader*>(
+ result, 0, sizeof(header));
+ link_status_ = header->link_status != 0;
+ if (!link_status_) {
+ return;
+ }
+ attrib_infos_.clear();
+ uniform_infos_.clear();
+ max_attrib_name_length_ = 0;
+ max_uniform_name_length_ = 0;
+ const ProgramInput* inputs = LocalGetAs<const ProgramInput*>(
+ result, sizeof(*header),
+ sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
+ const ProgramInput* input = inputs;
+ for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
+ const int32* location = LocalGetAs<const int32*>(
+ result, input->location_offset, sizeof(int32));
+ const char* name_buf = LocalGetAs<const char*>(
+ result, input->name_offset, input->name_length);
+ std::string name(name_buf, input->name_length);
+ attrib_infos_.push_back(
+ VertexAttrib(input->size, input->type, name, *location));
+ max_attrib_name_length_ = std::max(
+ static_cast<GLsizei>(name.size() + 1), max_attrib_name_length_);
+ ++input;
+ }
+ for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
+ const int32* locations = LocalGetAs<const int32*>(
+ result, input->location_offset, sizeof(int32) * input->size);
+ const char* name_buf = LocalGetAs<const char*>(
+ result, input->name_offset, input->name_length);
+ std::string name(name_buf, input->name_length);
+ UniformInfo info(input->size, input->type, name);
+ max_uniform_name_length_ = std::max(
+ static_cast<GLsizei>(name.size() + 1), max_uniform_name_length_);
+ for (int32 jj = 0; jj < input->size; ++jj) {
+ info.element_locations.push_back(locations[jj]);
+ }
+ uniform_infos_.push_back(info);
+ ++input;
+ }
+ GPU_DCHECK_EQ(header->num_attribs + header->num_uniforms,
+ static_cast<uint32>(input - inputs));
+ cached_ = true;
+}
+
+CachedProgramInfoManager::CachedProgramInfoManager() {
+}
+
+CachedProgramInfoManager::~CachedProgramInfoManager() {
+
+}
+
+CachedProgramInfoManager::Program*
+ CachedProgramInfoManager::GetProgramInfo(
+ GLES2Implementation* gl, GLuint program) {
+ ProgramInfoMap::iterator it = program_infos_.find(program);
+ if (it == program_infos_.end()) {
+ return NULL;
+ }
+ Program* info = &it->second;
+ info->Update(gl, program);
+ return info;
+}
+
+void CachedProgramInfoManager::CreateInfo(GLuint program) {
+ AutoLock auto_lock(lock_);
+ DeleteInfo(program);
+ std::pair<ProgramInfoMap::iterator, bool> result =
+ program_infos_.insert(std::make_pair(program, Program()));
+
+ GPU_DCHECK(result.second);
+}
+
+void CachedProgramInfoManager::DeleteInfo(GLuint program) {
+ program_infos_.erase(program);
+}
+
+bool CachedProgramInfoManager::GetProgramiv(
+ GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) {
+ AutoLock auto_lock(lock_);
+ Program* info = GetProgramInfo(gl, program);
+ if (!info) {
+ return false;
+ }
+ return info->GetProgramiv(pname, params);
+}
+
+GLint CachedProgramInfoManager::GetAttribLocation(
+ GLES2Implementation* gl, GLuint program, const char* name) {
+ AutoLock auto_lock(lock_);
+ Program* info = GetProgramInfo(gl, program);
+ if (info) {
+ return info->GetAttribLocation(name);
+ }
+ return gl->GetAttribLocationHelper(program, name);
+}
+
+GLint CachedProgramInfoManager::GetUniformLocation(
+ GLES2Implementation* gl, GLuint program, const char* name) {
+ AutoLock auto_lock(lock_);
+ Program* info = GetProgramInfo(gl, program);
+ if (info) {
+ return info->GetUniformLocation(name);
+ }
+ return gl->GetUniformLocationHelper(program, name);
+}
+
+bool CachedProgramInfoManager::GetActiveAttrib(
+ GLES2Implementation* gl,
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name) {
+ AutoLock auto_lock(lock_);
+ Program* info = GetProgramInfo(gl, program);
+ if (info) {
+ const Program::VertexAttrib* attrib_info =
+ info->GetAttribInfo(index);
+ if (attrib_info) {
+ if (size) {
+ *size = attrib_info->size;
+ }
+ if (type) {
+ *type = attrib_info->type;
+ }
+ if (length || name) {
+ GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
+ std::max(static_cast<size_t>(0),
+ attrib_info->name.size()));
+ if (length) {
+ *length = max_size;
+ }
+ if (name && bufsize > 0) {
+ memcpy(name, attrib_info->name.c_str(), max_size);
+ name[max_size] = '\0';
+ }
+ }
+ return true;
+ }
+ }
+ return gl->GetActiveAttribHelper(
+ program, index, bufsize, length, size, type, name);
+}
+
+bool CachedProgramInfoManager::GetActiveUniform(
+ GLES2Implementation* gl,
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name) {
+ AutoLock auto_lock(lock_);
+ Program* info = GetProgramInfo(gl, program);
+ if (info) {
+ const Program::UniformInfo* uniform_info = info->GetUniformInfo(index);
+ if (uniform_info) {
+ if (size) {
+ *size = uniform_info->size;
+ }
+ if (type) {
+ *type = uniform_info->type;
+ }
+ if (length || name) {
+ GLsizei max_size = std::min(static_cast<size_t>(bufsize) - 1,
+ std::max(static_cast<size_t>(0),
+ uniform_info->name.size()));
+ if (length) {
+ *length = max_size;
+ }
+ if (name && bufsize > 0) {
+ memcpy(name, uniform_info->name.c_str(), max_size);
+ name[max_size] = '\0';
+ }
+ }
+ return true;
+ }
+ }
+ return gl->GetActiveUniformHelper(
+ program, index, bufsize, length, size, type, name);
+}
+
+ProgramInfoManager::ProgramInfoManager() {
+}
+
+ProgramInfoManager::~ProgramInfoManager() {
+}
+
+ProgramInfoManager* ProgramInfoManager::Create(
+ bool shared_resources_across_processes) {
+ if (shared_resources_across_processes) {
+ return new NonCachedProgramInfoManager();
+ } else {
+ return new CachedProgramInfoManager();
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/client/program_info_manager.h b/chromium/gpu/command_buffer/client/program_info_manager.h
new file mode 100644
index 00000000000..099f182184b
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/program_info_manager.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_
+
+#include <GLES2/gl2.h>
+#include "gles2_impl_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2Implementation;
+
+// Manages info about OpenGL ES Programs.
+class GLES2_IMPL_EXPORT ProgramInfoManager {
+ public:
+ virtual ~ProgramInfoManager();
+
+ static ProgramInfoManager* Create(bool shared_resources_across_processes);
+
+ virtual void CreateInfo(GLuint program) = 0;
+
+ virtual void DeleteInfo(GLuint program) = 0;
+
+ virtual bool GetProgramiv(
+ GLES2Implementation* gl, GLuint program, GLenum pname, GLint* params) = 0;
+
+ virtual GLint GetAttribLocation(
+ GLES2Implementation* gl, GLuint program, const char* name) = 0;
+
+ virtual GLint GetUniformLocation(
+ GLES2Implementation* gl, GLuint program, const char* name) = 0;
+
+ virtual bool GetActiveAttrib(
+ GLES2Implementation* gl,
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name) = 0;
+
+ virtual bool GetActiveUniform(
+ GLES2Implementation* gl,
+ GLuint program, GLuint index, GLsizei bufsize, GLsizei* length,
+ GLint* size, GLenum* type, char* name) = 0;
+
+ protected:
+ ProgramInfoManager();
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_PROGRAM_INFO_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/client/program_info_manager_unittest.cc b/chromium/gpu/command_buffer/client/program_info_manager_unittest.cc
new file mode 100644
index 00000000000..e5002fd30a9
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/program_info_manager_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the Command Buffer Helper.
+
+#include "gpu/command_buffer/client/program_info_manager.h"
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ProgramInfoManagerTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+ scoped_ptr<ProgramInfoManager> program_info_manager_;
+};
+
+TEST_F(ProgramInfoManagerTest, Basic) {
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/query_tracker.cc b/chromium/gpu/command_buffer/client/query_tracker.cc
new file mode 100644
index 00000000000..35732bf4a83
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/query_tracker.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/query_tracker.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "gpu/command_buffer/client/atomicops.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
+#include "gpu/command_buffer/common/time.h"
+
+namespace gpu {
+namespace gles2 {
+
+QuerySyncManager::QuerySyncManager(MappedMemoryManager* manager)
+ : mapped_memory_(manager) {
+ GPU_DCHECK(manager);
+}
+
+QuerySyncManager::~QuerySyncManager() {
+ while (!buckets_.empty()) {
+ mapped_memory_->Free(buckets_.front()->syncs);
+ delete buckets_.front();
+ buckets_.pop_front();
+ }
+}
+
+bool QuerySyncManager::Alloc(QuerySyncManager::QueryInfo* info) {
+ GPU_DCHECK(info);
+ if (free_queries_.empty()) {
+ int32 shm_id;
+ unsigned int shm_offset;
+ void* mem = mapped_memory_->Alloc(
+ kSyncsPerBucket * sizeof(QuerySync), &shm_id, &shm_offset);
+ if (!mem) {
+ return false;
+ }
+ QuerySync* syncs = static_cast<QuerySync*>(mem);
+ Bucket* bucket = new Bucket(syncs);
+ buckets_.push_back(bucket);
+ for (size_t ii = 0; ii < kSyncsPerBucket; ++ii) {
+ free_queries_.push_back(QueryInfo(bucket, shm_id, shm_offset, syncs));
+ ++syncs;
+ shm_offset += sizeof(*syncs);
+ }
+ }
+ *info = free_queries_.front();
+ ++(info->bucket->used_query_count);
+ info->sync->Reset();
+ free_queries_.pop_front();
+ return true;
+}
+
+void QuerySyncManager::Free(const QuerySyncManager::QueryInfo& info) {
+ DCHECK_GT(info.bucket->used_query_count, 0u);
+ --(info.bucket->used_query_count);
+ free_queries_.push_back(info);
+}
+
+void QuerySyncManager::Shrink() {
+ std::deque<QueryInfo> new_queue;
+ while (!free_queries_.empty()) {
+ if (free_queries_.front().bucket->used_query_count)
+ new_queue.push_back(free_queries_.front());
+ free_queries_.pop_front();
+ }
+ free_queries_.swap(new_queue);
+
+ std::deque<Bucket*> new_buckets;
+ while (!buckets_.empty()) {
+ Bucket* bucket = buckets_.front();
+ if (bucket->used_query_count) {
+ new_buckets.push_back(bucket);
+ } else {
+ mapped_memory_->Free(bucket->syncs);
+ delete bucket;
+ }
+ buckets_.pop_front();
+ }
+ buckets_.swap(new_buckets);
+}
+
+QueryTracker::Query::Query(GLuint id, GLenum target,
+ const QuerySyncManager::QueryInfo& info)
+ : id_(id),
+ target_(target),
+ info_(info),
+ state_(kUninitialized),
+ submit_count_(0),
+ token_(0),
+ flushed_(false),
+ client_begin_time_us_(0),
+ result_(0) {
+ }
+
+
+void QueryTracker::Query::Begin(GLES2Implementation* gl) {
+ // init memory, inc count
+ MarkAsActive();
+
+ switch (target()) {
+ case GL_GET_ERROR_QUERY_CHROMIUM:
+ // To nothing on begin for error queries.
+ break;
+ case GL_LATENCY_QUERY_CHROMIUM:
+ client_begin_time_us_ = MicrosecondsSinceOriginOfTime();
+ // tell service about id, shared memory and count
+ gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
+ break;
+ case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
+ default:
+ // tell service about id, shared memory and count
+ gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
+ break;
+ }
+}
+
+void QueryTracker::Query::End(GLES2Implementation* gl) {
+ switch (target()) {
+ case GL_GET_ERROR_QUERY_CHROMIUM: {
+ GLenum error = gl->GetClientSideGLError();
+ if (error == GL_NO_ERROR) {
+ // There was no error so start the query on the serivce.
+ // it will end immediately.
+ gl->helper()->BeginQueryEXT(target(), id(), shm_id(), shm_offset());
+ } else {
+ // There's an error on the client, no need to bother the service. just
+ // set the query as completed and return the error.
+ if (error != GL_NO_ERROR) {
+ state_ = kComplete;
+ result_ = error;
+ return;
+ }
+ }
+ }
+ }
+ gl->helper()->EndQueryEXT(target(), submit_count());
+ MarkAsPending(gl->helper()->InsertToken());
+}
+
+bool QueryTracker::Query::CheckResultsAvailable(
+ CommandBufferHelper* helper) {
+ if (Pending()) {
+ if (info_.sync->process_count == submit_count_ ||
+ helper->IsContextLost()) {
+ // Need a MemoryBarrier here so that sync->result read after
+ // sync->process_count.
+ gpu::MemoryBarrier();
+ switch (target()) {
+ case GL_COMMANDS_ISSUED_CHROMIUM:
+ result_ = std::min(info_.sync->result,
+ static_cast<uint64>(0xFFFFFFFFL));
+ break;
+ case GL_LATENCY_QUERY_CHROMIUM:
+ GPU_DCHECK(info_.sync->result >= client_begin_time_us_);
+ result_ = std::min(info_.sync->result - client_begin_time_us_,
+ static_cast<uint64>(0xFFFFFFFFL));
+ break;
+ case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
+ default:
+ result_ = info_.sync->result;
+ break;
+ }
+ state_ = kComplete;
+ } else {
+ if (!flushed_) {
+ // TODO(gman): We could reduce the number of flushes by having a
+ // flush count, recording that count at the time we insert the
+ // EndQuery command and then only flushing here if we've have not
+ // passed that count yet.
+ flushed_ = true;
+ helper->Flush();
+ } else {
+ // Insert no-ops so that eventually the GPU process will see more work.
+ helper->Noop(1);
+ }
+ }
+ }
+ return state_ == kComplete;
+}
+
+uint32 QueryTracker::Query::GetResult() const {
+ GPU_DCHECK(state_ == kComplete || state_ == kUninitialized);
+ return result_;
+}
+
+QueryTracker::QueryTracker(MappedMemoryManager* manager)
+ : query_sync_manager_(manager) {
+}
+
+QueryTracker::~QueryTracker() {
+ while (!queries_.empty()) {
+ delete queries_.begin()->second;
+ queries_.erase(queries_.begin());
+ }
+ while (!removed_queries_.empty()) {
+ delete removed_queries_.front();
+ removed_queries_.pop_front();
+ }
+}
+
+QueryTracker::Query* QueryTracker::CreateQuery(GLuint id, GLenum target) {
+ GPU_DCHECK_NE(0u, id);
+ FreeCompletedQueries();
+ QuerySyncManager::QueryInfo info;
+ if (!query_sync_manager_.Alloc(&info)) {
+ return NULL;
+ }
+ Query* query = new Query(id, target, info);
+ std::pair<QueryMap::iterator, bool> result =
+ queries_.insert(std::make_pair(id, query));
+ GPU_DCHECK(result.second);
+ return query;
+}
+
+QueryTracker::Query* QueryTracker::GetQuery(
+ GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ return it != queries_.end() ? it->second : NULL;
+}
+
+void QueryTracker::RemoveQuery(GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ if (it != queries_.end()) {
+ Query* query = it->second;
+ // When you delete a query you can't mark its memory as unused until it's
+ // completed.
+ // Note: If you don't do this you won't mess up the service but you will
+ // mess up yourself.
+ removed_queries_.push_back(query);
+ queries_.erase(it);
+ FreeCompletedQueries();
+ }
+}
+
+void QueryTracker::Shrink() {
+ FreeCompletedQueries();
+ query_sync_manager_.Shrink();
+}
+
+void QueryTracker::FreeCompletedQueries() {
+ QueryList::iterator it = removed_queries_.begin();
+ while (it != removed_queries_.end()) {
+ Query* query = *it;
+ if (query->Pending() &&
+ query->info_.sync->process_count != query->submit_count()) {
+ ++it;
+ continue;
+ }
+
+ query_sync_manager_.Free(query->info_);
+ it = removed_queries_.erase(it);
+ delete query;
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/query_tracker.h b/chromium/gpu/command_buffer/client/query_tracker.h
new file mode 100644
index 00000000000..81861c997a9
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/query_tracker.h
@@ -0,0 +1,177 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_
+
+#include <GLES2/gl2.h>
+
+#include <deque>
+#include <list>
+
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/hash_tables.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+
+namespace gpu {
+
+class CommandBufferHelper;
+class MappedMemoryManager;
+
+namespace gles2 {
+
+class GLES2Implementation;
+
+// Manages buckets of QuerySync instances in mapped memory.
+class GLES2_IMPL_EXPORT QuerySyncManager {
+ public:
+ static const size_t kSyncsPerBucket = 4096;
+
+ struct Bucket {
+ explicit Bucket(QuerySync* sync_mem)
+ : syncs(sync_mem),
+ used_query_count(0) {
+ }
+ QuerySync* syncs;
+ unsigned used_query_count;
+ };
+ struct QueryInfo {
+ QueryInfo(Bucket* bucket, int32 id, uint32 offset, QuerySync* sync_mem)
+ : bucket(bucket),
+ shm_id(id),
+ shm_offset(offset),
+ sync(sync_mem) {
+ }
+
+ QueryInfo()
+ : bucket(NULL),
+ shm_id(0),
+ shm_offset(0),
+ sync(NULL) {
+ }
+
+ Bucket* bucket;
+ int32 shm_id;
+ uint32 shm_offset;
+ QuerySync* sync;
+ };
+
+ explicit QuerySyncManager(MappedMemoryManager* manager);
+ ~QuerySyncManager();
+
+ bool Alloc(QueryInfo* info);
+ void Free(const QueryInfo& sync);
+ void Shrink();
+
+ private:
+ MappedMemoryManager* mapped_memory_;
+ std::deque<Bucket*> buckets_;
+ std::deque<QueryInfo> free_queries_;
+
+ DISALLOW_COPY_AND_ASSIGN(QuerySyncManager);
+};
+
+// Tracks queries for client side of command buffer.
+class GLES2_IMPL_EXPORT QueryTracker {
+ public:
+ class GLES2_IMPL_EXPORT Query {
+ public:
+ enum State {
+ kUninitialized, // never used
+ kActive, // between begin - end
+ kPending, // not yet complete
+ kComplete // completed
+ };
+
+ Query(GLuint id, GLenum target, const QuerySyncManager::QueryInfo& info);
+
+ GLenum target() const {
+ return target_;
+ }
+
+ GLenum id() const {
+ return id_;
+ }
+
+ int32 shm_id() const {
+ return info_.shm_id;
+ }
+
+ uint32 shm_offset() const {
+ return info_.shm_offset;
+ }
+
+ void MarkAsActive() {
+ state_ = kActive;
+ ++submit_count_;
+ }
+
+ void MarkAsPending(int32 token) {
+ token_ = token;
+ state_ = kPending;
+ flushed_ = false;
+ }
+
+ uint32 submit_count() const {
+ return submit_count_;
+ }
+
+ int32 token() const {
+ return token_;
+ }
+
+ bool NeverUsed() const {
+ return state_ == kUninitialized;
+ }
+
+ bool Pending() const {
+ return state_ == kPending;
+ }
+
+ bool CheckResultsAvailable(CommandBufferHelper* helper);
+
+ uint32 GetResult() const;
+
+ void Begin(GLES2Implementation* gl);
+ void End(GLES2Implementation* gl);
+
+ private:
+ friend class QueryTracker;
+ friend class QueryTrackerTest;
+
+ GLuint id_;
+ GLenum target_;
+ QuerySyncManager::QueryInfo info_;
+ State state_;
+ uint32 submit_count_;
+ int32 token_;
+ bool flushed_;
+ uint64 client_begin_time_us_; // Only used for latency query target.
+ uint32 result_;
+ };
+
+ QueryTracker(MappedMemoryManager* manager);
+ ~QueryTracker();
+
+ Query* CreateQuery(GLuint id, GLenum target);
+ Query* GetQuery(GLuint id);
+ void RemoveQuery(GLuint id);
+ void Shrink();
+ void FreeCompletedQueries();
+
+ private:
+ typedef gpu::hash_map<GLuint, Query*> QueryMap;
+ typedef std::list<Query*> QueryList;
+
+ QueryMap queries_;
+ QueryList removed_queries_;
+ QuerySyncManager query_sync_manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryTracker);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_QUERY_TRACKER_H_
diff --git a/chromium/gpu/command_buffer/client/query_tracker_unittest.cc b/chromium/gpu/command_buffer/client/query_tracker_unittest.cc
new file mode 100644
index 00000000000..2dad335c7e7
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/query_tracker_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the QueryTracker.
+
+#include "gpu/command_buffer/client/query_tracker.h"
+
+#include <GLES2/gl2ext.h>
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/client/client_test_helper.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/mapped_memory.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class QuerySyncManagerTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+
+ virtual void SetUp() {
+ command_buffer_.reset(new MockClientCommandBuffer());
+ helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+ sync_manager_.reset(new QuerySyncManager(mapped_memory_.get()));
+ }
+
+ virtual void TearDown() {
+ sync_manager_.reset();
+ mapped_memory_.reset();
+ helper_.reset();
+ command_buffer_.reset();
+ }
+
+ scoped_ptr<CommandBuffer> command_buffer_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MappedMemoryManager> mapped_memory_;
+ scoped_ptr<QuerySyncManager> sync_manager_;
+};
+
+TEST_F(QuerySyncManagerTest, Basic) {
+ QuerySyncManager::QueryInfo infos[4];
+ memset(&infos, 0xBD, sizeof(infos));
+
+ for (size_t ii = 0; ii < arraysize(infos); ++ii) {
+ EXPECT_TRUE(sync_manager_->Alloc(&infos[ii]));
+ EXPECT_NE(0, infos[ii].shm_id);
+ ASSERT_TRUE(infos[ii].sync != NULL);
+ EXPECT_EQ(0u, infos[ii].sync->process_count);
+ EXPECT_EQ(0u, infos[ii].sync->result);
+ }
+
+ for (size_t ii = 0; ii < arraysize(infos); ++ii) {
+ sync_manager_->Free(infos[ii]);
+ }
+}
+
+TEST_F(QuerySyncManagerTest, DontFree) {
+ QuerySyncManager::QueryInfo infos[4];
+ memset(&infos, 0xBD, sizeof(infos));
+
+ for (size_t ii = 0; ii < arraysize(infos); ++ii) {
+ EXPECT_TRUE(sync_manager_->Alloc(&infos[ii]));
+ }
+}
+
+class QueryTrackerTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+
+ virtual void SetUp() {
+ command_buffer_.reset(new MockClientCommandBuffer());
+ helper_.reset(new GLES2CmdHelper(command_buffer_.get()));
+ helper_->Initialize(kCommandBufferSizeBytes);
+ mapped_memory_.reset(new MappedMemoryManager(helper_.get()));
+ query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
+ }
+
+ virtual void TearDown() {
+ query_tracker_.reset();
+ mapped_memory_.reset();
+ helper_.reset();
+ command_buffer_.reset();
+ }
+
+ QuerySync* GetSync(QueryTracker::Query* query) {
+ return query->info_.sync;
+ }
+
+ QuerySyncManager::Bucket* GetBucket(QueryTracker::Query* query) {
+ return query->info_.bucket;
+ }
+
+ scoped_ptr<CommandBuffer> command_buffer_;
+ scoped_ptr<GLES2CmdHelper> helper_;
+ scoped_ptr<MappedMemoryManager> mapped_memory_;
+ scoped_ptr<QueryTracker> query_tracker_;
+};
+
+TEST_F(QueryTrackerTest, Basic) {
+ const GLuint kId1 = 123;
+ const GLuint kId2 = 124;
+
+ // Check we can create a Query.
+ QueryTracker::Query* query = query_tracker_->CreateQuery(
+ kId1, GL_ANY_SAMPLES_PASSED_EXT);
+ ASSERT_TRUE(query != NULL);
+ // Check we can get the same Query.
+ EXPECT_EQ(query, query_tracker_->GetQuery(kId1));
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(query_tracker_->GetQuery(kId2) == NULL);
+ // Check we can delete the query.
+ query_tracker_->RemoveQuery(kId1);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
+}
+
+TEST_F(QueryTrackerTest, Query) {
+ const GLuint kId1 = 123;
+ const int32 kToken = 46;
+ const uint32 kResult = 456;
+
+ // Create a Query.
+ QueryTracker::Query* query = query_tracker_->CreateQuery(
+ kId1, GL_ANY_SAMPLES_PASSED_EXT);
+ ASSERT_TRUE(query != NULL);
+ EXPECT_TRUE(query->NeverUsed());
+ EXPECT_FALSE(query->Pending());
+ EXPECT_EQ(0, query->token());
+ EXPECT_EQ(0u, query->submit_count());
+
+ // Check MarkAsActive.
+ query->MarkAsActive();
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_FALSE(query->Pending());
+ EXPECT_EQ(0, query->token());
+ EXPECT_EQ(1u, query->submit_count());
+
+ // Check MarkAsPending.
+ query->MarkAsPending(kToken);
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_TRUE(query->Pending());
+ EXPECT_EQ(kToken, query->token());
+ EXPECT_EQ(1u, query->submit_count());
+
+ // Check CheckResultsAvailable.
+ EXPECT_FALSE(query->CheckResultsAvailable(helper_.get()));
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_TRUE(query->Pending());
+
+ // Simulate GPU process marking it as available.
+ QuerySync* sync = GetSync(query);
+ sync->process_count = query->submit_count();
+ sync->result = kResult;
+
+ // Check CheckResultsAvailable.
+ EXPECT_TRUE(query->CheckResultsAvailable(helper_.get()));
+ EXPECT_EQ(kResult, query->GetResult());
+ EXPECT_FALSE(query->NeverUsed());
+ EXPECT_FALSE(query->Pending());
+}
+
+TEST_F(QueryTrackerTest, Remove) {
+ const GLuint kId1 = 123;
+ const int32 kToken = 46;
+ const uint32 kResult = 456;
+
+ // Create a Query.
+ QueryTracker::Query* query = query_tracker_->CreateQuery(
+ kId1, GL_ANY_SAMPLES_PASSED_EXT);
+ ASSERT_TRUE(query != NULL);
+
+ QuerySyncManager::Bucket* bucket = GetBucket(query);
+ EXPECT_EQ(1u, bucket->used_query_count);
+
+ query->MarkAsActive();
+ query->MarkAsPending(kToken);
+
+ query_tracker_->RemoveQuery(kId1);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(query_tracker_->GetQuery(kId1) == NULL);
+
+ // Check that memory was not freed.
+ EXPECT_EQ(1u, bucket->used_query_count);
+
+ // Simulate GPU process marking it as available.
+ QuerySync* sync = GetSync(query);
+ sync->process_count = query->submit_count();
+ sync->result = kResult;
+
+ // Check FreeCompletedQueries.
+ query_tracker_->FreeCompletedQueries();
+ EXPECT_EQ(0u, bucket->used_query_count);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/ref_counted.h b/chromium/gpu/command_buffer/client/ref_counted.h
new file mode 100644
index 00000000000..79ee8bc43f7
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/ref_counted.h
@@ -0,0 +1,13 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_REF_COUNTED_H_
+#define GPU_COMMAND_BUFFER_CLIENT_REF_COUNTED_H_
+
+#include "base/memory/ref_counted.h"
+namespace gpu {
+using base::RefCountedThreadSafe;
+}
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_REF_COUNTED_H_
diff --git a/chromium/gpu/command_buffer/client/ring_buffer.cc b/chromium/gpu/command_buffer/client/ring_buffer.cc
new file mode 100644
index 00000000000..42e09bd3e1f
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/ring_buffer.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation of the RingBuffer class.
+
+#include "gpu/command_buffer/client/ring_buffer.h"
+#include <algorithm>
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+
+namespace gpu {
+
+RingBuffer::RingBuffer(
+ Offset base_offset, unsigned int size, CommandBufferHelper* helper)
+ : helper_(helper),
+ base_offset_(base_offset),
+ size_(size),
+ free_offset_(0),
+ in_use_offset_(0) {
+}
+
+RingBuffer::~RingBuffer() {
+ // Free blocks pending tokens.
+ while (!blocks_.empty()) {
+ FreeOldestBlock();
+ }
+}
+
+void RingBuffer::FreeOldestBlock() {
+ GPU_DCHECK(!blocks_.empty()) << "no free blocks";
+ Block& block = blocks_.front();
+ GPU_DCHECK(block.state != IN_USE)
+ << "attempt to allocate more than maximum memory";
+ if (block.state == FREE_PENDING_TOKEN) {
+ helper_->WaitForToken(block.token);
+ }
+ in_use_offset_ += block.size;
+ if (in_use_offset_ == size_) {
+ in_use_offset_ = 0;
+ }
+ // If they match then the entire buffer is free.
+ if (in_use_offset_ == free_offset_) {
+ in_use_offset_ = 0;
+ free_offset_ = 0;
+ }
+ blocks_.pop_front();
+}
+
+RingBuffer::Offset RingBuffer::Alloc(unsigned int size) {
+ GPU_DCHECK_LE(size, size_) << "attempt to allocate more than maximum memory";
+ GPU_DCHECK(blocks_.empty() || blocks_.back().state != IN_USE)
+ << "Attempt to alloc another block before freeing the previous.";
+ // Similarly to malloc, an allocation of 0 allocates at least 1 byte, to
+ // return different pointers every time.
+ if (size == 0) size = 1;
+
+ // Wait until there is enough room.
+ while (size > GetLargestFreeSizeNoWaiting()) {
+ FreeOldestBlock();
+ }
+
+ if (size + free_offset_ > size_) {
+ // Add padding to fill space before wrapping around
+ blocks_.push_back(Block(free_offset_, size_ - free_offset_, PADDING));
+ free_offset_ = 0;
+ }
+
+ Offset offset = free_offset_;
+ blocks_.push_back(Block(offset, size, IN_USE));
+ free_offset_ += size;
+ if (free_offset_ == size_) {
+ free_offset_ = 0;
+ }
+ return offset + base_offset_;
+}
+
+void RingBuffer::FreePendingToken(RingBuffer::Offset offset,
+ unsigned int token) {
+ offset -= base_offset_;
+ GPU_DCHECK(!blocks_.empty()) << "no allocations to free";
+ for (Container::reverse_iterator it = blocks_.rbegin();
+ it != blocks_.rend();
+ ++it) {
+ Block& block = *it;
+ if (block.offset == offset) {
+ GPU_DCHECK(block.state == IN_USE)
+ << "block that corresponds to offset already freed";
+ block.token = token;
+ block.state = FREE_PENDING_TOKEN;
+ return;
+ }
+ }
+ GPU_NOTREACHED() << "attempt to free non-existant block";
+}
+
+unsigned int RingBuffer::GetLargestFreeSizeNoWaiting() {
+ unsigned int last_token_read = helper_->last_token_read();
+ while (!blocks_.empty()) {
+ Block& block = blocks_.front();
+ if (block.token > last_token_read || block.state == IN_USE) break;
+ FreeOldestBlock();
+ }
+ if (free_offset_ == in_use_offset_) {
+ if (blocks_.empty()) {
+ // The entire buffer is free.
+ GPU_DCHECK_EQ(free_offset_, 0u);
+ return size_;
+ } else {
+ // The entire buffer is in use.
+ return 0;
+ }
+ } else if (free_offset_ > in_use_offset_) {
+ // It's free from free_offset_ to size_ and from 0 to in_use_offset_
+ return std::max(size_ - free_offset_, in_use_offset_);
+ } else {
+ // It's free from free_offset_ -> in_use_offset_;
+ return in_use_offset_ - free_offset_;
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/ring_buffer.h b/chromium/gpu/command_buffer/client/ring_buffer.h
new file mode 100644
index 00000000000..d1f70a26c69
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/ring_buffer.h
@@ -0,0 +1,198 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the definition of the RingBuffer class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_RING_BUFFER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_RING_BUFFER_H_
+
+#include <deque>
+
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+class CommandBufferHelper;
+
+// RingBuffer manages a piece of memory as a ring buffer. Memory is allocated
+// with Alloc and then a is freed pending a token with FreePendingToken. Old
+// allocations must not be kept past new allocations.
+class GPU_EXPORT RingBuffer {
+ public:
+ typedef unsigned int Offset;
+
+ // Creates a RingBuffer.
+ // Parameters:
+ // base_offset: The offset of the start of the buffer.
+ // size: The size of the buffer in bytes.
+ // helper: A CommandBufferHelper for dealing with tokens.
+ RingBuffer(
+ Offset base_offset, unsigned int size, CommandBufferHelper* helper);
+
+ ~RingBuffer();
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the offset of the allocated memory block.
+ Offset Alloc(unsigned int size);
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // offset: the offset of the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(Offset offset, unsigned int token);
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSizeNoWaiting();
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait. Allocating a block of this size will succeed, but may
+ // block.
+ unsigned int GetLargestFreeOrPendingSize() {
+ return size_;
+ }
+
+ private:
+ enum State {
+ IN_USE,
+ PADDING,
+ FREE_PENDING_TOKEN
+ };
+ // Book-keeping sturcture that describes a block of memory.
+ struct Block {
+ Block(Offset _offset, unsigned int _size, State _state)
+ : offset(_offset),
+ size(_size),
+ token(0),
+ state(_state) {
+ }
+ Offset offset;
+ unsigned int size;
+ unsigned int token; // token to wait for.
+ State state;
+ };
+
+ typedef std::deque<Block> Container;
+ typedef unsigned int BlockIndex;
+
+ void FreeOldestBlock();
+
+ CommandBufferHelper* helper_;
+
+ // Used blocks are added to the end, blocks are freed from the beginning.
+ Container blocks_;
+
+ // The base offset of the ring buffer.
+ Offset base_offset_;
+
+ // The size of the ring buffer.
+ Offset size_;
+
+ // Offset of first free byte.
+ Offset free_offset_;
+
+ // Offset of first used byte.
+ // Range between in_use_mark and free_mark is in use.
+ Offset in_use_offset_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RingBuffer);
+};
+
+// This class functions just like RingBuffer, but its API uses pointers
+// instead of offsets.
+class RingBufferWrapper {
+ public:
+ // Parameters:
+ // base_offset: The offset to the start of the buffer
+ // size: The size of the buffer in bytes.
+ // helper: A CommandBufferHelper for dealing with tokens.
+ // base: The physical address that corresponds to base_offset.
+ RingBufferWrapper(RingBuffer::Offset base_offset,
+ unsigned int size,
+ CommandBufferHelper* helper,
+ void* base)
+ : allocator_(base_offset, size, helper),
+ base_(static_cast<int8*>(base) - base_offset) {
+ }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ //
+ // Parameters:
+ // size: the size of the memory block to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ void* Alloc(unsigned int size) {
+ RingBuffer::Offset offset = allocator_.Alloc(size);
+ return GetPointer(offset);
+ }
+
+ // Allocates a block of memory. If the buffer is out of directly available
+ // memory, this function may wait until memory that was freed "pending a
+ // token" can be re-used.
+ // This is a type-safe version of Alloc, returning a typed pointer.
+ //
+ // Parameters:
+ // count: the number of elements to allocate.
+ //
+ // Returns:
+ // the pointer to the allocated memory block, or NULL if out of
+ // memory.
+ template <typename T> T* AllocTyped(unsigned int count) {
+ return static_cast<T*>(Alloc(count * sizeof(T)));
+ }
+
+ // Frees a block of memory, pending the passage of a token. That memory won't
+ // be re-allocated until the token has passed through the command stream.
+ //
+ // Parameters:
+ // pointer: the pointer to the memory block to free.
+ // token: the token value to wait for before re-using the memory.
+ void FreePendingToken(void* pointer, unsigned int token) {
+ GPU_DCHECK(pointer);
+ allocator_.FreePendingToken(GetOffset(pointer), token);
+ }
+
+ // Gets a pointer to a memory block given the base memory and the offset.
+ void* GetPointer(RingBuffer::Offset offset) const {
+ return static_cast<int8*>(base_) + offset;
+ }
+
+ // Gets the offset to a memory block given the base memory and the address.
+ RingBuffer::Offset GetOffset(void* pointer) const {
+ return static_cast<int8*>(pointer) - static_cast<int8*>(base_);
+ }
+
+ // Gets the size of the largest free block that is available without waiting.
+ unsigned int GetLargestFreeSizeNoWaiting() {
+ return allocator_.GetLargestFreeSizeNoWaiting();
+ }
+
+ // Gets the size of the largest free block that can be allocated if the
+ // caller can wait.
+ unsigned int GetLargestFreeOrPendingSize() {
+ return allocator_.GetLargestFreeOrPendingSize();
+ }
+
+ private:
+ RingBuffer allocator_;
+ void* base_;
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RingBufferWrapper);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_RING_BUFFER_H_
diff --git a/chromium/gpu/command_buffer/client/ring_buffer_test.cc b/chromium/gpu/command_buffer/client/ring_buffer_test.cc
new file mode 100644
index 00000000000..05014289eab
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/ring_buffer_test.cc
@@ -0,0 +1,301 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the tests for the RingBuffer class.
+
+#include "gpu/command_buffer/client/ring_buffer.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+namespace gpu {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::DoAll;
+using testing::Invoke;
+using testing::_;
+
+class BaseRingBufferTest : public testing::Test {
+ protected:
+ static const unsigned int kBaseOffset = 128;
+ static const unsigned int kBufferSize = 1024;
+
+ void RunPendingSetToken() {
+ for (std::vector<const void*>::iterator it = set_token_arguments_.begin();
+ it != set_token_arguments_.end();
+ ++it) {
+ api_mock_->SetToken(cmd::kSetToken, 1, *it);
+ }
+ set_token_arguments_.clear();
+ delay_set_token_ = false;
+ }
+
+ void SetToken(unsigned int command,
+ unsigned int arg_count,
+ const void* _args) {
+ EXPECT_EQ(static_cast<unsigned int>(cmd::kSetToken), command);
+ EXPECT_EQ(1u, arg_count);
+ if (delay_set_token_)
+ set_token_arguments_.push_back(_args);
+ else
+ api_mock_->SetToken(cmd::kSetToken, 1, _args);
+ }
+
+ virtual void SetUp() {
+ delay_set_token_ = false;
+ api_mock_.reset(new AsyncAPIMock);
+ // ignore noops in the mock - we don't want to inspect the internals of the
+ // helper.
+ EXPECT_CALL(*api_mock_, DoCommand(cmd::kNoop, 0, _))
+ .WillRepeatedly(Return(error::kNoError));
+ // Forward the SetToken calls to the engine
+ EXPECT_CALL(*api_mock_.get(), DoCommand(cmd::kSetToken, 1, _))
+ .WillRepeatedly(DoAll(Invoke(this, &BaseRingBufferTest::SetToken),
+ Return(error::kNoError)));
+
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ EXPECT_TRUE(manager->Initialize());
+ }
+ command_buffer_.reset(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ EXPECT_TRUE(command_buffer_->Initialize());
+
+ gpu_scheduler_.reset(new GpuScheduler(
+ command_buffer_.get(), api_mock_.get(), NULL));
+ command_buffer_->SetPutOffsetChangeCallback(base::Bind(
+ &GpuScheduler::PutChanged, base::Unretained(gpu_scheduler_.get())));
+ command_buffer_->SetGetBufferChangeCallback(base::Bind(
+ &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+
+ api_mock_->set_engine(gpu_scheduler_.get());
+
+ helper_.reset(new CommandBufferHelper(command_buffer_.get()));
+ helper_->Initialize(kBufferSize);
+ }
+
+ int32 GetToken() {
+ return command_buffer_->GetState().token;
+ }
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool_;
+#endif
+ base::MessageLoop message_loop_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<CommandBufferService> command_buffer_;
+ scoped_ptr<GpuScheduler> gpu_scheduler_;
+ scoped_ptr<CommandBufferHelper> helper_;
+ std::vector<const void*> set_token_arguments_;
+ bool delay_set_token_;
+
+};
+
+#ifndef _MSC_VER
+const unsigned int BaseRingBufferTest::kBaseOffset;
+const unsigned int BaseRingBufferTest::kBufferSize;
+#endif
+
+// Test fixture for RingBuffer test - Creates a RingBuffer, using a
+// CommandBufferHelper with a mock AsyncAPIInterface for its interface (calling
+// it directly, not through the RPC mechanism), making sure Noops are ignored
+// and SetToken are properly forwarded to the engine.
+class RingBufferTest : public BaseRingBufferTest {
+ protected:
+ virtual void SetUp() {
+ BaseRingBufferTest::SetUp();
+ allocator_.reset(new RingBuffer(kBaseOffset, kBufferSize, helper_.get()));
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ BaseRingBufferTest::TearDown();
+ }
+
+ scoped_ptr<RingBuffer> allocator_;
+};
+
+// Checks basic alloc and free.
+TEST_F(RingBufferTest, TestBasic) {
+ const unsigned int kSize = 16;
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSizeNoWaiting());
+ RingBuffer::Offset offset = allocator_->Alloc(kSize);
+ EXPECT_GE(kBufferSize, offset - kBaseOffset + kSize);
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeOrPendingSize());
+ EXPECT_EQ(kBufferSize - kSize, allocator_->GetLargestFreeSizeNoWaiting());
+ int32 token = helper_->InsertToken();
+ allocator_->FreePendingToken(offset, token);
+}
+
+// Checks the free-pending-token mechanism.
+TEST_F(RingBufferTest, TestFreePendingToken) {
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ delay_set_token_ = true;
+ // Allocate several buffers to fill in the memory.
+ int32 tokens[kAllocCount];
+ for (unsigned int ii = 0; ii < kAllocCount; ++ii) {
+ RingBuffer::Offset offset = allocator_->Alloc(kSize);
+ EXPECT_GE(kBufferSize, offset - kBaseOffset + kSize);
+ tokens[ii] = helper_->InsertToken();
+ allocator_->FreePendingToken(offset, tokens[ii]);
+ }
+
+ EXPECT_EQ(kBufferSize - (kSize * kAllocCount),
+ allocator_->GetLargestFreeSizeNoWaiting());
+
+ RunPendingSetToken();
+
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until a token is passed.
+ RingBuffer::Offset offset1 = allocator_->Alloc(kSize);
+ EXPECT_EQ(kBaseOffset, offset1);
+
+ // Check that the token has indeed passed.
+ EXPECT_LE(tokens[0], GetToken());
+
+ allocator_->FreePendingToken(offset1, helper_->InsertToken());
+}
+
+// Tests GetLargestFreeSizeNoWaiting
+TEST_F(RingBufferTest, TestGetLargestFreeSizeNoWaiting) {
+ EXPECT_EQ(kBufferSize, allocator_->GetLargestFreeSizeNoWaiting());
+
+ RingBuffer::Offset offset = allocator_->Alloc(kBufferSize);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+ allocator_->FreePendingToken(offset, helper_->InsertToken());
+}
+
+TEST_F(RingBufferTest, TestFreeBug) {
+ // The first and second allocations must not match.
+ const unsigned int kAlloc1 = 10;
+ const unsigned int kAlloc2 = 20;
+ RingBuffer::Offset offset = allocator_->Alloc(kAlloc1);
+ EXPECT_EQ(kBufferSize - kAlloc1, allocator_->GetLargestFreeSizeNoWaiting());
+ allocator_->FreePendingToken(offset, helper_.get()->InsertToken());
+ offset = allocator_->Alloc(kAlloc2);
+ EXPECT_EQ(kBufferSize - kAlloc1 - kAlloc2,
+ allocator_->GetLargestFreeSizeNoWaiting());
+ allocator_->FreePendingToken(offset, helper_.get()->InsertToken());
+ offset = allocator_->Alloc(kBufferSize);
+ EXPECT_EQ(0u, allocator_->GetLargestFreeSizeNoWaiting());
+ allocator_->FreePendingToken(offset, helper_.get()->InsertToken());
+}
+
+// Test fixture for RingBufferWrapper test - Creates a
+// RingBufferWrapper, using a CommandBufferHelper with a mock
+// AsyncAPIInterface for its interface (calling it directly, not through the
+// RPC mechanism), making sure Noops are ignored and SetToken are properly
+// forwarded to the engine.
+class RingBufferWrapperTest : public BaseRingBufferTest {
+ protected:
+ virtual void SetUp() {
+ BaseRingBufferTest::SetUp();
+
+ // Though allocating this buffer isn't strictly necessary, it makes
+ // allocations point to valid addresses, so they could be used for
+ // something.
+ buffer_.reset(new int8[kBufferSize + kBaseOffset]);
+ buffer_start_ = buffer_.get() + kBaseOffset;
+ allocator_.reset(new RingBufferWrapper(
+ kBaseOffset, kBufferSize, helper_.get(), buffer_start_));
+ }
+
+ virtual void TearDown() {
+ // If the GpuScheduler posts any tasks, this forces them to run.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ BaseRingBufferTest::TearDown();
+ }
+
+ scoped_ptr<RingBufferWrapper> allocator_;
+ scoped_ptr<int8[]> buffer_;
+ int8* buffer_start_;
+};
+
+// Checks basic alloc and free.
+TEST_F(RingBufferWrapperTest, TestBasic) {
+ const unsigned int kSize = 16;
+ void* pointer = allocator_->Alloc(kSize);
+ ASSERT_TRUE(pointer);
+ EXPECT_LE(buffer_start_, static_cast<int8*>(pointer));
+ EXPECT_GE(kBufferSize, static_cast<int8*>(pointer) - buffer_start_ + kSize);
+
+ allocator_->FreePendingToken(pointer, helper_->InsertToken());
+
+ int8* pointer_int8 = allocator_->AllocTyped<int8>(kSize);
+ ASSERT_TRUE(pointer_int8);
+ EXPECT_LE(buffer_start_, pointer_int8);
+ EXPECT_GE(buffer_start_ + kBufferSize, pointer_int8 + kSize);
+ allocator_->FreePendingToken(pointer_int8, helper_->InsertToken());
+
+ unsigned int* pointer_uint = allocator_->AllocTyped<unsigned int>(kSize);
+ ASSERT_TRUE(pointer_uint);
+ EXPECT_LE(buffer_start_, reinterpret_cast<int8*>(pointer_uint));
+ EXPECT_GE(buffer_start_ + kBufferSize,
+ reinterpret_cast<int8* >(pointer_uint + kSize));
+
+ // Check that it did allocate kSize * sizeof(unsigned int). We can't tell
+ // directly, except from the remaining size.
+ EXPECT_EQ(kBufferSize - kSize - kSize - kSize * sizeof(*pointer_uint),
+ allocator_->GetLargestFreeSizeNoWaiting());
+ allocator_->FreePendingToken(pointer_uint, helper_->InsertToken());
+}
+
+// Checks the free-pending-token mechanism.
+TEST_F(RingBufferWrapperTest, TestFreePendingToken) {
+ const unsigned int kSize = 16;
+ const unsigned int kAllocCount = kBufferSize / kSize;
+ CHECK(kAllocCount * kSize == kBufferSize);
+
+ delay_set_token_ = true;
+ // Allocate several buffers to fill in the memory.
+ int32 tokens[kAllocCount];
+ for (unsigned int ii = 0; ii < kAllocCount; ++ii) {
+ void* pointer = allocator_->Alloc(kSize);
+ EXPECT_TRUE(pointer != NULL);
+ tokens[ii] = helper_->InsertToken();
+ allocator_->FreePendingToken(pointer, helper_->InsertToken());
+ }
+
+ EXPECT_EQ(kBufferSize - (kSize * kAllocCount),
+ allocator_->GetLargestFreeSizeNoWaiting());
+
+ RunPendingSetToken();
+
+ // This allocation will need to reclaim the space freed above, so that should
+ // process the commands until the token is passed.
+ void* pointer1 = allocator_->Alloc(kSize);
+ EXPECT_EQ(buffer_start_, static_cast<int8*>(pointer1));
+
+ // Check that the token has indeed passed.
+ EXPECT_LE(tokens[0], GetToken());
+
+ allocator_->FreePendingToken(pointer1, helper_->InsertToken());
+ EXPECT_LE(command_buffer_->GetState().token, helper_->InsertToken());
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/share_group.cc b/chromium/gpu/command_buffer/client/share_group.cc
new file mode 100644
index 00000000000..9526df2efd6
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/share_group.cc
@@ -0,0 +1,216 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/atomicops.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/program_info_manager.h"
+#include "gpu/command_buffer/client/share_group.h"
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+namespace gles2 {
+
+COMPILE_ASSERT(gpu::kInvalidResource == 0,
+ INVALID_RESOURCE_NOT_0_AS_GL_EXPECTS);
+
+// The standard id handler.
+class IdHandler : public IdHandlerInterface {
+ public:
+ IdHandler() { }
+ virtual ~IdHandler() { }
+
+ // Overridden from IdHandlerInterface.
+ virtual void MakeIds(
+ GLES2Implementation* /* gl_impl */,
+ GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE {
+ if (id_offset == 0) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ ids[ii] = id_allocator_.AllocateID();
+ }
+ } else {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ ids[ii] = id_allocator_.AllocateIDAtOrAbove(id_offset);
+ id_offset = ids[ii] + 1;
+ }
+ }
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool FreeIds(
+ GLES2Implementation* gl_impl,
+ GLsizei n, const GLuint* ids, DeleteFn delete_fn) OVERRIDE {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ id_allocator_.FreeID(ids[ii]);
+ }
+ (gl_impl->*delete_fn)(n, ids);
+ // We need to ensure that the delete call is evaluated on the service side
+ // before any other contexts issue commands using these client ids.
+ gl_impl->helper()->CommandBufferHelper::Flush();
+ return true;
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool MarkAsUsedForBind(GLuint id) OVERRIDE {
+ return id == 0 ? true : id_allocator_.MarkAsUsed(id);
+ }
+ protected:
+ IdAllocator id_allocator_;
+};
+
+// An id handler that require Gen before Bind.
+class StrictIdHandler : public IdHandler {
+ public:
+ StrictIdHandler() {}
+ virtual ~StrictIdHandler() {}
+
+ // Overridden from IdHandler.
+ virtual bool MarkAsUsedForBind(GLuint id) OVERRIDE {
+ GPU_DCHECK(id == 0 || id_allocator_.InUse(id));
+ return IdHandler::MarkAsUsedForBind(id);
+ }
+};
+
+// An id handler for ids that are never reused.
+class NonReusedIdHandler : public IdHandlerInterface {
+ public:
+ NonReusedIdHandler() : last_id_(0) {}
+ virtual ~NonReusedIdHandler() {}
+
+ // Overridden from IdHandlerInterface.
+ virtual void MakeIds(
+ GLES2Implementation* /* gl_impl */,
+ GLuint id_offset, GLsizei n, GLuint* ids) OVERRIDE {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ ids[ii] = ++last_id_ + id_offset;
+ }
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool FreeIds(
+ GLES2Implementation* gl_impl,
+ GLsizei n, const GLuint* ids, DeleteFn delete_fn) OVERRIDE {
+ // Ids are never freed.
+ (gl_impl->*delete_fn)(n, ids);
+ return true;
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool MarkAsUsedForBind(GLuint /* id */) OVERRIDE {
+ // This is only used for Shaders and Programs which have no bind.
+ return false;
+ }
+
+ private:
+ GLuint last_id_;
+};
+
+// An id handler for shared ids.
+class SharedIdHandler : public IdHandlerInterface {
+ public:
+ SharedIdHandler(
+ id_namespaces::IdNamespaces id_namespace)
+ : id_namespace_(id_namespace) {
+ }
+
+ virtual ~SharedIdHandler() {}
+
+ virtual void MakeIds(GLES2Implementation* gl_impl,
+ GLuint id_offset,
+ GLsizei n,
+ GLuint* ids) OVERRIDE {
+ gl_impl->GenSharedIdsCHROMIUM(id_namespace_, id_offset, n, ids);
+ }
+
+ virtual bool FreeIds(GLES2Implementation* gl_impl,
+ GLsizei n,
+ const GLuint* ids,
+ DeleteFn delete_fn) OVERRIDE {
+ gl_impl->DeleteSharedIdsCHROMIUM(id_namespace_, n, ids);
+ (gl_impl->*delete_fn)(n, ids);
+ // We need to ensure that the delete call is evaluated on the service side
+ // before any other contexts issue commands using these client ids.
+ gl_impl->helper()->CommandBufferHelper::Flush();
+ return true;
+ }
+
+ virtual bool MarkAsUsedForBind(GLuint id) OVERRIDE {
+ // This has no meaning for shared resources.
+ return true;
+ }
+
+ private:
+ id_namespaces::IdNamespaces id_namespace_;
+};
+
+class ThreadSafeIdHandlerWrapper : public IdHandlerInterface {
+ public:
+ ThreadSafeIdHandlerWrapper(IdHandlerInterface* id_handler)
+ : id_handler_(id_handler) {
+ }
+ virtual ~ThreadSafeIdHandlerWrapper() { }
+
+ // Overridden from IdHandlerInterface.
+ virtual void MakeIds(GLES2Implementation* gl_impl,
+ GLuint id_offset,
+ GLsizei n,
+ GLuint* ids) OVERRIDE {
+ AutoLock auto_lock(lock_);
+ id_handler_->MakeIds(gl_impl, id_offset, n, ids);
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool FreeIds(GLES2Implementation* gl_impl,
+ GLsizei n,
+ const GLuint* ids,
+ DeleteFn delete_fn) OVERRIDE {
+ AutoLock auto_lock(lock_);
+ return id_handler_->FreeIds(gl_impl, n, ids, delete_fn);
+ }
+
+ // Overridden from IdHandlerInterface.
+ virtual bool MarkAsUsedForBind(GLuint id) OVERRIDE {
+ AutoLock auto_lock(lock_);
+ return id_handler_->MarkAsUsedForBind(id);
+ }
+
+ private:
+ scoped_ptr<IdHandlerInterface> id_handler_;
+ Lock lock_;
+};
+
+ShareGroup::ShareGroup(bool bind_generates_resource)
+ : bind_generates_resource_(bind_generates_resource) {
+ if (bind_generates_resource) {
+ for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
+ if (i == id_namespaces::kProgramsAndShaders) {
+ id_handlers_[i].reset(new ThreadSafeIdHandlerWrapper(
+ new NonReusedIdHandler()));
+ } else {
+ id_handlers_[i].reset(new ThreadSafeIdHandlerWrapper(
+ new IdHandler()));
+ }
+ }
+ } else {
+ for (int i = 0; i < id_namespaces::kNumIdNamespaces; ++i) {
+ if (i == id_namespaces::kProgramsAndShaders) {
+ id_handlers_[i].reset(new ThreadSafeIdHandlerWrapper(
+ new NonReusedIdHandler()));
+ } else {
+ id_handlers_[i].reset(new ThreadSafeIdHandlerWrapper(
+ new StrictIdHandler()));
+ }
+ }
+ }
+ program_info_manager_.reset(ProgramInfoManager::Create(false));
+}
+
+void ShareGroup::set_program_info_manager(ProgramInfoManager* manager) {
+ program_info_manager_.reset(manager);
+}
+
+ShareGroup::~ShareGroup() {}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/share_group.h b/chromium/gpu/command_buffer/client/share_group.h
new file mode 100644
index 00000000000..68ea6a9895a
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/share_group.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_SHARE_GROUP_H_
+#define GPU_COMMAND_BUFFER_CLIENT_SHARE_GROUP_H_
+
+#include <GLES2/gl2.h>
+#include "base/memory/scoped_ptr.h"
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/ref_counted.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2Implementation;
+class GLES2ImplementationTest;
+class ProgramInfoManager;
+
+typedef void (GLES2Implementation::*DeleteFn)(GLsizei n, const GLuint* ids);
+
+// Base class for IdHandlers
+class IdHandlerInterface {
+ public:
+ IdHandlerInterface() { }
+ virtual ~IdHandlerInterface() { }
+
+ // Makes some ids at or above id_offset.
+ virtual void MakeIds(
+ GLES2Implementation* gl_impl,
+ GLuint id_offset, GLsizei n, GLuint* ids) = 0;
+
+ // Frees some ids.
+ virtual bool FreeIds(
+ GLES2Implementation* gl_impl, GLsizei n, const GLuint* ids,
+ DeleteFn delete_fn) = 0;
+
+ // Marks an id as used for glBind functions. id = 0 does nothing.
+ virtual bool MarkAsUsedForBind(GLuint id) = 0;
+};
+
+// ShareGroup manages shared resources for contexts that are sharing resources.
+class GLES2_IMPL_EXPORT ShareGroup
+ : public gpu::RefCountedThreadSafe<ShareGroup> {
+ public:
+ ShareGroup(bool bind_generates_resource);
+
+ bool bind_generates_resource() const {
+ return bind_generates_resource_;
+ }
+
+ bool Initialize();
+
+ IdHandlerInterface* GetIdHandler(int namespace_id) const {
+ return id_handlers_[namespace_id].get();
+ }
+
+ ProgramInfoManager* program_info_manager() {
+ return program_info_manager_.get();
+ }
+
+ private:
+ friend class gpu::RefCountedThreadSafe<ShareGroup>;
+ friend class gpu::gles2::GLES2ImplementationTest;
+ ~ShareGroup();
+
+ // Install a new program info manager. Used for testing only;
+ void set_program_info_manager(ProgramInfoManager* manager);
+
+ scoped_ptr<IdHandlerInterface> id_handlers_[id_namespaces::kNumIdNamespaces];
+ scoped_ptr<ProgramInfoManager> program_info_manager_;
+
+ bool bind_generates_resource_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShareGroup);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_SHARE_GROUP_H_
diff --git a/chromium/gpu/command_buffer/client/transfer_buffer.cc b/chromium/gpu/command_buffer/client/transfer_buffer.cc
new file mode 100644
index 00000000000..f4fe66c9d64
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/transfer_buffer.cc
@@ -0,0 +1,227 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A class to Manage a growing transfer buffer.
+
+#include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+
+namespace gpu {
+
+AlignedRingBuffer::~AlignedRingBuffer() {
+}
+
+TransferBuffer::TransferBuffer(
+ CommandBufferHelper* helper)
+ : helper_(helper),
+ result_size_(0),
+ default_buffer_size_(0),
+ min_buffer_size_(0),
+ max_buffer_size_(0),
+ alignment_(0),
+ size_to_flush_(0),
+ bytes_since_last_flush_(0),
+ buffer_id_(-1),
+ result_buffer_(NULL),
+ result_shm_offset_(0),
+ usable_(true) {
+}
+
+TransferBuffer::~TransferBuffer() {
+ Free();
+}
+
+bool TransferBuffer::Initialize(
+ unsigned int default_buffer_size,
+ unsigned int result_size,
+ unsigned int min_buffer_size,
+ unsigned int max_buffer_size,
+ unsigned int alignment,
+ unsigned int size_to_flush) {
+ result_size_ = result_size;
+ default_buffer_size_ = default_buffer_size;
+ min_buffer_size_ = min_buffer_size;
+ max_buffer_size_ = max_buffer_size;
+ alignment_ = alignment;
+ size_to_flush_ = size_to_flush;
+ ReallocateRingBuffer(default_buffer_size_ - result_size);
+ return HaveBuffer();
+}
+
+void TransferBuffer::Free() {
+ if (HaveBuffer()) {
+ helper_->Finish();
+ helper_->command_buffer()->DestroyTransferBuffer(buffer_id_);
+ buffer_id_ = -1;
+ buffer_.ptr = NULL;
+ buffer_.size = 0;
+ result_buffer_ = NULL;
+ result_shm_offset_ = 0;
+ ring_buffer_.reset();
+ bytes_since_last_flush_ = 0;
+ }
+}
+
+bool TransferBuffer::HaveBuffer() const {
+ return buffer_id_ != -1;
+}
+
+RingBuffer::Offset TransferBuffer::GetOffset(void* pointer) const {
+ return ring_buffer_->GetOffset(pointer);
+}
+
+void TransferBuffer::FreePendingToken(void* p, unsigned int token) {
+ ring_buffer_->FreePendingToken(p, token);
+ if (bytes_since_last_flush_ >= size_to_flush_ && size_to_flush_ > 0) {
+ helper_->Flush();
+ bytes_since_last_flush_ = 0;
+ }
+}
+
+void TransferBuffer::AllocateRingBuffer(unsigned int size) {
+ for (;size >= min_buffer_size_; size /= 2) {
+ int32 id = -1;
+ gpu::Buffer buffer =
+ helper_->command_buffer()->CreateTransferBuffer(size, &id);
+ if (id != -1) {
+ buffer_ = buffer;
+ ring_buffer_.reset(new AlignedRingBuffer(
+ alignment_,
+ id,
+ result_size_,
+ buffer_.size - result_size_,
+ helper_,
+ static_cast<char*>(buffer_.ptr) + result_size_));
+ buffer_id_ = id;
+ result_buffer_ = buffer_.ptr;
+ result_shm_offset_ = 0;
+ return;
+ }
+ // we failed so don't try larger than this.
+ max_buffer_size_ = size / 2;
+ }
+ usable_ = false;
+}
+
+// Returns the integer i such as 2^i <= n < 2^(i+1)
+static int Log2Floor(uint32 n) {
+ if (n == 0)
+ return -1;
+ int log = 0;
+ uint32 value = n;
+ for (int i = 4; i >= 0; --i) {
+ int shift = (1 << i);
+ uint32 x = value >> shift;
+ if (x != 0) {
+ value = x;
+ log += shift;
+ }
+ }
+ GPU_DCHECK_EQ(value, 1u);
+ return log;
+}
+
+// Returns the integer i such as 2^(i-1) < n <= 2^i
+static int Log2Ceiling(uint32 n) {
+ if (n == 0) {
+ return -1;
+ } else {
+ // Log2Floor returns -1 for 0, so the following works correctly for n=1.
+ return 1 + Log2Floor(n - 1);
+ }
+}
+
+static unsigned int ComputePOTSize(unsigned int dimension) {
+ return (dimension == 0) ? 0 : 1 << Log2Ceiling(dimension);
+}
+
+void TransferBuffer::ReallocateRingBuffer(unsigned int size) {
+ // What size buffer would we ask for if we needed a new one?
+ unsigned int needed_buffer_size = ComputePOTSize(size + result_size_);
+ needed_buffer_size = std::max(needed_buffer_size, min_buffer_size_);
+ needed_buffer_size = std::max(needed_buffer_size, default_buffer_size_);
+ needed_buffer_size = std::min(needed_buffer_size, max_buffer_size_);
+
+ if (usable_ && (!HaveBuffer() || needed_buffer_size > buffer_.size)) {
+ if (HaveBuffer()) {
+ Free();
+ }
+ AllocateRingBuffer(needed_buffer_size);
+ }
+}
+
+void* TransferBuffer::AllocUpTo(
+ unsigned int size, unsigned int* size_allocated) {
+ GPU_DCHECK(size_allocated);
+
+ ReallocateRingBuffer(size);
+
+ if (!HaveBuffer()) {
+ return NULL;
+ }
+
+ unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
+ *size_allocated = std::min(max_size, size);
+ bytes_since_last_flush_ += *size_allocated;
+ return ring_buffer_->Alloc(*size_allocated);
+}
+
+void* TransferBuffer::Alloc(unsigned int size) {
+ ReallocateRingBuffer(size);
+
+ if (!HaveBuffer()) {
+ return NULL;
+ }
+
+ unsigned int max_size = ring_buffer_->GetLargestFreeOrPendingSize();
+ if (size > max_size) {
+ return NULL;
+ }
+
+ bytes_since_last_flush_ += size;
+ return ring_buffer_->Alloc(size);
+}
+
+void* TransferBuffer::GetResultBuffer() {
+ ReallocateRingBuffer(result_size_);
+ return result_buffer_;
+}
+
+int TransferBuffer::GetResultOffset() {
+ ReallocateRingBuffer(result_size_);
+ return result_shm_offset_;
+}
+
+int TransferBuffer::GetShmId() {
+ ReallocateRingBuffer(result_size_);
+ return buffer_id_;
+}
+
+unsigned int TransferBuffer::GetCurrentMaxAllocationWithoutRealloc() const {
+ return HaveBuffer() ? ring_buffer_->GetLargestFreeOrPendingSize() : 0;
+}
+
+unsigned int TransferBuffer::GetMaxAllocation() const {
+ return HaveBuffer() ? max_buffer_size_ - result_size_ : 0;
+}
+
+void ScopedTransferBufferPtr::Release() {
+ if (buffer_) {
+ transfer_buffer_->FreePendingToken(buffer_, helper_->InsertToken());
+ buffer_ = NULL;
+ size_ = 0;
+ }
+}
+
+void ScopedTransferBufferPtr::Reset(unsigned int new_size) {
+ Release();
+ // NOTE: we allocate buffers of size 0 so that HaveBuffer will be true, so
+ // that address will return a pointer just like malloc, and so that GetShmId
+ // will be valid. That has the side effect that we'll insert a token on free.
+ // We could add code skip the token for a zero size buffer but it doesn't seem
+ // worth the complication.
+ buffer_ = transfer_buffer_->AllocUpTo(new_size, &size_);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/client/transfer_buffer.h b/chromium/gpu/command_buffer/client/transfer_buffer.h
new file mode 100644
index 00000000000..273f0170bb0
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/transfer_buffer.h
@@ -0,0 +1,233 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/client/ring_buffer.h"
+#include "gpu/command_buffer/common/buffer.h"
+#include "gpu/command_buffer/common/compiler_specific.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class CommandBufferHelper;
+
+// Wraps RingBufferWrapper to provide aligned allocations.
+class AlignedRingBuffer : public RingBufferWrapper {
+ public:
+ AlignedRingBuffer(
+ unsigned int alignment,
+ int32 shm_id,
+ RingBuffer::Offset base_offset,
+ unsigned int size,
+ CommandBufferHelper* helper,
+ void* base)
+ : RingBufferWrapper(base_offset, size, helper, base),
+ alignment_(alignment),
+ shm_id_(shm_id) {
+ }
+ ~AlignedRingBuffer();
+
+ // Hiding Alloc from RingBufferWrapper
+ void* Alloc(unsigned int size) {
+ return RingBufferWrapper::Alloc(RoundToAlignment(size));
+ }
+
+ int32 GetShmId() const {
+ return shm_id_;
+ }
+
+ private:
+ unsigned int RoundToAlignment(unsigned int size) {
+ return (size + alignment_ - 1) & ~(alignment_ - 1);
+ }
+
+ unsigned int alignment_;
+ int32 shm_id_;
+};
+
+// Interface for managing the transfer buffer.
+class GPU_EXPORT TransferBufferInterface {
+ public:
+ TransferBufferInterface() { }
+ virtual ~TransferBufferInterface() { }
+
+ virtual bool Initialize(
+ unsigned int buffer_size,
+ unsigned int result_size,
+ unsigned int min_buffer_size,
+ unsigned int max_buffer_size,
+ unsigned int alignment,
+ unsigned int size_to_flush) = 0;
+
+ virtual int GetShmId() = 0;
+ virtual void* GetResultBuffer() = 0;
+ virtual int GetResultOffset() = 0;
+
+ virtual void Free() = 0;
+
+ virtual bool HaveBuffer() const = 0;
+
+ // Allocates up to size bytes.
+ virtual void* AllocUpTo(unsigned int size, unsigned int* size_allocated) = 0;
+
+ // Allocates size bytes.
+ // Note: Alloc will fail if it can not return size bytes.
+ virtual void* Alloc(unsigned int size) = 0;
+
+ virtual RingBuffer::Offset GetOffset(void* pointer) const = 0;
+
+ virtual void FreePendingToken(void* p, unsigned int token) = 0;
+};
+
+// Class that manages the transfer buffer.
+class GPU_EXPORT TransferBuffer : public TransferBufferInterface {
+ public:
+ TransferBuffer(CommandBufferHelper* helper);
+ virtual ~TransferBuffer();
+
+ // Overridden from TransferBufferInterface.
+ virtual bool Initialize(
+ unsigned int default_buffer_size,
+ unsigned int result_size,
+ unsigned int min_buffer_size,
+ unsigned int max_buffer_size,
+ unsigned int alignment,
+ unsigned int size_to_flush) OVERRIDE;
+ virtual int GetShmId() OVERRIDE;
+ virtual void* GetResultBuffer() OVERRIDE;
+ virtual int GetResultOffset() OVERRIDE;
+ virtual void Free() OVERRIDE;
+ virtual bool HaveBuffer() const OVERRIDE;
+ virtual void* AllocUpTo(
+ unsigned int size, unsigned int* size_allocated) OVERRIDE;
+ virtual void* Alloc(unsigned int size) OVERRIDE;
+ virtual RingBuffer::Offset GetOffset(void* pointer) const OVERRIDE;
+ virtual void FreePendingToken(void* p, unsigned int token) OVERRIDE;
+
+ // These are for testing.
+ unsigned int GetCurrentMaxAllocationWithoutRealloc() const;
+ unsigned int GetMaxAllocation() const;
+
+ private:
+ // Tries to reallocate the ring buffer if it's not large enough for size.
+ void ReallocateRingBuffer(unsigned int size);
+
+ void AllocateRingBuffer(unsigned int size);
+
+ CommandBufferHelper* helper_;
+ scoped_ptr<AlignedRingBuffer> ring_buffer_;
+
+ // size reserved for results
+ unsigned int result_size_;
+
+ // default size. Size we want when starting or re-allocating
+ unsigned int default_buffer_size_;
+
+ // min size we'll consider successful
+ unsigned int min_buffer_size_;
+
+ // max size we'll let the buffer grow
+ unsigned int max_buffer_size_;
+
+ // alignment for allocations
+ unsigned int alignment_;
+
+ // Size at which to do an async flush. 0 = never.
+ unsigned int size_to_flush_;
+
+ // Number of bytes since we last flushed.
+ unsigned int bytes_since_last_flush_;
+
+ // the current buffer.
+ gpu::Buffer buffer_;
+
+ // id of buffer. -1 = no buffer
+ int32 buffer_id_;
+
+ // address of result area
+ void* result_buffer_;
+
+ // offset to result area
+ uint32 result_shm_offset_;
+
+ // false if we failed to allocate min_buffer_size
+ bool usable_;
+};
+
+// A class that will manage the lifetime of a transferbuffer allocation.
+class GPU_EXPORT ScopedTransferBufferPtr {
+ public:
+ ScopedTransferBufferPtr(
+ unsigned int size,
+ CommandBufferHelper* helper,
+ TransferBufferInterface* transfer_buffer)
+ : buffer_(NULL),
+ size_(0),
+ helper_(helper),
+ transfer_buffer_(transfer_buffer) {
+ Reset(size);
+ }
+
+ ~ScopedTransferBufferPtr() {
+ Release();
+ }
+
+ bool valid() const {
+ return buffer_ != NULL;
+ }
+
+ unsigned int size() const {
+ return size_;
+ }
+
+ int shm_id() const {
+ return transfer_buffer_->GetShmId();
+ }
+
+ RingBuffer::Offset offset() const {
+ return transfer_buffer_->GetOffset(buffer_);
+ }
+
+ void* address() const {
+ return buffer_;
+ }
+
+ void Release();
+
+ void Reset(unsigned int new_size);
+
+ private:
+ void* buffer_;
+ unsigned int size_;
+ CommandBufferHelper* helper_;
+ TransferBufferInterface* transfer_buffer_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedTransferBufferPtr);
+};
+
+template <typename T>
+class ScopedTransferBufferArray : public ScopedTransferBufferPtr {
+ public:
+ ScopedTransferBufferArray(
+ unsigned int num_elements,
+ CommandBufferHelper* helper, TransferBufferInterface* transfer_buffer)
+ : ScopedTransferBufferPtr(
+ num_elements * sizeof(T), helper, transfer_buffer) {
+ }
+
+ T* elements() {
+ return static_cast<T*>(address());
+ }
+
+ unsigned int num_elements() const {
+ return size() / sizeof(T);
+ }
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_TRANSFER_BUFFER_H_
diff --git a/chromium/gpu/command_buffer/client/transfer_buffer_unittest.cc b/chromium/gpu/command_buffer/client/transfer_buffer_unittest.cc
new file mode 100644
index 00000000000..411e662871f
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/transfer_buffer_unittest.cc
@@ -0,0 +1,469 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the Command Buffer Helper.
+
+#include "gpu/command_buffer/client/transfer_buffer.h"
+
+#include "gpu/command_buffer/client/client_test_helper.h"
+#include "gpu/command_buffer/client/cmd_buffer_helper.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/compiler_specific.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using ::testing::_;
+using ::testing::AtMost;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
+namespace gpu {
+
+
+class TransferBufferTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+ static const unsigned int kStartingOffset = 64;
+ static const unsigned int kAlignment = 4;
+ static const size_t kTransferBufferSize = 256;
+
+ TransferBufferTest()
+ : transfer_buffer_id_(0) {
+ }
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ virtual void Initialize(unsigned int size_to_flush) {
+ ASSERT_TRUE(transfer_buffer_->Initialize(
+ kTransferBufferSize,
+ kStartingOffset,
+ kTransferBufferSize,
+ kTransferBufferSize,
+ kAlignment,
+ size_to_flush));
+ }
+
+ MockClientCommandBufferMockFlush* command_buffer() const {
+ return command_buffer_.get();
+ }
+
+ scoped_ptr<MockClientCommandBufferMockFlush> command_buffer_;
+ scoped_ptr<CommandBufferHelper> helper_;
+ scoped_ptr<TransferBuffer> transfer_buffer_;
+ int32 transfer_buffer_id_;
+};
+
+void TransferBufferTest::SetUp() {
+ command_buffer_.reset(new StrictMock<MockClientCommandBufferMockFlush>());
+ ASSERT_TRUE(command_buffer_->Initialize());
+
+ helper_.reset(new CommandBufferHelper(command_buffer()));
+ ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));
+
+ transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();
+
+ transfer_buffer_.reset(new TransferBuffer(helper_.get()));
+}
+
+void TransferBufferTest::TearDown() {
+ if (transfer_buffer_->HaveBuffer()) {
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ // For command buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*command_buffer(), OnFlush()).Times(AtMost(1));
+ transfer_buffer_.reset();
+}
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const int32 TransferBufferTest::kNumCommandEntries;
+const int32 TransferBufferTest::kCommandBufferSizeBytes;
+const unsigned int TransferBufferTest::kStartingOffset;
+const unsigned int TransferBufferTest::kAlignment;
+const size_t TransferBufferTest::kTransferBufferSize;
+#endif
+
+TEST_F(TransferBufferTest, Basic) {
+ Initialize(0);
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+ EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
+ EXPECT_EQ(
+ kTransferBufferSize - kStartingOffset,
+ transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+}
+
+TEST_F(TransferBufferTest, Free) {
+ Initialize(0);
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+ EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
+
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+ // See that it gets reallocated.
+ EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+ // See that it gets reallocated.
+ EXPECT_TRUE(transfer_buffer_->GetResultBuffer() != NULL);
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+ // See that it gets reallocated.
+ unsigned int size = 0;
+ void* data = transfer_buffer_->AllocUpTo(1, &size);
+ EXPECT_TRUE(data != NULL);
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+ transfer_buffer_->FreePendingToken(data, 1);
+
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+ // See that it gets reallocated.
+ transfer_buffer_->GetResultOffset();
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+
+ EXPECT_EQ(
+ kTransferBufferSize - kStartingOffset,
+ transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+
+ // Test freeing twice.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ transfer_buffer_->Free();
+}
+
+TEST_F(TransferBufferTest, TooLargeAllocation) {
+ Initialize(0);
+ // Check that we can't allocate large than max size.
+ void* ptr = transfer_buffer_->Alloc(kTransferBufferSize + 1);
+ EXPECT_TRUE(ptr == NULL);
+ // Check we if we try to allocate larger than max we get max.
+ unsigned int size_allocated = 0;
+ ptr = transfer_buffer_->AllocUpTo(
+ kTransferBufferSize + 1, &size_allocated);
+ ASSERT_TRUE(ptr != NULL);
+ EXPECT_EQ(kTransferBufferSize - kStartingOffset, size_allocated);
+ transfer_buffer_->FreePendingToken(ptr, 1);
+}
+
+TEST_F(TransferBufferTest, Flush) {
+ Initialize(16u);
+ unsigned int size_allocated = 0;
+ for (int i = 0; i < 8; ++i) {
+ void* ptr = transfer_buffer_->AllocUpTo(8u, &size_allocated);
+ ASSERT_TRUE(ptr != NULL);
+ EXPECT_EQ(8u, size_allocated);
+ if (i % 2) {
+ EXPECT_CALL(*command_buffer(), Flush(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
+ }
+ for (int i = 0; i < 8; ++i) {
+ void* ptr = transfer_buffer_->Alloc(8u);
+ ASSERT_TRUE(ptr != NULL);
+ if (i % 2) {
+ EXPECT_CALL(*command_buffer(), Flush(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ transfer_buffer_->FreePendingToken(ptr, helper_->InsertToken());
+ }
+}
+
+class MockClientCommandBufferCanFail : public MockClientCommandBufferMockFlush {
+ public:
+ MockClientCommandBufferCanFail() {
+ }
+ virtual ~MockClientCommandBufferCanFail() {
+ }
+
+ MOCK_METHOD2(CreateTransferBuffer, Buffer(size_t size, int32* id));
+
+ Buffer RealCreateTransferBuffer(size_t size, int32* id) {
+ return MockCommandBufferBase::CreateTransferBuffer(size, id);
+ }
+};
+
+class TransferBufferExpandContractTest : public testing::Test {
+ protected:
+ static const int32 kNumCommandEntries = 400;
+ static const int32 kCommandBufferSizeBytes =
+ kNumCommandEntries * sizeof(CommandBufferEntry);
+ static const unsigned int kStartingOffset = 64;
+ static const unsigned int kAlignment = 4;
+ static const size_t kStartTransferBufferSize = 256;
+ static const size_t kMaxTransferBufferSize = 1024;
+ static const size_t kMinTransferBufferSize = 128;
+
+ TransferBufferExpandContractTest()
+ : transfer_buffer_id_(0) {
+ }
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ MockClientCommandBufferCanFail* command_buffer() const {
+ return command_buffer_.get();
+ }
+
+ scoped_ptr<MockClientCommandBufferCanFail> command_buffer_;
+ scoped_ptr<CommandBufferHelper> helper_;
+ scoped_ptr<TransferBuffer> transfer_buffer_;
+ int32 transfer_buffer_id_;
+};
+
+void TransferBufferExpandContractTest::SetUp() {
+ command_buffer_.reset(new StrictMock<MockClientCommandBufferCanFail>());
+ ASSERT_TRUE(command_buffer_->Initialize());
+
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kCommandBufferSizeBytes, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+
+ helper_.reset(new CommandBufferHelper(command_buffer()));
+ ASSERT_TRUE(helper_->Initialize(kCommandBufferSizeBytes));
+
+ transfer_buffer_id_ = command_buffer()->GetNextFreeTransferBufferId();
+
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kStartTransferBufferSize, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+
+ transfer_buffer_.reset(new TransferBuffer(helper_.get()));
+ ASSERT_TRUE(transfer_buffer_->Initialize(
+ kStartTransferBufferSize,
+ kStartingOffset,
+ kMinTransferBufferSize,
+ kMaxTransferBufferSize,
+ kAlignment,
+ 0));
+}
+
+void TransferBufferExpandContractTest::TearDown() {
+ if (transfer_buffer_->HaveBuffer()) {
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ // For command buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_.reset();
+}
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const int32 TransferBufferExpandContractTest::kNumCommandEntries;
+const int32 TransferBufferExpandContractTest::kCommandBufferSizeBytes;
+const unsigned int TransferBufferExpandContractTest::kStartingOffset;
+const unsigned int TransferBufferExpandContractTest::kAlignment;
+const size_t TransferBufferExpandContractTest::kStartTransferBufferSize;
+const size_t TransferBufferExpandContractTest::kMaxTransferBufferSize;
+const size_t TransferBufferExpandContractTest::kMinTransferBufferSize;
+#endif
+
+TEST_F(TransferBufferExpandContractTest, Expand) {
+ // Check it starts at starting size.
+ EXPECT_EQ(
+ kStartTransferBufferSize - kStartingOffset,
+ transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kStartTransferBufferSize * 2, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+
+ // Try next power of 2.
+ const size_t kSize1 = 512 - kStartingOffset;
+ unsigned int size_allocated = 0;
+ void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
+ ASSERT_TRUE(ptr != NULL);
+ EXPECT_EQ(kSize1, size_allocated);
+ EXPECT_EQ(kSize1, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+ transfer_buffer_->FreePendingToken(ptr, 1);
+
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kMaxTransferBufferSize, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+
+ // Try next power of 2.
+ const size_t kSize2 = 1024 - kStartingOffset;
+ ptr = transfer_buffer_->AllocUpTo(kSize2, &size_allocated);
+ ASSERT_TRUE(ptr != NULL);
+ EXPECT_EQ(kSize2, size_allocated);
+ EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+ transfer_buffer_->FreePendingToken(ptr, 1);
+
+ // Try next one more. Should not go past max.
+ size_allocated = 0;
+ const size_t kSize3 = kSize2 + 1;
+ ptr = transfer_buffer_->AllocUpTo(kSize3, &size_allocated);
+ EXPECT_EQ(kSize2, size_allocated);
+ EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+ transfer_buffer_->FreePendingToken(ptr, 1);
+}
+
+TEST_F(TransferBufferExpandContractTest, Contract) {
+ // Check it starts at starting size.
+ EXPECT_EQ(
+ kStartTransferBufferSize - kStartingOffset,
+ transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+
+ // Try to allocate again, fail first request
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kStartTransferBufferSize, _))
+ .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kMinTransferBufferSize, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+
+ const size_t kSize1 = 256 - kStartingOffset;
+ const size_t kSize2 = 128 - kStartingOffset;
+ unsigned int size_allocated = 0;
+ void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
+ ASSERT_TRUE(ptr != NULL);
+ EXPECT_EQ(kSize2, size_allocated);
+ EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+ transfer_buffer_->FreePendingToken(ptr, 1);
+
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+
+ // Try to allocate again,
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kMinTransferBufferSize, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+
+ ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
+ ASSERT_TRUE(ptr != NULL);
+ EXPECT_EQ(kSize2, size_allocated);
+ EXPECT_EQ(kSize2, transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+ transfer_buffer_->FreePendingToken(ptr, 1);
+}
+
+TEST_F(TransferBufferExpandContractTest, OutOfMemory) {
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+
+ // Try to allocate again, fail both requests.
+ EXPECT_CALL(*command_buffer(), CreateTransferBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
+ .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
+ .WillOnce(DoAll(SetArgPointee<1>(-1), Return(Buffer())))
+ .RetiresOnSaturation();
+
+ const size_t kSize1 = 512 - kStartingOffset;
+ unsigned int size_allocated = 0;
+ void* ptr = transfer_buffer_->AllocUpTo(kSize1, &size_allocated);
+ ASSERT_TRUE(ptr == NULL);
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+}
+
+TEST_F(TransferBufferExpandContractTest, ReallocsToDefault) {
+ // Free buffer.
+ EXPECT_CALL(*command_buffer(), DestroyTransferBuffer(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ transfer_buffer_->Free();
+ // See it's freed.
+ EXPECT_FALSE(transfer_buffer_->HaveBuffer());
+
+ // See that it gets reallocated.
+ EXPECT_CALL(*command_buffer(),
+ CreateTransferBuffer(kStartTransferBufferSize, _))
+ .WillOnce(Invoke(
+ command_buffer(),
+ &MockClientCommandBufferCanFail::RealCreateTransferBuffer))
+ .RetiresOnSaturation();
+ EXPECT_EQ(transfer_buffer_id_, transfer_buffer_->GetShmId());
+ EXPECT_TRUE(transfer_buffer_->HaveBuffer());
+
+ // Check it's the default size.
+ EXPECT_EQ(
+ kStartTransferBufferSize - kStartingOffset,
+ transfer_buffer_->GetCurrentMaxAllocationWithoutRealloc());
+}
+
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/vertex_array_object_manager.cc b/chromium/gpu/command_buffer/client/vertex_array_object_manager.cc
new file mode 100644
index 00000000000..f2a156e9560
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/vertex_array_object_manager.cc
@@ -0,0 +1,640 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/vertex_array_object_manager.h"
+
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/common/logging.h"
+
+#if defined(__native_client__) && !defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+#define GLES2_SUPPORT_CLIENT_SIDE_ARRAYS
+#endif
+
+namespace gpu {
+namespace gles2 {
+
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+
+static GLsizei RoundUpToMultipleOf4(GLsizei size) {
+ return (size + 3) & ~3;
+}
+
+#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+
+// A 32-bit and 64-bit compatible way of converting a pointer to a GLuint.
+static GLuint ToGLuint(const void* ptr) {
+ return static_cast<GLuint>(reinterpret_cast<size_t>(ptr));
+}
+
+// This class tracks VertexAttribPointers and helps emulate client side buffers.
+//
+// The way client side buffers work is we shadow all the Vertex Attribs so we
+// know which ones are pointing to client side buffers.
+//
+// At Draw time, for any attribs pointing to client side buffers we copy them
+// to a special VBO and reset the actual vertex attrib pointers to point to this
+// VBO.
+//
+// This also means we have to catch calls to query those values so that when
+// an attrib is a client side buffer we pass the info back the user expects.
+
+class GLES2_IMPL_EXPORT VertexArrayObject {
+ public:
+ // Info about Vertex Attributes. This is used to track what the user currently
+ // has bound on each Vertex Attribute so we can simulate client side buffers
+ // at glDrawXXX time.
+ class VertexAttrib {
+ public:
+ VertexAttrib()
+ : enabled_(false),
+ buffer_id_(0),
+ size_(4),
+ type_(GL_FLOAT),
+ normalized_(GL_FALSE),
+ pointer_(NULL),
+ gl_stride_(0),
+ divisor_(0) {
+ }
+
+ bool enabled() const {
+ return enabled_;
+ }
+
+ void set_enabled(bool enabled) {
+ enabled_ = enabled;
+ }
+
+ GLuint buffer_id() const {
+ return buffer_id_;
+ }
+
+ void set_buffer_id(GLuint id) {
+ buffer_id_ = id;
+ }
+
+ GLenum type() const {
+ return type_;
+ }
+
+ GLint size() const {
+ return size_;
+ }
+
+ GLsizei stride() const {
+ return gl_stride_;
+ }
+
+ GLboolean normalized() const {
+ return normalized_;
+ }
+
+ const GLvoid* pointer() const {
+ return pointer_;
+ }
+
+ bool IsClientSide() const {
+ return buffer_id_ == 0;
+ }
+
+ GLuint divisor() const {
+ return divisor_;
+ }
+
+ void SetInfo(
+ GLuint buffer_id,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei gl_stride,
+ const GLvoid* pointer) {
+ buffer_id_ = buffer_id;
+ size_ = size;
+ type_ = type;
+ normalized_ = normalized;
+ gl_stride_ = gl_stride;
+ pointer_ = pointer;
+ }
+
+ void SetDivisor(GLuint divisor) {
+ divisor_ = divisor;
+ }
+
+ private:
+ // Whether or not this attribute is enabled.
+ bool enabled_;
+
+ // The id of the buffer. 0 = client side buffer.
+ GLuint buffer_id_;
+
+ // Number of components (1, 2, 3, 4).
+ GLint size_;
+
+ // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
+ GLenum type_;
+
+ // GL_TRUE or GL_FALSE
+ GLboolean normalized_;
+
+ // The pointer/offset into the buffer.
+ const GLvoid* pointer_;
+
+ // The stride that will be used to access the buffer. This is the bogus GL
+ // stride where 0 = compute the stride based on size and type.
+ GLsizei gl_stride_;
+
+ // Divisor, for geometry instancing.
+ GLuint divisor_;
+ };
+
+ typedef std::vector<VertexAttrib> VertexAttribs;
+
+ explicit VertexArrayObject(GLuint max_vertex_attribs);
+
+ void UnbindBuffer(GLuint id);
+
+ bool BindElementArray(GLuint id);
+
+ bool HaveEnabledClientSideBuffers() const;
+
+ void SetAttribEnable(GLuint index, bool enabled);
+
+ void SetAttribPointer(
+ GLuint buffer_id,
+ GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,
+ const void* ptr);
+
+ bool GetVertexAttrib(
+ GLuint index, GLenum pname, uint32* param) const;
+
+ void SetAttribDivisor(GLuint index, GLuint divisor);
+
+ bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
+
+ const VertexAttribs& vertex_attribs() const {
+ return vertex_attribs_;
+ }
+
+ GLuint bound_element_array_buffer() const {
+ return bound_element_array_buffer_id_;
+ }
+
+ private:
+ const VertexAttrib* GetAttrib(GLuint index) const;
+
+ int num_client_side_pointers_enabled_;
+
+ // The currently bound element array buffer.
+ GLuint bound_element_array_buffer_id_;
+
+ VertexAttribs vertex_attribs_;
+
+ DISALLOW_COPY_AND_ASSIGN(VertexArrayObject);
+};
+
+VertexArrayObject::VertexArrayObject(GLuint max_vertex_attribs)
+ : num_client_side_pointers_enabled_(0),
+ bound_element_array_buffer_id_(0) {
+ vertex_attribs_.resize(max_vertex_attribs);
+}
+
+void VertexArrayObject::UnbindBuffer(GLuint id) {
+ if (id == 0) {
+ return;
+ }
+ for (size_t ii = 0; ii < vertex_attribs_.size(); ++ii) {
+ VertexAttrib& attrib = vertex_attribs_[ii];
+ if (attrib.buffer_id() == id) {
+ attrib.set_buffer_id(0);
+ if (attrib.enabled()) {
+ ++num_client_side_pointers_enabled_;
+ }
+ }
+ }
+ if (bound_element_array_buffer_id_ == id) {
+ bound_element_array_buffer_id_ = 0;
+ }
+}
+
+bool VertexArrayObject::BindElementArray(GLuint id) {
+ if (id == bound_element_array_buffer_id_) {
+ return false;
+ }
+ bound_element_array_buffer_id_ = id;
+ return true;
+}
+bool VertexArrayObject::HaveEnabledClientSideBuffers() const {
+ return num_client_side_pointers_enabled_ > 0;
+}
+
+void VertexArrayObject::SetAttribEnable(GLuint index, bool enabled) {
+ if (index < vertex_attribs_.size()) {
+ VertexAttrib& attrib = vertex_attribs_[index];
+ if (attrib.enabled() != enabled) {
+ if (attrib.IsClientSide()) {
+ num_client_side_pointers_enabled_ += enabled ? 1 : -1;
+ GPU_DCHECK_GE(num_client_side_pointers_enabled_, 0);
+ }
+ attrib.set_enabled(enabled);
+ }
+ }
+}
+
+void VertexArrayObject::SetAttribPointer(
+ GLuint buffer_id,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const void* ptr) {
+ if (index < vertex_attribs_.size()) {
+ VertexAttrib& attrib = vertex_attribs_[index];
+ if (attrib.IsClientSide() && attrib.enabled()) {
+ --num_client_side_pointers_enabled_;
+ GPU_DCHECK_GE(num_client_side_pointers_enabled_, 0);
+ }
+
+ attrib.SetInfo(buffer_id, size, type, normalized, stride, ptr);
+
+ if (attrib.IsClientSide() && attrib.enabled()) {
+ ++num_client_side_pointers_enabled_;
+ }
+ }
+}
+
+bool VertexArrayObject::GetVertexAttrib(
+ GLuint index, GLenum pname, uint32* param) const {
+ const VertexAttrib* attrib = GetAttrib(index);
+ if (!attrib) {
+ return false;
+ }
+
+ switch (pname) {
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ *param = attrib->buffer_id();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ *param = attrib->enabled();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ *param = attrib->size();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ *param = attrib->stride();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ *param = attrib->type();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ *param = attrib->normalized();
+ break;
+ default:
+ return false; // pass through to service side.
+ break;
+ }
+ return true;
+}
+
+void VertexArrayObject::SetAttribDivisor(GLuint index, GLuint divisor) {
+ if (index < vertex_attribs_.size()) {
+ VertexAttrib& attrib = vertex_attribs_[index];
+ attrib.SetDivisor(divisor);
+ }
+}
+
+// Gets the Attrib pointer for an attrib but only if it's a client side
+// pointer. Returns true if it got the pointer.
+bool VertexArrayObject::GetAttribPointer(
+ GLuint index, GLenum pname, void** ptr) const {
+ const VertexAttrib* attrib = GetAttrib(index);
+ if (attrib && pname == GL_VERTEX_ATTRIB_ARRAY_POINTER) {
+ *ptr = const_cast<void*>(attrib->pointer());
+ return true;
+ }
+ return false;
+}
+
+// Gets an attrib if it's in range and it's client side.
+const VertexArrayObject::VertexAttrib* VertexArrayObject::GetAttrib(
+ GLuint index) const {
+ if (index < vertex_attribs_.size()) {
+ const VertexAttrib* attrib = &vertex_attribs_[index];
+ return attrib;
+ }
+ return NULL;
+}
+
+VertexArrayObjectManager::VertexArrayObjectManager(
+ GLuint max_vertex_attribs,
+ GLuint array_buffer_id,
+ GLuint element_array_buffer_id)
+ : max_vertex_attribs_(max_vertex_attribs),
+ array_buffer_id_(array_buffer_id),
+ array_buffer_size_(0),
+ array_buffer_offset_(0),
+ element_array_buffer_id_(element_array_buffer_id),
+ element_array_buffer_size_(0),
+ collection_buffer_size_(0),
+ default_vertex_array_object_(new VertexArrayObject(max_vertex_attribs)),
+ bound_vertex_array_object_(default_vertex_array_object_) {
+}
+
+VertexArrayObjectManager::~VertexArrayObjectManager() {
+ for (VertexArrayObjectMap::iterator it = vertex_array_objects_.begin();
+ it != vertex_array_objects_.end(); ++it) {
+ delete it->second;
+ }
+ delete default_vertex_array_object_;
+}
+
+bool VertexArrayObjectManager::IsReservedId(GLuint id) const {
+ return (id != 0 &&
+ (id == array_buffer_id_ || id == element_array_buffer_id_));
+}
+
+GLuint VertexArrayObjectManager::bound_element_array_buffer() const {
+ return bound_vertex_array_object_->bound_element_array_buffer();
+}
+
+void VertexArrayObjectManager::UnbindBuffer(GLuint id) {
+ bound_vertex_array_object_->UnbindBuffer(id);
+}
+
+bool VertexArrayObjectManager::BindElementArray(GLuint id) {
+ return bound_vertex_array_object_->BindElementArray(id);
+}
+
+void VertexArrayObjectManager::GenVertexArrays(
+ GLsizei n, const GLuint* arrays) {
+ GPU_DCHECK_GE(n, 0);
+ for (GLsizei i = 0; i < n; ++i) {
+ std::pair<VertexArrayObjectMap::iterator, bool> result =
+ vertex_array_objects_.insert(std::make_pair(
+ arrays[i], new VertexArrayObject(max_vertex_attribs_)));
+ GPU_DCHECK(result.second);
+ }
+}
+
+void VertexArrayObjectManager::DeleteVertexArrays(
+ GLsizei n, const GLuint* arrays) {
+ GPU_DCHECK_GE(n, 0);
+ for (GLsizei i = 0; i < n; ++i) {
+ GLuint id = arrays[i];
+ if (id) {
+ VertexArrayObjectMap::iterator it = vertex_array_objects_.find(id);
+ if (it != vertex_array_objects_.end()) {
+ if (bound_vertex_array_object_ == it->second) {
+ bound_vertex_array_object_ = default_vertex_array_object_;
+ }
+ delete it->second;
+ vertex_array_objects_.erase(it);
+ }
+ }
+ }
+}
+
+bool VertexArrayObjectManager::BindVertexArray(GLuint array, bool* changed) {
+ *changed = false;
+ VertexArrayObject* vertex_array_object = default_vertex_array_object_;
+ if (array != 0) {
+ VertexArrayObjectMap::iterator it = vertex_array_objects_.find(array);
+ if (it == vertex_array_objects_.end()) {
+ return false;
+ }
+ vertex_array_object = it->second;
+ }
+ *changed = vertex_array_object != bound_vertex_array_object_;
+ bound_vertex_array_object_ = vertex_array_object;
+ return true;
+}
+
+bool VertexArrayObjectManager::HaveEnabledClientSideBuffers() const {
+ return bound_vertex_array_object_->HaveEnabledClientSideBuffers();
+}
+
+void VertexArrayObjectManager::SetAttribEnable(GLuint index, bool enabled) {
+ bound_vertex_array_object_->SetAttribEnable(index, enabled);
+}
+
+bool VertexArrayObjectManager::GetVertexAttrib(
+ GLuint index, GLenum pname, uint32* param) {
+ return bound_vertex_array_object_->GetVertexAttrib(index, pname, param);
+}
+
+bool VertexArrayObjectManager::GetAttribPointer(
+ GLuint index, GLenum pname, void** ptr) const {
+ return bound_vertex_array_object_->GetAttribPointer(index, pname, ptr);
+}
+
+bool VertexArrayObjectManager::SetAttribPointer(
+ GLuint buffer_id,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const void* ptr) {
+ // Client side arrays are not allowed in vaos.
+ if (buffer_id == 0 && !IsDefaultVAOBound()) {
+ return false;
+ }
+ bound_vertex_array_object_->SetAttribPointer(
+ buffer_id, index, size, type, normalized, stride, ptr);
+ return true;
+}
+
+void VertexArrayObjectManager::SetAttribDivisor(GLuint index, GLuint divisor) {
+ bound_vertex_array_object_->SetAttribDivisor(index, divisor);
+}
+
+// Collects the data into the collection buffer and returns the number of
+// bytes collected.
+GLsizei VertexArrayObjectManager::CollectData(
+ const void* data,
+ GLsizei bytes_per_element,
+ GLsizei real_stride,
+ GLsizei num_elements) {
+ GLsizei bytes_needed = bytes_per_element * num_elements;
+ if (collection_buffer_size_ < bytes_needed) {
+ collection_buffer_.reset(new int8[bytes_needed]);
+ collection_buffer_size_ = bytes_needed;
+ }
+ const int8* src = static_cast<const int8*>(data);
+ int8* dst = collection_buffer_.get();
+ int8* end = dst + bytes_per_element * num_elements;
+ for (; dst < end; src += real_stride, dst += bytes_per_element) {
+ memcpy(dst, src, bytes_per_element);
+ }
+ return bytes_needed;
+}
+
+bool VertexArrayObjectManager::IsDefaultVAOBound() const {
+ return bound_vertex_array_object_ == default_vertex_array_object_;
+}
+
+// Returns true if buffers were setup.
+bool VertexArrayObjectManager::SetupSimulatedClientSideBuffers(
+ const char* function_name,
+ GLES2Implementation* gl,
+ GLES2CmdHelper* gl_helper,
+ GLsizei num_elements,
+ GLsizei primcount,
+ bool* simulated) {
+ *simulated = false;
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ if (!bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
+ return true;
+ }
+ if (!IsDefaultVAOBound()) {
+ gl->SetGLError(
+ GL_INVALID_OPERATION, function_name,
+ "client side arrays not allowed with vertex array object");
+ return false;
+ }
+ *simulated = true;
+ GLsizei total_size = 0;
+ // Compute the size of the buffer we need.
+ const VertexArrayObject::VertexAttribs& vertex_attribs =
+ bound_vertex_array_object_->vertex_attribs();
+ for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
+ const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
+ if (attrib.IsClientSide() && attrib.enabled()) {
+ size_t bytes_per_element =
+ GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
+ attrib.size();
+ GLsizei elements = (primcount && attrib.divisor() > 0) ?
+ ((primcount - 1) / attrib.divisor() + 1) : num_elements;
+ total_size += RoundUpToMultipleOf4(bytes_per_element * elements);
+ }
+ }
+ gl_helper->BindBuffer(GL_ARRAY_BUFFER, array_buffer_id_);
+ array_buffer_offset_ = 0;
+ if (total_size > array_buffer_size_) {
+ gl->BufferDataHelper(GL_ARRAY_BUFFER, total_size, NULL, GL_DYNAMIC_DRAW);
+ array_buffer_size_ = total_size;
+ }
+ for (GLuint ii = 0; ii < vertex_attribs.size(); ++ii) {
+ const VertexArrayObject::VertexAttrib& attrib = vertex_attribs[ii];
+ if (attrib.IsClientSide() && attrib.enabled()) {
+ size_t bytes_per_element =
+ GLES2Util::GetGLTypeSizeForTexturesAndBuffers(attrib.type()) *
+ attrib.size();
+ GLsizei real_stride = attrib.stride() ?
+ attrib.stride() : static_cast<GLsizei>(bytes_per_element);
+ GLsizei elements = (primcount && attrib.divisor() > 0) ?
+ ((primcount - 1) / attrib.divisor() + 1) : num_elements;
+ GLsizei bytes_collected = CollectData(
+ attrib.pointer(), bytes_per_element, real_stride, elements);
+ gl->BufferSubDataHelper(
+ GL_ARRAY_BUFFER, array_buffer_offset_, bytes_collected,
+ collection_buffer_.get());
+ gl_helper->VertexAttribPointer(
+ ii, attrib.size(), attrib.type(), attrib.normalized(), 0,
+ array_buffer_offset_);
+ array_buffer_offset_ += RoundUpToMultipleOf4(bytes_collected);
+ GPU_DCHECK_LE(array_buffer_offset_, array_buffer_size_);
+ }
+ }
+#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ return true;
+}
+
+// Copies in indices to the service and returns the highest index accessed + 1
+bool VertexArrayObjectManager::SetupSimulatedIndexAndClientSideBuffers(
+ const char* function_name,
+ GLES2Implementation* gl,
+ GLES2CmdHelper* gl_helper,
+ GLsizei count,
+ GLenum type,
+ GLsizei primcount,
+ const void* indices,
+ GLuint* offset,
+ bool* simulated) {
+ *simulated = false;
+ *offset = ToGLuint(indices);
+#if defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ GLsizei num_elements = 0;
+ if (bound_vertex_array_object_->bound_element_array_buffer() == 0) {
+ *simulated = true;
+ *offset = 0;
+ GLsizei max_index = -1;
+ switch (type) {
+ case GL_UNSIGNED_BYTE: {
+ const uint8* src = static_cast<const uint8*>(indices);
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ if (src[ii] > max_index) {
+ max_index = src[ii];
+ }
+ }
+ break;
+ }
+ case GL_UNSIGNED_SHORT: {
+ const uint16* src = static_cast<const uint16*>(indices);
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ if (src[ii] > max_index) {
+ max_index = src[ii];
+ }
+ }
+ break;
+ }
+ case GL_UNSIGNED_INT: {
+ uint32 max_glsizei = static_cast<uint32>(
+ std::numeric_limits<GLsizei>::max());
+ const uint32* src = static_cast<const uint32*>(indices);
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ // Other parts of the API use GLsizei (signed) to store limits.
+ // As such, if we encounter a index that cannot be represented with
+ // an unsigned int we need to flag it as an error here.
+ if(src[ii] > max_glsizei) {
+ gl->SetGLError(
+ GL_INVALID_OPERATION, function_name, "index too large.");
+ return false;
+ }
+ GLsizei signed_index = static_cast<GLsizei>(src[ii]);
+ if (signed_index > max_index) {
+ max_index = signed_index;
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ gl_helper->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, element_array_buffer_id_);
+ GLsizei bytes_per_element =
+ GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
+ GLsizei bytes_needed = bytes_per_element * count;
+ if (bytes_needed > element_array_buffer_size_) {
+ element_array_buffer_size_ = bytes_needed;
+ gl->BufferDataHelper(
+ GL_ELEMENT_ARRAY_BUFFER, bytes_needed, NULL, GL_DYNAMIC_DRAW);
+ }
+ gl->BufferSubDataHelper(
+ GL_ELEMENT_ARRAY_BUFFER, 0, bytes_needed, indices);
+
+ num_elements = max_index + 1;
+ } else if (bound_vertex_array_object_->HaveEnabledClientSideBuffers()) {
+ // Index buffer is GL buffer. Ask the service for the highest vertex
+ // that will be accessed. Note: It doesn't matter if another context
+ // changes the contents of any of the buffers. The service will still
+ // validate the indices. We just need to know how much to copy across.
+ num_elements = gl->GetMaxValueInBufferCHROMIUMHelper(
+ bound_vertex_array_object_->bound_element_array_buffer(),
+ count, type, ToGLuint(indices)) + 1;
+ }
+
+ bool simulated_client_side_buffers = false;
+ SetupSimulatedClientSideBuffers(
+ function_name, gl, gl_helper, num_elements, primcount,
+ &simulated_client_side_buffers);
+ *simulated = *simulated || simulated_client_side_buffers;
+#endif // defined(GLES2_SUPPORT_CLIENT_SIDE_ARRAYS)
+ return true;
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/client/vertex_array_object_manager.h b/chromium/gpu/command_buffer/client/vertex_array_object_manager.h
new file mode 100644
index 00000000000..254b15da055
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/vertex_array_object_manager.h
@@ -0,0 +1,125 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_VERTEX_ARRAY_OBJECT_MANAGER_H_
+#define GPU_COMMAND_BUFFER_CLIENT_VERTEX_ARRAY_OBJECT_MANAGER_H_
+
+#include <GLES2/gl2.h>
+#include "base/memory/scoped_ptr.h"
+#include "gles2_impl_export.h"
+#include "gpu/command_buffer/client/hash_tables.h"
+#include "gpu/command_buffer/common/types.h"
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2Implementation;
+class GLES2CmdHelper;
+class VertexArrayObject;
+
+// VertexArrayObjectManager manages vertex array objects on the client side
+// of the command buffer.
+class GLES2_IMPL_EXPORT VertexArrayObjectManager {
+ public:
+ VertexArrayObjectManager(
+ GLuint max_vertex_attribs,
+ GLuint array_buffer_id,
+ GLuint element_array_buffer_id);
+ ~VertexArrayObjectManager();
+
+ bool IsReservedId(GLuint id) const;
+
+ // Binds an element array.
+ // Returns true if service should be called.
+ bool BindElementArray(GLuint id);
+
+ // Unbind buffer.
+ void UnbindBuffer(GLuint id);
+
+ // Geneates array objects for the given ids.
+ void GenVertexArrays(GLsizei n, const GLuint* arrays);
+
+ // Deletes array objects for the given ids.
+ void DeleteVertexArrays(GLsizei n, const GLuint* arrays);
+
+ // Binds a vertex array.
+ // changed will be set to true if the service should be called.
+ // Returns false if array is an unknown id.
+ bool BindVertexArray(GLuint array, bool* changed);
+
+ // simulated will be set to true if buffers were simulated.
+ // Returns true service should be called.
+ bool SetupSimulatedClientSideBuffers(
+ const char* function_name,
+ GLES2Implementation* gl,
+ GLES2CmdHelper* gl_helper,
+ GLsizei num_elements,
+ GLsizei primcount,
+ bool* simulated);
+
+ // Returns true if buffers were setup.
+ bool SetupSimulatedIndexAndClientSideBuffers(
+ const char* function_name,
+ GLES2Implementation* gl,
+ GLES2CmdHelper* gl_helper,
+ GLsizei count,
+ GLenum type,
+ GLsizei primcount,
+ const void* indices,
+ GLuint* offset,
+ bool* simulated);
+
+ bool HaveEnabledClientSideBuffers() const;
+
+ void SetAttribEnable(GLuint index, bool enabled);
+
+ bool GetVertexAttrib(GLuint index, GLenum pname, uint32* param);
+
+ bool GetAttribPointer(GLuint index, GLenum pname, void** ptr) const;
+
+ // Returns false if error.
+ bool SetAttribPointer(
+ GLuint buffer_id,
+ GLuint index,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei stride,
+ const void* ptr);
+
+ void SetAttribDivisor(GLuint index, GLuint divisor);
+
+ GLuint bound_element_array_buffer() const;
+
+ private:
+ typedef gpu::hash_map<GLuint, VertexArrayObject*> VertexArrayObjectMap;
+
+ bool IsDefaultVAOBound() const;
+
+ GLsizei CollectData(const void* data,
+ GLsizei bytes_per_element,
+ GLsizei real_stride,
+ GLsizei num_elements);
+
+ GLuint max_vertex_attribs_;
+ GLuint array_buffer_id_;
+ GLsizei array_buffer_size_;
+ GLsizei array_buffer_offset_;
+ GLuint element_array_buffer_id_;
+ GLsizei element_array_buffer_size_;
+ GLsizei collection_buffer_size_;
+ scoped_ptr<int8[]> collection_buffer_;
+
+ VertexArrayObject* default_vertex_array_object_;
+ VertexArrayObject* bound_vertex_array_object_;
+ VertexArrayObjectMap vertex_array_objects_;
+
+ DISALLOW_COPY_AND_ASSIGN(VertexArrayObjectManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_VERTEX_ARRAY_OBJECT_MANAGER_H_
+
diff --git a/chromium/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc b/chromium/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc
new file mode 100644
index 00000000000..b3ac0654c18
--- /dev/null
+++ b/chromium/gpu/command_buffer/client/vertex_array_object_manager_unittest.cc
@@ -0,0 +1,262 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/client/vertex_array_object_manager.h"
+
+#include <GLES2/gl2ext.h>
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+class VertexArrayObjectManagerTest : public testing::Test {
+ protected:
+ static const GLuint kMaxAttribs = 4;
+ static const GLuint kClientSideArrayBuffer = 0x1234;
+ static const GLuint kClientSideElementArrayBuffer = 0x1235;
+
+ virtual void SetUp() {
+ manager_.reset(new VertexArrayObjectManager(
+ kMaxAttribs,
+ kClientSideArrayBuffer,
+ kClientSideElementArrayBuffer));
+ }
+ virtual void TearDown() {
+ }
+
+ scoped_ptr<VertexArrayObjectManager> manager_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const GLuint VertexArrayObjectManagerTest::kMaxAttribs;
+const GLuint VertexArrayObjectManagerTest::kClientSideArrayBuffer;
+const GLuint VertexArrayObjectManagerTest::kClientSideElementArrayBuffer;
+#endif
+
+TEST_F(VertexArrayObjectManagerTest, Basic) {
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+ // Check out of bounds access.
+ uint32 param;
+ void* ptr;
+ EXPECT_FALSE(manager_->GetVertexAttrib(
+ kMaxAttribs, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &param));
+ EXPECT_FALSE(manager_->GetAttribPointer(
+ kMaxAttribs, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr));
+ // Check defaults.
+ for (GLuint ii = 0; ii < kMaxAttribs; ++ii) {
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ ii, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &param));
+ EXPECT_EQ(0u, param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ ii, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &param));
+ EXPECT_EQ(0u, param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ ii, GL_VERTEX_ATTRIB_ARRAY_SIZE, &param));
+ EXPECT_EQ(4u, param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ ii, GL_VERTEX_ATTRIB_ARRAY_TYPE, &param));
+ EXPECT_EQ(static_cast<uint32>(GL_FLOAT), param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ ii, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &param));
+ EXPECT_EQ(0u, param);
+ EXPECT_TRUE(manager_->GetAttribPointer(
+ ii, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr));
+ EXPECT_TRUE(NULL == ptr);
+ }
+}
+
+TEST_F(VertexArrayObjectManagerTest, UnbindBuffer) {
+ const GLuint kBufferToUnbind = 123;
+ const GLuint kBufferToRemain = 456;
+ const GLuint kElementArray = 789;
+ bool changed = false;
+ GLuint ids[2] = { 1, 3, };
+ manager_->GenVertexArrays(arraysize(ids), ids);
+ // Bind buffers to attribs on 2 vaos.
+ for (size_t ii = 0; ii < arraysize(ids); ++ii) {
+ EXPECT_TRUE(manager_->BindVertexArray(ids[ii], &changed));
+ EXPECT_TRUE(manager_->SetAttribPointer(
+ kBufferToUnbind, 0, 4, GL_FLOAT, false, 0, 0));
+ EXPECT_TRUE(manager_->SetAttribPointer(
+ kBufferToRemain, 1, 4, GL_FLOAT, false, 0, 0));
+ EXPECT_TRUE(manager_->SetAttribPointer(
+ kBufferToUnbind, 2, 4, GL_FLOAT, false, 0, 0));
+ EXPECT_TRUE(manager_->SetAttribPointer(
+ kBufferToRemain, 3, 4, GL_FLOAT, false, 0, 0));
+ for (size_t jj = 0; jj < 4u; ++jj) {
+ manager_->SetAttribEnable(jj, true);
+ }
+ manager_->BindElementArray(kElementArray);
+ }
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+ EXPECT_TRUE(manager_->BindVertexArray(ids[0], &changed));
+ // Unbind the buffer.
+ manager_->UnbindBuffer(kBufferToUnbind);
+ manager_->UnbindBuffer(kElementArray);
+ // The attribs are still enabled but their buffer is 0.
+ EXPECT_TRUE(manager_->HaveEnabledClientSideBuffers());
+ // Check the status of the bindings.
+ static const uint32 expected[][4] = {
+ { 0, kBufferToRemain, 0, kBufferToRemain, },
+ { kBufferToUnbind, kBufferToRemain, kBufferToUnbind, kBufferToRemain, },
+ };
+ static const GLuint expected_element_array[] = {
+ 0, kElementArray,
+ };
+ for (size_t ii = 0; ii < arraysize(ids); ++ii) {
+ EXPECT_TRUE(manager_->BindVertexArray(ids[ii], &changed));
+ for (size_t jj = 0; jj < 4; ++jj) {
+ uint32 param = 1;
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ jj, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &param));
+ EXPECT_EQ(expected[ii][jj], param)
+ << "id: " << ids[ii] << ", attrib: " << jj;
+ }
+ EXPECT_EQ(expected_element_array[ii],
+ manager_->bound_element_array_buffer());
+ }
+
+ // The vao that was not bound still has all service side bufferws.
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+
+ // Make sure unbinding 0 does not effect count incorrectly.
+ EXPECT_TRUE(manager_->BindVertexArray(0, &changed));
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+ manager_->SetAttribEnable(2, true);
+ manager_->UnbindBuffer(0);
+ manager_->SetAttribEnable(2, false);
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+}
+
+TEST_F(VertexArrayObjectManagerTest, GetSet) {
+ const char* dummy = "dummy";
+ const void* p = reinterpret_cast<const void*>(dummy);
+ manager_->SetAttribEnable(1, true);
+ manager_->SetAttribPointer(123, 1, 3, GL_BYTE, true, 3, p);
+ uint32 param;
+ void* ptr;
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ 1, GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING, &param));
+ EXPECT_EQ(123u, param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ 1, GL_VERTEX_ATTRIB_ARRAY_ENABLED, &param));
+ EXPECT_NE(0u, param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ 1, GL_VERTEX_ATTRIB_ARRAY_SIZE, &param));
+ EXPECT_EQ(3u, param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ 1, GL_VERTEX_ATTRIB_ARRAY_TYPE, &param));
+ EXPECT_EQ(static_cast<uint32>(GL_BYTE), param);
+ EXPECT_TRUE(manager_->GetVertexAttrib(
+ 1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, &param));
+ EXPECT_NE(0u, param);
+ EXPECT_TRUE(manager_->GetAttribPointer(
+ 1, GL_VERTEX_ATTRIB_ARRAY_POINTER, &ptr));
+ EXPECT_EQ(p, ptr);
+
+ // Check that getting the divisor is passed to the service.
+ // This is because the divisor is an optional feature which
+ // only the service can validate.
+ EXPECT_FALSE(manager_->GetVertexAttrib(
+ 0, GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE, &param));
+}
+
+TEST_F(VertexArrayObjectManagerTest, HaveEnabledClientSideArrays) {
+ // Check turning on an array.
+ manager_->SetAttribEnable(1, true);
+ EXPECT_TRUE(manager_->HaveEnabledClientSideBuffers());
+ // Check turning off an array.
+ manager_->SetAttribEnable(1, false);
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+ // Check turning on an array and assigning a buffer.
+ manager_->SetAttribEnable(1, true);
+ manager_->SetAttribPointer(123, 1, 3, GL_BYTE, true, 3, NULL);
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+ // Check unassigning a buffer.
+ manager_->SetAttribPointer(0, 1, 3, GL_BYTE, true, 3, NULL);
+ EXPECT_TRUE(manager_->HaveEnabledClientSideBuffers());
+ // Check disabling the array.
+ manager_->SetAttribEnable(1, false);
+ EXPECT_FALSE(manager_->HaveEnabledClientSideBuffers());
+}
+
+TEST_F(VertexArrayObjectManagerTest, BindElementArray) {
+ bool changed = false;
+ GLuint ids[2] = { 1, 3, };
+ manager_->GenVertexArrays(arraysize(ids), ids);
+
+ // Check the default element array is 0.
+ EXPECT_EQ(0u, manager_->bound_element_array_buffer());
+ // Check binding the same array does not need a service call.
+ EXPECT_FALSE(manager_->BindElementArray(0u));
+ // Check binding a new element array requires a service call.
+ EXPECT_TRUE(manager_->BindElementArray(55u));
+ // Check the element array was bound.
+ EXPECT_EQ(55u, manager_->bound_element_array_buffer());
+ // Check binding the same array does not need a service call.
+ EXPECT_FALSE(manager_->BindElementArray(55u));
+
+ // Check with a new vao.
+ EXPECT_TRUE(manager_->BindVertexArray(1, &changed));
+ // Check the default element array is 0.
+ EXPECT_EQ(0u, manager_->bound_element_array_buffer());
+ // Check binding a new element array requires a service call.
+ EXPECT_TRUE(manager_->BindElementArray(11u));
+ // Check the element array was bound.
+ EXPECT_EQ(11u, manager_->bound_element_array_buffer());
+ // Check binding the same array does not need a service call.
+ EXPECT_FALSE(manager_->BindElementArray(11u));
+
+ // check switching vao bindings returns the correct element array.
+ EXPECT_TRUE(manager_->BindVertexArray(3, &changed));
+ EXPECT_EQ(0u, manager_->bound_element_array_buffer());
+ EXPECT_TRUE(manager_->BindVertexArray(0, &changed));
+ EXPECT_EQ(55u, manager_->bound_element_array_buffer());
+ EXPECT_TRUE(manager_->BindVertexArray(1, &changed));
+ EXPECT_EQ(11u, manager_->bound_element_array_buffer());
+}
+
+TEST_F(VertexArrayObjectManagerTest, GenBindDelete) {
+ // Check unknown array fails.
+ bool changed = false;
+ EXPECT_FALSE(manager_->BindVertexArray(123, &changed));
+ EXPECT_FALSE(changed);
+
+ GLuint ids[2] = { 1, 3, };
+ manager_->GenVertexArrays(arraysize(ids), ids);
+ // Check Genned arrays succeed.
+ EXPECT_TRUE(manager_->BindVertexArray(1, &changed));
+ EXPECT_TRUE(changed);
+ EXPECT_TRUE(manager_->BindVertexArray(3, &changed));
+ EXPECT_TRUE(changed);
+
+ // Check binding the same array returns changed as false.
+ EXPECT_TRUE(manager_->BindVertexArray(3, &changed));
+ EXPECT_FALSE(changed);
+
+ // Check deleted ararys fail to bind
+ manager_->DeleteVertexArrays(2, ids);
+ EXPECT_FALSE(manager_->BindVertexArray(1, &changed));
+ EXPECT_FALSE(changed);
+ EXPECT_FALSE(manager_->BindVertexArray(3, &changed));
+ EXPECT_FALSE(changed);
+
+ // Check binding 0 returns changed as false since it's
+ // already bound.
+ EXPECT_TRUE(manager_->BindVertexArray(0, &changed));
+ EXPECT_FALSE(changed);
+}
+
+TEST_F(VertexArrayObjectManagerTest, IsReservedId) {
+ EXPECT_TRUE(manager_->IsReservedId(kClientSideArrayBuffer));
+ EXPECT_TRUE(manager_->IsReservedId(kClientSideElementArrayBuffer));
+ EXPECT_FALSE(manager_->IsReservedId(0));
+ EXPECT_FALSE(manager_->IsReservedId(1));
+ EXPECT_FALSE(manager_->IsReservedId(2));
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/cmd_buffer_functions.txt b/chromium/gpu/command_buffer/cmd_buffer_functions.txt
new file mode 100644
index 00000000000..f7b9a5b74b5
--- /dev/null
+++ b/chromium/gpu/command_buffer/cmd_buffer_functions.txt
@@ -0,0 +1,222 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is read by build_gles2_cmd_buffer.py to generate commands.
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLidProgram program, GLidShader shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLidProgram program, GLuint index, const char* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenumBufferTarget target, GLidBindBuffer buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenumFrameBufferTarget target, GLidBindFramebuffer framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenumRenderBufferTarget target, GLidBindRenderbuffer renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenumTextureBindTarget target, GLidBindTexture texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenumEquation mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenumEquation modeRGB, GLenumEquation modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenumSrcBlendFactor sfactor, GLenumDstBlendFactor dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenumSrcBlendFactor srcRGB, GLenumDstBlendFactor dstRGB, GLenumSrcBlendFactor srcAlpha, GLenumDstBlendFactor dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenumBufferTarget target, GLsizeiptr size, const void* data, GLenumBufferUsage usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenumBufferTarget target, GLintptrNotNegative offset, GLsizeiptr size, const void* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenumFrameBufferTarget target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLidShader shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenumTextureTarget target, GLint level, GLenumCompressedTextureFormat internalformat, GLsizei width, GLsizei height, GLintTextureBorder border, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenumTextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenumCompressedTextureFormat format, GLsizei imageSize, const void* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenumTextureTarget target, GLint level, GLenumTextureInternalFormat internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLintTextureBorder border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenumTextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenumShaderType type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenumFaceType mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizeiNotNegative n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizeiNotNegative n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLidProgram program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizeiNotNegative n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLidShader shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizeiNotNegative n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenumCmpFunction func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLidProgram program, GLidShader shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenumCapability cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenumDrawMode mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenumDrawMode mode, GLsizei count, GLenumIndexType type, const void* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenumCapability cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenumFrameBufferTarget target, GLenumAttachment attachment, GLenumRenderBufferTarget renderbuffertarget, GLidRenderbuffer renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenumFrameBufferTarget target, GLenumAttachment attachment, GLenumTextureTarget textarget, GLidTexture texture, GLintZeroOnly level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenumFaceMode mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizeiNotNegative n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenumTextureBindTarget target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizeiNotNegative n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizeiNotNegative n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizeiNotNegative n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLidProgram program, GLuint index, GLsizeiNotNegative bufsize, GLsizeiOptional* length, GLint* size, GLenum* type, char* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLidProgram program, GLsizeiNotNegative maxcount, GLsizeiOptional* count, GLuint* shaders);
+GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLidProgram program, const char* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenumGLState pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenumBufferTarget target, GLenumBufferParameter pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenumGLState pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenumFrameBufferTarget target, GLenumAttachment attachment, GLenumFrameBufferParameter pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenumGLState pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLidProgram program, GLenumProgramParameter pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLidProgram program, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenumRenderBufferTarget target, GLenumRenderBufferParameter pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLidShader shader, GLenumShaderParameter pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenumShaderType shadertype, GLenumShaderPrecision precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenumStringType name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenumGetTexParamTarget target, GLenumTextureParameter pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenumGetTexParamTarget target, GLenumTextureParameter pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLidProgram program, GLintUniformLocation location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLidProgram program, GLintUniformLocation location, GLint* params);
+GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLidProgram program, const char* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenumVertexAttribute pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenumVertexAttribute pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenumVertexPointer pname, void** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenumHintTarget target, GLenumHintMode mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLidBuffer buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenumCapability cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLidFramebuffer framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLidProgram program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLidRenderbuffer renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLidShader shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLidTexture texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLidProgram program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenumPixelStore pname, GLintPixelStoreAlignment param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenumReadPixelFormat format, GLenumPixelType type, void* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenumRenderBufferTarget target, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizeiNotNegative n, const GLuint* shaders, GLenumShaderBinaryFormat binaryformat, const void* binary, GLsizeiNotNegative length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLidShader shader, GLsizeiNotNegative count, const GLchar* const* str, const GLint* length);
+GL_APICALL void GL_APIENTRY glShallowFinishCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glShallowFlushCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenumCmpFunction func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenumFaceType face, GLenumCmpFunction func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenumFaceType face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenumStencilOp fail, GLenumStencilOp zfail, GLenumStencilOp zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenumFaceType face, GLenumStencilOp fail, GLenumStencilOp zfail, GLenumStencilOp zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenumTextureTarget target, GLint level, GLintTextureInternalFormat internalformat, GLsizei width, GLsizei height, GLintTextureBorder border, GLenumTextureFormat format, GLenumPixelType type, const void* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenumTextureBindTarget target, GLenumTextureParameter pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenumTextureBindTarget target, GLenumTextureParameter pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenumTextureBindTarget target, GLenumTextureParameter pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenumTextureBindTarget target, GLenumTextureParameter pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenumTextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenumTextureFormat format, GLenumPixelType type, const void* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLintUniformLocation location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLintUniformLocation location, GLsizeiNotNegative count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLintUniformLocation location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLintUniformLocation location, GLsizeiNotNegative count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLintUniformLocation location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLintUniformLocation location, GLsizeiNotNegative count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLintUniformLocation location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLintUniformLocation location, GLsizeiNotNegative count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLintUniformLocation location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLintUniformLocation location, GLsizeiNotNegative count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLintUniformLocation location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLintUniformLocation location, GLsizeiNotNegative count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLintUniformLocation location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLintUniformLocation location, GLsizeiNotNegative count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLintUniformLocation location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLintUniformLocation location, GLsizeiNotNegative count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLintUniformLocation location, GLsizeiNotNegative count, GLbooleanFalseOnly transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLintUniformLocation location, GLsizeiNotNegative count, GLbooleanFalseOnly transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLintUniformLocation location, GLsizeiNotNegative count, GLbooleanFalseOnly transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLidZeroProgram program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLidProgram program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLintVertexAttribSize size, GLenumVertexAttribType type, GLboolean normalized, GLsizei stride, const void* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glBlitFramebufferEXT (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenumBlitFilter filter);
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenumRenderBufferTarget target, GLsizei samples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenumFrameBufferTarget target, GLenumAttachment attachment, GLenumTextureTarget textarget, GLidTexture texture, GLintZeroOnly level, GLsizei samples);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenumTextureTarget target, GLsizei levels, GLenumTextureInternalFormatStorage internalFormat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizeiNotNegative n, GLuint* queries);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizeiNotNegative n, const GLuint* queries);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLidQuery id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenumQueryTarget target, GLidQuery id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenumQueryTarget target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenumQueryTarget target, GLenumQueryParameter pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLidQuery id, GLenumQueryObjectParameter pname, GLuint* params);
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar* marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar* marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizeiNotNegative n, GLuint* arrays);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizeiNotNegative n, const GLuint* arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLidVertexArray array);
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLidBindVertexArray array);
+
+// Non-GL commands.
+GL_APICALL void GL_APIENTRY glSwapBuffers (void);
+GL_APICALL GLuint GL_APIENTRY glGetMaxValueInBufferCHROMIUM (GLidBuffer buffer_id, GLsizei count, GLenumGetMaxIndexType type, GLuint offset);
+GL_APICALL void GL_APIENTRY glGenSharedIdsCHROMIUM (GLuint namespace_id, GLuint id_offset, GLsizeiNotNegative n, GLuint* ids);
+GL_APICALL void GL_APIENTRY glDeleteSharedIdsCHROMIUM (GLuint namespace_id, GLsizeiNotNegative n, const GLuint* ids);
+GL_APICALL void GL_APIENTRY glRegisterSharedIdsCHROMIUM (GLuint namespace_id, GLsizeiNotNegative n, const GLuint* ids);
+GL_APICALL GLboolean GL_APIENTRY glEnableFeatureCHROMIUM (const char* feature);
+GL_APICALL void* GL_APIENTRY glMapBufferCHROMIUM (GLuint target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferCHROMIUM (GLuint target);
+GL_APICALL void* GL_APIENTRY glMapImageCHROMIUM (GLuint image_id, GLenum access);
+GL_APICALL void GL_APIENTRY glUnmapImageCHROMIUM (GLuint image_id);
+
+GL_APICALL void* GL_APIENTRY glMapBufferSubDataCHROMIUM (GLuint target, GLintptrNotNegative offset, GLsizeiptr size, GLenum access);
+GL_APICALL void GL_APIENTRY glUnmapBufferSubDataCHROMIUM (const void* mem);
+GL_APICALL void* GL_APIENTRY glMapTexSubImage2DCHROMIUM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLenum access);
+GL_APICALL void GL_APIENTRY glUnmapTexSubImage2DCHROMIUM (const void* mem);
+GL_APICALL void GL_APIENTRY glResizeCHROMIUM (GLuint width, GLuint height, GLfloat scale_factor);
+GL_APICALL const GLchar* GL_APIENTRY glGetRequestableExtensionsCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glRequestExtensionCHROMIUM (const char* extension);
+GL_APICALL void GL_APIENTRY glRateLimitOffscreenContextCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
+GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
+GL_APICALL GLuint GL_APIENTRY glCreateStreamTextureCHROMIUM (GLuint texture);
+GL_APICALL void GL_APIENTRY glDestroyStreamTextureCHROMIUM (GLuint texture);
+GL_APICALL GLuint GL_APIENTRY glCreateImageCHROMIUM (GLsizei width, GLsizei height, GLenum internalformat);
+GL_APICALL void GL_APIENTRY glDestroyImageCHROMIUM (GLuint image_id);
+GL_APICALL void GL_APIENTRY glGetImageParameterivCHROMIUM (GLuint image_id, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLidShader shader, GLsizeiNotNegative bufsize, GLsizeiOptional* length, char* source);
+GL_APICALL void GL_APIENTRY glPostSubBufferCHROMIUM (GLint x, GLint y, GLint width, GLint height);
+GL_APICALL void GL_APIENTRY glTexImageIOSurface2DCHROMIUM (GLenumTextureBindTarget target, GLsizei width, GLsizei height, GLuint ioSurfaceId, GLuint plane);
+GL_APICALL void GL_APIENTRY glCopyTextureCHROMIUM (GLenum target, GLenum source_id, GLenum dest_id, GLint level, GLintTextureInternalFormat internalformat, GLenumPixelType dest_type);
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenumDrawMode mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenumDrawMode mode, GLsizei count, GLenumIndexType type, const void* indices, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
+GL_APICALL void GL_APIENTRY glGenMailboxCHROMIUM (GLbyte* mailbox);
+GL_APICALL void GL_APIENTRY glProduceTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
+GL_APICALL void GL_APIENTRY glConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
+GL_APICALL void GL_APIENTRY glBindUniformLocationCHROMIUM (GLidProgram program, GLint location, const char* name);
+GL_APICALL void GL_APIENTRY glBindTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
+GL_APICALL void GL_APIENTRY glReleaseTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
+GL_APICALL void GL_APIENTRY glTraceBeginCHROMIUM (const char* name);
+GL_APICALL void GL_APIENTRY glTraceEndCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glAsyncTexSubImage2DCHROMIUM (GLenumTextureTarget target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenumTextureFormat format, GLenumPixelType type, const void* data);
+GL_APICALL void GL_APIENTRY glAsyncTexImage2DCHROMIUM (GLenumTextureTarget target, GLint level, GLintTextureInternalFormat internalformat, GLsizei width, GLsizei height, GLintTextureBorder border, GLenumTextureFormat format, GLenumPixelType type, const void* pixels);
+GL_APICALL void GL_APIENTRY glWaitAsyncTexImage2DCHROMIUM (GLenumTextureTarget target);
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei count, const GLenum* attachments);
+GL_APICALL void GL_APIENTRY glLoseContextCHROMIUM (GLenum current, GLenum other);
+GL_APICALL GLuint GL_APIENTRY glInsertSyncPointCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glWaitSyncPointCHROMIUM (GLuint sync_point);
+GL_APICALL void GL_APIENTRY glDrawBuffersEXT (GLsizei count, const GLenum* bufs);
+
+
diff --git a/chromium/gpu/command_buffer/command_buffer.gyp b/chromium/gpu/command_buffer/command_buffer.gyp
new file mode 100644
index 00000000000..8ffd15b80a2
--- /dev/null
+++ b/chromium/gpu/command_buffer/command_buffer.gyp
@@ -0,0 +1,29 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ 'command_buffer.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'gles2_utils',
+ 'type': '<(component)',
+ 'variables': {
+ 'gles2_utils_target': 1,
+ },
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'export_dependent_settings': [
+ '../../base/base.gyp:base',
+ ],
+ },
+ ],
+}
+
diff --git a/chromium/gpu/command_buffer/command_buffer.gypi b/chromium/gpu/command_buffer/command_buffer.gypi
new file mode 100644
index 00000000000..e63a1c1b7f1
--- /dev/null
+++ b/chromium/gpu/command_buffer/command_buffer.gypi
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'target_defaults': {
+ 'variables': {
+ 'gles2_utils_target': 0,
+ },
+ 'target_conditions': [
+ # This part is shared between the targets defined below.
+ ['gles2_utils_target==1', {
+ 'defines': [
+ 'GLES2_UTILS_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'common/gles2_cmd_format.h',
+ 'common/gles2_cmd_utils.cc',
+ 'common/gles2_cmd_utils.h',
+ 'common/gles2_utils_export.h',
+ 'common/logging.cc',
+ 'common/logging.h',
+ ],
+ 'conditions': [
+ ['OS=="android"', {
+ 'sources!': [
+ 'common/logging.cc',
+ ],
+ 'sources': [
+ 'common/logging_android.cc',
+ ],
+ }],
+ ],
+ }],
+ ],
+ },
+}
diff --git a/chromium/gpu/command_buffer/command_buffer_untrusted.gyp b/chromium/gpu/command_buffer/command_buffer_untrusted.gyp
new file mode 100644
index 00000000000..8f27a0b0569
--- /dev/null
+++ b/chromium/gpu/command_buffer/command_buffer_untrusted.gyp
@@ -0,0 +1,36 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ '../../build/common_untrusted.gypi',
+ 'command_buffer.gypi',
+ ],
+ 'conditions': [
+ ['disable_nacl==0 and disable_nacl_untrusted==0', {
+ 'targets': [
+ {
+ 'target_name': 'gles2_utils_untrusted',
+ 'type': 'none',
+ 'variables': {
+ 'gles2_utils_target': 1,
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libgles2_utils_untrusted.a',
+ 'build_glibc': 0,
+ 'build_newlib': 1,
+ 'build_irt': 1,
+ },
+ 'dependencies': [
+ '../../native_client/tools.gyp:prep_toolchain',
+ '../../base/base_untrusted.gyp:base_untrusted',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/gpu/command_buffer/common/bitfield_helpers.h b/chromium/gpu/command_buffer/common/bitfield_helpers.h
new file mode 100644
index 00000000000..62841eec5ad
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/bitfield_helpers.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains a helper template class used to access bit fields in
+// unsigned int_ts.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_BITFIELD_HELPERS_H_
+#define GPU_COMMAND_BUFFER_COMMON_BITFIELD_HELPERS_H_
+
+namespace gpu {
+
+// Bitfield template class, used to access bit fields in unsigned int_ts.
+template<int shift, int length> class BitField {
+ public:
+ static const unsigned int kShift = shift;
+ static const unsigned int kLength = length;
+ // the following is really (1<<length)-1 but also work for length == 32
+ // without compiler warning.
+ static const unsigned int kMask = 1U + ((1U << (length-1)) - 1U) * 2U;
+
+ // Gets the value contained in this field.
+ static unsigned int Get(unsigned int container) {
+ return (container >> kShift) & kMask;
+ }
+
+ // Makes a value that can be or-ed into this field.
+ static unsigned int MakeValue(unsigned int value) {
+ return (value & kMask) << kShift;
+ }
+
+ // Changes the value of this field.
+ static void Set(unsigned int *container, unsigned int field_value) {
+ *container = (*container & ~(kMask << kShift)) | MakeValue(field_value);
+ }
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_BITFIELD_HELPERS_H_
diff --git a/chromium/gpu/command_buffer/common/bitfield_helpers_test.cc b/chromium/gpu/command_buffer/common/bitfield_helpers_test.cc
new file mode 100644
index 00000000000..705e9337e4f
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/bitfield_helpers_test.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the bitfield helper class.
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "gpu/command_buffer/common/bitfield_helpers.h"
+
+namespace gpu {
+
+// Tests that BitField<>::Get returns the right bits.
+TEST(BitFieldTest, TestGet) {
+ unsigned int value = 0x12345678u;
+ EXPECT_EQ(0x8u, (BitField<0, 4>::Get(value)));
+ EXPECT_EQ(0x45u, (BitField<12, 8>::Get(value)));
+ EXPECT_EQ(0x12345678u, (BitField<0, 32>::Get(value)));
+}
+
+// Tests that BitField<>::MakeValue generates the right bits.
+TEST(BitFieldTest, TestMakeValue) {
+ EXPECT_EQ(0x00000003u, (BitField<0, 4>::MakeValue(0x3)));
+ EXPECT_EQ(0x00023000u, (BitField<12, 8>::MakeValue(0x123)));
+ EXPECT_EQ(0x87654321u, (BitField<0, 32>::MakeValue(0x87654321)));
+}
+
+// Tests that BitField<>::Set modifies the right bits.
+TEST(BitFieldTest, TestSet) {
+ unsigned int value = 0x12345678u;
+ BitField<0, 4>::Set(&value, 0x9);
+ EXPECT_EQ(0x12345679u, value);
+ BitField<12, 8>::Set(&value, 0x123);
+ EXPECT_EQ(0x12323679u, value);
+ BitField<0, 32>::Set(&value, 0x87654321);
+ EXPECT_EQ(0x87654321u, value);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/buffer.h b/chromium/gpu/command_buffer/common/buffer.h
new file mode 100644
index 00000000000..a2721a83590
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/buffer.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_BUFFER_H_
+#define GPU_COMMAND_BUFFER_COMMON_BUFFER_H_
+
+#include "gpu/command_buffer/common/types.h"
+
+namespace base {
+ class SharedMemory;
+}
+
+namespace gpu {
+
+// Address and size of a buffer and optionally a shared memory object. This
+// type has value semantics.
+struct Buffer {
+ Buffer() : ptr(NULL), size(0), shared_memory(NULL) {
+ }
+
+ void* ptr;
+ size_t size;
+
+ // Null if the buffer is not shared memory or if it is not exposed as such.
+ base::SharedMemory* shared_memory;
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_BUFFER_H_
diff --git a/chromium/gpu/command_buffer/common/cmd_buffer_common.cc b/chromium/gpu/command_buffer/common/cmd_buffer_common.cc
new file mode 100644
index 00000000000..bfa625c7384
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/cmd_buffer_common.cc
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the binary format definition of the command buffer and
+// command buffer commands.
+
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+#if !defined(_WIN32)
+// gcc needs this to link, but MSVC requires it not be present
+const int32 CommandHeader::kMaxSize;
+#endif
+namespace cmd {
+
+const char* GetCommandName(CommandId command_id) {
+ static const char* const names[] = {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) # name,
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+ };
+
+ int id = static_cast<int>(command_id);
+ return (id >= 0 && id < kNumCommands) ? names[id] : "*unknown-command*";
+}
+
+} // namespace cmd
+
+// TODO(apatrick): this is a temporary optimization while skia is calling
+// RendererGLContext::MakeCurrent prior to every GL call. It saves returning 6
+// ints redundantly when only the error is needed for the CommandBufferProxy
+// implementation.
+error::Error CommandBuffer::GetLastError() {
+ return GetLastState().error;
+}
+
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/common/cmd_buffer_common.h b/chromium/gpu/command_buffer/common/cmd_buffer_common.h
new file mode 100644
index 00000000000..090819805a5
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/cmd_buffer_common.h
@@ -0,0 +1,529 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the common parts of command buffer formats.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
+#define GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
+
+#include <stddef.h>
+
+#include "gpu/command_buffer/common/bitfield_helpers.h"
+#include "gpu/command_buffer/common/logging.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+namespace cmd {
+ enum ArgFlags {
+ kFixed = 0x0,
+ kAtLeastN = 0x1
+ };
+} // namespace cmd
+
+// Computes the number of command buffer entries needed for a certain size. In
+// other words it rounds up to a multiple of entries.
+inline uint32 ComputeNumEntries(size_t size_in_bytes) {
+ return static_cast<uint32>(
+ (size_in_bytes + sizeof(uint32) - 1) / sizeof(uint32)); // NOLINT
+}
+
+// Rounds up to a multiple of entries in bytes.
+inline size_t RoundSizeToMultipleOfEntries(size_t size_in_bytes) {
+ return ComputeNumEntries(size_in_bytes) * sizeof(uint32); // NOLINT
+}
+
+// Struct that defines the command header in the command buffer.
+struct CommandHeader {
+ Uint32 size:21;
+ Uint32 command:11;
+
+ GPU_EXPORT static const int32 kMaxSize = (1 << 21) - 1;
+
+ void Init(uint32 _command, int32 _size) {
+ GPU_DCHECK_LE(_size, kMaxSize);
+ command = _command;
+ size = _size;
+ }
+
+ // Sets the header based on the passed in command. Can not be used for
+ // variable sized commands like immediate commands or Noop.
+ template <typename T>
+ void SetCmd() {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ Init(T::kCmdId, ComputeNumEntries(sizeof(T))); // NOLINT
+ }
+
+ // Sets the header by a size in bytes of the immediate data after the command.
+ template <typename T>
+ void SetCmdBySize(uint32 size_of_data_in_bytes) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ Init(T::kCmdId,
+ ComputeNumEntries(sizeof(T) + size_of_data_in_bytes)); // NOLINT
+ }
+
+ // Sets the header by a size in bytes.
+ template <typename T>
+ void SetCmdByTotalSize(uint32 size_in_bytes) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ GPU_DCHECK_GE(size_in_bytes, sizeof(T)); // NOLINT
+ Init(T::kCmdId, ComputeNumEntries(size_in_bytes));
+ }
+};
+
+COMPILE_ASSERT(sizeof(CommandHeader) == 4, Sizeof_CommandHeader_is_not_4);
+
+// Union that defines possible command buffer entries.
+union CommandBufferEntry {
+ CommandHeader value_header;
+ Uint32 value_uint32;
+ Int32 value_int32;
+ float value_float;
+};
+
+const size_t kCommandBufferEntrySize = 4;
+
+COMPILE_ASSERT(sizeof(CommandBufferEntry) == kCommandBufferEntrySize,
+ Sizeof_CommandBufferEntry_is_not_4);
+
+// Make sure the compiler does not add extra padding to any of the command
+// structures.
+#pragma pack(push, 1)
+
+// Gets the address of memory just after a structure in a typesafe way. This is
+// used for IMMEDIATE commands to get the address of the place to put the data.
+// Immediate command put their data direclty in the command buffer.
+// Parameters:
+// cmd: Address of command.
+template <typename T>
+void* ImmediateDataAddress(T* cmd) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ return reinterpret_cast<char*>(cmd) + sizeof(*cmd);
+}
+
+// Gets the address of the place to put the next command in a typesafe way.
+// This can only be used for fixed sized commands.
+template <typename T>
+// Parameters:
+// cmd: Address of command.
+void* NextCmdAddress(void* cmd) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ return reinterpret_cast<char*>(cmd) + sizeof(T);
+}
+
+// Gets the address of the place to put the next command in a typesafe way.
+// This can only be used for variable sized command like IMMEDIATE commands.
+// Parameters:
+// cmd: Address of command.
+// size_of_data_in_bytes: Size of the data for the command.
+template <typename T>
+void* NextImmediateCmdAddress(void* cmd, uint32 size_of_data_in_bytes) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ return reinterpret_cast<char*>(cmd) + sizeof(T) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_of_data_in_bytes);
+}
+
+// Gets the address of the place to put the next command in a typesafe way.
+// This can only be used for variable sized command like IMMEDIATE commands.
+// Parameters:
+// cmd: Address of command.
+// size_of_cmd_in_bytes: Size of the cmd and data.
+template <typename T>
+void* NextImmediateCmdAddressTotalSize(void* cmd, uint32 total_size_in_bytes) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ GPU_DCHECK_GE(total_size_in_bytes, sizeof(T)); // NOLINT
+ return reinterpret_cast<char*>(cmd) +
+ RoundSizeToMultipleOfEntries(total_size_in_bytes);
+}
+
+namespace cmd {
+
+// This macro is used to safely and convienently expand the list of commnad
+// buffer commands in to various lists and never have them get out of sync. To
+// add a new command, add it this list, create the corresponding structure below
+// and then add a function in gapi_decoder.cc called Handle_COMMAND_NAME where
+// COMMAND_NAME is the name of your command structure.
+//
+// NOTE: THE ORDER OF THESE MUST NOT CHANGE (their id is derived by order)
+#define COMMON_COMMAND_BUFFER_CMDS(OP) \
+ OP(Noop) /* 0 */ \
+ OP(SetToken) /* 1 */ \
+ OP(SetBucketSize) /* 2 */ \
+ OP(SetBucketData) /* 3 */ \
+ OP(SetBucketDataImmediate) /* 4 */ \
+ OP(GetBucketStart) /* 5 */ \
+ OP(GetBucketData) /* 6 */ \
+
+// Common commands.
+enum CommandId {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) k ## name,
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+
+ kNumCommands,
+ kLastCommonId = 255 // reserve 256 spaces for common commands.
+};
+
+COMPILE_ASSERT(kNumCommands - 1 <= kLastCommonId, Too_many_common_commands);
+
+const char* GetCommandName(CommandId id);
+
+// A Noop command.
+struct Noop {
+ typedef Noop ValueType;
+ static const CommandId kCmdId = kNoop;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 skip_count) {
+ GPU_DCHECK_GT(skip_count, 0u);
+ header.Init(kCmdId, skip_count);
+ }
+
+ void Init(uint32 skip_count) {
+ SetHeader(skip_count);
+ }
+
+ static void* Set(void* cmd, uint32 skip_count) {
+ static_cast<ValueType*>(cmd)->Init(skip_count);
+ return NextImmediateCmdAddress<ValueType>(
+ cmd, skip_count * sizeof(CommandBufferEntry)); // NOLINT
+ }
+
+ CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(Noop) == 4, Sizeof_Noop_is_not_4);
+COMPILE_ASSERT(offsetof(Noop, header) == 0, Offsetof_Noop_header_not_0);
+
+// The SetToken command puts a token in the command stream that you can
+// use to check if that token has been passed in the command stream.
+struct SetToken {
+ typedef SetToken ValueType;
+ static const CommandId kCmdId = kSetToken;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _token) {
+ SetHeader();
+ token = _token;
+ }
+ static void* Set(void* cmd, uint32 token) {
+ static_cast<ValueType*>(cmd)->Init(token);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 token;
+};
+
+COMPILE_ASSERT(sizeof(SetToken) == 8, Sizeof_SetToken_is_not_8);
+COMPILE_ASSERT(offsetof(SetToken, header) == 0,
+ Offsetof_SetToken_header_not_0);
+COMPILE_ASSERT(offsetof(SetToken, token) == 4,
+ Offsetof_SetToken_token_not_4);
+
+// Sets the size of a bucket for collecting data on the service side.
+// This is a utility for gathering data on the service side so it can be used
+// all at once when some service side API is called. It removes the need to add
+// special commands just to support a particular API. For example, any API
+// command that needs a string needs a way to send that string to the API over
+// the command buffers. While you can require that the command buffer or
+// transfer buffer be large enough to hold the largest string you can send,
+// using this command removes that restriction by letting you send smaller
+// pieces over and build up the data on the service side.
+//
+// You can clear a bucket on the service side and thereby free memory by sending
+// a size of 0.
+struct SetBucketSize {
+ typedef SetBucketSize ValueType;
+ static const CommandId kCmdId = kSetBucketSize;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _bucket_id, uint32 _size) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ size = _size;
+ }
+ static void* Set(void* cmd, uint32 _bucket_id, uint32 _size) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id, _size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 size;
+};
+
+COMPILE_ASSERT(sizeof(SetBucketSize) == 12, Sizeof_SetBucketSize_is_not_8);
+COMPILE_ASSERT(offsetof(SetBucketSize, header) == 0,
+ Offsetof_SetBucketSize_header_not_0);
+COMPILE_ASSERT(offsetof(SetBucketSize, bucket_id) == 4,
+ Offsetof_SetBucketSize_bucket_id_4);
+COMPILE_ASSERT(offsetof(SetBucketSize, size) == 8,
+ Offsetof_SetBucketSize_size_8);
+
+// Sets the contents of a portion of a bucket on the service side from data in
+// shared memory.
+// See SetBucketSize.
+struct SetBucketData {
+ typedef SetBucketData ValueType;
+ static const CommandId kCmdId = kSetBucketData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _bucket_id,
+ uint32 _offset,
+ uint32 _size,
+ uint32 _shared_memory_id,
+ uint32 _shared_memory_offset) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ offset = _offset;
+ size = _size;
+ shared_memory_id = _shared_memory_id;
+ shared_memory_offset = _shared_memory_offset;
+ }
+ static void* Set(void* cmd,
+ uint32 _bucket_id,
+ uint32 _offset,
+ uint32 _size,
+ uint32 _shared_memory_id,
+ uint32 _shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(
+ _bucket_id,
+ _offset,
+ _size,
+ _shared_memory_id,
+ _shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 offset;
+ uint32 size;
+ uint32 shared_memory_id;
+ uint32 shared_memory_offset;
+};
+
+COMPILE_ASSERT(sizeof(SetBucketData) == 24, Sizeof_SetBucketData_is_not_24);
+COMPILE_ASSERT(offsetof(SetBucketData, header) == 0,
+ Offsetof_SetBucketData_header_not_0);
+COMPILE_ASSERT(offsetof(SetBucketData, bucket_id) == 4,
+ Offsetof_SetBucketData_bucket_id_not_4);
+COMPILE_ASSERT(offsetof(SetBucketData, offset) == 8,
+ Offsetof_SetBucketData_offset_not_8);
+COMPILE_ASSERT(offsetof(SetBucketData, size) == 12,
+ Offsetof_SetBucketData_size_not_12);
+COMPILE_ASSERT(offsetof(SetBucketData, shared_memory_id) == 16,
+ Offsetof_SetBucketData_shared_memory_id_not_16);
+COMPILE_ASSERT(offsetof(SetBucketData, shared_memory_offset) == 20,
+ Offsetof_SetBucketData_shared_memory_offset_not_20);
+
+// Sets the contents of a portion of a bucket on the service side from data in
+// the command buffer.
+// See SetBucketSize.
+struct SetBucketDataImmediate {
+ typedef SetBucketDataImmediate ValueType;
+ static const CommandId kCmdId = kSetBucketDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ void SetHeader(uint32 size) {
+ header.SetCmdBySize<ValueType>(size);
+ }
+
+ void Init(uint32 _bucket_id,
+ uint32 _offset,
+ uint32 _size) {
+ SetHeader(_size);
+ bucket_id = _bucket_id;
+ offset = _offset;
+ size = _size;
+ }
+ static void* Set(void* cmd,
+ uint32 _bucket_id,
+ uint32 _offset,
+ uint32 _size) {
+ static_cast<ValueType*>(cmd)->Init(
+ _bucket_id,
+ _offset,
+ _size);
+ return NextImmediateCmdAddress<ValueType>(cmd, _size);
+ }
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 offset;
+ uint32 size;
+};
+
+COMPILE_ASSERT(sizeof(SetBucketDataImmediate) == 16,
+ Sizeof_SetBucketDataImmediate_is_not_24);
+COMPILE_ASSERT(offsetof(SetBucketDataImmediate, header) == 0,
+ Offsetof_SetBucketDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(SetBucketDataImmediate, bucket_id) == 4,
+ Offsetof_SetBucketDataImmediate_bucket_id_not_4);
+COMPILE_ASSERT(offsetof(SetBucketDataImmediate, offset) == 8,
+ Offsetof_SetBucketDataImmediate_offset_not_8);
+COMPILE_ASSERT(offsetof(SetBucketDataImmediate, size) == 12,
+ Offsetof_SetBucketDataImmediate_size_not_12);
+
+// Gets the start of a bucket the service has available. Sending a variable size
+// result back to the client and the portion of that result that fits in the
+// supplied shared memory. If the size of the result is larger than the supplied
+// shared memory the rest of the bucket's contents can be retrieved with
+// GetBucketData.
+//
+// This is used for example for any API that returns a string. The problem is
+// the largest thing you can send back in 1 command is the size of your shared
+// memory. This command along with GetBucketData implements a way to get a
+// result a piece at a time to help solve that problem in a generic way.
+struct GetBucketStart {
+ typedef GetBucketStart ValueType;
+ static const CommandId kCmdId = kGetBucketStart;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _bucket_id,
+ uint32 _result_memory_id,
+ uint32 _result_memory_offset,
+ uint32 _data_memory_size,
+ uint32 _data_memory_id,
+ uint32 _data_memory_offset) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ result_memory_id = _result_memory_id;
+ result_memory_offset = _result_memory_offset;
+ data_memory_size = _data_memory_size;
+ data_memory_id = _data_memory_id;
+ data_memory_offset = _data_memory_offset;
+ }
+ static void* Set(void* cmd,
+ uint32 _bucket_id,
+ uint32 _result_memory_id,
+ uint32 _result_memory_offset,
+ uint32 _data_memory_size,
+ uint32 _data_memory_id,
+ uint32 _data_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(
+ _bucket_id,
+ _result_memory_id,
+ _result_memory_offset,
+ _data_memory_size,
+ _data_memory_id,
+ _data_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 result_memory_id;
+ uint32 result_memory_offset;
+ uint32 data_memory_size;
+ uint32 data_memory_id;
+ uint32 data_memory_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetBucketStart) == 28, Sizeof_GetBucketStart_is_not_28);
+COMPILE_ASSERT(offsetof(GetBucketStart, header) == 0,
+ Offsetof_GetBucketStart_header_not_0);
+COMPILE_ASSERT(offsetof(GetBucketStart, bucket_id) == 4,
+ Offsetof_GetBucketStart_bucket_id_not_4);
+COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_id) == 8,
+ Offsetof_GetBucketStart_result_memory_id_not_8);
+COMPILE_ASSERT(offsetof(GetBucketStart, result_memory_offset) == 12,
+ Offsetof_GetBucketStart_result_memory_offset_not_12);
+COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_size) == 16,
+ Offsetof_GetBucketStart_data_memory_size_not_16);
+COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_id) == 20,
+ Offsetof_GetBucketStart_data_memory_id_not_20);
+COMPILE_ASSERT(offsetof(GetBucketStart, data_memory_offset) == 24,
+ Offsetof_GetBucketStart_data_memory_offset_not_24);
+
+// Gets a piece of a result the service as available.
+// See GetBucketSize.
+struct GetBucketData {
+ typedef GetBucketData ValueType;
+ static const CommandId kCmdId = kGetBucketData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _bucket_id,
+ uint32 _offset,
+ uint32 _size,
+ uint32 _shared_memory_id,
+ uint32 _shared_memory_offset) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ offset = _offset;
+ size = _size;
+ shared_memory_id = _shared_memory_id;
+ shared_memory_offset = _shared_memory_offset;
+ }
+ static void* Set(void* cmd,
+ uint32 _bucket_id,
+ uint32 _offset,
+ uint32 _size,
+ uint32 _shared_memory_id,
+ uint32 _shared_memory_offset) {
+ static_cast<ValueType*>(cmd)->Init(
+ _bucket_id,
+ _offset,
+ _size,
+ _shared_memory_id,
+ _shared_memory_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 offset;
+ uint32 size;
+ uint32 shared_memory_id;
+ uint32 shared_memory_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetBucketData) == 24, Sizeof_GetBucketData_is_not_20);
+COMPILE_ASSERT(offsetof(GetBucketData, header) == 0,
+ Offsetof_GetBucketData_header_not_0);
+COMPILE_ASSERT(offsetof(GetBucketData, bucket_id) == 4,
+ Offsetof_GetBucketData_bucket_id_not_4);
+COMPILE_ASSERT(offsetof(GetBucketData, offset) == 8,
+ Offsetof_GetBucketData_offset_not_8);
+COMPILE_ASSERT(offsetof(GetBucketData, size) == 12,
+ Offsetof_GetBucketData_size_not_12);
+COMPILE_ASSERT(offsetof(GetBucketData, shared_memory_id) == 16,
+ Offsetof_GetBucketData_shared_memory_id_not_16);
+COMPILE_ASSERT(offsetof(GetBucketData, shared_memory_offset) == 20,
+ Offsetof_GetBucketData_shared_memory_offset_not_20);
+
+} // namespace cmd
+
+#pragma pack(pop)
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CMD_BUFFER_COMMON_H_
+
diff --git a/chromium/gpu/command_buffer/common/command_buffer.h b/chromium/gpu/command_buffer/common/command_buffer.h
new file mode 100644
index 00000000000..3078bca2ba3
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/command_buffer.h
@@ -0,0 +1,150 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_H_
+#define GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_H_
+
+#include "gpu/command_buffer/common/buffer.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/gpu_export.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace gpu {
+
+// Common interface for CommandBuffer implementations.
+class GPU_EXPORT CommandBuffer {
+ public:
+ struct State {
+ State()
+ : num_entries(0),
+ get_offset(0),
+ put_offset(0),
+ token(-1),
+ error(error::kNoError),
+ context_lost_reason(error::kUnknown),
+ generation(0) {
+ }
+
+ // Size of the command buffer in command buffer entries.
+ int32 num_entries;
+
+ // The offset (in entries) from which the reader is reading.
+ int32 get_offset;
+
+ // The offset (in entries) at which the writer is writing.
+ int32 put_offset;
+
+ // The current token value. This is used by the writer to defer
+ // changes to shared memory objects until the reader has reached a certain
+ // point in the command buffer. The reader is responsible for updating the
+ // token value, for example in response to an asynchronous set token command
+ // embedded in the command buffer. The default token value is zero.
+ int32 token;
+
+ // Error status.
+ error::Error error;
+
+ // Lost context detail information.
+ error::ContextLostReason context_lost_reason;
+
+ // Generation index of this state. The generation index is incremented every
+ // time a new state is retrieved from the command processor, so that
+ // consistency can be kept even if IPC messages are processed out-of-order.
+ uint32 generation;
+ };
+
+ struct ConsoleMessage {
+ // An user supplied id.
+ int32 id;
+ // The message.
+ std::string message;
+ };
+
+ CommandBuffer() {
+ }
+
+ virtual ~CommandBuffer() {
+ }
+
+ // Initialize the command buffer with the given size.
+ virtual bool Initialize() = 0;
+
+ // Returns the current status.
+ virtual State GetState() = 0;
+
+ // Returns the last state without synchronizing with the service.
+ virtual State GetLastState() = 0;
+
+ // Returns the last token without synchronizing with the service. Note that
+ // while you could just call GetLastState().token, GetLastState needs to be
+ // fast as it is called for every command where GetLastToken is only called
+ // by code that needs to know the last token so it can be slower but more up
+ // to date than GetLastState.
+ virtual int32 GetLastToken() = 0;
+
+ // The writer calls this to update its put offset. This ensures the reader
+ // sees the latest added commands, and will eventually process them. On the
+ // service side, commands are processed up to the given put_offset before
+ // subsequent Flushes on the same GpuChannel.
+ virtual void Flush(int32 put_offset) = 0;
+
+ // The writer calls this to update its put offset. This function returns the
+ // reader's most recent get offset. Does not return until all pending commands
+ // have been executed.
+ virtual State FlushSync(int32 put_offset, int32 last_known_get) = 0;
+
+ // Sets the buffer commands are read from.
+ // Also resets the get and put offsets to 0.
+ virtual void SetGetBuffer(int32 transfer_buffer_id) = 0;
+
+ // Sets the current get offset. This can be called from any thread.
+ virtual void SetGetOffset(int32 get_offset) = 0;
+
+ // Create a transfer buffer of the given size. Returns its ID or -1 on
+ // error.
+ virtual Buffer CreateTransferBuffer(size_t size, int32* id) = 0;
+
+ // Destroy a transfer buffer. The ID must be positive.
+ virtual void DestroyTransferBuffer(int32 id) = 0;
+
+ // Get the transfer buffer associated with an ID. Returns a null buffer for
+ // ID 0.
+ virtual Buffer GetTransferBuffer(int32 id) = 0;
+
+ // Allows the reader to update the current token value.
+ virtual void SetToken(int32 token) = 0;
+
+ // Allows the reader to set the current parse error.
+ virtual void SetParseError(error::Error) = 0;
+
+ // Allows the reader to set the current context lost reason.
+ // NOTE: if calling this in conjunction with SetParseError,
+ // call this first.
+ virtual void SetContextLostReason(error::ContextLostReason) = 0;
+
+// The NaCl Win64 build only really needs the struct definitions above; having
+// GetLastError declared would mean we'd have to also define it, and pull more
+// of gpu in to the NaCl Win64 build.
+#if !defined(NACL_WIN64)
+ // TODO(apatrick): this is a temporary optimization while skia is calling
+ // RendererGLContext::MakeCurrent prior to every GL call. It saves returning 6
+ // ints redundantly when only the error is needed for the CommandBufferProxy
+ // implementation.
+ virtual error::Error GetLastError();
+#endif
+
+ // Inserts a sync point, returning its ID. Sync point IDs are global and can
+ // be used for cross-context synchronization.
+ virtual uint32 InsertSyncPoint() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CommandBuffer);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_H_
diff --git a/chromium/gpu/command_buffer/common/command_buffer_mock.cc b/chromium/gpu/command_buffer/common/command_buffer_mock.cc
new file mode 100644
index 00000000000..6ed2eee61b5
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/command_buffer_mock.cc
@@ -0,0 +1,16 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/command_buffer_mock.h"
+
+namespace gpu {
+
+MockCommandBuffer::MockCommandBuffer() {
+ ON_CALL(*this, GetTransferBuffer(testing::_))
+ .WillByDefault(testing::Return(Buffer()));
+}
+
+MockCommandBuffer::~MockCommandBuffer() {}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/command_buffer_mock.h b/chromium/gpu/command_buffer/common/command_buffer_mock.h
new file mode 100644
index 00000000000..0e78b7b8c32
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/command_buffer_mock.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_MOCK_H_
+#define GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_MOCK_H_
+
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace gpu {
+
+// An NPObject that implements a shared memory command buffer and a synchronous
+// API to manage the put and get pointers.
+class MockCommandBuffer : public CommandBuffer {
+ public:
+ MockCommandBuffer();
+ virtual ~MockCommandBuffer();
+
+ MOCK_METHOD0(Initialize, bool());
+ MOCK_METHOD0(GetState, State());
+ MOCK_METHOD0(GetLastState, State());
+ MOCK_METHOD0(GetLastToken, int32());
+ MOCK_METHOD1(Flush, void(int32 put_offset));
+ MOCK_METHOD2(FlushSync, State(int32 put_offset, int32 last_known_get));
+ MOCK_METHOD1(SetGetBuffer, void(int32 transfer_buffer_id));
+ MOCK_METHOD1(SetGetOffset, void(int32 get_offset));
+ MOCK_METHOD2(CreateTransferBuffer, Buffer(size_t size, int32* id));
+ MOCK_METHOD1(DestroyTransferBuffer, void(int32 id));
+ MOCK_METHOD1(GetTransferBuffer, Buffer(int32 id));
+ MOCK_METHOD1(SetToken, void(int32 token));
+ MOCK_METHOD1(SetParseError, void(error::Error error));
+ MOCK_METHOD1(SetContextLostReason,
+ void(error::ContextLostReason context_lost_reason));
+ MOCK_METHOD0(InsertSyncPoint, uint32());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCommandBuffer);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_MOCK_H_
diff --git a/chromium/gpu/command_buffer/common/command_buffer_shared.h b/chromium/gpu/command_buffer/common/command_buffer_shared.h
new file mode 100644
index 00000000000..fafe767bdb1
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/command_buffer_shared.h
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_SHARED_H_
+#define GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_SHARED_H_
+
+#include "command_buffer.h"
+#include "base/atomicops.h"
+
+namespace gpu {
+
+// This is a standard 4-slot asynchronous communication mechanism, used to
+// ensure that the reader gets a consistent copy of what the writer wrote.
+template<typename T>
+class SharedState {
+ T states_[2][2];
+ base::subtle::Atomic32 reading_;
+ base::subtle::Atomic32 latest_;
+ base::subtle::Atomic32 slots_[2];
+
+public:
+
+ void Initialize() {
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ states_[i][j] = T();
+ }
+ }
+ base::subtle::NoBarrier_Store(&reading_, 0);
+ base::subtle::NoBarrier_Store(&latest_, 0);
+ base::subtle::NoBarrier_Store(&slots_[0], 0);
+ base::subtle::Release_Store(&slots_[1], 0);
+ base::subtle::MemoryBarrier();
+ }
+
+ void Write(const T& state) {
+ int towrite = !base::subtle::Acquire_Load(&reading_);
+ int index = !base::subtle::Acquire_Load(&slots_[towrite]);
+ states_[towrite][index] = state;
+ base::subtle::Release_Store(&slots_[towrite], index);
+ base::subtle::Release_Store(&latest_, towrite);
+ base::subtle::MemoryBarrier();
+ }
+
+ // Attempt to update the state, updating only if the generation counter is
+ // newer.
+ void Read(T* state) {
+ base::subtle::MemoryBarrier();
+ int toread = !!base::subtle::Acquire_Load(&latest_);
+ base::subtle::Release_Store(&reading_, toread);
+ base::subtle::MemoryBarrier();
+ int index = !!base::subtle::Acquire_Load(&slots_[toread]);
+ if (states_[toread][index].generation - state->generation < 0x80000000U)
+ *state = states_[toread][index];
+ }
+};
+
+typedef SharedState<CommandBuffer::State> CommandBufferSharedState;
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_COMMAND_BUFFER_SHARED_H_
diff --git a/chromium/gpu/command_buffer/common/command_buffer_shared_test.cc b/chromium/gpu/command_buffer/common/command_buffer_shared_test.cc
new file mode 100644
index 00000000000..d2c599a35e8
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/command_buffer_shared_test.cc
@@ -0,0 +1,96 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the tests for the CommandBufferSharedState class.
+
+#include "gpu/command_buffer/common/command_buffer_shared.h"
+#include "base/bind.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class CommandBufferSharedTest : public testing::Test {
+ protected:
+
+ virtual void SetUp() {
+ shared_state_.reset(new CommandBufferSharedState());
+ shared_state_->Initialize();
+ }
+
+ scoped_ptr<CommandBufferSharedState> shared_state_;
+};
+
+TEST_F(CommandBufferSharedTest, TestBasic) {
+ CommandBuffer::State state;
+
+ shared_state_->Read(&state);
+
+ EXPECT_LT(state.generation, 0x80000000);
+ EXPECT_EQ(state.get_offset, 0);
+ EXPECT_EQ(state.put_offset, 0);
+ EXPECT_EQ(state.token, -1);
+ EXPECT_EQ(state.error, gpu::error::kNoError);
+ EXPECT_EQ(state.context_lost_reason, gpu::error::kUnknown);
+}
+
+static const int kSize = 100000;
+
+void WriteToState(int32 *buffer,
+ CommandBufferSharedState* shared_state) {
+ CommandBuffer::State state;
+ for (int i = 0; i < kSize; i++) {
+ state.token = i - 1;
+ state.get_offset = i + 1;
+ state.generation = i + 2;
+ state.error = static_cast<gpu::error::Error>(i + 3);
+ // Ensure that the producer doesn't update the buffer until after the
+ // consumer reads from it.
+ EXPECT_EQ(buffer[i], 0);
+
+ shared_state->Write(state);
+ }
+}
+
+TEST_F(CommandBufferSharedTest, TestConsistency) {
+ scoped_ptr<int32[]> buffer;
+ buffer.reset(new int32[kSize]);
+ base::Thread consumer("Reader Thread");
+
+ memset(buffer.get(), 0, kSize * sizeof(int32));
+
+ consumer.Start();
+ consumer.message_loop()->PostTask(
+ FROM_HERE, base::Bind(&WriteToState, buffer.get(),
+ shared_state_.get()));
+
+ CommandBuffer::State last_state;
+ while (1) {
+ CommandBuffer::State state = last_state;
+
+ shared_state_->Read(&state);
+
+ if (state.generation < last_state.generation)
+ continue;
+
+ if (state.get_offset >= 1) {
+ buffer[state.get_offset - 1] = 1;
+ // Check that the state is consistent
+ EXPECT_LE(last_state.token, state.token);
+ EXPECT_LE(last_state.generation, state.generation);
+ last_state = state;
+ EXPECT_EQ(state.token, state.get_offset - 2);
+ EXPECT_EQ(state.generation,
+ static_cast<unsigned int>(state.get_offset) + 1);
+ EXPECT_EQ(state.error, state.get_offset + 2);
+
+ if (state.get_offset == kSize)
+ break;
+ }
+ }
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/common/compiler_specific.h b/chromium/gpu/command_buffer/common/compiler_specific.h
new file mode 100644
index 00000000000..2669bff5740
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/compiler_specific.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_COMPILER_SPECIFIC_H_
+#define GPU_COMMAND_BUFFER_COMMON_COMPILER_SPECIFIC_H_
+
+// Annotate a virtual method indicating it must be overriding a virtual
+// method in the parent class.
+// Use like:
+// virtual void foo() OVERRIDE;
+#ifndef OVERRIDE
+#ifdef _MSC_VER
+#define OVERRIDE override
+#elif defined(__clang__)
+#define OVERRIDE override
+#else
+#define OVERRIDE
+#endif
+#endif
+
+#endif // GPU_COMMAND_BUFFER_COMMON_COMPILER_SPECIFIC_H_
diff --git a/chromium/gpu/command_buffer/common/constants.h b/chromium/gpu/command_buffer/common/constants.h
new file mode 100644
index 00000000000..ab25987af9d
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/constants.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_CONSTANTS_H_
+#define GPU_COMMAND_BUFFER_COMMON_CONSTANTS_H_
+
+#include "gpu/command_buffer/common/types.h"
+
+namespace gpu {
+
+typedef int32 CommandBufferOffset;
+const CommandBufferOffset kInvalidCommandBufferOffset = -1;
+
+// This enum must stay in sync with NPDeviceContext3DError.
+namespace error {
+ enum Error {
+ kNoError,
+ kInvalidSize,
+ kOutOfBounds,
+ kUnknownCommand,
+ kInvalidArguments,
+ kLostContext,
+ kGenericError,
+ kDeferCommandUntilLater
+ };
+
+ // Return true if the given error code is an actual error.
+ inline bool IsError(Error error) {
+ return error != kNoError && error != kDeferCommandUntilLater;
+ }
+
+ // Provides finer grained information about why the context was lost.
+ enum ContextLostReason {
+ // This context definitely provoked the loss of context.
+ kGuilty,
+
+ // This context definitely did not provoke the loss of context.
+ kInnocent,
+
+ // It is unknown whether this context provoked the loss of context.
+ kUnknown
+ };
+}
+
+// Invalid shared memory Id, returned by RegisterSharedMemory in case of
+// failure.
+const int32 kInvalidSharedMemoryId = -1;
+
+// Common Command Buffer shared memory transfer buffer ID.
+const int32 kCommandBufferSharedMemoryId = 4;
+
+// The size to set for the program cache.
+const size_t kDefaultMaxProgramCacheMemoryBytes = 6 * 1024 * 1024;
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_CONSTANTS_H_
diff --git a/chromium/gpu/command_buffer/common/debug_marker_manager.cc b/chromium/gpu/command_buffer/common/debug_marker_manager.cc
new file mode 100644
index 00000000000..c6336f98f62
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/debug_marker_manager.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/debug_marker_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+DebugMarkerManager::Group::Group(const std::string& name)
+ : name_(name),
+ marker_(name) {
+}
+
+DebugMarkerManager::Group::~Group() {
+}
+
+void DebugMarkerManager::Group::SetMarker(const std::string& marker) {
+ marker_ = name_ + "." + marker;
+}
+
+DebugMarkerManager::DebugMarkerManager() {
+ // Push root group.
+ group_stack_.push(Group(std::string("")));
+}
+
+DebugMarkerManager::~DebugMarkerManager() {
+}
+
+void DebugMarkerManager::SetMarker(const std::string& marker) {
+ group_stack_.top().SetMarker(marker);
+}
+
+const std::string& DebugMarkerManager::GetMarker() const {
+ return group_stack_.top().marker();
+}
+
+void DebugMarkerManager::PushGroup(const std::string& name) {
+ group_stack_.push(Group(group_stack_.top().name() + "." + name));
+}
+
+void DebugMarkerManager::PopGroup(void) {
+ if (group_stack_.size() > 1) {
+ group_stack_.pop();
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/common/debug_marker_manager.h b/chromium/gpu/command_buffer/common/debug_marker_manager.h
new file mode 100644
index 00000000000..65e0cd011d6
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/debug_marker_manager.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_DEBUG_MARKER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_DEBUG_MARKER_MANAGER_H_
+
+#include <stack>
+#include <string>
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+// Tracks debug marker.
+class GPU_EXPORT DebugMarkerManager {
+ public:
+ DebugMarkerManager();
+ ~DebugMarkerManager();
+
+ // Gets the current marker on the top group.
+ const std::string& GetMarker() const;
+ // Sets the current marker on the top group.
+ void SetMarker(const std::string& marker);
+ // Pushes a new group.
+ void PushGroup(const std::string& name);
+ // Removes the top group. This is safe to call even when stack is empty.
+ void PopGroup(void);
+
+ private:
+ // Info about Buffers currently in the system.
+ class Group {
+ public:
+ explicit Group(const std::string& name);
+ ~Group();
+
+ const std::string& name() const {
+ return name_;
+ }
+
+ void SetMarker(const std::string& marker);
+
+ const std::string& marker() const {
+ return marker_;
+ }
+
+ private:
+ std::string name_;
+ std::string marker_;
+ };
+
+ typedef std::stack<Group> GroupStack;
+
+ GroupStack group_stack_;
+ std::string empty_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_DEBUG_MARKER_MANAGER_H_
+
diff --git a/chromium/gpu/command_buffer/common/debug_marker_manager_unittest.cc b/chromium/gpu/command_buffer/common/debug_marker_manager_unittest.cc
new file mode 100644
index 00000000000..fa1cfccac32
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/debug_marker_manager_unittest.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/debug_marker_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class DebugMarkerManagerTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+ DebugMarkerManager manager_;
+};
+
+TEST_F(DebugMarkerManagerTest, Basic) {
+ // Test we can get root
+ EXPECT_STREQ("", manager_.GetMarker().c_str());
+ // Test it's safe to pop an empty stack.
+ manager_.PopGroup();
+ // Test we can still get root.
+ EXPECT_STREQ("", manager_.GetMarker().c_str());
+ // Test setting a marker.
+ manager_.SetMarker("mark1");
+ EXPECT_STREQ(".mark1", manager_.GetMarker().c_str());
+ manager_.SetMarker("mark2");
+ EXPECT_STREQ(".mark2", manager_.GetMarker().c_str());
+ // Test pushing a group.
+ manager_.PushGroup("abc");
+ EXPECT_STREQ(".abc", manager_.GetMarker().c_str());
+ // Test setting a marker on the group
+ manager_.SetMarker("mark3");
+ EXPECT_STREQ(".abc.mark3", manager_.GetMarker().c_str());
+ manager_.SetMarker("mark4");
+ EXPECT_STREQ(".abc.mark4", manager_.GetMarker().c_str());
+ // Test pushing a 2nd group.
+ manager_.PushGroup("def");
+ EXPECT_STREQ(".abc.def", manager_.GetMarker().c_str());
+ // Test setting a marker on the group
+ manager_.SetMarker("mark5");
+ EXPECT_STREQ(".abc.def.mark5", manager_.GetMarker().c_str());
+ manager_.SetMarker("mark6");
+ EXPECT_STREQ(".abc.def.mark6", manager_.GetMarker().c_str());
+ // Test poping 2nd group.
+ manager_.PopGroup();
+ EXPECT_STREQ(".abc.mark4", manager_.GetMarker().c_str());
+ manager_.PopGroup();
+ EXPECT_STREQ(".mark2", manager_.GetMarker().c_str());
+ manager_.PopGroup();
+ EXPECT_STREQ(".mark2", manager_.GetMarker().c_str());
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_format.cc b/chromium/gpu/command_buffer/common/gles2_cmd_format.cc
new file mode 100644
index 00000000000..5b437a5b2f1
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_format.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the binary format definition of the command buffer and
+// command buffer commands.
+
+// We explicitly do NOT include gles2_cmd_format.h here because client side
+// and service side have different requirements.
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+
+namespace gpu {
+namespace gles2 {
+
+#include "gpu/command_buffer/common/gles2_cmd_ids_autogen.h"
+
+const char* GetCommandName(CommandId id) {
+ static const char* const names[] = {
+ #define GLES2_CMD_OP(name) "k" # name,
+
+ GLES2_COMMAND_LIST(GLES2_CMD_OP)
+
+ #undef GLES2_CMD_OP
+ };
+
+ size_t index = static_cast<size_t>(id) - kStartPoint - 1;
+ return (index < arraysize(names)) ? names[index] : "*unknown-command*";
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_format.h b/chromium/gpu/command_buffer/common/gles2_cmd_format.h
new file mode 100644
index 00000000000..37c7a53d970
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_format.h
@@ -0,0 +1,557 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the GLES2 command buffer commands.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_H_
+
+
+#include <KHR/khrplatform.h>
+
+#include <string.h>
+
+#include "base/safe_numerics.h"
+#include "gpu/command_buffer/common/bitfield_helpers.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/gles2_cmd_ids.h"
+#include "gpu/command_buffer/common/types.h"
+
+// GL types are forward declared to avoid including the GL headers. The problem
+// is determining which GL headers to include from code that is common to the
+// client and service sides (GLES2 or one of several GL implementations).
+typedef unsigned int GLenum;
+typedef unsigned int GLbitfield;
+typedef unsigned int GLuint;
+typedef int GLint;
+typedef int GLsizei;
+typedef unsigned char GLboolean;
+typedef signed char GLbyte;
+typedef short GLshort;
+typedef unsigned char GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned long GLulong;
+typedef float GLfloat;
+typedef float GLclampf;
+typedef double GLdouble;
+typedef double GLclampd;
+typedef void GLvoid;
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+namespace gpu {
+namespace gles2 {
+
+#pragma pack(push, 1)
+
+namespace id_namespaces {
+
+// These are used when contexts share resources.
+enum IdNamespaces {
+ kBuffers,
+ kFramebuffers,
+ kProgramsAndShaders,
+ kRenderbuffers,
+ kTextures,
+ kQueries,
+ kVertexArrays,
+ kImages,
+ kNumIdNamespaces
+};
+
+// These numbers must not change
+COMPILE_ASSERT(kBuffers == 0, kBuffers_is_not_0);
+COMPILE_ASSERT(kFramebuffers == 1, kFramebuffers_is_not_1);
+COMPILE_ASSERT(kProgramsAndShaders == 2, kProgramsAndShaders_is_not_2);
+COMPILE_ASSERT(kRenderbuffers == 3, kRenderbuffers_is_not_3);
+COMPILE_ASSERT(kTextures == 4, kTextures_is_not_4);
+
+} // namespace id_namespaces
+
+// Used for some glGetXXX commands that return a result through a pointer. We
+// need to know if the command succeeded or not and the size of the result. If
+// the command failed its result size will 0.
+template <typename T>
+struct SizedResult {
+ typedef T Type;
+
+ T* GetData() {
+ return static_cast<T*>(static_cast<void*>(&data));
+ }
+
+ // Returns the total size in bytes of the SizedResult for a given number of
+ // results including the size field.
+ static size_t ComputeSize(size_t num_results) {
+ return sizeof(T) * num_results + sizeof(uint32); // NOLINT
+ }
+
+ // Returns the total size in bytes of the SizedResult for a given size of
+ // results.
+ static size_t ComputeSizeFromBytes(size_t size_of_result_in_bytes) {
+ return size_of_result_in_bytes + sizeof(uint32); // NOLINT
+ }
+
+ // Returns the maximum number of results for a given buffer size.
+ static uint32 ComputeMaxResults(size_t size_of_buffer) {
+ return (size_of_buffer >= sizeof(uint32)) ?
+ ((size_of_buffer - sizeof(uint32)) / sizeof(T)) : 0; // NOLINT
+ }
+
+ // Set the size for a given number of results.
+ void SetNumResults(size_t num_results) {
+ size = sizeof(T) * num_results; // NOLINT
+ }
+
+ // Get the number of elements in the result
+ int32 GetNumResults() const {
+ return size / sizeof(T); // NOLINT
+ }
+
+ // Copy the result.
+ void CopyResult(void* dst) const {
+ memcpy(dst, &data, size);
+ }
+
+ uint32 size; // in bytes.
+ int32 data; // this is just here to get an offset.
+};
+
+COMPILE_ASSERT(sizeof(SizedResult<int8>) == 8, SizedResult_size_not_8);
+COMPILE_ASSERT(offsetof(SizedResult<int8>, size) == 0,
+ OffsetOf_SizedResult_size_not_0);
+COMPILE_ASSERT(offsetof(SizedResult<int8>, data) == 4,
+ OffsetOf_SizedResult_data_not_4);
+
+// The data for one attrib or uniform from GetProgramInfoCHROMIUM.
+struct ProgramInput {
+ uint32 type; // The type (GL_VEC3, GL_MAT3, GL_SAMPLER_2D, etc.
+ int32 size; // The size (how big the array is for uniforms)
+ uint32 location_offset; // offset from ProgramInfoHeader to 'size' locations
+ // for uniforms, 1 for attribs.
+ uint32 name_offset; // offset from ProgrmaInfoHeader to start of name.
+ uint32 name_length; // length of the name.
+};
+
+// The format of the bucket filled out by GetProgramInfoCHROMIUM
+struct ProgramInfoHeader {
+ uint32 link_status;
+ uint32 num_attribs;
+ uint32 num_uniforms;
+ // ProgramInput inputs[num_attribs + num_uniforms];
+};
+
+// The format of QuerySync used by EXT_occlusion_query_boolean
+struct QuerySync {
+ void Reset() {
+ process_count = 0;
+ result = 0;
+ }
+
+ uint32 process_count;
+ uint64 result;
+};
+
+COMPILE_ASSERT(sizeof(ProgramInput) == 20, ProgramInput_size_not_20);
+COMPILE_ASSERT(offsetof(ProgramInput, type) == 0,
+ OffsetOf_ProgramInput_type_not_0);
+COMPILE_ASSERT(offsetof(ProgramInput, size) == 4,
+ OffsetOf_ProgramInput_size_not_4);
+COMPILE_ASSERT(offsetof(ProgramInput, location_offset) == 8,
+ OffsetOf_ProgramInput_location_offset_not_8);
+COMPILE_ASSERT(offsetof(ProgramInput, name_offset) == 12,
+ OffsetOf_ProgramInput_name_offset_not_12);
+COMPILE_ASSERT(offsetof(ProgramInput, name_length) == 16,
+ OffsetOf_ProgramInput_name_length_not_16);
+
+COMPILE_ASSERT(sizeof(ProgramInfoHeader) == 12, ProgramInfoHeader_size_not_12);
+COMPILE_ASSERT(offsetof(ProgramInfoHeader, link_status) == 0,
+ OffsetOf_ProgramInfoHeader_link_status_not_0);
+COMPILE_ASSERT(offsetof(ProgramInfoHeader, num_attribs) == 4,
+ OffsetOf_ProgramInfoHeader_num_attribs_not_4);
+COMPILE_ASSERT(offsetof(ProgramInfoHeader, num_uniforms) == 8,
+ OffsetOf_ProgramInfoHeader_num_uniforms_not_8);
+
+namespace cmds {
+
+#include "../common/gles2_cmd_format_autogen.h"
+
+// These are hand written commands.
+// TODO(gman): Attempt to make these auto-generated.
+
+struct GetAttribLocation {
+ typedef GetAttribLocation ValueType;
+ static const CommandId kCmdId = kGetAttribLocation;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, uint32 _name_shm_id, uint32 _name_shm_offset,
+ uint32 _location_shm_id, uint32 _location_shm_offset,
+ uint32 _data_size) {
+ SetHeader();
+ program = _program;
+ name_shm_id = _name_shm_id;
+ name_shm_offset = _name_shm_offset;
+ location_shm_id = _location_shm_id;
+ location_shm_offset = _location_shm_offset;
+ data_size = _data_size;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, uint32 _name_shm_id, uint32 _name_shm_offset,
+ uint32 _location_shm_id, uint32 _location_shm_offset,
+ uint32 _data_size) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _name_shm_id, _name_shm_offset, _location_shm_id,
+ _location_shm_offset, _data_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_shm_id;
+ uint32 name_shm_offset;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(GetAttribLocation) == 28,
+ Sizeof_GetAttribLocation_is_not_28);
+COMPILE_ASSERT(offsetof(GetAttribLocation, header) == 0,
+ OffsetOf_GetAttribLocation_header_not_0);
+COMPILE_ASSERT(offsetof(GetAttribLocation, program) == 4,
+ OffsetOf_GetAttribLocation_program_not_4);
+COMPILE_ASSERT(offsetof(GetAttribLocation, name_shm_id) == 8,
+ OffsetOf_GetAttribLocation_name_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetAttribLocation, name_shm_offset) == 12,
+ OffsetOf_GetAttribLocation_name_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(GetAttribLocation, location_shm_id) == 16,
+ OffsetOf_GetAttribLocation_location_shm_id_not_16);
+COMPILE_ASSERT(offsetof(GetAttribLocation, location_shm_offset) == 20,
+ OffsetOf_GetAttribLocation_location_shm_offset_not_20);
+COMPILE_ASSERT(offsetof(GetAttribLocation, data_size) == 24,
+ OffsetOf_GetAttribLocation_data_size_not_24);
+
+struct GetAttribLocationImmediate {
+ typedef GetAttribLocationImmediate ValueType;
+ static const CommandId kCmdId = kGetAttribLocationImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ typedef GLint Result;
+
+ static uint32 ComputeDataSize(const char* s) {
+ return base::checked_numeric_cast<uint32>(strlen(s));
+ }
+
+ static uint32 ComputeSize(const char* s) {
+ return base::checked_numeric_cast<uint32>(sizeof(ValueType) +
+ ComputeDataSize(s));
+ }
+
+ void SetHeader(const char* s) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(s));
+ }
+
+ void Init(
+ GLuint _program, const char* _name,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ SetHeader(_name);
+ program = _program;
+ location_shm_id = _location_shm_id;
+ location_shm_offset = _location_shm_offset;
+ data_size = ComputeDataSize(_name);
+ memcpy(ImmediateDataAddress(this), _name, data_size);
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, const char* _name,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ uint32 total_size = ComputeSize(_name);
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _name, _location_shm_id, _location_shm_offset);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ CommandHeader header;
+ uint32 program;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(GetAttribLocationImmediate) == 20,
+ Sizeof_GetAttribLocationImmediate_is_not_20);
+COMPILE_ASSERT(offsetof(GetAttribLocationImmediate, header) == 0,
+ OffsetOf_GetAttribLocationImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GetAttribLocationImmediate, program) == 4,
+ OffsetOf_GetAttribLocationImmediate_program_not_4);
+COMPILE_ASSERT(offsetof(GetAttribLocationImmediate, location_shm_id) == 8,
+ OffsetOf_GetAttribLocationImmediate_location_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetAttribLocationImmediate, location_shm_offset) == 12,
+ OffsetOf_GetAttribLocationImmediate_location_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(GetAttribLocationImmediate, data_size) == 16,
+ OffsetOf_GetAttribLocationImmediate_data_size_not_16);
+
+
+struct GetAttribLocationBucket {
+ typedef GetAttribLocationBucket ValueType;
+ static const CommandId kCmdId = kGetAttribLocationBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, uint32 _name_bucket_id,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ SetHeader();
+ program = _program;
+ name_bucket_id = _name_bucket_id;
+ location_shm_id = _location_shm_id;
+ location_shm_offset = _location_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, uint32 _name_bucket_id,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _name_bucket_id, _location_shm_id,
+ _location_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_bucket_id;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetAttribLocationBucket) == 20,
+ Sizeof_GetAttribLocationBucket_is_not_24);
+COMPILE_ASSERT(offsetof(GetAttribLocationBucket, header) == 0,
+ OffsetOf_GetAttribLocationBucket_header_not_0);
+COMPILE_ASSERT(offsetof(GetAttribLocationBucket, program) == 4,
+ OffsetOf_GetAttribLocationBucket_program_not_4);
+COMPILE_ASSERT(offsetof(GetAttribLocationBucket, name_bucket_id) == 8,
+ OffsetOf_GetAttribLocationBucket_name_bucket_id_not_8);
+COMPILE_ASSERT(offsetof(GetAttribLocationBucket, location_shm_id) == 12,
+ OffsetOf_GetAttribLocationBucket_location_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetAttribLocationBucket, location_shm_offset) == 16,
+ OffsetOf_GetAttribLocationBucket_location_shm_offset_not_16);
+
+struct GetUniformLocation {
+ typedef GetUniformLocation ValueType;
+ static const CommandId kCmdId = kGetUniformLocation;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, uint32 _name_shm_id, uint32 _name_shm_offset,
+ uint32 _location_shm_id, uint32 _location_shm_offset,
+ uint32 _data_size) {
+ SetHeader();
+ program = _program;
+ name_shm_id = _name_shm_id;
+ name_shm_offset = _name_shm_offset;
+ location_shm_id = _location_shm_id;
+ location_shm_offset = _location_shm_offset;
+ data_size = _data_size;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, uint32 _name_shm_id, uint32 _name_shm_offset,
+ uint32 _location_shm_id, uint32 _location_shm_offset,
+ uint32 _data_size) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _name_shm_id, _name_shm_offset, _location_shm_id,
+ _location_shm_offset, _data_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_shm_id;
+ uint32 name_shm_offset;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(GetUniformLocation) == 28,
+ Sizeof_GetUniformLocation_is_not_28);
+COMPILE_ASSERT(offsetof(GetUniformLocation, header) == 0,
+ OffsetOf_GetUniformLocation_header_not_0);
+COMPILE_ASSERT(offsetof(GetUniformLocation, program) == 4,
+ OffsetOf_GetUniformLocation_program_not_4);
+COMPILE_ASSERT(offsetof(GetUniformLocation, name_shm_id) == 8,
+ OffsetOf_GetUniformLocation_name_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetUniformLocation, name_shm_offset) == 12,
+ OffsetOf_GetUniformLocation_name_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(GetUniformLocation, location_shm_id) == 16,
+ OffsetOf_GetUniformLocation_location_shm_id_not_16);
+COMPILE_ASSERT(offsetof(GetUniformLocation, location_shm_offset) == 20,
+ OffsetOf_GetUniformLocation_location_shm_offset_not_20);
+COMPILE_ASSERT(offsetof(GetUniformLocation, data_size) == 24,
+ OffsetOf_GetUniformLocation_data_size_not_24);
+
+struct GetUniformLocationImmediate {
+ typedef GetUniformLocationImmediate ValueType;
+ static const CommandId kCmdId = kGetUniformLocationImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ typedef GLint Result;
+
+ static uint32 ComputeDataSize(const char* s) {
+ return base::checked_numeric_cast<uint32>(strlen(s));
+ }
+
+ static uint32 ComputeSize(const char* s) {
+ return base::checked_numeric_cast<uint32>(sizeof(ValueType) +
+ ComputeDataSize(s));
+ }
+
+ void SetHeader(const char* s) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(s));
+ }
+
+ void Init(
+ GLuint _program, const char* _name,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ SetHeader(_name);
+ program = _program;
+ location_shm_id = _location_shm_id;
+ location_shm_offset = _location_shm_offset;
+ data_size = ComputeDataSize(_name);
+ memcpy(ImmediateDataAddress(this), _name, data_size);
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, const char* _name,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ uint32 total_size = ComputeSize(_name);
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _name, _location_shm_id, _location_shm_offset);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ CommandHeader header;
+ uint32 program;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(GetUniformLocationImmediate) == 20,
+ Sizeof_GetUniformLocationImmediate_is_not_20);
+COMPILE_ASSERT(offsetof(GetUniformLocationImmediate, header) == 0,
+ OffsetOf_GetUniformLocationImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GetUniformLocationImmediate, program) == 4,
+ OffsetOf_GetUniformLocationImmediate_program_not_4);
+COMPILE_ASSERT(offsetof(GetUniformLocationImmediate, location_shm_id) == 8,
+ OffsetOf_GetUniformLocationImmediate_location_shm_id_not_8);
+COMPILE_ASSERT(
+ offsetof(GetUniformLocationImmediate, location_shm_offset) == 12,
+ OffsetOf_GetUniformLocationImmediate_location_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(GetUniformLocationImmediate, data_size) == 16,
+ OffsetOf_GetUniformLocationImmediate_data_size_not_16);
+
+struct GetUniformLocationBucket {
+ typedef GetUniformLocationBucket ValueType;
+ static const CommandId kCmdId = kGetUniformLocationBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, uint32 _name_bucket_id,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ SetHeader();
+ program = _program;
+ name_bucket_id = _name_bucket_id;
+ location_shm_id = _location_shm_id;
+ location_shm_offset = _location_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, uint32 _name_bucket_id,
+ uint32 _location_shm_id, uint32 _location_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _name_bucket_id, _location_shm_id,
+ _location_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_bucket_id;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetUniformLocationBucket) == 20,
+ Sizeof_GetUniformLocationBucket_is_not_24);
+COMPILE_ASSERT(offsetof(GetUniformLocationBucket, header) == 0,
+ OffsetOf_GetUniformLocationBucket_header_not_0);
+COMPILE_ASSERT(offsetof(GetUniformLocationBucket, program) == 4,
+ OffsetOf_GetUniformLocationBucket_program_not_4);
+COMPILE_ASSERT(offsetof(GetUniformLocationBucket, name_bucket_id) == 8,
+ OffsetOf_GetUniformLocationBucket_name_bucket_id_not_8);
+COMPILE_ASSERT(offsetof(GetUniformLocationBucket, location_shm_id) == 12,
+ OffsetOf_GetUniformLocationBucket_location_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetUniformLocationBucket, location_shm_offset) == 16,
+ OffsetOf_GetUniformLocationBucket_location_shm_offset_not_16);
+
+struct InsertSyncPointCHROMIUM {
+ typedef InsertSyncPointCHROMIUM ValueType;
+ static const CommandId kCmdId = kInsertSyncPointCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ CommandHeader header;
+};
+
+#pragma pack(pop)
+
+} // namespace cmd
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_H_
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/chromium/gpu/command_buffer/common/gles2_cmd_format_autogen.h
new file mode 100644
index 00000000000..11b990145d2
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -0,0 +1,11102 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
+
+struct ActiveTexture {
+ typedef ActiveTexture ValueType;
+ static const CommandId kCmdId = kActiveTexture;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _texture) {
+ SetHeader();
+ texture = _texture;
+ }
+
+ void* Set(void* cmd, GLenum _texture) {
+ static_cast<ValueType*>(cmd)->Init(_texture);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 texture;
+};
+
+COMPILE_ASSERT(sizeof(ActiveTexture) == 8,
+ Sizeof_ActiveTexture_is_not_8);
+COMPILE_ASSERT(offsetof(ActiveTexture, header) == 0,
+ OffsetOf_ActiveTexture_header_not_0);
+COMPILE_ASSERT(offsetof(ActiveTexture, texture) == 4,
+ OffsetOf_ActiveTexture_texture_not_4);
+
+struct AttachShader {
+ typedef AttachShader ValueType;
+ static const CommandId kCmdId = kAttachShader;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, GLuint _shader) {
+ SetHeader();
+ program = _program;
+ shader = _shader;
+ }
+
+ void* Set(void* cmd, GLuint _program, GLuint _shader) {
+ static_cast<ValueType*>(cmd)->Init(_program, _shader);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 shader;
+};
+
+COMPILE_ASSERT(sizeof(AttachShader) == 12,
+ Sizeof_AttachShader_is_not_12);
+COMPILE_ASSERT(offsetof(AttachShader, header) == 0,
+ OffsetOf_AttachShader_header_not_0);
+COMPILE_ASSERT(offsetof(AttachShader, program) == 4,
+ OffsetOf_AttachShader_program_not_4);
+COMPILE_ASSERT(offsetof(AttachShader, shader) == 8,
+ OffsetOf_AttachShader_shader_not_8);
+
+struct BindAttribLocation {
+ typedef BindAttribLocation ValueType;
+ static const CommandId kCmdId = kBindAttribLocation;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLuint _index, uint32 _name_shm_id,
+ uint32 _name_shm_offset, uint32 _data_size) {
+ SetHeader();
+ program = _program;
+ index = _index;
+ name_shm_id = _name_shm_id;
+ name_shm_offset = _name_shm_offset;
+ data_size = _data_size;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLuint _index, uint32 _name_shm_id,
+ uint32 _name_shm_offset, uint32 _data_size) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _index, _name_shm_id, _name_shm_offset, _data_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 index;
+ uint32 name_shm_id;
+ uint32 name_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(BindAttribLocation) == 24,
+ Sizeof_BindAttribLocation_is_not_24);
+COMPILE_ASSERT(offsetof(BindAttribLocation, header) == 0,
+ OffsetOf_BindAttribLocation_header_not_0);
+COMPILE_ASSERT(offsetof(BindAttribLocation, program) == 4,
+ OffsetOf_BindAttribLocation_program_not_4);
+COMPILE_ASSERT(offsetof(BindAttribLocation, index) == 8,
+ OffsetOf_BindAttribLocation_index_not_8);
+COMPILE_ASSERT(offsetof(BindAttribLocation, name_shm_id) == 12,
+ OffsetOf_BindAttribLocation_name_shm_id_not_12);
+COMPILE_ASSERT(offsetof(BindAttribLocation, name_shm_offset) == 16,
+ OffsetOf_BindAttribLocation_name_shm_offset_not_16);
+COMPILE_ASSERT(offsetof(BindAttribLocation, data_size) == 20,
+ OffsetOf_BindAttribLocation_data_size_not_20);
+
+struct BindAttribLocationImmediate {
+ typedef BindAttribLocationImmediate ValueType;
+ static const CommandId kCmdId = kBindAttribLocationImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 data_size) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + data_size); // NOLINT
+ }
+
+ void SetHeader(uint32 data_size) {
+ header.SetCmdBySize<ValueType>(data_size);
+ }
+
+ void Init(
+ GLuint _program, GLuint _index, const char* _name, uint32 _data_size) {
+ SetHeader(_data_size);
+ program = _program;
+ index = _index;
+ data_size = _data_size;
+ memcpy(ImmediateDataAddress(this), _name, _data_size);
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLuint _index, const char* _name,
+ uint32 _data_size) {
+ static_cast<ValueType*>(cmd)->Init(_program, _index, _name, _data_size);
+ return NextImmediateCmdAddress<ValueType>(cmd, _data_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 index;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(BindAttribLocationImmediate) == 16,
+ Sizeof_BindAttribLocationImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(BindAttribLocationImmediate, header) == 0,
+ OffsetOf_BindAttribLocationImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(BindAttribLocationImmediate, program) == 4,
+ OffsetOf_BindAttribLocationImmediate_program_not_4);
+COMPILE_ASSERT(offsetof(BindAttribLocationImmediate, index) == 8,
+ OffsetOf_BindAttribLocationImmediate_index_not_8);
+COMPILE_ASSERT(offsetof(BindAttribLocationImmediate, data_size) == 12,
+ OffsetOf_BindAttribLocationImmediate_data_size_not_12);
+
+struct BindAttribLocationBucket {
+ typedef BindAttribLocationBucket ValueType;
+ static const CommandId kCmdId = kBindAttribLocationBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, GLuint _index, uint32 _name_bucket_id) {
+ SetHeader();
+ program = _program;
+ index = _index;
+ name_bucket_id = _name_bucket_id;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLuint _index, uint32 _name_bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_program, _index, _name_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 index;
+ uint32 name_bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(BindAttribLocationBucket) == 16,
+ Sizeof_BindAttribLocationBucket_is_not_16);
+COMPILE_ASSERT(offsetof(BindAttribLocationBucket, header) == 0,
+ OffsetOf_BindAttribLocationBucket_header_not_0);
+COMPILE_ASSERT(offsetof(BindAttribLocationBucket, program) == 4,
+ OffsetOf_BindAttribLocationBucket_program_not_4);
+COMPILE_ASSERT(offsetof(BindAttribLocationBucket, index) == 8,
+ OffsetOf_BindAttribLocationBucket_index_not_8);
+COMPILE_ASSERT(offsetof(BindAttribLocationBucket, name_bucket_id) == 12,
+ OffsetOf_BindAttribLocationBucket_name_bucket_id_not_12);
+
+struct BindBuffer {
+ typedef BindBuffer ValueType;
+ static const CommandId kCmdId = kBindBuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLuint _buffer) {
+ SetHeader();
+ target = _target;
+ buffer = _buffer;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLuint _buffer) {
+ static_cast<ValueType*>(cmd)->Init(_target, _buffer);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 buffer;
+};
+
+COMPILE_ASSERT(sizeof(BindBuffer) == 12,
+ Sizeof_BindBuffer_is_not_12);
+COMPILE_ASSERT(offsetof(BindBuffer, header) == 0,
+ OffsetOf_BindBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(BindBuffer, target) == 4,
+ OffsetOf_BindBuffer_target_not_4);
+COMPILE_ASSERT(offsetof(BindBuffer, buffer) == 8,
+ OffsetOf_BindBuffer_buffer_not_8);
+
+struct BindFramebuffer {
+ typedef BindFramebuffer ValueType;
+ static const CommandId kCmdId = kBindFramebuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLuint _framebuffer) {
+ SetHeader();
+ target = _target;
+ framebuffer = _framebuffer;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLuint _framebuffer) {
+ static_cast<ValueType*>(cmd)->Init(_target, _framebuffer);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 framebuffer;
+};
+
+COMPILE_ASSERT(sizeof(BindFramebuffer) == 12,
+ Sizeof_BindFramebuffer_is_not_12);
+COMPILE_ASSERT(offsetof(BindFramebuffer, header) == 0,
+ OffsetOf_BindFramebuffer_header_not_0);
+COMPILE_ASSERT(offsetof(BindFramebuffer, target) == 4,
+ OffsetOf_BindFramebuffer_target_not_4);
+COMPILE_ASSERT(offsetof(BindFramebuffer, framebuffer) == 8,
+ OffsetOf_BindFramebuffer_framebuffer_not_8);
+
+struct BindRenderbuffer {
+ typedef BindRenderbuffer ValueType;
+ static const CommandId kCmdId = kBindRenderbuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLuint _renderbuffer) {
+ SetHeader();
+ target = _target;
+ renderbuffer = _renderbuffer;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLuint _renderbuffer) {
+ static_cast<ValueType*>(cmd)->Init(_target, _renderbuffer);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 renderbuffer;
+};
+
+COMPILE_ASSERT(sizeof(BindRenderbuffer) == 12,
+ Sizeof_BindRenderbuffer_is_not_12);
+COMPILE_ASSERT(offsetof(BindRenderbuffer, header) == 0,
+ OffsetOf_BindRenderbuffer_header_not_0);
+COMPILE_ASSERT(offsetof(BindRenderbuffer, target) == 4,
+ OffsetOf_BindRenderbuffer_target_not_4);
+COMPILE_ASSERT(offsetof(BindRenderbuffer, renderbuffer) == 8,
+ OffsetOf_BindRenderbuffer_renderbuffer_not_8);
+
+struct BindTexture {
+ typedef BindTexture ValueType;
+ static const CommandId kCmdId = kBindTexture;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLuint _texture) {
+ SetHeader();
+ target = _target;
+ texture = _texture;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLuint _texture) {
+ static_cast<ValueType*>(cmd)->Init(_target, _texture);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 texture;
+};
+
+COMPILE_ASSERT(sizeof(BindTexture) == 12,
+ Sizeof_BindTexture_is_not_12);
+COMPILE_ASSERT(offsetof(BindTexture, header) == 0,
+ OffsetOf_BindTexture_header_not_0);
+COMPILE_ASSERT(offsetof(BindTexture, target) == 4,
+ OffsetOf_BindTexture_target_not_4);
+COMPILE_ASSERT(offsetof(BindTexture, texture) == 8,
+ OffsetOf_BindTexture_texture_not_8);
+
+struct BlendColor {
+ typedef BlendColor ValueType;
+ static const CommandId kCmdId = kBlendColor;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLclampf _red, GLclampf _green, GLclampf _blue, GLclampf _alpha) {
+ SetHeader();
+ red = _red;
+ green = _green;
+ blue = _blue;
+ alpha = _alpha;
+ }
+
+ void* Set(
+ void* cmd, GLclampf _red, GLclampf _green, GLclampf _blue,
+ GLclampf _alpha) {
+ static_cast<ValueType*>(cmd)->Init(_red, _green, _blue, _alpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float red;
+ float green;
+ float blue;
+ float alpha;
+};
+
+COMPILE_ASSERT(sizeof(BlendColor) == 20,
+ Sizeof_BlendColor_is_not_20);
+COMPILE_ASSERT(offsetof(BlendColor, header) == 0,
+ OffsetOf_BlendColor_header_not_0);
+COMPILE_ASSERT(offsetof(BlendColor, red) == 4,
+ OffsetOf_BlendColor_red_not_4);
+COMPILE_ASSERT(offsetof(BlendColor, green) == 8,
+ OffsetOf_BlendColor_green_not_8);
+COMPILE_ASSERT(offsetof(BlendColor, blue) == 12,
+ OffsetOf_BlendColor_blue_not_12);
+COMPILE_ASSERT(offsetof(BlendColor, alpha) == 16,
+ OffsetOf_BlendColor_alpha_not_16);
+
+struct BlendEquation {
+ typedef BlendEquation ValueType;
+ static const CommandId kCmdId = kBlendEquation;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _mode) {
+ SetHeader();
+ mode = _mode;
+ }
+
+ void* Set(void* cmd, GLenum _mode) {
+ static_cast<ValueType*>(cmd)->Init(_mode);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+};
+
+COMPILE_ASSERT(sizeof(BlendEquation) == 8,
+ Sizeof_BlendEquation_is_not_8);
+COMPILE_ASSERT(offsetof(BlendEquation, header) == 0,
+ OffsetOf_BlendEquation_header_not_0);
+COMPILE_ASSERT(offsetof(BlendEquation, mode) == 4,
+ OffsetOf_BlendEquation_mode_not_4);
+
+struct BlendEquationSeparate {
+ typedef BlendEquationSeparate ValueType;
+ static const CommandId kCmdId = kBlendEquationSeparate;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _modeRGB, GLenum _modeAlpha) {
+ SetHeader();
+ modeRGB = _modeRGB;
+ modeAlpha = _modeAlpha;
+ }
+
+ void* Set(void* cmd, GLenum _modeRGB, GLenum _modeAlpha) {
+ static_cast<ValueType*>(cmd)->Init(_modeRGB, _modeAlpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 modeRGB;
+ uint32 modeAlpha;
+};
+
+COMPILE_ASSERT(sizeof(BlendEquationSeparate) == 12,
+ Sizeof_BlendEquationSeparate_is_not_12);
+COMPILE_ASSERT(offsetof(BlendEquationSeparate, header) == 0,
+ OffsetOf_BlendEquationSeparate_header_not_0);
+COMPILE_ASSERT(offsetof(BlendEquationSeparate, modeRGB) == 4,
+ OffsetOf_BlendEquationSeparate_modeRGB_not_4);
+COMPILE_ASSERT(offsetof(BlendEquationSeparate, modeAlpha) == 8,
+ OffsetOf_BlendEquationSeparate_modeAlpha_not_8);
+
+struct BlendFunc {
+ typedef BlendFunc ValueType;
+ static const CommandId kCmdId = kBlendFunc;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _sfactor, GLenum _dfactor) {
+ SetHeader();
+ sfactor = _sfactor;
+ dfactor = _dfactor;
+ }
+
+ void* Set(void* cmd, GLenum _sfactor, GLenum _dfactor) {
+ static_cast<ValueType*>(cmd)->Init(_sfactor, _dfactor);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 sfactor;
+ uint32 dfactor;
+};
+
+COMPILE_ASSERT(sizeof(BlendFunc) == 12,
+ Sizeof_BlendFunc_is_not_12);
+COMPILE_ASSERT(offsetof(BlendFunc, header) == 0,
+ OffsetOf_BlendFunc_header_not_0);
+COMPILE_ASSERT(offsetof(BlendFunc, sfactor) == 4,
+ OffsetOf_BlendFunc_sfactor_not_4);
+COMPILE_ASSERT(offsetof(BlendFunc, dfactor) == 8,
+ OffsetOf_BlendFunc_dfactor_not_8);
+
+struct BlendFuncSeparate {
+ typedef BlendFuncSeparate ValueType;
+ static const CommandId kCmdId = kBlendFuncSeparate;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _srcRGB, GLenum _dstRGB, GLenum _srcAlpha, GLenum _dstAlpha) {
+ SetHeader();
+ srcRGB = _srcRGB;
+ dstRGB = _dstRGB;
+ srcAlpha = _srcAlpha;
+ dstAlpha = _dstAlpha;
+ }
+
+ void* Set(
+ void* cmd, GLenum _srcRGB, GLenum _dstRGB, GLenum _srcAlpha,
+ GLenum _dstAlpha) {
+ static_cast<ValueType*>(cmd)->Init(_srcRGB, _dstRGB, _srcAlpha, _dstAlpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 srcRGB;
+ uint32 dstRGB;
+ uint32 srcAlpha;
+ uint32 dstAlpha;
+};
+
+COMPILE_ASSERT(sizeof(BlendFuncSeparate) == 20,
+ Sizeof_BlendFuncSeparate_is_not_20);
+COMPILE_ASSERT(offsetof(BlendFuncSeparate, header) == 0,
+ OffsetOf_BlendFuncSeparate_header_not_0);
+COMPILE_ASSERT(offsetof(BlendFuncSeparate, srcRGB) == 4,
+ OffsetOf_BlendFuncSeparate_srcRGB_not_4);
+COMPILE_ASSERT(offsetof(BlendFuncSeparate, dstRGB) == 8,
+ OffsetOf_BlendFuncSeparate_dstRGB_not_8);
+COMPILE_ASSERT(offsetof(BlendFuncSeparate, srcAlpha) == 12,
+ OffsetOf_BlendFuncSeparate_srcAlpha_not_12);
+COMPILE_ASSERT(offsetof(BlendFuncSeparate, dstAlpha) == 16,
+ OffsetOf_BlendFuncSeparate_dstAlpha_not_16);
+
+struct BufferData {
+ typedef BufferData ValueType;
+ static const CommandId kCmdId = kBufferData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLsizeiptr _size, uint32 _data_shm_id,
+ uint32 _data_shm_offset, GLenum _usage) {
+ SetHeader();
+ target = _target;
+ size = _size;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ usage = _usage;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLsizeiptr _size, uint32 _data_shm_id,
+ uint32 _data_shm_offset, GLenum _usage) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _size, _data_shm_id, _data_shm_offset, _usage);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 size;
+ uint32 data_shm_id;
+ uint32 data_shm_offset;
+ uint32 usage;
+};
+
+COMPILE_ASSERT(sizeof(BufferData) == 24,
+ Sizeof_BufferData_is_not_24);
+COMPILE_ASSERT(offsetof(BufferData, header) == 0,
+ OffsetOf_BufferData_header_not_0);
+COMPILE_ASSERT(offsetof(BufferData, target) == 4,
+ OffsetOf_BufferData_target_not_4);
+COMPILE_ASSERT(offsetof(BufferData, size) == 8,
+ OffsetOf_BufferData_size_not_8);
+COMPILE_ASSERT(offsetof(BufferData, data_shm_id) == 12,
+ OffsetOf_BufferData_data_shm_id_not_12);
+COMPILE_ASSERT(offsetof(BufferData, data_shm_offset) == 16,
+ OffsetOf_BufferData_data_shm_offset_not_16);
+COMPILE_ASSERT(offsetof(BufferData, usage) == 20,
+ OffsetOf_BufferData_usage_not_20);
+
+struct BufferDataImmediate {
+ typedef BufferDataImmediate ValueType;
+ static const CommandId kCmdId = kBufferDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(GLenum _target, GLsizeiptr _size, GLenum _usage) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ SetHeader(total_size);
+ target = _target;
+ size = _size;
+ usage = _usage;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLsizeiptr _size, GLenum _usage) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ static_cast<ValueType*>(cmd)->Init(_target, _size, _usage);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 size;
+ uint32 usage;
+};
+
+COMPILE_ASSERT(sizeof(BufferDataImmediate) == 16,
+ Sizeof_BufferDataImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(BufferDataImmediate, header) == 0,
+ OffsetOf_BufferDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(BufferDataImmediate, target) == 4,
+ OffsetOf_BufferDataImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(BufferDataImmediate, size) == 8,
+ OffsetOf_BufferDataImmediate_size_not_8);
+COMPILE_ASSERT(offsetof(BufferDataImmediate, usage) == 12,
+ OffsetOf_BufferDataImmediate_usage_not_12);
+
+struct BufferSubData {
+ typedef BufferSubData ValueType;
+ static const CommandId kCmdId = kBufferSubData;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLintptr _offset, GLsizeiptr _size, uint32 _data_shm_id,
+ uint32 _data_shm_offset) {
+ SetHeader();
+ target = _target;
+ offset = _offset;
+ size = _size;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLintptr _offset, GLsizeiptr _size,
+ uint32 _data_shm_id, uint32 _data_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _offset, _size, _data_shm_id, _data_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 offset;
+ int32 size;
+ uint32 data_shm_id;
+ uint32 data_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(BufferSubData) == 24,
+ Sizeof_BufferSubData_is_not_24);
+COMPILE_ASSERT(offsetof(BufferSubData, header) == 0,
+ OffsetOf_BufferSubData_header_not_0);
+COMPILE_ASSERT(offsetof(BufferSubData, target) == 4,
+ OffsetOf_BufferSubData_target_not_4);
+COMPILE_ASSERT(offsetof(BufferSubData, offset) == 8,
+ OffsetOf_BufferSubData_offset_not_8);
+COMPILE_ASSERT(offsetof(BufferSubData, size) == 12,
+ OffsetOf_BufferSubData_size_not_12);
+COMPILE_ASSERT(offsetof(BufferSubData, data_shm_id) == 16,
+ OffsetOf_BufferSubData_data_shm_id_not_16);
+COMPILE_ASSERT(offsetof(BufferSubData, data_shm_offset) == 20,
+ OffsetOf_BufferSubData_data_shm_offset_not_20);
+
+struct BufferSubDataImmediate {
+ typedef BufferSubDataImmediate ValueType;
+ static const CommandId kCmdId = kBufferSubDataImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(GLenum _target, GLintptr _offset, GLsizeiptr _size) {
+ uint32 total_size = ComputeSize(_size);
+ SetHeader(total_size);
+ target = _target;
+ offset = _offset;
+ size = _size;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLintptr _offset, GLsizeiptr _size) {
+ uint32 total_size = ComputeSize(_size);
+ static_cast<ValueType*>(cmd)->Init(_target, _offset, _size);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 offset;
+ int32 size;
+};
+
+COMPILE_ASSERT(sizeof(BufferSubDataImmediate) == 16,
+ Sizeof_BufferSubDataImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(BufferSubDataImmediate, header) == 0,
+ OffsetOf_BufferSubDataImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(BufferSubDataImmediate, target) == 4,
+ OffsetOf_BufferSubDataImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(BufferSubDataImmediate, offset) == 8,
+ OffsetOf_BufferSubDataImmediate_offset_not_8);
+COMPILE_ASSERT(offsetof(BufferSubDataImmediate, size) == 12,
+ OffsetOf_BufferSubDataImmediate_size_not_12);
+
+struct CheckFramebufferStatus {
+ typedef CheckFramebufferStatus ValueType;
+ static const CommandId kCmdId = kCheckFramebufferStatus;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLenum Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ target = _target;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(CheckFramebufferStatus) == 16,
+ Sizeof_CheckFramebufferStatus_is_not_16);
+COMPILE_ASSERT(offsetof(CheckFramebufferStatus, header) == 0,
+ OffsetOf_CheckFramebufferStatus_header_not_0);
+COMPILE_ASSERT(offsetof(CheckFramebufferStatus, target) == 4,
+ OffsetOf_CheckFramebufferStatus_target_not_4);
+COMPILE_ASSERT(offsetof(CheckFramebufferStatus, result_shm_id) == 8,
+ OffsetOf_CheckFramebufferStatus_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(CheckFramebufferStatus, result_shm_offset) == 12,
+ OffsetOf_CheckFramebufferStatus_result_shm_offset_not_12);
+
+struct Clear {
+ typedef Clear ValueType;
+ static const CommandId kCmdId = kClear;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLbitfield _mask) {
+ SetHeader();
+ mask = _mask;
+ }
+
+ void* Set(void* cmd, GLbitfield _mask) {
+ static_cast<ValueType*>(cmd)->Init(_mask);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mask;
+};
+
+COMPILE_ASSERT(sizeof(Clear) == 8,
+ Sizeof_Clear_is_not_8);
+COMPILE_ASSERT(offsetof(Clear, header) == 0,
+ OffsetOf_Clear_header_not_0);
+COMPILE_ASSERT(offsetof(Clear, mask) == 4,
+ OffsetOf_Clear_mask_not_4);
+
+struct ClearColor {
+ typedef ClearColor ValueType;
+ static const CommandId kCmdId = kClearColor;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLclampf _red, GLclampf _green, GLclampf _blue, GLclampf _alpha) {
+ SetHeader();
+ red = _red;
+ green = _green;
+ blue = _blue;
+ alpha = _alpha;
+ }
+
+ void* Set(
+ void* cmd, GLclampf _red, GLclampf _green, GLclampf _blue,
+ GLclampf _alpha) {
+ static_cast<ValueType*>(cmd)->Init(_red, _green, _blue, _alpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float red;
+ float green;
+ float blue;
+ float alpha;
+};
+
+COMPILE_ASSERT(sizeof(ClearColor) == 20,
+ Sizeof_ClearColor_is_not_20);
+COMPILE_ASSERT(offsetof(ClearColor, header) == 0,
+ OffsetOf_ClearColor_header_not_0);
+COMPILE_ASSERT(offsetof(ClearColor, red) == 4,
+ OffsetOf_ClearColor_red_not_4);
+COMPILE_ASSERT(offsetof(ClearColor, green) == 8,
+ OffsetOf_ClearColor_green_not_8);
+COMPILE_ASSERT(offsetof(ClearColor, blue) == 12,
+ OffsetOf_ClearColor_blue_not_12);
+COMPILE_ASSERT(offsetof(ClearColor, alpha) == 16,
+ OffsetOf_ClearColor_alpha_not_16);
+
+struct ClearDepthf {
+ typedef ClearDepthf ValueType;
+ static const CommandId kCmdId = kClearDepthf;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLclampf _depth) {
+ SetHeader();
+ depth = _depth;
+ }
+
+ void* Set(void* cmd, GLclampf _depth) {
+ static_cast<ValueType*>(cmd)->Init(_depth);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float depth;
+};
+
+COMPILE_ASSERT(sizeof(ClearDepthf) == 8,
+ Sizeof_ClearDepthf_is_not_8);
+COMPILE_ASSERT(offsetof(ClearDepthf, header) == 0,
+ OffsetOf_ClearDepthf_header_not_0);
+COMPILE_ASSERT(offsetof(ClearDepthf, depth) == 4,
+ OffsetOf_ClearDepthf_depth_not_4);
+
+struct ClearStencil {
+ typedef ClearStencil ValueType;
+ static const CommandId kCmdId = kClearStencil;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _s) {
+ SetHeader();
+ s = _s;
+ }
+
+ void* Set(void* cmd, GLint _s) {
+ static_cast<ValueType*>(cmd)->Init(_s);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 s;
+};
+
+COMPILE_ASSERT(sizeof(ClearStencil) == 8,
+ Sizeof_ClearStencil_is_not_8);
+COMPILE_ASSERT(offsetof(ClearStencil, header) == 0,
+ OffsetOf_ClearStencil_header_not_0);
+COMPILE_ASSERT(offsetof(ClearStencil, s) == 4,
+ OffsetOf_ClearStencil_s_not_4);
+
+struct ColorMask {
+ typedef ColorMask ValueType;
+ static const CommandId kCmdId = kColorMask;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLboolean _red, GLboolean _green, GLboolean _blue, GLboolean _alpha) {
+ SetHeader();
+ red = _red;
+ green = _green;
+ blue = _blue;
+ alpha = _alpha;
+ }
+
+ void* Set(
+ void* cmd, GLboolean _red, GLboolean _green, GLboolean _blue,
+ GLboolean _alpha) {
+ static_cast<ValueType*>(cmd)->Init(_red, _green, _blue, _alpha);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 red;
+ uint32 green;
+ uint32 blue;
+ uint32 alpha;
+};
+
+COMPILE_ASSERT(sizeof(ColorMask) == 20,
+ Sizeof_ColorMask_is_not_20);
+COMPILE_ASSERT(offsetof(ColorMask, header) == 0,
+ OffsetOf_ColorMask_header_not_0);
+COMPILE_ASSERT(offsetof(ColorMask, red) == 4,
+ OffsetOf_ColorMask_red_not_4);
+COMPILE_ASSERT(offsetof(ColorMask, green) == 8,
+ OffsetOf_ColorMask_green_not_8);
+COMPILE_ASSERT(offsetof(ColorMask, blue) == 12,
+ OffsetOf_ColorMask_blue_not_12);
+COMPILE_ASSERT(offsetof(ColorMask, alpha) == 16,
+ OffsetOf_ColorMask_alpha_not_16);
+
+struct CompileShader {
+ typedef CompileShader ValueType;
+ static const CommandId kCmdId = kCompileShader;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader) {
+ SetHeader();
+ shader = _shader;
+ }
+
+ void* Set(void* cmd, GLuint _shader) {
+ static_cast<ValueType*>(cmd)->Init(_shader);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+};
+
+COMPILE_ASSERT(sizeof(CompileShader) == 8,
+ Sizeof_CompileShader_is_not_8);
+COMPILE_ASSERT(offsetof(CompileShader, header) == 0,
+ OffsetOf_CompileShader_header_not_0);
+COMPILE_ASSERT(offsetof(CompileShader, shader) == 4,
+ OffsetOf_CompileShader_shader_not_4);
+
+struct CompressedTexImage2D {
+ typedef CompressedTexImage2D ValueType;
+ static const CommandId kCmdId = kCompressedTexImage2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLenum _internalformat, GLsizei _width,
+ GLsizei _height, GLint _border, GLsizei _imageSize, uint32 _data_shm_id,
+ uint32 _data_shm_offset) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ border = _border;
+ imageSize = _imageSize;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLenum _internalformat,
+ GLsizei _width, GLsizei _height, GLint _border, GLsizei _imageSize,
+ uint32 _data_shm_id, uint32 _data_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _width, _height, _border,
+ _imageSize, _data_shm_id, _data_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ uint32 internalformat;
+ int32 width;
+ int32 height;
+ int32 border;
+ int32 imageSize;
+ uint32 data_shm_id;
+ uint32 data_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(CompressedTexImage2D) == 40,
+ Sizeof_CompressedTexImage2D_is_not_40);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, header) == 0,
+ OffsetOf_CompressedTexImage2D_header_not_0);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, target) == 4,
+ OffsetOf_CompressedTexImage2D_target_not_4);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, level) == 8,
+ OffsetOf_CompressedTexImage2D_level_not_8);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, internalformat) == 12,
+ OffsetOf_CompressedTexImage2D_internalformat_not_12);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, width) == 16,
+ OffsetOf_CompressedTexImage2D_width_not_16);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, height) == 20,
+ OffsetOf_CompressedTexImage2D_height_not_20);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, border) == 24,
+ OffsetOf_CompressedTexImage2D_border_not_24);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, imageSize) == 28,
+ OffsetOf_CompressedTexImage2D_imageSize_not_28);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, data_shm_id) == 32,
+ OffsetOf_CompressedTexImage2D_data_shm_id_not_32);
+COMPILE_ASSERT(offsetof(CompressedTexImage2D, data_shm_offset) == 36,
+ OffsetOf_CompressedTexImage2D_data_shm_offset_not_36);
+
+struct CompressedTexImage2DImmediate {
+ typedef CompressedTexImage2DImmediate ValueType;
+ static const CommandId kCmdId = kCompressedTexImage2DImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLenum _internalformat, GLsizei _width,
+ GLsizei _height, GLint _border, GLsizei _imageSize) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ SetHeader(total_size);
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ border = _border;
+ imageSize = _imageSize;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLenum _internalformat,
+ GLsizei _width, GLsizei _height, GLint _border, GLsizei _imageSize) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _width, _height, _border,
+ _imageSize);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ uint32 internalformat;
+ int32 width;
+ int32 height;
+ int32 border;
+ int32 imageSize;
+};
+
+COMPILE_ASSERT(sizeof(CompressedTexImage2DImmediate) == 32,
+ Sizeof_CompressedTexImage2DImmediate_is_not_32);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, header) == 0,
+ OffsetOf_CompressedTexImage2DImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, target) == 4,
+ OffsetOf_CompressedTexImage2DImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, level) == 8,
+ OffsetOf_CompressedTexImage2DImmediate_level_not_8);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, internalformat) == 12,
+ OffsetOf_CompressedTexImage2DImmediate_internalformat_not_12);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, width) == 16,
+ OffsetOf_CompressedTexImage2DImmediate_width_not_16);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, height) == 20,
+ OffsetOf_CompressedTexImage2DImmediate_height_not_20);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, border) == 24,
+ OffsetOf_CompressedTexImage2DImmediate_border_not_24);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DImmediate, imageSize) == 28,
+ OffsetOf_CompressedTexImage2DImmediate_imageSize_not_28);
+
+struct CompressedTexImage2DBucket {
+ typedef CompressedTexImage2DBucket ValueType;
+ static const CommandId kCmdId = kCompressedTexImage2DBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLenum _internalformat, GLsizei _width,
+ GLsizei _height, GLint _border, GLuint _bucket_id) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ border = _border;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLenum _internalformat,
+ GLsizei _width, GLsizei _height, GLint _border, GLuint _bucket_id) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _width, _height, _border,
+ _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ uint32 internalformat;
+ int32 width;
+ int32 height;
+ int32 border;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(CompressedTexImage2DBucket) == 32,
+ Sizeof_CompressedTexImage2DBucket_is_not_32);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, header) == 0,
+ OffsetOf_CompressedTexImage2DBucket_header_not_0);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, target) == 4,
+ OffsetOf_CompressedTexImage2DBucket_target_not_4);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, level) == 8,
+ OffsetOf_CompressedTexImage2DBucket_level_not_8);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, internalformat) == 12,
+ OffsetOf_CompressedTexImage2DBucket_internalformat_not_12);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, width) == 16,
+ OffsetOf_CompressedTexImage2DBucket_width_not_16);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, height) == 20,
+ OffsetOf_CompressedTexImage2DBucket_height_not_20);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, border) == 24,
+ OffsetOf_CompressedTexImage2DBucket_border_not_24);
+COMPILE_ASSERT(offsetof(CompressedTexImage2DBucket, bucket_id) == 28,
+ OffsetOf_CompressedTexImage2DBucket_bucket_id_not_28);
+
+struct CompressedTexSubImage2D {
+ typedef CompressedTexSubImage2D ValueType;
+ static const CommandId kCmdId = kCompressedTexSubImage2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLsizei _imageSize,
+ uint32 _data_shm_id, uint32 _data_shm_offset) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ width = _width;
+ height = _height;
+ format = _format;
+ imageSize = _imageSize;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLsizei _imageSize,
+ uint32 _data_shm_id, uint32 _data_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _width, _height, _format,
+ _imageSize, _data_shm_id, _data_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 width;
+ int32 height;
+ uint32 format;
+ int32 imageSize;
+ uint32 data_shm_id;
+ uint32 data_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(CompressedTexSubImage2D) == 44,
+ Sizeof_CompressedTexSubImage2D_is_not_44);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, header) == 0,
+ OffsetOf_CompressedTexSubImage2D_header_not_0);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, target) == 4,
+ OffsetOf_CompressedTexSubImage2D_target_not_4);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, level) == 8,
+ OffsetOf_CompressedTexSubImage2D_level_not_8);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, xoffset) == 12,
+ OffsetOf_CompressedTexSubImage2D_xoffset_not_12);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, yoffset) == 16,
+ OffsetOf_CompressedTexSubImage2D_yoffset_not_16);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, width) == 20,
+ OffsetOf_CompressedTexSubImage2D_width_not_20);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, height) == 24,
+ OffsetOf_CompressedTexSubImage2D_height_not_24);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, format) == 28,
+ OffsetOf_CompressedTexSubImage2D_format_not_28);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, imageSize) == 32,
+ OffsetOf_CompressedTexSubImage2D_imageSize_not_32);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, data_shm_id) == 36,
+ OffsetOf_CompressedTexSubImage2D_data_shm_id_not_36);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2D, data_shm_offset) == 40,
+ OffsetOf_CompressedTexSubImage2D_data_shm_offset_not_40);
+
+struct CompressedTexSubImage2DImmediate {
+ typedef CompressedTexSubImage2DImmediate ValueType;
+ static const CommandId kCmdId = kCompressedTexSubImage2DImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLsizei _imageSize) {
+ uint32 total_size = ComputeSize(_imageSize);
+ SetHeader(total_size);
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ width = _width;
+ height = _height;
+ format = _format;
+ imageSize = _imageSize;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLsizei _imageSize) {
+ uint32 total_size = ComputeSize(_imageSize);
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _width, _height, _format,
+ _imageSize);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 width;
+ int32 height;
+ uint32 format;
+ int32 imageSize;
+};
+
+COMPILE_ASSERT(sizeof(CompressedTexSubImage2DImmediate) == 36,
+ Sizeof_CompressedTexSubImage2DImmediate_is_not_36);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, header) == 0,
+ OffsetOf_CompressedTexSubImage2DImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, target) == 4,
+ OffsetOf_CompressedTexSubImage2DImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, level) == 8,
+ OffsetOf_CompressedTexSubImage2DImmediate_level_not_8);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, xoffset) == 12,
+ OffsetOf_CompressedTexSubImage2DImmediate_xoffset_not_12);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, yoffset) == 16,
+ OffsetOf_CompressedTexSubImage2DImmediate_yoffset_not_16);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, width) == 20,
+ OffsetOf_CompressedTexSubImage2DImmediate_width_not_20);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, height) == 24,
+ OffsetOf_CompressedTexSubImage2DImmediate_height_not_24);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, format) == 28,
+ OffsetOf_CompressedTexSubImage2DImmediate_format_not_28);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DImmediate, imageSize) == 32,
+ OffsetOf_CompressedTexSubImage2DImmediate_imageSize_not_32);
+
+struct CompressedTexSubImage2DBucket {
+ typedef CompressedTexSubImage2DBucket ValueType;
+ static const CommandId kCmdId = kCompressedTexSubImage2DBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLuint _bucket_id) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ width = _width;
+ height = _height;
+ format = _format;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLuint _bucket_id) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _width, _height, _format,
+ _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 width;
+ int32 height;
+ uint32 format;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(CompressedTexSubImage2DBucket) == 36,
+ Sizeof_CompressedTexSubImage2DBucket_is_not_36);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, header) == 0,
+ OffsetOf_CompressedTexSubImage2DBucket_header_not_0);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, target) == 4,
+ OffsetOf_CompressedTexSubImage2DBucket_target_not_4);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, level) == 8,
+ OffsetOf_CompressedTexSubImage2DBucket_level_not_8);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, xoffset) == 12,
+ OffsetOf_CompressedTexSubImage2DBucket_xoffset_not_12);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, yoffset) == 16,
+ OffsetOf_CompressedTexSubImage2DBucket_yoffset_not_16);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, width) == 20,
+ OffsetOf_CompressedTexSubImage2DBucket_width_not_20);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, height) == 24,
+ OffsetOf_CompressedTexSubImage2DBucket_height_not_24);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, format) == 28,
+ OffsetOf_CompressedTexSubImage2DBucket_format_not_28);
+COMPILE_ASSERT(offsetof(CompressedTexSubImage2DBucket, bucket_id) == 32,
+ OffsetOf_CompressedTexSubImage2DBucket_bucket_id_not_32);
+
+struct CopyTexImage2D {
+ typedef CopyTexImage2D ValueType;
+ static const CommandId kCmdId = kCopyTexImage2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLenum _internalformat, GLint _x, GLint _y,
+ GLsizei _width, GLsizei _height, GLint _border) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ x = _x;
+ y = _y;
+ width = _width;
+ height = _height;
+ border = _border;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLenum _internalformat, GLint _x,
+ GLint _y, GLsizei _width, GLsizei _height, GLint _border) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _x, _y, _width, _height,
+ _border);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ uint32 internalformat;
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+ int32 border;
+};
+
+COMPILE_ASSERT(sizeof(CopyTexImage2D) == 36,
+ Sizeof_CopyTexImage2D_is_not_36);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, header) == 0,
+ OffsetOf_CopyTexImage2D_header_not_0);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, target) == 4,
+ OffsetOf_CopyTexImage2D_target_not_4);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, level) == 8,
+ OffsetOf_CopyTexImage2D_level_not_8);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, internalformat) == 12,
+ OffsetOf_CopyTexImage2D_internalformat_not_12);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, x) == 16,
+ OffsetOf_CopyTexImage2D_x_not_16);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, y) == 20,
+ OffsetOf_CopyTexImage2D_y_not_20);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, width) == 24,
+ OffsetOf_CopyTexImage2D_width_not_24);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, height) == 28,
+ OffsetOf_CopyTexImage2D_height_not_28);
+COMPILE_ASSERT(offsetof(CopyTexImage2D, border) == 32,
+ OffsetOf_CopyTexImage2D_border_not_32);
+
+struct CopyTexSubImage2D {
+ typedef CopyTexSubImage2D ValueType;
+ static const CommandId kCmdId = kCopyTexSubImage2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset, GLint _x,
+ GLint _y, GLsizei _width, GLsizei _height) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ x = _x;
+ y = _y;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLint _x, GLint _y, GLsizei _width, GLsizei _height) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _x, _y, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(CopyTexSubImage2D) == 36,
+ Sizeof_CopyTexSubImage2D_is_not_36);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, header) == 0,
+ OffsetOf_CopyTexSubImage2D_header_not_0);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, target) == 4,
+ OffsetOf_CopyTexSubImage2D_target_not_4);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, level) == 8,
+ OffsetOf_CopyTexSubImage2D_level_not_8);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, xoffset) == 12,
+ OffsetOf_CopyTexSubImage2D_xoffset_not_12);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, yoffset) == 16,
+ OffsetOf_CopyTexSubImage2D_yoffset_not_16);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, x) == 20,
+ OffsetOf_CopyTexSubImage2D_x_not_20);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, y) == 24,
+ OffsetOf_CopyTexSubImage2D_y_not_24);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, width) == 28,
+ OffsetOf_CopyTexSubImage2D_width_not_28);
+COMPILE_ASSERT(offsetof(CopyTexSubImage2D, height) == 32,
+ OffsetOf_CopyTexSubImage2D_height_not_32);
+
+struct CreateProgram {
+ typedef CreateProgram ValueType;
+ static const CommandId kCmdId = kCreateProgram;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _client_id) {
+ SetHeader();
+ client_id = _client_id;
+ }
+
+ void* Set(void* cmd, uint32 _client_id) {
+ static_cast<ValueType*>(cmd)->Init(_client_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 client_id;
+};
+
+COMPILE_ASSERT(sizeof(CreateProgram) == 8,
+ Sizeof_CreateProgram_is_not_8);
+COMPILE_ASSERT(offsetof(CreateProgram, header) == 0,
+ OffsetOf_CreateProgram_header_not_0);
+COMPILE_ASSERT(offsetof(CreateProgram, client_id) == 4,
+ OffsetOf_CreateProgram_client_id_not_4);
+
+struct CreateShader {
+ typedef CreateShader ValueType;
+ static const CommandId kCmdId = kCreateShader;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _type, uint32 _client_id) {
+ SetHeader();
+ type = _type;
+ client_id = _client_id;
+ }
+
+ void* Set(void* cmd, GLenum _type, uint32 _client_id) {
+ static_cast<ValueType*>(cmd)->Init(_type, _client_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 type;
+ uint32 client_id;
+};
+
+COMPILE_ASSERT(sizeof(CreateShader) == 12,
+ Sizeof_CreateShader_is_not_12);
+COMPILE_ASSERT(offsetof(CreateShader, header) == 0,
+ OffsetOf_CreateShader_header_not_0);
+COMPILE_ASSERT(offsetof(CreateShader, type) == 4,
+ OffsetOf_CreateShader_type_not_4);
+COMPILE_ASSERT(offsetof(CreateShader, client_id) == 8,
+ OffsetOf_CreateShader_client_id_not_8);
+
+struct CullFace {
+ typedef CullFace ValueType;
+ static const CommandId kCmdId = kCullFace;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _mode) {
+ SetHeader();
+ mode = _mode;
+ }
+
+ void* Set(void* cmd, GLenum _mode) {
+ static_cast<ValueType*>(cmd)->Init(_mode);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+};
+
+COMPILE_ASSERT(sizeof(CullFace) == 8,
+ Sizeof_CullFace_is_not_8);
+COMPILE_ASSERT(offsetof(CullFace, header) == 0,
+ OffsetOf_CullFace_header_not_0);
+COMPILE_ASSERT(offsetof(CullFace, mode) == 4,
+ OffsetOf_CullFace_mode_not_4);
+
+struct DeleteBuffers {
+ typedef DeleteBuffers ValueType;
+ static const CommandId kCmdId = kDeleteBuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _buffers_shm_id, uint32 _buffers_shm_offset) {
+ SetHeader();
+ n = _n;
+ buffers_shm_id = _buffers_shm_id;
+ buffers_shm_offset = _buffers_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _buffers_shm_id,
+ uint32 _buffers_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _buffers_shm_id, _buffers_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 buffers_shm_id;
+ uint32 buffers_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteBuffers) == 16,
+ Sizeof_DeleteBuffers_is_not_16);
+COMPILE_ASSERT(offsetof(DeleteBuffers, header) == 0,
+ OffsetOf_DeleteBuffers_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteBuffers, n) == 4,
+ OffsetOf_DeleteBuffers_n_not_4);
+COMPILE_ASSERT(offsetof(DeleteBuffers, buffers_shm_id) == 8,
+ OffsetOf_DeleteBuffers_buffers_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteBuffers, buffers_shm_offset) == 12,
+ OffsetOf_DeleteBuffers_buffers_shm_offset_not_12);
+
+struct DeleteBuffersImmediate {
+ typedef DeleteBuffersImmediate ValueType;
+ static const CommandId kCmdId = kDeleteBuffersImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _buffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _buffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _buffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _buffers);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteBuffersImmediate) == 8,
+ Sizeof_DeleteBuffersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteBuffersImmediate, header) == 0,
+ OffsetOf_DeleteBuffersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteBuffersImmediate, n) == 4,
+ OffsetOf_DeleteBuffersImmediate_n_not_4);
+
+struct DeleteFramebuffers {
+ typedef DeleteFramebuffers ValueType;
+ static const CommandId kCmdId = kDeleteFramebuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLsizei _n, uint32 _framebuffers_shm_id,
+ uint32 _framebuffers_shm_offset) {
+ SetHeader();
+ n = _n;
+ framebuffers_shm_id = _framebuffers_shm_id;
+ framebuffers_shm_offset = _framebuffers_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _framebuffers_shm_id,
+ uint32 _framebuffers_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _framebuffers_shm_id, _framebuffers_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 framebuffers_shm_id;
+ uint32 framebuffers_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteFramebuffers) == 16,
+ Sizeof_DeleteFramebuffers_is_not_16);
+COMPILE_ASSERT(offsetof(DeleteFramebuffers, header) == 0,
+ OffsetOf_DeleteFramebuffers_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteFramebuffers, n) == 4,
+ OffsetOf_DeleteFramebuffers_n_not_4);
+COMPILE_ASSERT(offsetof(DeleteFramebuffers, framebuffers_shm_id) == 8,
+ OffsetOf_DeleteFramebuffers_framebuffers_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteFramebuffers, framebuffers_shm_offset) == 12,
+ OffsetOf_DeleteFramebuffers_framebuffers_shm_offset_not_12);
+
+struct DeleteFramebuffersImmediate {
+ typedef DeleteFramebuffersImmediate ValueType;
+ static const CommandId kCmdId = kDeleteFramebuffersImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _framebuffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _framebuffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _framebuffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _framebuffers);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteFramebuffersImmediate) == 8,
+ Sizeof_DeleteFramebuffersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteFramebuffersImmediate, header) == 0,
+ OffsetOf_DeleteFramebuffersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteFramebuffersImmediate, n) == 4,
+ OffsetOf_DeleteFramebuffersImmediate_n_not_4);
+
+struct DeleteProgram {
+ typedef DeleteProgram ValueType;
+ static const CommandId kCmdId = kDeleteProgram;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program) {
+ SetHeader();
+ program = _program;
+ }
+
+ void* Set(void* cmd, GLuint _program) {
+ static_cast<ValueType*>(cmd)->Init(_program);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+};
+
+COMPILE_ASSERT(sizeof(DeleteProgram) == 8,
+ Sizeof_DeleteProgram_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteProgram, header) == 0,
+ OffsetOf_DeleteProgram_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteProgram, program) == 4,
+ OffsetOf_DeleteProgram_program_not_4);
+
+struct DeleteRenderbuffers {
+ typedef DeleteRenderbuffers ValueType;
+ static const CommandId kCmdId = kDeleteRenderbuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLsizei _n, uint32 _renderbuffers_shm_id,
+ uint32 _renderbuffers_shm_offset) {
+ SetHeader();
+ n = _n;
+ renderbuffers_shm_id = _renderbuffers_shm_id;
+ renderbuffers_shm_offset = _renderbuffers_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _renderbuffers_shm_id,
+ uint32 _renderbuffers_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _renderbuffers_shm_id, _renderbuffers_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 renderbuffers_shm_id;
+ uint32 renderbuffers_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteRenderbuffers) == 16,
+ Sizeof_DeleteRenderbuffers_is_not_16);
+COMPILE_ASSERT(offsetof(DeleteRenderbuffers, header) == 0,
+ OffsetOf_DeleteRenderbuffers_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteRenderbuffers, n) == 4,
+ OffsetOf_DeleteRenderbuffers_n_not_4);
+COMPILE_ASSERT(offsetof(DeleteRenderbuffers, renderbuffers_shm_id) == 8,
+ OffsetOf_DeleteRenderbuffers_renderbuffers_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteRenderbuffers, renderbuffers_shm_offset) == 12,
+ OffsetOf_DeleteRenderbuffers_renderbuffers_shm_offset_not_12);
+
+struct DeleteRenderbuffersImmediate {
+ typedef DeleteRenderbuffersImmediate ValueType;
+ static const CommandId kCmdId = kDeleteRenderbuffersImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _renderbuffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _renderbuffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _renderbuffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _renderbuffers);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteRenderbuffersImmediate) == 8,
+ Sizeof_DeleteRenderbuffersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteRenderbuffersImmediate, header) == 0,
+ OffsetOf_DeleteRenderbuffersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteRenderbuffersImmediate, n) == 4,
+ OffsetOf_DeleteRenderbuffersImmediate_n_not_4);
+
+struct DeleteShader {
+ typedef DeleteShader ValueType;
+ static const CommandId kCmdId = kDeleteShader;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader) {
+ SetHeader();
+ shader = _shader;
+ }
+
+ void* Set(void* cmd, GLuint _shader) {
+ static_cast<ValueType*>(cmd)->Init(_shader);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+};
+
+COMPILE_ASSERT(sizeof(DeleteShader) == 8,
+ Sizeof_DeleteShader_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteShader, header) == 0,
+ OffsetOf_DeleteShader_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteShader, shader) == 4,
+ OffsetOf_DeleteShader_shader_not_4);
+
+struct DeleteTextures {
+ typedef DeleteTextures ValueType;
+ static const CommandId kCmdId = kDeleteTextures;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _textures_shm_id, uint32 _textures_shm_offset) {
+ SetHeader();
+ n = _n;
+ textures_shm_id = _textures_shm_id;
+ textures_shm_offset = _textures_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _textures_shm_id,
+ uint32 _textures_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _textures_shm_id, _textures_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 textures_shm_id;
+ uint32 textures_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteTextures) == 16,
+ Sizeof_DeleteTextures_is_not_16);
+COMPILE_ASSERT(offsetof(DeleteTextures, header) == 0,
+ OffsetOf_DeleteTextures_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteTextures, n) == 4,
+ OffsetOf_DeleteTextures_n_not_4);
+COMPILE_ASSERT(offsetof(DeleteTextures, textures_shm_id) == 8,
+ OffsetOf_DeleteTextures_textures_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteTextures, textures_shm_offset) == 12,
+ OffsetOf_DeleteTextures_textures_shm_offset_not_12);
+
+struct DeleteTexturesImmediate {
+ typedef DeleteTexturesImmediate ValueType;
+ static const CommandId kCmdId = kDeleteTexturesImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _textures) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _textures, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _textures) {
+ static_cast<ValueType*>(cmd)->Init(_n, _textures);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteTexturesImmediate) == 8,
+ Sizeof_DeleteTexturesImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteTexturesImmediate, header) == 0,
+ OffsetOf_DeleteTexturesImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteTexturesImmediate, n) == 4,
+ OffsetOf_DeleteTexturesImmediate_n_not_4);
+
+struct DepthFunc {
+ typedef DepthFunc ValueType;
+ static const CommandId kCmdId = kDepthFunc;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _func) {
+ SetHeader();
+ func = _func;
+ }
+
+ void* Set(void* cmd, GLenum _func) {
+ static_cast<ValueType*>(cmd)->Init(_func);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 func;
+};
+
+COMPILE_ASSERT(sizeof(DepthFunc) == 8,
+ Sizeof_DepthFunc_is_not_8);
+COMPILE_ASSERT(offsetof(DepthFunc, header) == 0,
+ OffsetOf_DepthFunc_header_not_0);
+COMPILE_ASSERT(offsetof(DepthFunc, func) == 4,
+ OffsetOf_DepthFunc_func_not_4);
+
+struct DepthMask {
+ typedef DepthMask ValueType;
+ static const CommandId kCmdId = kDepthMask;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLboolean _flag) {
+ SetHeader();
+ flag = _flag;
+ }
+
+ void* Set(void* cmd, GLboolean _flag) {
+ static_cast<ValueType*>(cmd)->Init(_flag);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 flag;
+};
+
+COMPILE_ASSERT(sizeof(DepthMask) == 8,
+ Sizeof_DepthMask_is_not_8);
+COMPILE_ASSERT(offsetof(DepthMask, header) == 0,
+ OffsetOf_DepthMask_header_not_0);
+COMPILE_ASSERT(offsetof(DepthMask, flag) == 4,
+ OffsetOf_DepthMask_flag_not_4);
+
+struct DepthRangef {
+ typedef DepthRangef ValueType;
+ static const CommandId kCmdId = kDepthRangef;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLclampf _zNear, GLclampf _zFar) {
+ SetHeader();
+ zNear = _zNear;
+ zFar = _zFar;
+ }
+
+ void* Set(void* cmd, GLclampf _zNear, GLclampf _zFar) {
+ static_cast<ValueType*>(cmd)->Init(_zNear, _zFar);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float zNear;
+ float zFar;
+};
+
+COMPILE_ASSERT(sizeof(DepthRangef) == 12,
+ Sizeof_DepthRangef_is_not_12);
+COMPILE_ASSERT(offsetof(DepthRangef, header) == 0,
+ OffsetOf_DepthRangef_header_not_0);
+COMPILE_ASSERT(offsetof(DepthRangef, zNear) == 4,
+ OffsetOf_DepthRangef_zNear_not_4);
+COMPILE_ASSERT(offsetof(DepthRangef, zFar) == 8,
+ OffsetOf_DepthRangef_zFar_not_8);
+
+struct DetachShader {
+ typedef DetachShader ValueType;
+ static const CommandId kCmdId = kDetachShader;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, GLuint _shader) {
+ SetHeader();
+ program = _program;
+ shader = _shader;
+ }
+
+ void* Set(void* cmd, GLuint _program, GLuint _shader) {
+ static_cast<ValueType*>(cmd)->Init(_program, _shader);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 shader;
+};
+
+COMPILE_ASSERT(sizeof(DetachShader) == 12,
+ Sizeof_DetachShader_is_not_12);
+COMPILE_ASSERT(offsetof(DetachShader, header) == 0,
+ OffsetOf_DetachShader_header_not_0);
+COMPILE_ASSERT(offsetof(DetachShader, program) == 4,
+ OffsetOf_DetachShader_program_not_4);
+COMPILE_ASSERT(offsetof(DetachShader, shader) == 8,
+ OffsetOf_DetachShader_shader_not_8);
+
+struct Disable {
+ typedef Disable ValueType;
+ static const CommandId kCmdId = kDisable;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _cap) {
+ SetHeader();
+ cap = _cap;
+ }
+
+ void* Set(void* cmd, GLenum _cap) {
+ static_cast<ValueType*>(cmd)->Init(_cap);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 cap;
+};
+
+COMPILE_ASSERT(sizeof(Disable) == 8,
+ Sizeof_Disable_is_not_8);
+COMPILE_ASSERT(offsetof(Disable, header) == 0,
+ OffsetOf_Disable_header_not_0);
+COMPILE_ASSERT(offsetof(Disable, cap) == 4,
+ OffsetOf_Disable_cap_not_4);
+
+struct DisableVertexAttribArray {
+ typedef DisableVertexAttribArray ValueType;
+ static const CommandId kCmdId = kDisableVertexAttribArray;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _index) {
+ SetHeader();
+ index = _index;
+ }
+
+ void* Set(void* cmd, GLuint _index) {
+ static_cast<ValueType*>(cmd)->Init(_index);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 index;
+};
+
+COMPILE_ASSERT(sizeof(DisableVertexAttribArray) == 8,
+ Sizeof_DisableVertexAttribArray_is_not_8);
+COMPILE_ASSERT(offsetof(DisableVertexAttribArray, header) == 0,
+ OffsetOf_DisableVertexAttribArray_header_not_0);
+COMPILE_ASSERT(offsetof(DisableVertexAttribArray, index) == 4,
+ OffsetOf_DisableVertexAttribArray_index_not_4);
+
+struct DrawArrays {
+ typedef DrawArrays ValueType;
+ static const CommandId kCmdId = kDrawArrays;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _mode, GLint _first, GLsizei _count) {
+ SetHeader();
+ mode = _mode;
+ first = _first;
+ count = _count;
+ }
+
+ void* Set(void* cmd, GLenum _mode, GLint _first, GLsizei _count) {
+ static_cast<ValueType*>(cmd)->Init(_mode, _first, _count);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+ int32 first;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(DrawArrays) == 16,
+ Sizeof_DrawArrays_is_not_16);
+COMPILE_ASSERT(offsetof(DrawArrays, header) == 0,
+ OffsetOf_DrawArrays_header_not_0);
+COMPILE_ASSERT(offsetof(DrawArrays, mode) == 4,
+ OffsetOf_DrawArrays_mode_not_4);
+COMPILE_ASSERT(offsetof(DrawArrays, first) == 8,
+ OffsetOf_DrawArrays_first_not_8);
+COMPILE_ASSERT(offsetof(DrawArrays, count) == 12,
+ OffsetOf_DrawArrays_count_not_12);
+
+struct DrawElements {
+ typedef DrawElements ValueType;
+ static const CommandId kCmdId = kDrawElements;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _mode, GLsizei _count, GLenum _type, GLuint _index_offset) {
+ SetHeader();
+ mode = _mode;
+ count = _count;
+ type = _type;
+ index_offset = _index_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _mode, GLsizei _count, GLenum _type,
+ GLuint _index_offset) {
+ static_cast<ValueType*>(cmd)->Init(_mode, _count, _type, _index_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+ int32 count;
+ uint32 type;
+ uint32 index_offset;
+};
+
+COMPILE_ASSERT(sizeof(DrawElements) == 20,
+ Sizeof_DrawElements_is_not_20);
+COMPILE_ASSERT(offsetof(DrawElements, header) == 0,
+ OffsetOf_DrawElements_header_not_0);
+COMPILE_ASSERT(offsetof(DrawElements, mode) == 4,
+ OffsetOf_DrawElements_mode_not_4);
+COMPILE_ASSERT(offsetof(DrawElements, count) == 8,
+ OffsetOf_DrawElements_count_not_8);
+COMPILE_ASSERT(offsetof(DrawElements, type) == 12,
+ OffsetOf_DrawElements_type_not_12);
+COMPILE_ASSERT(offsetof(DrawElements, index_offset) == 16,
+ OffsetOf_DrawElements_index_offset_not_16);
+
+struct Enable {
+ typedef Enable ValueType;
+ static const CommandId kCmdId = kEnable;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _cap) {
+ SetHeader();
+ cap = _cap;
+ }
+
+ void* Set(void* cmd, GLenum _cap) {
+ static_cast<ValueType*>(cmd)->Init(_cap);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 cap;
+};
+
+COMPILE_ASSERT(sizeof(Enable) == 8,
+ Sizeof_Enable_is_not_8);
+COMPILE_ASSERT(offsetof(Enable, header) == 0,
+ OffsetOf_Enable_header_not_0);
+COMPILE_ASSERT(offsetof(Enable, cap) == 4,
+ OffsetOf_Enable_cap_not_4);
+
+struct EnableVertexAttribArray {
+ typedef EnableVertexAttribArray ValueType;
+ static const CommandId kCmdId = kEnableVertexAttribArray;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _index) {
+ SetHeader();
+ index = _index;
+ }
+
+ void* Set(void* cmd, GLuint _index) {
+ static_cast<ValueType*>(cmd)->Init(_index);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 index;
+};
+
+COMPILE_ASSERT(sizeof(EnableVertexAttribArray) == 8,
+ Sizeof_EnableVertexAttribArray_is_not_8);
+COMPILE_ASSERT(offsetof(EnableVertexAttribArray, header) == 0,
+ OffsetOf_EnableVertexAttribArray_header_not_0);
+COMPILE_ASSERT(offsetof(EnableVertexAttribArray, index) == 4,
+ OffsetOf_EnableVertexAttribArray_index_not_4);
+
+struct Finish {
+ typedef Finish ValueType;
+ static const CommandId kCmdId = kFinish;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(Finish) == 4,
+ Sizeof_Finish_is_not_4);
+COMPILE_ASSERT(offsetof(Finish, header) == 0,
+ OffsetOf_Finish_header_not_0);
+
+struct Flush {
+ typedef Flush ValueType;
+ static const CommandId kCmdId = kFlush;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(Flush) == 4,
+ Sizeof_Flush_is_not_4);
+COMPILE_ASSERT(offsetof(Flush, header) == 0,
+ OffsetOf_Flush_header_not_0);
+
+struct FramebufferRenderbuffer {
+ typedef FramebufferRenderbuffer ValueType;
+ static const CommandId kCmdId = kFramebufferRenderbuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _attachment, GLenum _renderbuffertarget,
+ GLuint _renderbuffer) {
+ SetHeader();
+ target = _target;
+ attachment = _attachment;
+ renderbuffertarget = _renderbuffertarget;
+ renderbuffer = _renderbuffer;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _attachment, GLenum _renderbuffertarget,
+ GLuint _renderbuffer) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _attachment, _renderbuffertarget, _renderbuffer);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 attachment;
+ uint32 renderbuffertarget;
+ uint32 renderbuffer;
+};
+
+COMPILE_ASSERT(sizeof(FramebufferRenderbuffer) == 20,
+ Sizeof_FramebufferRenderbuffer_is_not_20);
+COMPILE_ASSERT(offsetof(FramebufferRenderbuffer, header) == 0,
+ OffsetOf_FramebufferRenderbuffer_header_not_0);
+COMPILE_ASSERT(offsetof(FramebufferRenderbuffer, target) == 4,
+ OffsetOf_FramebufferRenderbuffer_target_not_4);
+COMPILE_ASSERT(offsetof(FramebufferRenderbuffer, attachment) == 8,
+ OffsetOf_FramebufferRenderbuffer_attachment_not_8);
+COMPILE_ASSERT(offsetof(FramebufferRenderbuffer, renderbuffertarget) == 12,
+ OffsetOf_FramebufferRenderbuffer_renderbuffertarget_not_12);
+COMPILE_ASSERT(offsetof(FramebufferRenderbuffer, renderbuffer) == 16,
+ OffsetOf_FramebufferRenderbuffer_renderbuffer_not_16);
+
+struct FramebufferTexture2D {
+ typedef FramebufferTexture2D ValueType;
+ static const CommandId kCmdId = kFramebufferTexture2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _attachment, GLenum _textarget, GLuint _texture,
+ GLint _level) {
+ SetHeader();
+ target = _target;
+ attachment = _attachment;
+ textarget = _textarget;
+ texture = _texture;
+ level = _level;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _attachment, GLenum _textarget,
+ GLuint _texture, GLint _level) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _attachment, _textarget, _texture, _level);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 attachment;
+ uint32 textarget;
+ uint32 texture;
+ int32 level;
+};
+
+COMPILE_ASSERT(sizeof(FramebufferTexture2D) == 24,
+ Sizeof_FramebufferTexture2D_is_not_24);
+COMPILE_ASSERT(offsetof(FramebufferTexture2D, header) == 0,
+ OffsetOf_FramebufferTexture2D_header_not_0);
+COMPILE_ASSERT(offsetof(FramebufferTexture2D, target) == 4,
+ OffsetOf_FramebufferTexture2D_target_not_4);
+COMPILE_ASSERT(offsetof(FramebufferTexture2D, attachment) == 8,
+ OffsetOf_FramebufferTexture2D_attachment_not_8);
+COMPILE_ASSERT(offsetof(FramebufferTexture2D, textarget) == 12,
+ OffsetOf_FramebufferTexture2D_textarget_not_12);
+COMPILE_ASSERT(offsetof(FramebufferTexture2D, texture) == 16,
+ OffsetOf_FramebufferTexture2D_texture_not_16);
+COMPILE_ASSERT(offsetof(FramebufferTexture2D, level) == 20,
+ OffsetOf_FramebufferTexture2D_level_not_20);
+
+struct FrontFace {
+ typedef FrontFace ValueType;
+ static const CommandId kCmdId = kFrontFace;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _mode) {
+ SetHeader();
+ mode = _mode;
+ }
+
+ void* Set(void* cmd, GLenum _mode) {
+ static_cast<ValueType*>(cmd)->Init(_mode);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+};
+
+COMPILE_ASSERT(sizeof(FrontFace) == 8,
+ Sizeof_FrontFace_is_not_8);
+COMPILE_ASSERT(offsetof(FrontFace, header) == 0,
+ OffsetOf_FrontFace_header_not_0);
+COMPILE_ASSERT(offsetof(FrontFace, mode) == 4,
+ OffsetOf_FrontFace_mode_not_4);
+
+struct GenBuffers {
+ typedef GenBuffers ValueType;
+ static const CommandId kCmdId = kGenBuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _buffers_shm_id, uint32 _buffers_shm_offset) {
+ SetHeader();
+ n = _n;
+ buffers_shm_id = _buffers_shm_id;
+ buffers_shm_offset = _buffers_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _buffers_shm_id,
+ uint32 _buffers_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _buffers_shm_id, _buffers_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 buffers_shm_id;
+ uint32 buffers_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenBuffers) == 16,
+ Sizeof_GenBuffers_is_not_16);
+COMPILE_ASSERT(offsetof(GenBuffers, header) == 0,
+ OffsetOf_GenBuffers_header_not_0);
+COMPILE_ASSERT(offsetof(GenBuffers, n) == 4,
+ OffsetOf_GenBuffers_n_not_4);
+COMPILE_ASSERT(offsetof(GenBuffers, buffers_shm_id) == 8,
+ OffsetOf_GenBuffers_buffers_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenBuffers, buffers_shm_offset) == 12,
+ OffsetOf_GenBuffers_buffers_shm_offset_not_12);
+
+struct GenBuffersImmediate {
+ typedef GenBuffersImmediate ValueType;
+ static const CommandId kCmdId = kGenBuffersImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _buffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _buffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _buffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _buffers);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenBuffersImmediate) == 8,
+ Sizeof_GenBuffersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenBuffersImmediate, header) == 0,
+ OffsetOf_GenBuffersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenBuffersImmediate, n) == 4,
+ OffsetOf_GenBuffersImmediate_n_not_4);
+
+struct GenerateMipmap {
+ typedef GenerateMipmap ValueType;
+ static const CommandId kCmdId = kGenerateMipmap;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target) {
+ SetHeader();
+ target = _target;
+ }
+
+ void* Set(void* cmd, GLenum _target) {
+ static_cast<ValueType*>(cmd)->Init(_target);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+};
+
+COMPILE_ASSERT(sizeof(GenerateMipmap) == 8,
+ Sizeof_GenerateMipmap_is_not_8);
+COMPILE_ASSERT(offsetof(GenerateMipmap, header) == 0,
+ OffsetOf_GenerateMipmap_header_not_0);
+COMPILE_ASSERT(offsetof(GenerateMipmap, target) == 4,
+ OffsetOf_GenerateMipmap_target_not_4);
+
+struct GenFramebuffers {
+ typedef GenFramebuffers ValueType;
+ static const CommandId kCmdId = kGenFramebuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLsizei _n, uint32 _framebuffers_shm_id,
+ uint32 _framebuffers_shm_offset) {
+ SetHeader();
+ n = _n;
+ framebuffers_shm_id = _framebuffers_shm_id;
+ framebuffers_shm_offset = _framebuffers_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _framebuffers_shm_id,
+ uint32 _framebuffers_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _framebuffers_shm_id, _framebuffers_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 framebuffers_shm_id;
+ uint32 framebuffers_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenFramebuffers) == 16,
+ Sizeof_GenFramebuffers_is_not_16);
+COMPILE_ASSERT(offsetof(GenFramebuffers, header) == 0,
+ OffsetOf_GenFramebuffers_header_not_0);
+COMPILE_ASSERT(offsetof(GenFramebuffers, n) == 4,
+ OffsetOf_GenFramebuffers_n_not_4);
+COMPILE_ASSERT(offsetof(GenFramebuffers, framebuffers_shm_id) == 8,
+ OffsetOf_GenFramebuffers_framebuffers_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenFramebuffers, framebuffers_shm_offset) == 12,
+ OffsetOf_GenFramebuffers_framebuffers_shm_offset_not_12);
+
+struct GenFramebuffersImmediate {
+ typedef GenFramebuffersImmediate ValueType;
+ static const CommandId kCmdId = kGenFramebuffersImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _framebuffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _framebuffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _framebuffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _framebuffers);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenFramebuffersImmediate) == 8,
+ Sizeof_GenFramebuffersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenFramebuffersImmediate, header) == 0,
+ OffsetOf_GenFramebuffersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenFramebuffersImmediate, n) == 4,
+ OffsetOf_GenFramebuffersImmediate_n_not_4);
+
+struct GenRenderbuffers {
+ typedef GenRenderbuffers ValueType;
+ static const CommandId kCmdId = kGenRenderbuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLsizei _n, uint32 _renderbuffers_shm_id,
+ uint32 _renderbuffers_shm_offset) {
+ SetHeader();
+ n = _n;
+ renderbuffers_shm_id = _renderbuffers_shm_id;
+ renderbuffers_shm_offset = _renderbuffers_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _renderbuffers_shm_id,
+ uint32 _renderbuffers_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _renderbuffers_shm_id, _renderbuffers_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 renderbuffers_shm_id;
+ uint32 renderbuffers_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenRenderbuffers) == 16,
+ Sizeof_GenRenderbuffers_is_not_16);
+COMPILE_ASSERT(offsetof(GenRenderbuffers, header) == 0,
+ OffsetOf_GenRenderbuffers_header_not_0);
+COMPILE_ASSERT(offsetof(GenRenderbuffers, n) == 4,
+ OffsetOf_GenRenderbuffers_n_not_4);
+COMPILE_ASSERT(offsetof(GenRenderbuffers, renderbuffers_shm_id) == 8,
+ OffsetOf_GenRenderbuffers_renderbuffers_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenRenderbuffers, renderbuffers_shm_offset) == 12,
+ OffsetOf_GenRenderbuffers_renderbuffers_shm_offset_not_12);
+
+struct GenRenderbuffersImmediate {
+ typedef GenRenderbuffersImmediate ValueType;
+ static const CommandId kCmdId = kGenRenderbuffersImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _renderbuffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _renderbuffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _renderbuffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _renderbuffers);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenRenderbuffersImmediate) == 8,
+ Sizeof_GenRenderbuffersImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenRenderbuffersImmediate, header) == 0,
+ OffsetOf_GenRenderbuffersImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenRenderbuffersImmediate, n) == 4,
+ OffsetOf_GenRenderbuffersImmediate_n_not_4);
+
+struct GenTextures {
+ typedef GenTextures ValueType;
+ static const CommandId kCmdId = kGenTextures;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _textures_shm_id, uint32 _textures_shm_offset) {
+ SetHeader();
+ n = _n;
+ textures_shm_id = _textures_shm_id;
+ textures_shm_offset = _textures_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _textures_shm_id,
+ uint32 _textures_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _textures_shm_id, _textures_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 textures_shm_id;
+ uint32 textures_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenTextures) == 16,
+ Sizeof_GenTextures_is_not_16);
+COMPILE_ASSERT(offsetof(GenTextures, header) == 0,
+ OffsetOf_GenTextures_header_not_0);
+COMPILE_ASSERT(offsetof(GenTextures, n) == 4,
+ OffsetOf_GenTextures_n_not_4);
+COMPILE_ASSERT(offsetof(GenTextures, textures_shm_id) == 8,
+ OffsetOf_GenTextures_textures_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenTextures, textures_shm_offset) == 12,
+ OffsetOf_GenTextures_textures_shm_offset_not_12);
+
+struct GenTexturesImmediate {
+ typedef GenTexturesImmediate ValueType;
+ static const CommandId kCmdId = kGenTexturesImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _textures) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _textures, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _textures) {
+ static_cast<ValueType*>(cmd)->Init(_n, _textures);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenTexturesImmediate) == 8,
+ Sizeof_GenTexturesImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenTexturesImmediate, header) == 0,
+ OffsetOf_GenTexturesImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenTexturesImmediate, n) == 4,
+ OffsetOf_GenTexturesImmediate_n_not_4);
+
+struct GetActiveAttrib {
+ typedef GetActiveAttrib ValueType;
+ static const CommandId kCmdId = kGetActiveAttrib;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ struct Result {
+ int32 success;
+ int32 size;
+ uint32 type;
+ };
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLuint _index, uint32 _name_bucket_id,
+ uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ program = _program;
+ index = _index;
+ name_bucket_id = _name_bucket_id;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLuint _index, uint32 _name_bucket_id,
+ uint32 _result_shm_id, uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _index, _name_bucket_id, _result_shm_id,
+ _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 index;
+ uint32 name_bucket_id;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetActiveAttrib) == 24,
+ Sizeof_GetActiveAttrib_is_not_24);
+COMPILE_ASSERT(offsetof(GetActiveAttrib, header) == 0,
+ OffsetOf_GetActiveAttrib_header_not_0);
+COMPILE_ASSERT(offsetof(GetActiveAttrib, program) == 4,
+ OffsetOf_GetActiveAttrib_program_not_4);
+COMPILE_ASSERT(offsetof(GetActiveAttrib, index) == 8,
+ OffsetOf_GetActiveAttrib_index_not_8);
+COMPILE_ASSERT(offsetof(GetActiveAttrib, name_bucket_id) == 12,
+ OffsetOf_GetActiveAttrib_name_bucket_id_not_12);
+COMPILE_ASSERT(offsetof(GetActiveAttrib, result_shm_id) == 16,
+ OffsetOf_GetActiveAttrib_result_shm_id_not_16);
+COMPILE_ASSERT(offsetof(GetActiveAttrib, result_shm_offset) == 20,
+ OffsetOf_GetActiveAttrib_result_shm_offset_not_20);
+COMPILE_ASSERT(offsetof(GetActiveAttrib::Result, success) == 0,
+ OffsetOf_GetActiveAttrib_Result_success_not_0);
+COMPILE_ASSERT(offsetof(GetActiveAttrib::Result, size) == 4,
+ OffsetOf_GetActiveAttrib_Result_size_not_4);
+COMPILE_ASSERT(offsetof(GetActiveAttrib::Result, type) == 8,
+ OffsetOf_GetActiveAttrib_Result_type_not_8);
+
+struct GetActiveUniform {
+ typedef GetActiveUniform ValueType;
+ static const CommandId kCmdId = kGetActiveUniform;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ struct Result {
+ int32 success;
+ int32 size;
+ uint32 type;
+ };
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLuint _index, uint32 _name_bucket_id,
+ uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ program = _program;
+ index = _index;
+ name_bucket_id = _name_bucket_id;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLuint _index, uint32 _name_bucket_id,
+ uint32 _result_shm_id, uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _index, _name_bucket_id, _result_shm_id,
+ _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 index;
+ uint32 name_bucket_id;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetActiveUniform) == 24,
+ Sizeof_GetActiveUniform_is_not_24);
+COMPILE_ASSERT(offsetof(GetActiveUniform, header) == 0,
+ OffsetOf_GetActiveUniform_header_not_0);
+COMPILE_ASSERT(offsetof(GetActiveUniform, program) == 4,
+ OffsetOf_GetActiveUniform_program_not_4);
+COMPILE_ASSERT(offsetof(GetActiveUniform, index) == 8,
+ OffsetOf_GetActiveUniform_index_not_8);
+COMPILE_ASSERT(offsetof(GetActiveUniform, name_bucket_id) == 12,
+ OffsetOf_GetActiveUniform_name_bucket_id_not_12);
+COMPILE_ASSERT(offsetof(GetActiveUniform, result_shm_id) == 16,
+ OffsetOf_GetActiveUniform_result_shm_id_not_16);
+COMPILE_ASSERT(offsetof(GetActiveUniform, result_shm_offset) == 20,
+ OffsetOf_GetActiveUniform_result_shm_offset_not_20);
+COMPILE_ASSERT(offsetof(GetActiveUniform::Result, success) == 0,
+ OffsetOf_GetActiveUniform_Result_success_not_0);
+COMPILE_ASSERT(offsetof(GetActiveUniform::Result, size) == 4,
+ OffsetOf_GetActiveUniform_Result_size_not_4);
+COMPILE_ASSERT(offsetof(GetActiveUniform::Result, type) == 8,
+ OffsetOf_GetActiveUniform_Result_type_not_8);
+
+struct GetAttachedShaders {
+ typedef GetAttachedShaders ValueType;
+ static const CommandId kCmdId = kGetAttachedShaders;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLuint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, uint32 _result_shm_id, uint32 _result_shm_offset,
+ uint32 _result_size) {
+ SetHeader();
+ program = _program;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ result_size = _result_size;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, uint32 _result_shm_id,
+ uint32 _result_shm_offset, uint32 _result_size) {
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _result_shm_id, _result_shm_offset, _result_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+ uint32 result_size;
+};
+
+COMPILE_ASSERT(sizeof(GetAttachedShaders) == 20,
+ Sizeof_GetAttachedShaders_is_not_20);
+COMPILE_ASSERT(offsetof(GetAttachedShaders, header) == 0,
+ OffsetOf_GetAttachedShaders_header_not_0);
+COMPILE_ASSERT(offsetof(GetAttachedShaders, program) == 4,
+ OffsetOf_GetAttachedShaders_program_not_4);
+COMPILE_ASSERT(offsetof(GetAttachedShaders, result_shm_id) == 8,
+ OffsetOf_GetAttachedShaders_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetAttachedShaders, result_shm_offset) == 12,
+ OffsetOf_GetAttachedShaders_result_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(GetAttachedShaders, result_size) == 16,
+ OffsetOf_GetAttachedShaders_result_size_not_16);
+
+struct GetBooleanv {
+ typedef GetBooleanv ValueType;
+ static const CommandId kCmdId = kGetBooleanv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLboolean> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _pname, uint32 _params_shm_id, uint32 _params_shm_offset) {
+ SetHeader();
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetBooleanv) == 16,
+ Sizeof_GetBooleanv_is_not_16);
+COMPILE_ASSERT(offsetof(GetBooleanv, header) == 0,
+ OffsetOf_GetBooleanv_header_not_0);
+COMPILE_ASSERT(offsetof(GetBooleanv, pname) == 4,
+ OffsetOf_GetBooleanv_pname_not_4);
+COMPILE_ASSERT(offsetof(GetBooleanv, params_shm_id) == 8,
+ OffsetOf_GetBooleanv_params_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetBooleanv, params_shm_offset) == 12,
+ OffsetOf_GetBooleanv_params_shm_offset_not_12);
+
+struct GetBufferParameteriv {
+ typedef GetBufferParameteriv ValueType;
+ static const CommandId kCmdId = kGetBufferParameteriv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetBufferParameteriv) == 20,
+ Sizeof_GetBufferParameteriv_is_not_20);
+COMPILE_ASSERT(offsetof(GetBufferParameteriv, header) == 0,
+ OffsetOf_GetBufferParameteriv_header_not_0);
+COMPILE_ASSERT(offsetof(GetBufferParameteriv, target) == 4,
+ OffsetOf_GetBufferParameteriv_target_not_4);
+COMPILE_ASSERT(offsetof(GetBufferParameteriv, pname) == 8,
+ OffsetOf_GetBufferParameteriv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetBufferParameteriv, params_shm_id) == 12,
+ OffsetOf_GetBufferParameteriv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetBufferParameteriv, params_shm_offset) == 16,
+ OffsetOf_GetBufferParameteriv_params_shm_offset_not_16);
+
+struct GetError {
+ typedef GetError ValueType;
+ static const CommandId kCmdId = kGetError;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLenum Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(void* cmd, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ static_cast<ValueType*>(cmd)->Init(_result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetError) == 12,
+ Sizeof_GetError_is_not_12);
+COMPILE_ASSERT(offsetof(GetError, header) == 0,
+ OffsetOf_GetError_header_not_0);
+COMPILE_ASSERT(offsetof(GetError, result_shm_id) == 4,
+ OffsetOf_GetError_result_shm_id_not_4);
+COMPILE_ASSERT(offsetof(GetError, result_shm_offset) == 8,
+ OffsetOf_GetError_result_shm_offset_not_8);
+
+struct GetFloatv {
+ typedef GetFloatv ValueType;
+ static const CommandId kCmdId = kGetFloatv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLfloat> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _pname, uint32 _params_shm_id, uint32 _params_shm_offset) {
+ SetHeader();
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetFloatv) == 16,
+ Sizeof_GetFloatv_is_not_16);
+COMPILE_ASSERT(offsetof(GetFloatv, header) == 0,
+ OffsetOf_GetFloatv_header_not_0);
+COMPILE_ASSERT(offsetof(GetFloatv, pname) == 4,
+ OffsetOf_GetFloatv_pname_not_4);
+COMPILE_ASSERT(offsetof(GetFloatv, params_shm_id) == 8,
+ OffsetOf_GetFloatv_params_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetFloatv, params_shm_offset) == 12,
+ OffsetOf_GetFloatv_params_shm_offset_not_12);
+
+struct GetFramebufferAttachmentParameteriv {
+ typedef GetFramebufferAttachmentParameteriv ValueType;
+ static const CommandId kCmdId = kGetFramebufferAttachmentParameteriv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _attachment, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ attachment = _attachment;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _attachment, GLenum _pname,
+ uint32 _params_shm_id, uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _attachment, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 attachment;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetFramebufferAttachmentParameteriv) == 24,
+ Sizeof_GetFramebufferAttachmentParameteriv_is_not_24);
+COMPILE_ASSERT(offsetof(GetFramebufferAttachmentParameteriv, header) == 0,
+ OffsetOf_GetFramebufferAttachmentParameteriv_header_not_0);
+COMPILE_ASSERT(offsetof(GetFramebufferAttachmentParameteriv, target) == 4,
+ OffsetOf_GetFramebufferAttachmentParameteriv_target_not_4);
+COMPILE_ASSERT(offsetof(GetFramebufferAttachmentParameteriv, attachment) == 8,
+ OffsetOf_GetFramebufferAttachmentParameteriv_attachment_not_8);
+COMPILE_ASSERT(offsetof(GetFramebufferAttachmentParameteriv, pname) == 12,
+ OffsetOf_GetFramebufferAttachmentParameteriv_pname_not_12);
+COMPILE_ASSERT(
+ offsetof(GetFramebufferAttachmentParameteriv, params_shm_id) == 16,
+ OffsetOf_GetFramebufferAttachmentParameteriv_params_shm_id_not_16); // NOLINT
+COMPILE_ASSERT(
+ offsetof(GetFramebufferAttachmentParameteriv, params_shm_offset) == 20,
+ OffsetOf_GetFramebufferAttachmentParameteriv_params_shm_offset_not_20); // NOLINT
+
+struct GetIntegerv {
+ typedef GetIntegerv ValueType;
+ static const CommandId kCmdId = kGetIntegerv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _pname, uint32 _params_shm_id, uint32 _params_shm_offset) {
+ SetHeader();
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetIntegerv) == 16,
+ Sizeof_GetIntegerv_is_not_16);
+COMPILE_ASSERT(offsetof(GetIntegerv, header) == 0,
+ OffsetOf_GetIntegerv_header_not_0);
+COMPILE_ASSERT(offsetof(GetIntegerv, pname) == 4,
+ OffsetOf_GetIntegerv_pname_not_4);
+COMPILE_ASSERT(offsetof(GetIntegerv, params_shm_id) == 8,
+ OffsetOf_GetIntegerv_params_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GetIntegerv, params_shm_offset) == 12,
+ OffsetOf_GetIntegerv_params_shm_offset_not_12);
+
+struct GetProgramiv {
+ typedef GetProgramiv ValueType;
+ static const CommandId kCmdId = kGetProgramiv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ program = _program;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetProgramiv) == 20,
+ Sizeof_GetProgramiv_is_not_20);
+COMPILE_ASSERT(offsetof(GetProgramiv, header) == 0,
+ OffsetOf_GetProgramiv_header_not_0);
+COMPILE_ASSERT(offsetof(GetProgramiv, program) == 4,
+ OffsetOf_GetProgramiv_program_not_4);
+COMPILE_ASSERT(offsetof(GetProgramiv, pname) == 8,
+ OffsetOf_GetProgramiv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetProgramiv, params_shm_id) == 12,
+ OffsetOf_GetProgramiv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetProgramiv, params_shm_offset) == 16,
+ OffsetOf_GetProgramiv_params_shm_offset_not_16);
+
+struct GetProgramInfoLog {
+ typedef GetProgramInfoLog ValueType;
+ static const CommandId kCmdId = kGetProgramInfoLog;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, uint32 _bucket_id) {
+ SetHeader();
+ program = _program;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _program, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_program, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetProgramInfoLog) == 12,
+ Sizeof_GetProgramInfoLog_is_not_12);
+COMPILE_ASSERT(offsetof(GetProgramInfoLog, header) == 0,
+ OffsetOf_GetProgramInfoLog_header_not_0);
+COMPILE_ASSERT(offsetof(GetProgramInfoLog, program) == 4,
+ OffsetOf_GetProgramInfoLog_program_not_4);
+COMPILE_ASSERT(offsetof(GetProgramInfoLog, bucket_id) == 8,
+ OffsetOf_GetProgramInfoLog_bucket_id_not_8);
+
+struct GetRenderbufferParameteriv {
+ typedef GetRenderbufferParameteriv ValueType;
+ static const CommandId kCmdId = kGetRenderbufferParameteriv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetRenderbufferParameteriv) == 20,
+ Sizeof_GetRenderbufferParameteriv_is_not_20);
+COMPILE_ASSERT(offsetof(GetRenderbufferParameteriv, header) == 0,
+ OffsetOf_GetRenderbufferParameteriv_header_not_0);
+COMPILE_ASSERT(offsetof(GetRenderbufferParameteriv, target) == 4,
+ OffsetOf_GetRenderbufferParameteriv_target_not_4);
+COMPILE_ASSERT(offsetof(GetRenderbufferParameteriv, pname) == 8,
+ OffsetOf_GetRenderbufferParameteriv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetRenderbufferParameteriv, params_shm_id) == 12,
+ OffsetOf_GetRenderbufferParameteriv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetRenderbufferParameteriv, params_shm_offset) == 16,
+ OffsetOf_GetRenderbufferParameteriv_params_shm_offset_not_16);
+
+struct GetShaderiv {
+ typedef GetShaderiv ValueType;
+ static const CommandId kCmdId = kGetShaderiv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _shader, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ shader = _shader;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _shader, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_shader, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetShaderiv) == 20,
+ Sizeof_GetShaderiv_is_not_20);
+COMPILE_ASSERT(offsetof(GetShaderiv, header) == 0,
+ OffsetOf_GetShaderiv_header_not_0);
+COMPILE_ASSERT(offsetof(GetShaderiv, shader) == 4,
+ OffsetOf_GetShaderiv_shader_not_4);
+COMPILE_ASSERT(offsetof(GetShaderiv, pname) == 8,
+ OffsetOf_GetShaderiv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetShaderiv, params_shm_id) == 12,
+ OffsetOf_GetShaderiv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetShaderiv, params_shm_offset) == 16,
+ OffsetOf_GetShaderiv_params_shm_offset_not_16);
+
+struct GetShaderInfoLog {
+ typedef GetShaderInfoLog ValueType;
+ static const CommandId kCmdId = kGetShaderInfoLog;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader, uint32 _bucket_id) {
+ SetHeader();
+ shader = _shader;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _shader, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_shader, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetShaderInfoLog) == 12,
+ Sizeof_GetShaderInfoLog_is_not_12);
+COMPILE_ASSERT(offsetof(GetShaderInfoLog, header) == 0,
+ OffsetOf_GetShaderInfoLog_header_not_0);
+COMPILE_ASSERT(offsetof(GetShaderInfoLog, shader) == 4,
+ OffsetOf_GetShaderInfoLog_shader_not_4);
+COMPILE_ASSERT(offsetof(GetShaderInfoLog, bucket_id) == 8,
+ OffsetOf_GetShaderInfoLog_bucket_id_not_8);
+
+struct GetShaderPrecisionFormat {
+ typedef GetShaderPrecisionFormat ValueType;
+ static const CommandId kCmdId = kGetShaderPrecisionFormat;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ struct Result {
+ int32 success;
+ int32 min_range;
+ int32 max_range;
+ int32 precision;
+ };
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _shadertype, GLenum _precisiontype, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ SetHeader();
+ shadertype = _shadertype;
+ precisiontype = _precisiontype;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _shadertype, GLenum _precisiontype,
+ uint32 _result_shm_id, uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _shadertype, _precisiontype, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shadertype;
+ uint32 precisiontype;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetShaderPrecisionFormat) == 20,
+ Sizeof_GetShaderPrecisionFormat_is_not_20);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat, header) == 0,
+ OffsetOf_GetShaderPrecisionFormat_header_not_0);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat, shadertype) == 4,
+ OffsetOf_GetShaderPrecisionFormat_shadertype_not_4);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat, precisiontype) == 8,
+ OffsetOf_GetShaderPrecisionFormat_precisiontype_not_8);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat, result_shm_id) == 12,
+ OffsetOf_GetShaderPrecisionFormat_result_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat, result_shm_offset) == 16,
+ OffsetOf_GetShaderPrecisionFormat_result_shm_offset_not_16);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat::Result, success) == 0,
+ OffsetOf_GetShaderPrecisionFormat_Result_success_not_0);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat::Result, min_range) == 4,
+ OffsetOf_GetShaderPrecisionFormat_Result_min_range_not_4);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat::Result, max_range) == 8,
+ OffsetOf_GetShaderPrecisionFormat_Result_max_range_not_8);
+COMPILE_ASSERT(offsetof(GetShaderPrecisionFormat::Result, precision) == 12,
+ OffsetOf_GetShaderPrecisionFormat_Result_precision_not_12);
+
+struct GetShaderSource {
+ typedef GetShaderSource ValueType;
+ static const CommandId kCmdId = kGetShaderSource;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader, uint32 _bucket_id) {
+ SetHeader();
+ shader = _shader;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _shader, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_shader, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetShaderSource) == 12,
+ Sizeof_GetShaderSource_is_not_12);
+COMPILE_ASSERT(offsetof(GetShaderSource, header) == 0,
+ OffsetOf_GetShaderSource_header_not_0);
+COMPILE_ASSERT(offsetof(GetShaderSource, shader) == 4,
+ OffsetOf_GetShaderSource_shader_not_4);
+COMPILE_ASSERT(offsetof(GetShaderSource, bucket_id) == 8,
+ OffsetOf_GetShaderSource_bucket_id_not_8);
+
+struct GetString {
+ typedef GetString ValueType;
+ static const CommandId kCmdId = kGetString;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _name, uint32 _bucket_id) {
+ SetHeader();
+ name = _name;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLenum _name, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_name, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 name;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetString) == 12,
+ Sizeof_GetString_is_not_12);
+COMPILE_ASSERT(offsetof(GetString, header) == 0,
+ OffsetOf_GetString_header_not_0);
+COMPILE_ASSERT(offsetof(GetString, name) == 4,
+ OffsetOf_GetString_name_not_4);
+COMPILE_ASSERT(offsetof(GetString, bucket_id) == 8,
+ OffsetOf_GetString_bucket_id_not_8);
+
+struct GetTexParameterfv {
+ typedef GetTexParameterfv ValueType;
+ static const CommandId kCmdId = kGetTexParameterfv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLfloat> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetTexParameterfv) == 20,
+ Sizeof_GetTexParameterfv_is_not_20);
+COMPILE_ASSERT(offsetof(GetTexParameterfv, header) == 0,
+ OffsetOf_GetTexParameterfv_header_not_0);
+COMPILE_ASSERT(offsetof(GetTexParameterfv, target) == 4,
+ OffsetOf_GetTexParameterfv_target_not_4);
+COMPILE_ASSERT(offsetof(GetTexParameterfv, pname) == 8,
+ OffsetOf_GetTexParameterfv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetTexParameterfv, params_shm_id) == 12,
+ OffsetOf_GetTexParameterfv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetTexParameterfv, params_shm_offset) == 16,
+ OffsetOf_GetTexParameterfv_params_shm_offset_not_16);
+
+struct GetTexParameteriv {
+ typedef GetTexParameteriv ValueType;
+ static const CommandId kCmdId = kGetTexParameteriv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetTexParameteriv) == 20,
+ Sizeof_GetTexParameteriv_is_not_20);
+COMPILE_ASSERT(offsetof(GetTexParameteriv, header) == 0,
+ OffsetOf_GetTexParameteriv_header_not_0);
+COMPILE_ASSERT(offsetof(GetTexParameteriv, target) == 4,
+ OffsetOf_GetTexParameteriv_target_not_4);
+COMPILE_ASSERT(offsetof(GetTexParameteriv, pname) == 8,
+ OffsetOf_GetTexParameteriv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetTexParameteriv, params_shm_id) == 12,
+ OffsetOf_GetTexParameteriv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetTexParameteriv, params_shm_offset) == 16,
+ OffsetOf_GetTexParameteriv_params_shm_offset_not_16);
+
+struct GetUniformfv {
+ typedef GetUniformfv ValueType;
+ static const CommandId kCmdId = kGetUniformfv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLfloat> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLint _location, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ program = _program;
+ location = _location;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLint _location, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _location, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ int32 location;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetUniformfv) == 20,
+ Sizeof_GetUniformfv_is_not_20);
+COMPILE_ASSERT(offsetof(GetUniformfv, header) == 0,
+ OffsetOf_GetUniformfv_header_not_0);
+COMPILE_ASSERT(offsetof(GetUniformfv, program) == 4,
+ OffsetOf_GetUniformfv_program_not_4);
+COMPILE_ASSERT(offsetof(GetUniformfv, location) == 8,
+ OffsetOf_GetUniformfv_location_not_8);
+COMPILE_ASSERT(offsetof(GetUniformfv, params_shm_id) == 12,
+ OffsetOf_GetUniformfv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetUniformfv, params_shm_offset) == 16,
+ OffsetOf_GetUniformfv_params_shm_offset_not_16);
+
+struct GetUniformiv {
+ typedef GetUniformiv ValueType;
+ static const CommandId kCmdId = kGetUniformiv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLint _location, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ program = _program;
+ location = _location;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLint _location, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _location, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ int32 location;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetUniformiv) == 20,
+ Sizeof_GetUniformiv_is_not_20);
+COMPILE_ASSERT(offsetof(GetUniformiv, header) == 0,
+ OffsetOf_GetUniformiv_header_not_0);
+COMPILE_ASSERT(offsetof(GetUniformiv, program) == 4,
+ OffsetOf_GetUniformiv_program_not_4);
+COMPILE_ASSERT(offsetof(GetUniformiv, location) == 8,
+ OffsetOf_GetUniformiv_location_not_8);
+COMPILE_ASSERT(offsetof(GetUniformiv, params_shm_id) == 12,
+ OffsetOf_GetUniformiv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetUniformiv, params_shm_offset) == 16,
+ OffsetOf_GetUniformiv_params_shm_offset_not_16);
+
+struct GetVertexAttribfv {
+ typedef GetVertexAttribfv ValueType;
+ static const CommandId kCmdId = kGetVertexAttribfv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLfloat> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _index, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ index = _index;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _index, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_index, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 index;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetVertexAttribfv) == 20,
+ Sizeof_GetVertexAttribfv_is_not_20);
+COMPILE_ASSERT(offsetof(GetVertexAttribfv, header) == 0,
+ OffsetOf_GetVertexAttribfv_header_not_0);
+COMPILE_ASSERT(offsetof(GetVertexAttribfv, index) == 4,
+ OffsetOf_GetVertexAttribfv_index_not_4);
+COMPILE_ASSERT(offsetof(GetVertexAttribfv, pname) == 8,
+ OffsetOf_GetVertexAttribfv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetVertexAttribfv, params_shm_id) == 12,
+ OffsetOf_GetVertexAttribfv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetVertexAttribfv, params_shm_offset) == 16,
+ OffsetOf_GetVertexAttribfv_params_shm_offset_not_16);
+
+struct GetVertexAttribiv {
+ typedef GetVertexAttribiv ValueType;
+ static const CommandId kCmdId = kGetVertexAttribiv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _index, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ index = _index;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _index, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_index, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 index;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetVertexAttribiv) == 20,
+ Sizeof_GetVertexAttribiv_is_not_20);
+COMPILE_ASSERT(offsetof(GetVertexAttribiv, header) == 0,
+ OffsetOf_GetVertexAttribiv_header_not_0);
+COMPILE_ASSERT(offsetof(GetVertexAttribiv, index) == 4,
+ OffsetOf_GetVertexAttribiv_index_not_4);
+COMPILE_ASSERT(offsetof(GetVertexAttribiv, pname) == 8,
+ OffsetOf_GetVertexAttribiv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetVertexAttribiv, params_shm_id) == 12,
+ OffsetOf_GetVertexAttribiv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetVertexAttribiv, params_shm_offset) == 16,
+ OffsetOf_GetVertexAttribiv_params_shm_offset_not_16);
+
+struct GetVertexAttribPointerv {
+ typedef GetVertexAttribPointerv ValueType;
+ static const CommandId kCmdId = kGetVertexAttribPointerv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLuint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _index, GLenum _pname, uint32 _pointer_shm_id,
+ uint32 _pointer_shm_offset) {
+ SetHeader();
+ index = _index;
+ pname = _pname;
+ pointer_shm_id = _pointer_shm_id;
+ pointer_shm_offset = _pointer_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _index, GLenum _pname, uint32 _pointer_shm_id,
+ uint32 _pointer_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_index, _pname, _pointer_shm_id, _pointer_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 index;
+ uint32 pname;
+ uint32 pointer_shm_id;
+ uint32 pointer_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetVertexAttribPointerv) == 20,
+ Sizeof_GetVertexAttribPointerv_is_not_20);
+COMPILE_ASSERT(offsetof(GetVertexAttribPointerv, header) == 0,
+ OffsetOf_GetVertexAttribPointerv_header_not_0);
+COMPILE_ASSERT(offsetof(GetVertexAttribPointerv, index) == 4,
+ OffsetOf_GetVertexAttribPointerv_index_not_4);
+COMPILE_ASSERT(offsetof(GetVertexAttribPointerv, pname) == 8,
+ OffsetOf_GetVertexAttribPointerv_pname_not_8);
+COMPILE_ASSERT(offsetof(GetVertexAttribPointerv, pointer_shm_id) == 12,
+ OffsetOf_GetVertexAttribPointerv_pointer_shm_id_not_12);
+COMPILE_ASSERT(offsetof(GetVertexAttribPointerv, pointer_shm_offset) == 16,
+ OffsetOf_GetVertexAttribPointerv_pointer_shm_offset_not_16);
+
+struct Hint {
+ typedef Hint ValueType;
+ static const CommandId kCmdId = kHint;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLenum _mode) {
+ SetHeader();
+ target = _target;
+ mode = _mode;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLenum _mode) {
+ static_cast<ValueType*>(cmd)->Init(_target, _mode);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 mode;
+};
+
+COMPILE_ASSERT(sizeof(Hint) == 12,
+ Sizeof_Hint_is_not_12);
+COMPILE_ASSERT(offsetof(Hint, header) == 0,
+ OffsetOf_Hint_header_not_0);
+COMPILE_ASSERT(offsetof(Hint, target) == 4,
+ OffsetOf_Hint_target_not_4);
+COMPILE_ASSERT(offsetof(Hint, mode) == 8,
+ OffsetOf_Hint_mode_not_8);
+
+struct IsBuffer {
+ typedef IsBuffer ValueType;
+ static const CommandId kCmdId = kIsBuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _buffer, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ buffer = _buffer;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _buffer, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_buffer, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 buffer;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsBuffer) == 16,
+ Sizeof_IsBuffer_is_not_16);
+COMPILE_ASSERT(offsetof(IsBuffer, header) == 0,
+ OffsetOf_IsBuffer_header_not_0);
+COMPILE_ASSERT(offsetof(IsBuffer, buffer) == 4,
+ OffsetOf_IsBuffer_buffer_not_4);
+COMPILE_ASSERT(offsetof(IsBuffer, result_shm_id) == 8,
+ OffsetOf_IsBuffer_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsBuffer, result_shm_offset) == 12,
+ OffsetOf_IsBuffer_result_shm_offset_not_12);
+
+struct IsEnabled {
+ typedef IsEnabled ValueType;
+ static const CommandId kCmdId = kIsEnabled;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _cap, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ cap = _cap;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _cap, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_cap, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 cap;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsEnabled) == 16,
+ Sizeof_IsEnabled_is_not_16);
+COMPILE_ASSERT(offsetof(IsEnabled, header) == 0,
+ OffsetOf_IsEnabled_header_not_0);
+COMPILE_ASSERT(offsetof(IsEnabled, cap) == 4,
+ OffsetOf_IsEnabled_cap_not_4);
+COMPILE_ASSERT(offsetof(IsEnabled, result_shm_id) == 8,
+ OffsetOf_IsEnabled_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsEnabled, result_shm_offset) == 12,
+ OffsetOf_IsEnabled_result_shm_offset_not_12);
+
+struct IsFramebuffer {
+ typedef IsFramebuffer ValueType;
+ static const CommandId kCmdId = kIsFramebuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _framebuffer, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ framebuffer = _framebuffer;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _framebuffer, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_framebuffer, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 framebuffer;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsFramebuffer) == 16,
+ Sizeof_IsFramebuffer_is_not_16);
+COMPILE_ASSERT(offsetof(IsFramebuffer, header) == 0,
+ OffsetOf_IsFramebuffer_header_not_0);
+COMPILE_ASSERT(offsetof(IsFramebuffer, framebuffer) == 4,
+ OffsetOf_IsFramebuffer_framebuffer_not_4);
+COMPILE_ASSERT(offsetof(IsFramebuffer, result_shm_id) == 8,
+ OffsetOf_IsFramebuffer_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsFramebuffer, result_shm_offset) == 12,
+ OffsetOf_IsFramebuffer_result_shm_offset_not_12);
+
+struct IsProgram {
+ typedef IsProgram ValueType;
+ static const CommandId kCmdId = kIsProgram;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ program = _program;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_program, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsProgram) == 16,
+ Sizeof_IsProgram_is_not_16);
+COMPILE_ASSERT(offsetof(IsProgram, header) == 0,
+ OffsetOf_IsProgram_header_not_0);
+COMPILE_ASSERT(offsetof(IsProgram, program) == 4,
+ OffsetOf_IsProgram_program_not_4);
+COMPILE_ASSERT(offsetof(IsProgram, result_shm_id) == 8,
+ OffsetOf_IsProgram_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsProgram, result_shm_offset) == 12,
+ OffsetOf_IsProgram_result_shm_offset_not_12);
+
+struct IsRenderbuffer {
+ typedef IsRenderbuffer ValueType;
+ static const CommandId kCmdId = kIsRenderbuffer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _renderbuffer, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ renderbuffer = _renderbuffer;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _renderbuffer, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_renderbuffer, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 renderbuffer;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsRenderbuffer) == 16,
+ Sizeof_IsRenderbuffer_is_not_16);
+COMPILE_ASSERT(offsetof(IsRenderbuffer, header) == 0,
+ OffsetOf_IsRenderbuffer_header_not_0);
+COMPILE_ASSERT(offsetof(IsRenderbuffer, renderbuffer) == 4,
+ OffsetOf_IsRenderbuffer_renderbuffer_not_4);
+COMPILE_ASSERT(offsetof(IsRenderbuffer, result_shm_id) == 8,
+ OffsetOf_IsRenderbuffer_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsRenderbuffer, result_shm_offset) == 12,
+ OffsetOf_IsRenderbuffer_result_shm_offset_not_12);
+
+struct IsShader {
+ typedef IsShader ValueType;
+ static const CommandId kCmdId = kIsShader;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ shader = _shader;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _shader, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_shader, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsShader) == 16,
+ Sizeof_IsShader_is_not_16);
+COMPILE_ASSERT(offsetof(IsShader, header) == 0,
+ OffsetOf_IsShader_header_not_0);
+COMPILE_ASSERT(offsetof(IsShader, shader) == 4,
+ OffsetOf_IsShader_shader_not_4);
+COMPILE_ASSERT(offsetof(IsShader, result_shm_id) == 8,
+ OffsetOf_IsShader_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsShader, result_shm_offset) == 12,
+ OffsetOf_IsShader_result_shm_offset_not_12);
+
+struct IsTexture {
+ typedef IsTexture ValueType;
+ static const CommandId kCmdId = kIsTexture;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _texture, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ texture = _texture;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _texture, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_texture, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 texture;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsTexture) == 16,
+ Sizeof_IsTexture_is_not_16);
+COMPILE_ASSERT(offsetof(IsTexture, header) == 0,
+ OffsetOf_IsTexture_header_not_0);
+COMPILE_ASSERT(offsetof(IsTexture, texture) == 4,
+ OffsetOf_IsTexture_texture_not_4);
+COMPILE_ASSERT(offsetof(IsTexture, result_shm_id) == 8,
+ OffsetOf_IsTexture_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsTexture, result_shm_offset) == 12,
+ OffsetOf_IsTexture_result_shm_offset_not_12);
+
+struct LineWidth {
+ typedef LineWidth ValueType;
+ static const CommandId kCmdId = kLineWidth;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLfloat _width) {
+ SetHeader();
+ width = _width;
+ }
+
+ void* Set(void* cmd, GLfloat _width) {
+ static_cast<ValueType*>(cmd)->Init(_width);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float width;
+};
+
+COMPILE_ASSERT(sizeof(LineWidth) == 8,
+ Sizeof_LineWidth_is_not_8);
+COMPILE_ASSERT(offsetof(LineWidth, header) == 0,
+ OffsetOf_LineWidth_header_not_0);
+COMPILE_ASSERT(offsetof(LineWidth, width) == 4,
+ OffsetOf_LineWidth_width_not_4);
+
+struct LinkProgram {
+ typedef LinkProgram ValueType;
+ static const CommandId kCmdId = kLinkProgram;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program) {
+ SetHeader();
+ program = _program;
+ }
+
+ void* Set(void* cmd, GLuint _program) {
+ static_cast<ValueType*>(cmd)->Init(_program);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+};
+
+COMPILE_ASSERT(sizeof(LinkProgram) == 8,
+ Sizeof_LinkProgram_is_not_8);
+COMPILE_ASSERT(offsetof(LinkProgram, header) == 0,
+ OffsetOf_LinkProgram_header_not_0);
+COMPILE_ASSERT(offsetof(LinkProgram, program) == 4,
+ OffsetOf_LinkProgram_program_not_4);
+
+struct PixelStorei {
+ typedef PixelStorei ValueType;
+ static const CommandId kCmdId = kPixelStorei;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _pname, GLint _param) {
+ SetHeader();
+ pname = _pname;
+ param = _param;
+ }
+
+ void* Set(void* cmd, GLenum _pname, GLint _param) {
+ static_cast<ValueType*>(cmd)->Init(_pname, _param);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 pname;
+ int32 param;
+};
+
+COMPILE_ASSERT(sizeof(PixelStorei) == 12,
+ Sizeof_PixelStorei_is_not_12);
+COMPILE_ASSERT(offsetof(PixelStorei, header) == 0,
+ OffsetOf_PixelStorei_header_not_0);
+COMPILE_ASSERT(offsetof(PixelStorei, pname) == 4,
+ OffsetOf_PixelStorei_pname_not_4);
+COMPILE_ASSERT(offsetof(PixelStorei, param) == 8,
+ OffsetOf_PixelStorei_param_not_8);
+
+struct PolygonOffset {
+ typedef PolygonOffset ValueType;
+ static const CommandId kCmdId = kPolygonOffset;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLfloat _factor, GLfloat _units) {
+ SetHeader();
+ factor = _factor;
+ units = _units;
+ }
+
+ void* Set(void* cmd, GLfloat _factor, GLfloat _units) {
+ static_cast<ValueType*>(cmd)->Init(_factor, _units);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float factor;
+ float units;
+};
+
+COMPILE_ASSERT(sizeof(PolygonOffset) == 12,
+ Sizeof_PolygonOffset_is_not_12);
+COMPILE_ASSERT(offsetof(PolygonOffset, header) == 0,
+ OffsetOf_PolygonOffset_header_not_0);
+COMPILE_ASSERT(offsetof(PolygonOffset, factor) == 4,
+ OffsetOf_PolygonOffset_factor_not_4);
+COMPILE_ASSERT(offsetof(PolygonOffset, units) == 8,
+ OffsetOf_PolygonOffset_units_not_8);
+
+// ReadPixels has the result separated from the pixel buffer so that
+// it is easier to specify the result going to some specific place
+// that exactly fits the rectangle of pixels.
+struct ReadPixels {
+ typedef ReadPixels ValueType;
+ static const CommandId kCmdId = kReadPixels;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _x, GLint _y, GLsizei _width, GLsizei _height, GLenum _format,
+ GLenum _type, uint32 _pixels_shm_id, uint32 _pixels_shm_offset,
+ uint32 _result_shm_id, uint32 _result_shm_offset, GLboolean _async) {
+ SetHeader();
+ x = _x;
+ y = _y;
+ width = _width;
+ height = _height;
+ format = _format;
+ type = _type;
+ pixels_shm_id = _pixels_shm_id;
+ pixels_shm_offset = _pixels_shm_offset;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ async = _async;
+ }
+
+ void* Set(
+ void* cmd, GLint _x, GLint _y, GLsizei _width, GLsizei _height,
+ GLenum _format, GLenum _type, uint32 _pixels_shm_id,
+ uint32 _pixels_shm_offset, uint32 _result_shm_id,
+ uint32 _result_shm_offset, GLboolean _async) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _x, _y, _width, _height, _format, _type, _pixels_shm_id,
+ _pixels_shm_offset, _result_shm_id, _result_shm_offset, _async);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+ uint32 format;
+ uint32 type;
+ uint32 pixels_shm_id;
+ uint32 pixels_shm_offset;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+ uint32 async;
+};
+
+COMPILE_ASSERT(sizeof(ReadPixels) == 48,
+ Sizeof_ReadPixels_is_not_48);
+COMPILE_ASSERT(offsetof(ReadPixels, header) == 0,
+ OffsetOf_ReadPixels_header_not_0);
+COMPILE_ASSERT(offsetof(ReadPixels, x) == 4,
+ OffsetOf_ReadPixels_x_not_4);
+COMPILE_ASSERT(offsetof(ReadPixels, y) == 8,
+ OffsetOf_ReadPixels_y_not_8);
+COMPILE_ASSERT(offsetof(ReadPixels, width) == 12,
+ OffsetOf_ReadPixels_width_not_12);
+COMPILE_ASSERT(offsetof(ReadPixels, height) == 16,
+ OffsetOf_ReadPixels_height_not_16);
+COMPILE_ASSERT(offsetof(ReadPixels, format) == 20,
+ OffsetOf_ReadPixels_format_not_20);
+COMPILE_ASSERT(offsetof(ReadPixels, type) == 24,
+ OffsetOf_ReadPixels_type_not_24);
+COMPILE_ASSERT(offsetof(ReadPixels, pixels_shm_id) == 28,
+ OffsetOf_ReadPixels_pixels_shm_id_not_28);
+COMPILE_ASSERT(offsetof(ReadPixels, pixels_shm_offset) == 32,
+ OffsetOf_ReadPixels_pixels_shm_offset_not_32);
+COMPILE_ASSERT(offsetof(ReadPixels, result_shm_id) == 36,
+ OffsetOf_ReadPixels_result_shm_id_not_36);
+COMPILE_ASSERT(offsetof(ReadPixels, result_shm_offset) == 40,
+ OffsetOf_ReadPixels_result_shm_offset_not_40);
+COMPILE_ASSERT(offsetof(ReadPixels, async) == 44,
+ OffsetOf_ReadPixels_async_not_44);
+
+struct ReleaseShaderCompiler {
+ typedef ReleaseShaderCompiler ValueType;
+ static const CommandId kCmdId = kReleaseShaderCompiler;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(ReleaseShaderCompiler) == 4,
+ Sizeof_ReleaseShaderCompiler_is_not_4);
+COMPILE_ASSERT(offsetof(ReleaseShaderCompiler, header) == 0,
+ OffsetOf_ReleaseShaderCompiler_header_not_0);
+
+struct RenderbufferStorage {
+ typedef RenderbufferStorage ValueType;
+ static const CommandId kCmdId = kRenderbufferStorage;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _internalformat, GLsizei _width,
+ GLsizei _height) {
+ SetHeader();
+ target = _target;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _internalformat, GLsizei _width,
+ GLsizei _height) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _internalformat, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 internalformat;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(RenderbufferStorage) == 20,
+ Sizeof_RenderbufferStorage_is_not_20);
+COMPILE_ASSERT(offsetof(RenderbufferStorage, header) == 0,
+ OffsetOf_RenderbufferStorage_header_not_0);
+COMPILE_ASSERT(offsetof(RenderbufferStorage, target) == 4,
+ OffsetOf_RenderbufferStorage_target_not_4);
+COMPILE_ASSERT(offsetof(RenderbufferStorage, internalformat) == 8,
+ OffsetOf_RenderbufferStorage_internalformat_not_8);
+COMPILE_ASSERT(offsetof(RenderbufferStorage, width) == 12,
+ OffsetOf_RenderbufferStorage_width_not_12);
+COMPILE_ASSERT(offsetof(RenderbufferStorage, height) == 16,
+ OffsetOf_RenderbufferStorage_height_not_16);
+
+struct SampleCoverage {
+ typedef SampleCoverage ValueType;
+ static const CommandId kCmdId = kSampleCoverage;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLclampf _value, GLboolean _invert) {
+ SetHeader();
+ value = _value;
+ invert = _invert;
+ }
+
+ void* Set(void* cmd, GLclampf _value, GLboolean _invert) {
+ static_cast<ValueType*>(cmd)->Init(_value, _invert);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ float value;
+ uint32 invert;
+};
+
+COMPILE_ASSERT(sizeof(SampleCoverage) == 12,
+ Sizeof_SampleCoverage_is_not_12);
+COMPILE_ASSERT(offsetof(SampleCoverage, header) == 0,
+ OffsetOf_SampleCoverage_header_not_0);
+COMPILE_ASSERT(offsetof(SampleCoverage, value) == 4,
+ OffsetOf_SampleCoverage_value_not_4);
+COMPILE_ASSERT(offsetof(SampleCoverage, invert) == 8,
+ OffsetOf_SampleCoverage_invert_not_8);
+
+struct Scissor {
+ typedef Scissor ValueType;
+ static const CommandId kCmdId = kScissor;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _x, GLint _y, GLsizei _width, GLsizei _height) {
+ SetHeader();
+ x = _x;
+ y = _y;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(void* cmd, GLint _x, GLint _y, GLsizei _width, GLsizei _height) {
+ static_cast<ValueType*>(cmd)->Init(_x, _y, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(Scissor) == 20,
+ Sizeof_Scissor_is_not_20);
+COMPILE_ASSERT(offsetof(Scissor, header) == 0,
+ OffsetOf_Scissor_header_not_0);
+COMPILE_ASSERT(offsetof(Scissor, x) == 4,
+ OffsetOf_Scissor_x_not_4);
+COMPILE_ASSERT(offsetof(Scissor, y) == 8,
+ OffsetOf_Scissor_y_not_8);
+COMPILE_ASSERT(offsetof(Scissor, width) == 12,
+ OffsetOf_Scissor_width_not_12);
+COMPILE_ASSERT(offsetof(Scissor, height) == 16,
+ OffsetOf_Scissor_height_not_16);
+
+struct ShaderBinary {
+ typedef ShaderBinary ValueType;
+ static const CommandId kCmdId = kShaderBinary;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLsizei _n, uint32 _shaders_shm_id, uint32 _shaders_shm_offset,
+ GLenum _binaryformat, uint32 _binary_shm_id, uint32 _binary_shm_offset,
+ GLsizei _length) {
+ SetHeader();
+ n = _n;
+ shaders_shm_id = _shaders_shm_id;
+ shaders_shm_offset = _shaders_shm_offset;
+ binaryformat = _binaryformat;
+ binary_shm_id = _binary_shm_id;
+ binary_shm_offset = _binary_shm_offset;
+ length = _length;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _shaders_shm_id, uint32 _shaders_shm_offset,
+ GLenum _binaryformat, uint32 _binary_shm_id, uint32 _binary_shm_offset,
+ GLsizei _length) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _n, _shaders_shm_id, _shaders_shm_offset, _binaryformat,
+ _binary_shm_id, _binary_shm_offset, _length);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 shaders_shm_id;
+ uint32 shaders_shm_offset;
+ uint32 binaryformat;
+ uint32 binary_shm_id;
+ uint32 binary_shm_offset;
+ int32 length;
+};
+
+COMPILE_ASSERT(sizeof(ShaderBinary) == 32,
+ Sizeof_ShaderBinary_is_not_32);
+COMPILE_ASSERT(offsetof(ShaderBinary, header) == 0,
+ OffsetOf_ShaderBinary_header_not_0);
+COMPILE_ASSERT(offsetof(ShaderBinary, n) == 4,
+ OffsetOf_ShaderBinary_n_not_4);
+COMPILE_ASSERT(offsetof(ShaderBinary, shaders_shm_id) == 8,
+ OffsetOf_ShaderBinary_shaders_shm_id_not_8);
+COMPILE_ASSERT(offsetof(ShaderBinary, shaders_shm_offset) == 12,
+ OffsetOf_ShaderBinary_shaders_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(ShaderBinary, binaryformat) == 16,
+ OffsetOf_ShaderBinary_binaryformat_not_16);
+COMPILE_ASSERT(offsetof(ShaderBinary, binary_shm_id) == 20,
+ OffsetOf_ShaderBinary_binary_shm_id_not_20);
+COMPILE_ASSERT(offsetof(ShaderBinary, binary_shm_offset) == 24,
+ OffsetOf_ShaderBinary_binary_shm_offset_not_24);
+COMPILE_ASSERT(offsetof(ShaderBinary, length) == 28,
+ OffsetOf_ShaderBinary_length_not_28);
+
+struct ShaderSource {
+ typedef ShaderSource ValueType;
+ static const CommandId kCmdId = kShaderSource;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _shader, uint32 _data_shm_id, uint32 _data_shm_offset,
+ uint32 _data_size) {
+ SetHeader();
+ shader = _shader;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ data_size = _data_size;
+ }
+
+ void* Set(
+ void* cmd, GLuint _shader, uint32 _data_shm_id, uint32 _data_shm_offset,
+ uint32 _data_size) {
+ static_cast<ValueType*>(
+ cmd)->Init(_shader, _data_shm_id, _data_shm_offset, _data_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 data_shm_id;
+ uint32 data_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(ShaderSource) == 20,
+ Sizeof_ShaderSource_is_not_20);
+COMPILE_ASSERT(offsetof(ShaderSource, header) == 0,
+ OffsetOf_ShaderSource_header_not_0);
+COMPILE_ASSERT(offsetof(ShaderSource, shader) == 4,
+ OffsetOf_ShaderSource_shader_not_4);
+COMPILE_ASSERT(offsetof(ShaderSource, data_shm_id) == 8,
+ OffsetOf_ShaderSource_data_shm_id_not_8);
+COMPILE_ASSERT(offsetof(ShaderSource, data_shm_offset) == 12,
+ OffsetOf_ShaderSource_data_shm_offset_not_12);
+COMPILE_ASSERT(offsetof(ShaderSource, data_size) == 16,
+ OffsetOf_ShaderSource_data_size_not_16);
+
+struct ShaderSourceImmediate {
+ typedef ShaderSourceImmediate ValueType;
+ static const CommandId kCmdId = kShaderSourceImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(GLuint _shader, uint32 _data_size) {
+ uint32 total_size = ComputeSize(_data_size);
+ SetHeader(total_size);
+ shader = _shader;
+ data_size = _data_size;
+ }
+
+ void* Set(void* cmd, GLuint _shader, uint32 _data_size) {
+ uint32 total_size = ComputeSize(_data_size);
+ static_cast<ValueType*>(cmd)->Init(_shader, _data_size);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(ShaderSourceImmediate) == 12,
+ Sizeof_ShaderSourceImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(ShaderSourceImmediate, header) == 0,
+ OffsetOf_ShaderSourceImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(ShaderSourceImmediate, shader) == 4,
+ OffsetOf_ShaderSourceImmediate_shader_not_4);
+COMPILE_ASSERT(offsetof(ShaderSourceImmediate, data_size) == 8,
+ OffsetOf_ShaderSourceImmediate_data_size_not_8);
+
+struct ShaderSourceBucket {
+ typedef ShaderSourceBucket ValueType;
+ static const CommandId kCmdId = kShaderSourceBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader, uint32 _data_bucket_id) {
+ SetHeader();
+ shader = _shader;
+ data_bucket_id = _data_bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _shader, uint32 _data_bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_shader, _data_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 data_bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(ShaderSourceBucket) == 12,
+ Sizeof_ShaderSourceBucket_is_not_12);
+COMPILE_ASSERT(offsetof(ShaderSourceBucket, header) == 0,
+ OffsetOf_ShaderSourceBucket_header_not_0);
+COMPILE_ASSERT(offsetof(ShaderSourceBucket, shader) == 4,
+ OffsetOf_ShaderSourceBucket_shader_not_4);
+COMPILE_ASSERT(offsetof(ShaderSourceBucket, data_bucket_id) == 8,
+ OffsetOf_ShaderSourceBucket_data_bucket_id_not_8);
+
+struct StencilFunc {
+ typedef StencilFunc ValueType;
+ static const CommandId kCmdId = kStencilFunc;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _func, GLint _ref, GLuint _mask) {
+ SetHeader();
+ func = _func;
+ ref = _ref;
+ mask = _mask;
+ }
+
+ void* Set(void* cmd, GLenum _func, GLint _ref, GLuint _mask) {
+ static_cast<ValueType*>(cmd)->Init(_func, _ref, _mask);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 func;
+ int32 ref;
+ uint32 mask;
+};
+
+COMPILE_ASSERT(sizeof(StencilFunc) == 16,
+ Sizeof_StencilFunc_is_not_16);
+COMPILE_ASSERT(offsetof(StencilFunc, header) == 0,
+ OffsetOf_StencilFunc_header_not_0);
+COMPILE_ASSERT(offsetof(StencilFunc, func) == 4,
+ OffsetOf_StencilFunc_func_not_4);
+COMPILE_ASSERT(offsetof(StencilFunc, ref) == 8,
+ OffsetOf_StencilFunc_ref_not_8);
+COMPILE_ASSERT(offsetof(StencilFunc, mask) == 12,
+ OffsetOf_StencilFunc_mask_not_12);
+
+struct StencilFuncSeparate {
+ typedef StencilFuncSeparate ValueType;
+ static const CommandId kCmdId = kStencilFuncSeparate;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _face, GLenum _func, GLint _ref, GLuint _mask) {
+ SetHeader();
+ face = _face;
+ func = _func;
+ ref = _ref;
+ mask = _mask;
+ }
+
+ void* Set(void* cmd, GLenum _face, GLenum _func, GLint _ref, GLuint _mask) {
+ static_cast<ValueType*>(cmd)->Init(_face, _func, _ref, _mask);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 face;
+ uint32 func;
+ int32 ref;
+ uint32 mask;
+};
+
+COMPILE_ASSERT(sizeof(StencilFuncSeparate) == 20,
+ Sizeof_StencilFuncSeparate_is_not_20);
+COMPILE_ASSERT(offsetof(StencilFuncSeparate, header) == 0,
+ OffsetOf_StencilFuncSeparate_header_not_0);
+COMPILE_ASSERT(offsetof(StencilFuncSeparate, face) == 4,
+ OffsetOf_StencilFuncSeparate_face_not_4);
+COMPILE_ASSERT(offsetof(StencilFuncSeparate, func) == 8,
+ OffsetOf_StencilFuncSeparate_func_not_8);
+COMPILE_ASSERT(offsetof(StencilFuncSeparate, ref) == 12,
+ OffsetOf_StencilFuncSeparate_ref_not_12);
+COMPILE_ASSERT(offsetof(StencilFuncSeparate, mask) == 16,
+ OffsetOf_StencilFuncSeparate_mask_not_16);
+
+struct StencilMask {
+ typedef StencilMask ValueType;
+ static const CommandId kCmdId = kStencilMask;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _mask) {
+ SetHeader();
+ mask = _mask;
+ }
+
+ void* Set(void* cmd, GLuint _mask) {
+ static_cast<ValueType*>(cmd)->Init(_mask);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mask;
+};
+
+COMPILE_ASSERT(sizeof(StencilMask) == 8,
+ Sizeof_StencilMask_is_not_8);
+COMPILE_ASSERT(offsetof(StencilMask, header) == 0,
+ OffsetOf_StencilMask_header_not_0);
+COMPILE_ASSERT(offsetof(StencilMask, mask) == 4,
+ OffsetOf_StencilMask_mask_not_4);
+
+struct StencilMaskSeparate {
+ typedef StencilMaskSeparate ValueType;
+ static const CommandId kCmdId = kStencilMaskSeparate;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _face, GLuint _mask) {
+ SetHeader();
+ face = _face;
+ mask = _mask;
+ }
+
+ void* Set(void* cmd, GLenum _face, GLuint _mask) {
+ static_cast<ValueType*>(cmd)->Init(_face, _mask);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 face;
+ uint32 mask;
+};
+
+COMPILE_ASSERT(sizeof(StencilMaskSeparate) == 12,
+ Sizeof_StencilMaskSeparate_is_not_12);
+COMPILE_ASSERT(offsetof(StencilMaskSeparate, header) == 0,
+ OffsetOf_StencilMaskSeparate_header_not_0);
+COMPILE_ASSERT(offsetof(StencilMaskSeparate, face) == 4,
+ OffsetOf_StencilMaskSeparate_face_not_4);
+COMPILE_ASSERT(offsetof(StencilMaskSeparate, mask) == 8,
+ OffsetOf_StencilMaskSeparate_mask_not_8);
+
+struct StencilOp {
+ typedef StencilOp ValueType;
+ static const CommandId kCmdId = kStencilOp;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _fail, GLenum _zfail, GLenum _zpass) {
+ SetHeader();
+ fail = _fail;
+ zfail = _zfail;
+ zpass = _zpass;
+ }
+
+ void* Set(void* cmd, GLenum _fail, GLenum _zfail, GLenum _zpass) {
+ static_cast<ValueType*>(cmd)->Init(_fail, _zfail, _zpass);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 fail;
+ uint32 zfail;
+ uint32 zpass;
+};
+
+COMPILE_ASSERT(sizeof(StencilOp) == 16,
+ Sizeof_StencilOp_is_not_16);
+COMPILE_ASSERT(offsetof(StencilOp, header) == 0,
+ OffsetOf_StencilOp_header_not_0);
+COMPILE_ASSERT(offsetof(StencilOp, fail) == 4,
+ OffsetOf_StencilOp_fail_not_4);
+COMPILE_ASSERT(offsetof(StencilOp, zfail) == 8,
+ OffsetOf_StencilOp_zfail_not_8);
+COMPILE_ASSERT(offsetof(StencilOp, zpass) == 12,
+ OffsetOf_StencilOp_zpass_not_12);
+
+struct StencilOpSeparate {
+ typedef StencilOpSeparate ValueType;
+ static const CommandId kCmdId = kStencilOpSeparate;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _face, GLenum _fail, GLenum _zfail, GLenum _zpass) {
+ SetHeader();
+ face = _face;
+ fail = _fail;
+ zfail = _zfail;
+ zpass = _zpass;
+ }
+
+ void* Set(
+ void* cmd, GLenum _face, GLenum _fail, GLenum _zfail, GLenum _zpass) {
+ static_cast<ValueType*>(cmd)->Init(_face, _fail, _zfail, _zpass);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 face;
+ uint32 fail;
+ uint32 zfail;
+ uint32 zpass;
+};
+
+COMPILE_ASSERT(sizeof(StencilOpSeparate) == 20,
+ Sizeof_StencilOpSeparate_is_not_20);
+COMPILE_ASSERT(offsetof(StencilOpSeparate, header) == 0,
+ OffsetOf_StencilOpSeparate_header_not_0);
+COMPILE_ASSERT(offsetof(StencilOpSeparate, face) == 4,
+ OffsetOf_StencilOpSeparate_face_not_4);
+COMPILE_ASSERT(offsetof(StencilOpSeparate, fail) == 8,
+ OffsetOf_StencilOpSeparate_fail_not_8);
+COMPILE_ASSERT(offsetof(StencilOpSeparate, zfail) == 12,
+ OffsetOf_StencilOpSeparate_zfail_not_12);
+COMPILE_ASSERT(offsetof(StencilOpSeparate, zpass) == 16,
+ OffsetOf_StencilOpSeparate_zpass_not_16);
+
+struct TexImage2D {
+ typedef TexImage2D ValueType;
+ static const CommandId kCmdId = kTexImage2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _internalformat, GLsizei _width,
+ GLsizei _height, GLint _border, GLenum _format, GLenum _type,
+ uint32 _pixels_shm_id, uint32 _pixels_shm_offset) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ border = _border;
+ format = _format;
+ type = _type;
+ pixels_shm_id = _pixels_shm_id;
+ pixels_shm_offset = _pixels_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _internalformat,
+ GLsizei _width, GLsizei _height, GLint _border, GLenum _format,
+ GLenum _type, uint32 _pixels_shm_id, uint32 _pixels_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _width, _height, _border, _format,
+ _type, _pixels_shm_id, _pixels_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 internalformat;
+ int32 width;
+ int32 height;
+ int32 border;
+ uint32 format;
+ uint32 type;
+ uint32 pixels_shm_id;
+ uint32 pixels_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(TexImage2D) == 44,
+ Sizeof_TexImage2D_is_not_44);
+COMPILE_ASSERT(offsetof(TexImage2D, header) == 0,
+ OffsetOf_TexImage2D_header_not_0);
+COMPILE_ASSERT(offsetof(TexImage2D, target) == 4,
+ OffsetOf_TexImage2D_target_not_4);
+COMPILE_ASSERT(offsetof(TexImage2D, level) == 8,
+ OffsetOf_TexImage2D_level_not_8);
+COMPILE_ASSERT(offsetof(TexImage2D, internalformat) == 12,
+ OffsetOf_TexImage2D_internalformat_not_12);
+COMPILE_ASSERT(offsetof(TexImage2D, width) == 16,
+ OffsetOf_TexImage2D_width_not_16);
+COMPILE_ASSERT(offsetof(TexImage2D, height) == 20,
+ OffsetOf_TexImage2D_height_not_20);
+COMPILE_ASSERT(offsetof(TexImage2D, border) == 24,
+ OffsetOf_TexImage2D_border_not_24);
+COMPILE_ASSERT(offsetof(TexImage2D, format) == 28,
+ OffsetOf_TexImage2D_format_not_28);
+COMPILE_ASSERT(offsetof(TexImage2D, type) == 32,
+ OffsetOf_TexImage2D_type_not_32);
+COMPILE_ASSERT(offsetof(TexImage2D, pixels_shm_id) == 36,
+ OffsetOf_TexImage2D_pixels_shm_id_not_36);
+COMPILE_ASSERT(offsetof(TexImage2D, pixels_shm_offset) == 40,
+ OffsetOf_TexImage2D_pixels_shm_offset_not_40);
+
+struct TexImage2DImmediate {
+ typedef TexImage2DImmediate ValueType;
+ static const CommandId kCmdId = kTexImage2DImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _internalformat, GLsizei _width,
+ GLsizei _height, GLint _border, GLenum _format, GLenum _type) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ SetHeader(total_size);
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ border = _border;
+ format = _format;
+ type = _type;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _internalformat,
+ GLsizei _width, GLsizei _height, GLint _border, GLenum _format,
+ GLenum _type) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _width, _height, _border, _format,
+ _type);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 internalformat;
+ int32 width;
+ int32 height;
+ int32 border;
+ uint32 format;
+ uint32 type;
+};
+
+COMPILE_ASSERT(sizeof(TexImage2DImmediate) == 36,
+ Sizeof_TexImage2DImmediate_is_not_36);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, header) == 0,
+ OffsetOf_TexImage2DImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, target) == 4,
+ OffsetOf_TexImage2DImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, level) == 8,
+ OffsetOf_TexImage2DImmediate_level_not_8);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, internalformat) == 12,
+ OffsetOf_TexImage2DImmediate_internalformat_not_12);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, width) == 16,
+ OffsetOf_TexImage2DImmediate_width_not_16);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, height) == 20,
+ OffsetOf_TexImage2DImmediate_height_not_20);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, border) == 24,
+ OffsetOf_TexImage2DImmediate_border_not_24);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, format) == 28,
+ OffsetOf_TexImage2DImmediate_format_not_28);
+COMPILE_ASSERT(offsetof(TexImage2DImmediate, type) == 32,
+ OffsetOf_TexImage2DImmediate_type_not_32);
+
+struct TexParameterf {
+ typedef TexParameterf ValueType;
+ static const CommandId kCmdId = kTexParameterf;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLenum _pname, GLfloat _param) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ param = _param;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLenum _pname, GLfloat _param) {
+ static_cast<ValueType*>(cmd)->Init(_target, _pname, _param);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ float param;
+};
+
+COMPILE_ASSERT(sizeof(TexParameterf) == 16,
+ Sizeof_TexParameterf_is_not_16);
+COMPILE_ASSERT(offsetof(TexParameterf, header) == 0,
+ OffsetOf_TexParameterf_header_not_0);
+COMPILE_ASSERT(offsetof(TexParameterf, target) == 4,
+ OffsetOf_TexParameterf_target_not_4);
+COMPILE_ASSERT(offsetof(TexParameterf, pname) == 8,
+ OffsetOf_TexParameterf_pname_not_8);
+COMPILE_ASSERT(offsetof(TexParameterf, param) == 12,
+ OffsetOf_TexParameterf_param_not_12);
+
+struct TexParameterfv {
+ typedef TexParameterfv ValueType;
+ static const CommandId kCmdId = kTexParameterfv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(TexParameterfv) == 20,
+ Sizeof_TexParameterfv_is_not_20);
+COMPILE_ASSERT(offsetof(TexParameterfv, header) == 0,
+ OffsetOf_TexParameterfv_header_not_0);
+COMPILE_ASSERT(offsetof(TexParameterfv, target) == 4,
+ OffsetOf_TexParameterfv_target_not_4);
+COMPILE_ASSERT(offsetof(TexParameterfv, pname) == 8,
+ OffsetOf_TexParameterfv_pname_not_8);
+COMPILE_ASSERT(offsetof(TexParameterfv, params_shm_id) == 12,
+ OffsetOf_TexParameterfv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(TexParameterfv, params_shm_offset) == 16,
+ OffsetOf_TexParameterfv_params_shm_offset_not_16);
+
+struct TexParameterfvImmediate {
+ typedef TexParameterfvImmediate ValueType;
+ static const CommandId kCmdId = kTexParameterfvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 1); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLenum _target, GLenum _pname, const GLfloat* _params) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ memcpy(ImmediateDataAddress(this),
+ _params, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLenum _target, GLenum _pname, const GLfloat* _params) {
+ static_cast<ValueType*>(cmd)->Init(_target, _pname, _params);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+};
+
+COMPILE_ASSERT(sizeof(TexParameterfvImmediate) == 12,
+ Sizeof_TexParameterfvImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(TexParameterfvImmediate, header) == 0,
+ OffsetOf_TexParameterfvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(TexParameterfvImmediate, target) == 4,
+ OffsetOf_TexParameterfvImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(TexParameterfvImmediate, pname) == 8,
+ OffsetOf_TexParameterfvImmediate_pname_not_8);
+
+struct TexParameteri {
+ typedef TexParameteri ValueType;
+ static const CommandId kCmdId = kTexParameteri;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLenum _pname, GLint _param) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ param = _param;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLenum _pname, GLint _param) {
+ static_cast<ValueType*>(cmd)->Init(_target, _pname, _param);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ int32 param;
+};
+
+COMPILE_ASSERT(sizeof(TexParameteri) == 16,
+ Sizeof_TexParameteri_is_not_16);
+COMPILE_ASSERT(offsetof(TexParameteri, header) == 0,
+ OffsetOf_TexParameteri_header_not_0);
+COMPILE_ASSERT(offsetof(TexParameteri, target) == 4,
+ OffsetOf_TexParameteri_target_not_4);
+COMPILE_ASSERT(offsetof(TexParameteri, pname) == 8,
+ OffsetOf_TexParameteri_pname_not_8);
+COMPILE_ASSERT(offsetof(TexParameteri, param) == 12,
+ OffsetOf_TexParameteri_param_not_12);
+
+struct TexParameteriv {
+ typedef TexParameteriv ValueType;
+ static const CommandId kCmdId = kTexParameteriv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ params_shm_id = _params_shm_id;
+ params_shm_offset = _params_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _pname, uint32 _params_shm_id,
+ uint32 _params_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _pname, _params_shm_id, _params_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+ uint32 params_shm_id;
+ uint32 params_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(TexParameteriv) == 20,
+ Sizeof_TexParameteriv_is_not_20);
+COMPILE_ASSERT(offsetof(TexParameteriv, header) == 0,
+ OffsetOf_TexParameteriv_header_not_0);
+COMPILE_ASSERT(offsetof(TexParameteriv, target) == 4,
+ OffsetOf_TexParameteriv_target_not_4);
+COMPILE_ASSERT(offsetof(TexParameteriv, pname) == 8,
+ OffsetOf_TexParameteriv_pname_not_8);
+COMPILE_ASSERT(offsetof(TexParameteriv, params_shm_id) == 12,
+ OffsetOf_TexParameteriv_params_shm_id_not_12);
+COMPILE_ASSERT(offsetof(TexParameteriv, params_shm_offset) == 16,
+ OffsetOf_TexParameteriv_params_shm_offset_not_16);
+
+struct TexParameterivImmediate {
+ typedef TexParameterivImmediate ValueType;
+ static const CommandId kCmdId = kTexParameterivImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLint) * 1); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLenum _target, GLenum _pname, const GLint* _params) {
+ SetHeader();
+ target = _target;
+ pname = _pname;
+ memcpy(ImmediateDataAddress(this),
+ _params, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLenum _target, GLenum _pname, const GLint* _params) {
+ static_cast<ValueType*>(cmd)->Init(_target, _pname, _params);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 pname;
+};
+
+COMPILE_ASSERT(sizeof(TexParameterivImmediate) == 12,
+ Sizeof_TexParameterivImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(TexParameterivImmediate, header) == 0,
+ OffsetOf_TexParameterivImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(TexParameterivImmediate, target) == 4,
+ OffsetOf_TexParameterivImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(TexParameterivImmediate, pname) == 8,
+ OffsetOf_TexParameterivImmediate_pname_not_8);
+
+struct TexSubImage2D {
+ typedef TexSubImage2D ValueType;
+ static const CommandId kCmdId = kTexSubImage2D;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLenum _type,
+ uint32 _pixels_shm_id, uint32 _pixels_shm_offset, GLboolean _internal) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ width = _width;
+ height = _height;
+ format = _format;
+ type = _type;
+ pixels_shm_id = _pixels_shm_id;
+ pixels_shm_offset = _pixels_shm_offset;
+ internal = _internal;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLenum _type,
+ uint32 _pixels_shm_id, uint32 _pixels_shm_offset, GLboolean _internal) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _width, _height, _format,
+ _type, _pixels_shm_id, _pixels_shm_offset, _internal);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 width;
+ int32 height;
+ uint32 format;
+ uint32 type;
+ uint32 pixels_shm_id;
+ uint32 pixels_shm_offset;
+ uint32 internal;
+};
+
+COMPILE_ASSERT(sizeof(TexSubImage2D) == 48,
+ Sizeof_TexSubImage2D_is_not_48);
+COMPILE_ASSERT(offsetof(TexSubImage2D, header) == 0,
+ OffsetOf_TexSubImage2D_header_not_0);
+COMPILE_ASSERT(offsetof(TexSubImage2D, target) == 4,
+ OffsetOf_TexSubImage2D_target_not_4);
+COMPILE_ASSERT(offsetof(TexSubImage2D, level) == 8,
+ OffsetOf_TexSubImage2D_level_not_8);
+COMPILE_ASSERT(offsetof(TexSubImage2D, xoffset) == 12,
+ OffsetOf_TexSubImage2D_xoffset_not_12);
+COMPILE_ASSERT(offsetof(TexSubImage2D, yoffset) == 16,
+ OffsetOf_TexSubImage2D_yoffset_not_16);
+COMPILE_ASSERT(offsetof(TexSubImage2D, width) == 20,
+ OffsetOf_TexSubImage2D_width_not_20);
+COMPILE_ASSERT(offsetof(TexSubImage2D, height) == 24,
+ OffsetOf_TexSubImage2D_height_not_24);
+COMPILE_ASSERT(offsetof(TexSubImage2D, format) == 28,
+ OffsetOf_TexSubImage2D_format_not_28);
+COMPILE_ASSERT(offsetof(TexSubImage2D, type) == 32,
+ OffsetOf_TexSubImage2D_type_not_32);
+COMPILE_ASSERT(offsetof(TexSubImage2D, pixels_shm_id) == 36,
+ OffsetOf_TexSubImage2D_pixels_shm_id_not_36);
+COMPILE_ASSERT(offsetof(TexSubImage2D, pixels_shm_offset) == 40,
+ OffsetOf_TexSubImage2D_pixels_shm_offset_not_40);
+COMPILE_ASSERT(offsetof(TexSubImage2D, internal) == 44,
+ OffsetOf_TexSubImage2D_internal_not_44);
+
+struct TexSubImage2DImmediate {
+ typedef TexSubImage2DImmediate ValueType;
+ static const CommandId kCmdId = kTexSubImage2DImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 size_in_bytes) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + // NOLINT
+ RoundSizeToMultipleOfEntries(size_in_bytes));
+ }
+
+ void SetHeader(uint32 size_in_bytes) {
+ header.SetCmdByTotalSize<ValueType>(size_in_bytes);
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLenum _type,
+ GLboolean _internal) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ SetHeader(total_size);
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ width = _width;
+ height = _height;
+ format = _format;
+ type = _type;
+ internal = _internal;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLenum _type,
+ GLboolean _internal) {
+ uint32 total_size = 0; // TODO(gman): get correct size.
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _width, _height, _format,
+ _type, _internal);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, total_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 width;
+ int32 height;
+ uint32 format;
+ uint32 type;
+ uint32 internal;
+};
+
+COMPILE_ASSERT(sizeof(TexSubImage2DImmediate) == 40,
+ Sizeof_TexSubImage2DImmediate_is_not_40);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, header) == 0,
+ OffsetOf_TexSubImage2DImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, target) == 4,
+ OffsetOf_TexSubImage2DImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, level) == 8,
+ OffsetOf_TexSubImage2DImmediate_level_not_8);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, xoffset) == 12,
+ OffsetOf_TexSubImage2DImmediate_xoffset_not_12);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, yoffset) == 16,
+ OffsetOf_TexSubImage2DImmediate_yoffset_not_16);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, width) == 20,
+ OffsetOf_TexSubImage2DImmediate_width_not_20);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, height) == 24,
+ OffsetOf_TexSubImage2DImmediate_height_not_24);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, format) == 28,
+ OffsetOf_TexSubImage2DImmediate_format_not_28);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, type) == 32,
+ OffsetOf_TexSubImage2DImmediate_type_not_32);
+COMPILE_ASSERT(offsetof(TexSubImage2DImmediate, internal) == 36,
+ OffsetOf_TexSubImage2DImmediate_internal_not_36);
+
+struct Uniform1f {
+ typedef Uniform1f ValueType;
+ static const CommandId kCmdId = kUniform1f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLfloat _x) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ }
+
+ void* Set(void* cmd, GLint _location, GLfloat _x) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ float x;
+};
+
+COMPILE_ASSERT(sizeof(Uniform1f) == 12,
+ Sizeof_Uniform1f_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform1f, header) == 0,
+ OffsetOf_Uniform1f_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform1f, location) == 4,
+ OffsetOf_Uniform1f_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform1f, x) == 8,
+ OffsetOf_Uniform1f_x_not_8);
+
+struct Uniform1fv {
+ typedef Uniform1fv ValueType;
+ static const CommandId kCmdId = kUniform1fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform1fv) == 20,
+ Sizeof_Uniform1fv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform1fv, header) == 0,
+ OffsetOf_Uniform1fv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform1fv, location) == 4,
+ OffsetOf_Uniform1fv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform1fv, count) == 8,
+ OffsetOf_Uniform1fv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform1fv, v_shm_id) == 12,
+ OffsetOf_Uniform1fv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform1fv, v_shm_offset) == 16,
+ OffsetOf_Uniform1fv_v_shm_offset_not_16);
+
+struct Uniform1fvImmediate {
+ typedef Uniform1fvImmediate ValueType;
+ static const CommandId kCmdId = kUniform1fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 1 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLfloat* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLfloat* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform1fvImmediate) == 12,
+ Sizeof_Uniform1fvImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform1fvImmediate, header) == 0,
+ OffsetOf_Uniform1fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform1fvImmediate, location) == 4,
+ OffsetOf_Uniform1fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform1fvImmediate, count) == 8,
+ OffsetOf_Uniform1fvImmediate_count_not_8);
+
+struct Uniform1i {
+ typedef Uniform1i ValueType;
+ static const CommandId kCmdId = kUniform1i;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLint _x) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ }
+
+ void* Set(void* cmd, GLint _location, GLint _x) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 x;
+};
+
+COMPILE_ASSERT(sizeof(Uniform1i) == 12,
+ Sizeof_Uniform1i_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform1i, header) == 0,
+ OffsetOf_Uniform1i_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform1i, location) == 4,
+ OffsetOf_Uniform1i_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform1i, x) == 8,
+ OffsetOf_Uniform1i_x_not_8);
+
+struct Uniform1iv {
+ typedef Uniform1iv ValueType;
+ static const CommandId kCmdId = kUniform1iv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform1iv) == 20,
+ Sizeof_Uniform1iv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform1iv, header) == 0,
+ OffsetOf_Uniform1iv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform1iv, location) == 4,
+ OffsetOf_Uniform1iv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform1iv, count) == 8,
+ OffsetOf_Uniform1iv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform1iv, v_shm_id) == 12,
+ OffsetOf_Uniform1iv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform1iv, v_shm_offset) == 16,
+ OffsetOf_Uniform1iv_v_shm_offset_not_16);
+
+struct Uniform1ivImmediate {
+ typedef Uniform1ivImmediate ValueType;
+ static const CommandId kCmdId = kUniform1ivImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLint) * 1 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLint* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLint* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform1ivImmediate) == 12,
+ Sizeof_Uniform1ivImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform1ivImmediate, header) == 0,
+ OffsetOf_Uniform1ivImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform1ivImmediate, location) == 4,
+ OffsetOf_Uniform1ivImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform1ivImmediate, count) == 8,
+ OffsetOf_Uniform1ivImmediate_count_not_8);
+
+struct Uniform2f {
+ typedef Uniform2f ValueType;
+ static const CommandId kCmdId = kUniform2f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLfloat _x, GLfloat _y) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ y = _y;
+ }
+
+ void* Set(void* cmd, GLint _location, GLfloat _x, GLfloat _y) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x, _y);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ float x;
+ float y;
+};
+
+COMPILE_ASSERT(sizeof(Uniform2f) == 16,
+ Sizeof_Uniform2f_is_not_16);
+COMPILE_ASSERT(offsetof(Uniform2f, header) == 0,
+ OffsetOf_Uniform2f_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform2f, location) == 4,
+ OffsetOf_Uniform2f_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform2f, x) == 8,
+ OffsetOf_Uniform2f_x_not_8);
+COMPILE_ASSERT(offsetof(Uniform2f, y) == 12,
+ OffsetOf_Uniform2f_y_not_12);
+
+struct Uniform2fv {
+ typedef Uniform2fv ValueType;
+ static const CommandId kCmdId = kUniform2fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform2fv) == 20,
+ Sizeof_Uniform2fv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform2fv, header) == 0,
+ OffsetOf_Uniform2fv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform2fv, location) == 4,
+ OffsetOf_Uniform2fv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform2fv, count) == 8,
+ OffsetOf_Uniform2fv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform2fv, v_shm_id) == 12,
+ OffsetOf_Uniform2fv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform2fv, v_shm_offset) == 16,
+ OffsetOf_Uniform2fv_v_shm_offset_not_16);
+
+struct Uniform2fvImmediate {
+ typedef Uniform2fvImmediate ValueType;
+ static const CommandId kCmdId = kUniform2fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 2 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLfloat* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLfloat* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform2fvImmediate) == 12,
+ Sizeof_Uniform2fvImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform2fvImmediate, header) == 0,
+ OffsetOf_Uniform2fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform2fvImmediate, location) == 4,
+ OffsetOf_Uniform2fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform2fvImmediate, count) == 8,
+ OffsetOf_Uniform2fvImmediate_count_not_8);
+
+struct Uniform2i {
+ typedef Uniform2i ValueType;
+ static const CommandId kCmdId = kUniform2i;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLint _x, GLint _y) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ y = _y;
+ }
+
+ void* Set(void* cmd, GLint _location, GLint _x, GLint _y) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x, _y);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 x;
+ int32 y;
+};
+
+COMPILE_ASSERT(sizeof(Uniform2i) == 16,
+ Sizeof_Uniform2i_is_not_16);
+COMPILE_ASSERT(offsetof(Uniform2i, header) == 0,
+ OffsetOf_Uniform2i_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform2i, location) == 4,
+ OffsetOf_Uniform2i_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform2i, x) == 8,
+ OffsetOf_Uniform2i_x_not_8);
+COMPILE_ASSERT(offsetof(Uniform2i, y) == 12,
+ OffsetOf_Uniform2i_y_not_12);
+
+struct Uniform2iv {
+ typedef Uniform2iv ValueType;
+ static const CommandId kCmdId = kUniform2iv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform2iv) == 20,
+ Sizeof_Uniform2iv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform2iv, header) == 0,
+ OffsetOf_Uniform2iv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform2iv, location) == 4,
+ OffsetOf_Uniform2iv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform2iv, count) == 8,
+ OffsetOf_Uniform2iv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform2iv, v_shm_id) == 12,
+ OffsetOf_Uniform2iv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform2iv, v_shm_offset) == 16,
+ OffsetOf_Uniform2iv_v_shm_offset_not_16);
+
+struct Uniform2ivImmediate {
+ typedef Uniform2ivImmediate ValueType;
+ static const CommandId kCmdId = kUniform2ivImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLint) * 2 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLint* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLint* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform2ivImmediate) == 12,
+ Sizeof_Uniform2ivImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform2ivImmediate, header) == 0,
+ OffsetOf_Uniform2ivImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform2ivImmediate, location) == 4,
+ OffsetOf_Uniform2ivImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform2ivImmediate, count) == 8,
+ OffsetOf_Uniform2ivImmediate_count_not_8);
+
+struct Uniform3f {
+ typedef Uniform3f ValueType;
+ static const CommandId kCmdId = kUniform3f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLfloat _x, GLfloat _y, GLfloat _z) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ void* Set(void* cmd, GLint _location, GLfloat _x, GLfloat _y, GLfloat _z) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x, _y, _z);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ float x;
+ float y;
+ float z;
+};
+
+COMPILE_ASSERT(sizeof(Uniform3f) == 20,
+ Sizeof_Uniform3f_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform3f, header) == 0,
+ OffsetOf_Uniform3f_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform3f, location) == 4,
+ OffsetOf_Uniform3f_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform3f, x) == 8,
+ OffsetOf_Uniform3f_x_not_8);
+COMPILE_ASSERT(offsetof(Uniform3f, y) == 12,
+ OffsetOf_Uniform3f_y_not_12);
+COMPILE_ASSERT(offsetof(Uniform3f, z) == 16,
+ OffsetOf_Uniform3f_z_not_16);
+
+struct Uniform3fv {
+ typedef Uniform3fv ValueType;
+ static const CommandId kCmdId = kUniform3fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform3fv) == 20,
+ Sizeof_Uniform3fv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform3fv, header) == 0,
+ OffsetOf_Uniform3fv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform3fv, location) == 4,
+ OffsetOf_Uniform3fv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform3fv, count) == 8,
+ OffsetOf_Uniform3fv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform3fv, v_shm_id) == 12,
+ OffsetOf_Uniform3fv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform3fv, v_shm_offset) == 16,
+ OffsetOf_Uniform3fv_v_shm_offset_not_16);
+
+struct Uniform3fvImmediate {
+ typedef Uniform3fvImmediate ValueType;
+ static const CommandId kCmdId = kUniform3fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 3 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLfloat* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLfloat* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform3fvImmediate) == 12,
+ Sizeof_Uniform3fvImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform3fvImmediate, header) == 0,
+ OffsetOf_Uniform3fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform3fvImmediate, location) == 4,
+ OffsetOf_Uniform3fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform3fvImmediate, count) == 8,
+ OffsetOf_Uniform3fvImmediate_count_not_8);
+
+struct Uniform3i {
+ typedef Uniform3i ValueType;
+ static const CommandId kCmdId = kUniform3i;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLint _x, GLint _y, GLint _z) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ void* Set(void* cmd, GLint _location, GLint _x, GLint _y, GLint _z) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x, _y, _z);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 x;
+ int32 y;
+ int32 z;
+};
+
+COMPILE_ASSERT(sizeof(Uniform3i) == 20,
+ Sizeof_Uniform3i_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform3i, header) == 0,
+ OffsetOf_Uniform3i_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform3i, location) == 4,
+ OffsetOf_Uniform3i_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform3i, x) == 8,
+ OffsetOf_Uniform3i_x_not_8);
+COMPILE_ASSERT(offsetof(Uniform3i, y) == 12,
+ OffsetOf_Uniform3i_y_not_12);
+COMPILE_ASSERT(offsetof(Uniform3i, z) == 16,
+ OffsetOf_Uniform3i_z_not_16);
+
+struct Uniform3iv {
+ typedef Uniform3iv ValueType;
+ static const CommandId kCmdId = kUniform3iv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform3iv) == 20,
+ Sizeof_Uniform3iv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform3iv, header) == 0,
+ OffsetOf_Uniform3iv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform3iv, location) == 4,
+ OffsetOf_Uniform3iv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform3iv, count) == 8,
+ OffsetOf_Uniform3iv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform3iv, v_shm_id) == 12,
+ OffsetOf_Uniform3iv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform3iv, v_shm_offset) == 16,
+ OffsetOf_Uniform3iv_v_shm_offset_not_16);
+
+struct Uniform3ivImmediate {
+ typedef Uniform3ivImmediate ValueType;
+ static const CommandId kCmdId = kUniform3ivImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLint) * 3 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLint* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLint* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform3ivImmediate) == 12,
+ Sizeof_Uniform3ivImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform3ivImmediate, header) == 0,
+ OffsetOf_Uniform3ivImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform3ivImmediate, location) == 4,
+ OffsetOf_Uniform3ivImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform3ivImmediate, count) == 8,
+ OffsetOf_Uniform3ivImmediate_count_not_8);
+
+struct Uniform4f {
+ typedef Uniform4f ValueType;
+ static const CommandId kCmdId = kUniform4f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLfloat _x, GLfloat _y, GLfloat _z, GLfloat _w) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ y = _y;
+ z = _z;
+ w = _w;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLfloat _x, GLfloat _y, GLfloat _z,
+ GLfloat _w) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x, _y, _z, _w);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+COMPILE_ASSERT(sizeof(Uniform4f) == 24,
+ Sizeof_Uniform4f_is_not_24);
+COMPILE_ASSERT(offsetof(Uniform4f, header) == 0,
+ OffsetOf_Uniform4f_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform4f, location) == 4,
+ OffsetOf_Uniform4f_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform4f, x) == 8,
+ OffsetOf_Uniform4f_x_not_8);
+COMPILE_ASSERT(offsetof(Uniform4f, y) == 12,
+ OffsetOf_Uniform4f_y_not_12);
+COMPILE_ASSERT(offsetof(Uniform4f, z) == 16,
+ OffsetOf_Uniform4f_z_not_16);
+COMPILE_ASSERT(offsetof(Uniform4f, w) == 20,
+ OffsetOf_Uniform4f_w_not_20);
+
+struct Uniform4fv {
+ typedef Uniform4fv ValueType;
+ static const CommandId kCmdId = kUniform4fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform4fv) == 20,
+ Sizeof_Uniform4fv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform4fv, header) == 0,
+ OffsetOf_Uniform4fv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform4fv, location) == 4,
+ OffsetOf_Uniform4fv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform4fv, count) == 8,
+ OffsetOf_Uniform4fv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform4fv, v_shm_id) == 12,
+ OffsetOf_Uniform4fv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform4fv, v_shm_offset) == 16,
+ OffsetOf_Uniform4fv_v_shm_offset_not_16);
+
+struct Uniform4fvImmediate {
+ typedef Uniform4fvImmediate ValueType;
+ static const CommandId kCmdId = kUniform4fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 4 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLfloat* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLfloat* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform4fvImmediate) == 12,
+ Sizeof_Uniform4fvImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform4fvImmediate, header) == 0,
+ OffsetOf_Uniform4fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform4fvImmediate, location) == 4,
+ OffsetOf_Uniform4fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform4fvImmediate, count) == 8,
+ OffsetOf_Uniform4fvImmediate_count_not_8);
+
+struct Uniform4i {
+ typedef Uniform4i ValueType;
+ static const CommandId kCmdId = kUniform4i;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _location, GLint _x, GLint _y, GLint _z, GLint _w) {
+ SetHeader();
+ location = _location;
+ x = _x;
+ y = _y;
+ z = _z;
+ w = _w;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLint _x, GLint _y, GLint _z, GLint _w) {
+ static_cast<ValueType*>(cmd)->Init(_location, _x, _y, _z, _w);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 x;
+ int32 y;
+ int32 z;
+ int32 w;
+};
+
+COMPILE_ASSERT(sizeof(Uniform4i) == 24,
+ Sizeof_Uniform4i_is_not_24);
+COMPILE_ASSERT(offsetof(Uniform4i, header) == 0,
+ OffsetOf_Uniform4i_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform4i, location) == 4,
+ OffsetOf_Uniform4i_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform4i, x) == 8,
+ OffsetOf_Uniform4i_x_not_8);
+COMPILE_ASSERT(offsetof(Uniform4i, y) == 12,
+ OffsetOf_Uniform4i_y_not_12);
+COMPILE_ASSERT(offsetof(Uniform4i, z) == 16,
+ OffsetOf_Uniform4i_z_not_16);
+COMPILE_ASSERT(offsetof(Uniform4i, w) == 20,
+ OffsetOf_Uniform4i_w_not_20);
+
+struct Uniform4iv {
+ typedef Uniform4iv ValueType;
+ static const CommandId kCmdId = kUniform4iv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ v_shm_id = _v_shm_id;
+ v_shm_offset = _v_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, uint32 _v_shm_id,
+ uint32 _v_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_location, _count, _v_shm_id, _v_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 v_shm_id;
+ uint32 v_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(Uniform4iv) == 20,
+ Sizeof_Uniform4iv_is_not_20);
+COMPILE_ASSERT(offsetof(Uniform4iv, header) == 0,
+ OffsetOf_Uniform4iv_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform4iv, location) == 4,
+ OffsetOf_Uniform4iv_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform4iv, count) == 8,
+ OffsetOf_Uniform4iv_count_not_8);
+COMPILE_ASSERT(offsetof(Uniform4iv, v_shm_id) == 12,
+ OffsetOf_Uniform4iv_v_shm_id_not_12);
+COMPILE_ASSERT(offsetof(Uniform4iv, v_shm_offset) == 16,
+ OffsetOf_Uniform4iv_v_shm_offset_not_16);
+
+struct Uniform4ivImmediate {
+ typedef Uniform4ivImmediate ValueType;
+ static const CommandId kCmdId = kUniform4ivImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLint) * 4 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLint _location, GLsizei _count, const GLint* _v) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _v, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLint _location, GLsizei _count, const GLint* _v) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _v);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(Uniform4ivImmediate) == 12,
+ Sizeof_Uniform4ivImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(Uniform4ivImmediate, header) == 0,
+ OffsetOf_Uniform4ivImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(Uniform4ivImmediate, location) == 4,
+ OffsetOf_Uniform4ivImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(Uniform4ivImmediate, count) == 8,
+ OffsetOf_Uniform4ivImmediate_count_not_8);
+
+struct UniformMatrix2fv {
+ typedef UniformMatrix2fv ValueType;
+ static const CommandId kCmdId = kUniformMatrix2fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, GLboolean _transpose,
+ uint32 _value_shm_id, uint32 _value_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ transpose = _transpose;
+ value_shm_id = _value_shm_id;
+ value_shm_offset = _value_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, GLboolean _transpose,
+ uint32 _value_shm_id, uint32 _value_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _location, _count, _transpose, _value_shm_id, _value_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 transpose;
+ uint32 value_shm_id;
+ uint32 value_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(UniformMatrix2fv) == 24,
+ Sizeof_UniformMatrix2fv_is_not_24);
+COMPILE_ASSERT(offsetof(UniformMatrix2fv, header) == 0,
+ OffsetOf_UniformMatrix2fv_header_not_0);
+COMPILE_ASSERT(offsetof(UniformMatrix2fv, location) == 4,
+ OffsetOf_UniformMatrix2fv_location_not_4);
+COMPILE_ASSERT(offsetof(UniformMatrix2fv, count) == 8,
+ OffsetOf_UniformMatrix2fv_count_not_8);
+COMPILE_ASSERT(offsetof(UniformMatrix2fv, transpose) == 12,
+ OffsetOf_UniformMatrix2fv_transpose_not_12);
+COMPILE_ASSERT(offsetof(UniformMatrix2fv, value_shm_id) == 16,
+ OffsetOf_UniformMatrix2fv_value_shm_id_not_16);
+COMPILE_ASSERT(offsetof(UniformMatrix2fv, value_shm_offset) == 20,
+ OffsetOf_UniformMatrix2fv_value_shm_offset_not_20);
+
+struct UniformMatrix2fvImmediate {
+ typedef UniformMatrix2fvImmediate ValueType;
+ static const CommandId kCmdId = kUniformMatrix2fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 4 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, GLboolean _transpose,
+ const GLfloat* _value) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ transpose = _transpose;
+ memcpy(ImmediateDataAddress(this),
+ _value, ComputeDataSize(_count));
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, GLboolean _transpose,
+ const GLfloat* _value) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _transpose, _value);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 transpose;
+};
+
+COMPILE_ASSERT(sizeof(UniformMatrix2fvImmediate) == 16,
+ Sizeof_UniformMatrix2fvImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(UniformMatrix2fvImmediate, header) == 0,
+ OffsetOf_UniformMatrix2fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(UniformMatrix2fvImmediate, location) == 4,
+ OffsetOf_UniformMatrix2fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(UniformMatrix2fvImmediate, count) == 8,
+ OffsetOf_UniformMatrix2fvImmediate_count_not_8);
+COMPILE_ASSERT(offsetof(UniformMatrix2fvImmediate, transpose) == 12,
+ OffsetOf_UniformMatrix2fvImmediate_transpose_not_12);
+
+struct UniformMatrix3fv {
+ typedef UniformMatrix3fv ValueType;
+ static const CommandId kCmdId = kUniformMatrix3fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, GLboolean _transpose,
+ uint32 _value_shm_id, uint32 _value_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ transpose = _transpose;
+ value_shm_id = _value_shm_id;
+ value_shm_offset = _value_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, GLboolean _transpose,
+ uint32 _value_shm_id, uint32 _value_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _location, _count, _transpose, _value_shm_id, _value_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 transpose;
+ uint32 value_shm_id;
+ uint32 value_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(UniformMatrix3fv) == 24,
+ Sizeof_UniformMatrix3fv_is_not_24);
+COMPILE_ASSERT(offsetof(UniformMatrix3fv, header) == 0,
+ OffsetOf_UniformMatrix3fv_header_not_0);
+COMPILE_ASSERT(offsetof(UniformMatrix3fv, location) == 4,
+ OffsetOf_UniformMatrix3fv_location_not_4);
+COMPILE_ASSERT(offsetof(UniformMatrix3fv, count) == 8,
+ OffsetOf_UniformMatrix3fv_count_not_8);
+COMPILE_ASSERT(offsetof(UniformMatrix3fv, transpose) == 12,
+ OffsetOf_UniformMatrix3fv_transpose_not_12);
+COMPILE_ASSERT(offsetof(UniformMatrix3fv, value_shm_id) == 16,
+ OffsetOf_UniformMatrix3fv_value_shm_id_not_16);
+COMPILE_ASSERT(offsetof(UniformMatrix3fv, value_shm_offset) == 20,
+ OffsetOf_UniformMatrix3fv_value_shm_offset_not_20);
+
+struct UniformMatrix3fvImmediate {
+ typedef UniformMatrix3fvImmediate ValueType;
+ static const CommandId kCmdId = kUniformMatrix3fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 9 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, GLboolean _transpose,
+ const GLfloat* _value) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ transpose = _transpose;
+ memcpy(ImmediateDataAddress(this),
+ _value, ComputeDataSize(_count));
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, GLboolean _transpose,
+ const GLfloat* _value) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _transpose, _value);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 transpose;
+};
+
+COMPILE_ASSERT(sizeof(UniformMatrix3fvImmediate) == 16,
+ Sizeof_UniformMatrix3fvImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(UniformMatrix3fvImmediate, header) == 0,
+ OffsetOf_UniformMatrix3fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(UniformMatrix3fvImmediate, location) == 4,
+ OffsetOf_UniformMatrix3fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(UniformMatrix3fvImmediate, count) == 8,
+ OffsetOf_UniformMatrix3fvImmediate_count_not_8);
+COMPILE_ASSERT(offsetof(UniformMatrix3fvImmediate, transpose) == 12,
+ OffsetOf_UniformMatrix3fvImmediate_transpose_not_12);
+
+struct UniformMatrix4fv {
+ typedef UniformMatrix4fv ValueType;
+ static const CommandId kCmdId = kUniformMatrix4fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, GLboolean _transpose,
+ uint32 _value_shm_id, uint32 _value_shm_offset) {
+ SetHeader();
+ location = _location;
+ count = _count;
+ transpose = _transpose;
+ value_shm_id = _value_shm_id;
+ value_shm_offset = _value_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, GLboolean _transpose,
+ uint32 _value_shm_id, uint32 _value_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _location, _count, _transpose, _value_shm_id, _value_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 transpose;
+ uint32 value_shm_id;
+ uint32 value_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(UniformMatrix4fv) == 24,
+ Sizeof_UniformMatrix4fv_is_not_24);
+COMPILE_ASSERT(offsetof(UniformMatrix4fv, header) == 0,
+ OffsetOf_UniformMatrix4fv_header_not_0);
+COMPILE_ASSERT(offsetof(UniformMatrix4fv, location) == 4,
+ OffsetOf_UniformMatrix4fv_location_not_4);
+COMPILE_ASSERT(offsetof(UniformMatrix4fv, count) == 8,
+ OffsetOf_UniformMatrix4fv_count_not_8);
+COMPILE_ASSERT(offsetof(UniformMatrix4fv, transpose) == 12,
+ OffsetOf_UniformMatrix4fv_transpose_not_12);
+COMPILE_ASSERT(offsetof(UniformMatrix4fv, value_shm_id) == 16,
+ OffsetOf_UniformMatrix4fv_value_shm_id_not_16);
+COMPILE_ASSERT(offsetof(UniformMatrix4fv, value_shm_offset) == 20,
+ OffsetOf_UniformMatrix4fv_value_shm_offset_not_20);
+
+struct UniformMatrix4fvImmediate {
+ typedef UniformMatrix4fvImmediate ValueType;
+ static const CommandId kCmdId = kUniformMatrix4fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 16 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(
+ GLint _location, GLsizei _count, GLboolean _transpose,
+ const GLfloat* _value) {
+ SetHeader(_count);
+ location = _location;
+ count = _count;
+ transpose = _transpose;
+ memcpy(ImmediateDataAddress(this),
+ _value, ComputeDataSize(_count));
+ }
+
+ void* Set(
+ void* cmd, GLint _location, GLsizei _count, GLboolean _transpose,
+ const GLfloat* _value) {
+ static_cast<ValueType*>(cmd)->Init(_location, _count, _transpose, _value);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 location;
+ int32 count;
+ uint32 transpose;
+};
+
+COMPILE_ASSERT(sizeof(UniformMatrix4fvImmediate) == 16,
+ Sizeof_UniformMatrix4fvImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(UniformMatrix4fvImmediate, header) == 0,
+ OffsetOf_UniformMatrix4fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(UniformMatrix4fvImmediate, location) == 4,
+ OffsetOf_UniformMatrix4fvImmediate_location_not_4);
+COMPILE_ASSERT(offsetof(UniformMatrix4fvImmediate, count) == 8,
+ OffsetOf_UniformMatrix4fvImmediate_count_not_8);
+COMPILE_ASSERT(offsetof(UniformMatrix4fvImmediate, transpose) == 12,
+ OffsetOf_UniformMatrix4fvImmediate_transpose_not_12);
+
+struct UseProgram {
+ typedef UseProgram ValueType;
+ static const CommandId kCmdId = kUseProgram;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program) {
+ SetHeader();
+ program = _program;
+ }
+
+ void* Set(void* cmd, GLuint _program) {
+ static_cast<ValueType*>(cmd)->Init(_program);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+};
+
+COMPILE_ASSERT(sizeof(UseProgram) == 8,
+ Sizeof_UseProgram_is_not_8);
+COMPILE_ASSERT(offsetof(UseProgram, header) == 0,
+ OffsetOf_UseProgram_header_not_0);
+COMPILE_ASSERT(offsetof(UseProgram, program) == 4,
+ OffsetOf_UseProgram_program_not_4);
+
+struct ValidateProgram {
+ typedef ValidateProgram ValueType;
+ static const CommandId kCmdId = kValidateProgram;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program) {
+ SetHeader();
+ program = _program;
+ }
+
+ void* Set(void* cmd, GLuint _program) {
+ static_cast<ValueType*>(cmd)->Init(_program);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+};
+
+COMPILE_ASSERT(sizeof(ValidateProgram) == 8,
+ Sizeof_ValidateProgram_is_not_8);
+COMPILE_ASSERT(offsetof(ValidateProgram, header) == 0,
+ OffsetOf_ValidateProgram_header_not_0);
+COMPILE_ASSERT(offsetof(ValidateProgram, program) == 4,
+ OffsetOf_ValidateProgram_program_not_4);
+
+struct VertexAttrib1f {
+ typedef VertexAttrib1f ValueType;
+ static const CommandId kCmdId = kVertexAttrib1f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, GLfloat _x) {
+ SetHeader();
+ indx = _indx;
+ x = _x;
+ }
+
+ void* Set(void* cmd, GLuint _indx, GLfloat _x) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _x);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ float x;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib1f) == 12,
+ Sizeof_VertexAttrib1f_is_not_12);
+COMPILE_ASSERT(offsetof(VertexAttrib1f, header) == 0,
+ OffsetOf_VertexAttrib1f_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib1f, indx) == 4,
+ OffsetOf_VertexAttrib1f_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib1f, x) == 8,
+ OffsetOf_VertexAttrib1f_x_not_8);
+
+struct VertexAttrib1fv {
+ typedef VertexAttrib1fv ValueType;
+ static const CommandId kCmdId = kVertexAttrib1fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, uint32 _values_shm_id, uint32 _values_shm_offset) {
+ SetHeader();
+ indx = _indx;
+ values_shm_id = _values_shm_id;
+ values_shm_offset = _values_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _indx, uint32 _values_shm_id,
+ uint32 _values_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_indx, _values_shm_id, _values_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ uint32 values_shm_id;
+ uint32 values_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib1fv) == 16,
+ Sizeof_VertexAttrib1fv_is_not_16);
+COMPILE_ASSERT(offsetof(VertexAttrib1fv, header) == 0,
+ OffsetOf_VertexAttrib1fv_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib1fv, indx) == 4,
+ OffsetOf_VertexAttrib1fv_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib1fv, values_shm_id) == 8,
+ OffsetOf_VertexAttrib1fv_values_shm_id_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib1fv, values_shm_offset) == 12,
+ OffsetOf_VertexAttrib1fv_values_shm_offset_not_12);
+
+struct VertexAttrib1fvImmediate {
+ typedef VertexAttrib1fvImmediate ValueType;
+ static const CommandId kCmdId = kVertexAttrib1fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 1); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLuint _indx, const GLfloat* _values) {
+ SetHeader();
+ indx = _indx;
+ memcpy(ImmediateDataAddress(this),
+ _values, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLuint _indx, const GLfloat* _values) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _values);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib1fvImmediate) == 8,
+ Sizeof_VertexAttrib1fvImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib1fvImmediate, header) == 0,
+ OffsetOf_VertexAttrib1fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib1fvImmediate, indx) == 4,
+ OffsetOf_VertexAttrib1fvImmediate_indx_not_4);
+
+struct VertexAttrib2f {
+ typedef VertexAttrib2f ValueType;
+ static const CommandId kCmdId = kVertexAttrib2f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, GLfloat _x, GLfloat _y) {
+ SetHeader();
+ indx = _indx;
+ x = _x;
+ y = _y;
+ }
+
+ void* Set(void* cmd, GLuint _indx, GLfloat _x, GLfloat _y) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _x, _y);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ float x;
+ float y;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib2f) == 16,
+ Sizeof_VertexAttrib2f_is_not_16);
+COMPILE_ASSERT(offsetof(VertexAttrib2f, header) == 0,
+ OffsetOf_VertexAttrib2f_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib2f, indx) == 4,
+ OffsetOf_VertexAttrib2f_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib2f, x) == 8,
+ OffsetOf_VertexAttrib2f_x_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib2f, y) == 12,
+ OffsetOf_VertexAttrib2f_y_not_12);
+
+struct VertexAttrib2fv {
+ typedef VertexAttrib2fv ValueType;
+ static const CommandId kCmdId = kVertexAttrib2fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, uint32 _values_shm_id, uint32 _values_shm_offset) {
+ SetHeader();
+ indx = _indx;
+ values_shm_id = _values_shm_id;
+ values_shm_offset = _values_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _indx, uint32 _values_shm_id,
+ uint32 _values_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_indx, _values_shm_id, _values_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ uint32 values_shm_id;
+ uint32 values_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib2fv) == 16,
+ Sizeof_VertexAttrib2fv_is_not_16);
+COMPILE_ASSERT(offsetof(VertexAttrib2fv, header) == 0,
+ OffsetOf_VertexAttrib2fv_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib2fv, indx) == 4,
+ OffsetOf_VertexAttrib2fv_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib2fv, values_shm_id) == 8,
+ OffsetOf_VertexAttrib2fv_values_shm_id_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib2fv, values_shm_offset) == 12,
+ OffsetOf_VertexAttrib2fv_values_shm_offset_not_12);
+
+struct VertexAttrib2fvImmediate {
+ typedef VertexAttrib2fvImmediate ValueType;
+ static const CommandId kCmdId = kVertexAttrib2fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 2); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLuint _indx, const GLfloat* _values) {
+ SetHeader();
+ indx = _indx;
+ memcpy(ImmediateDataAddress(this),
+ _values, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLuint _indx, const GLfloat* _values) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _values);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib2fvImmediate) == 8,
+ Sizeof_VertexAttrib2fvImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib2fvImmediate, header) == 0,
+ OffsetOf_VertexAttrib2fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib2fvImmediate, indx) == 4,
+ OffsetOf_VertexAttrib2fvImmediate_indx_not_4);
+
+struct VertexAttrib3f {
+ typedef VertexAttrib3f ValueType;
+ static const CommandId kCmdId = kVertexAttrib3f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, GLfloat _x, GLfloat _y, GLfloat _z) {
+ SetHeader();
+ indx = _indx;
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ void* Set(void* cmd, GLuint _indx, GLfloat _x, GLfloat _y, GLfloat _z) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _x, _y, _z);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ float x;
+ float y;
+ float z;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib3f) == 20,
+ Sizeof_VertexAttrib3f_is_not_20);
+COMPILE_ASSERT(offsetof(VertexAttrib3f, header) == 0,
+ OffsetOf_VertexAttrib3f_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib3f, indx) == 4,
+ OffsetOf_VertexAttrib3f_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib3f, x) == 8,
+ OffsetOf_VertexAttrib3f_x_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib3f, y) == 12,
+ OffsetOf_VertexAttrib3f_y_not_12);
+COMPILE_ASSERT(offsetof(VertexAttrib3f, z) == 16,
+ OffsetOf_VertexAttrib3f_z_not_16);
+
+struct VertexAttrib3fv {
+ typedef VertexAttrib3fv ValueType;
+ static const CommandId kCmdId = kVertexAttrib3fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, uint32 _values_shm_id, uint32 _values_shm_offset) {
+ SetHeader();
+ indx = _indx;
+ values_shm_id = _values_shm_id;
+ values_shm_offset = _values_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _indx, uint32 _values_shm_id,
+ uint32 _values_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_indx, _values_shm_id, _values_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ uint32 values_shm_id;
+ uint32 values_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib3fv) == 16,
+ Sizeof_VertexAttrib3fv_is_not_16);
+COMPILE_ASSERT(offsetof(VertexAttrib3fv, header) == 0,
+ OffsetOf_VertexAttrib3fv_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib3fv, indx) == 4,
+ OffsetOf_VertexAttrib3fv_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib3fv, values_shm_id) == 8,
+ OffsetOf_VertexAttrib3fv_values_shm_id_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib3fv, values_shm_offset) == 12,
+ OffsetOf_VertexAttrib3fv_values_shm_offset_not_12);
+
+struct VertexAttrib3fvImmediate {
+ typedef VertexAttrib3fvImmediate ValueType;
+ static const CommandId kCmdId = kVertexAttrib3fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 3); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLuint _indx, const GLfloat* _values) {
+ SetHeader();
+ indx = _indx;
+ memcpy(ImmediateDataAddress(this),
+ _values, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLuint _indx, const GLfloat* _values) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _values);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib3fvImmediate) == 8,
+ Sizeof_VertexAttrib3fvImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib3fvImmediate, header) == 0,
+ OffsetOf_VertexAttrib3fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib3fvImmediate, indx) == 4,
+ OffsetOf_VertexAttrib3fvImmediate_indx_not_4);
+
+struct VertexAttrib4f {
+ typedef VertexAttrib4f ValueType;
+ static const CommandId kCmdId = kVertexAttrib4f;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, GLfloat _x, GLfloat _y, GLfloat _z, GLfloat _w) {
+ SetHeader();
+ indx = _indx;
+ x = _x;
+ y = _y;
+ z = _z;
+ w = _w;
+ }
+
+ void* Set(
+ void* cmd, GLuint _indx, GLfloat _x, GLfloat _y, GLfloat _z,
+ GLfloat _w) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _x, _y, _z, _w);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ float x;
+ float y;
+ float z;
+ float w;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib4f) == 24,
+ Sizeof_VertexAttrib4f_is_not_24);
+COMPILE_ASSERT(offsetof(VertexAttrib4f, header) == 0,
+ OffsetOf_VertexAttrib4f_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib4f, indx) == 4,
+ OffsetOf_VertexAttrib4f_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib4f, x) == 8,
+ OffsetOf_VertexAttrib4f_x_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib4f, y) == 12,
+ OffsetOf_VertexAttrib4f_y_not_12);
+COMPILE_ASSERT(offsetof(VertexAttrib4f, z) == 16,
+ OffsetOf_VertexAttrib4f_z_not_16);
+COMPILE_ASSERT(offsetof(VertexAttrib4f, w) == 20,
+ OffsetOf_VertexAttrib4f_w_not_20);
+
+struct VertexAttrib4fv {
+ typedef VertexAttrib4fv ValueType;
+ static const CommandId kCmdId = kVertexAttrib4fv;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _indx, uint32 _values_shm_id, uint32 _values_shm_offset) {
+ SetHeader();
+ indx = _indx;
+ values_shm_id = _values_shm_id;
+ values_shm_offset = _values_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _indx, uint32 _values_shm_id,
+ uint32 _values_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_indx, _values_shm_id, _values_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ uint32 values_shm_id;
+ uint32 values_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib4fv) == 16,
+ Sizeof_VertexAttrib4fv_is_not_16);
+COMPILE_ASSERT(offsetof(VertexAttrib4fv, header) == 0,
+ OffsetOf_VertexAttrib4fv_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib4fv, indx) == 4,
+ OffsetOf_VertexAttrib4fv_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttrib4fv, values_shm_id) == 8,
+ OffsetOf_VertexAttrib4fv_values_shm_id_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib4fv, values_shm_offset) == 12,
+ OffsetOf_VertexAttrib4fv_values_shm_offset_not_12);
+
+struct VertexAttrib4fvImmediate {
+ typedef VertexAttrib4fvImmediate ValueType;
+ static const CommandId kCmdId = kVertexAttrib4fvImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLfloat) * 4); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLuint _indx, const GLfloat* _values) {
+ SetHeader();
+ indx = _indx;
+ memcpy(ImmediateDataAddress(this),
+ _values, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLuint _indx, const GLfloat* _values) {
+ static_cast<ValueType*>(cmd)->Init(_indx, _values);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttrib4fvImmediate) == 8,
+ Sizeof_VertexAttrib4fvImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(VertexAttrib4fvImmediate, header) == 0,
+ OffsetOf_VertexAttrib4fvImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttrib4fvImmediate, indx) == 4,
+ OffsetOf_VertexAttrib4fvImmediate_indx_not_4);
+
+struct VertexAttribPointer {
+ typedef VertexAttribPointer ValueType;
+ static const CommandId kCmdId = kVertexAttribPointer;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _indx, GLint _size, GLenum _type, GLboolean _normalized,
+ GLsizei _stride, GLuint _offset) {
+ SetHeader();
+ indx = _indx;
+ size = _size;
+ type = _type;
+ normalized = _normalized;
+ stride = _stride;
+ offset = _offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _indx, GLint _size, GLenum _type, GLboolean _normalized,
+ GLsizei _stride, GLuint _offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_indx, _size, _type, _normalized, _stride, _offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 indx;
+ int32 size;
+ uint32 type;
+ uint32 normalized;
+ int32 stride;
+ uint32 offset;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttribPointer) == 28,
+ Sizeof_VertexAttribPointer_is_not_28);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, header) == 0,
+ OffsetOf_VertexAttribPointer_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, indx) == 4,
+ OffsetOf_VertexAttribPointer_indx_not_4);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, size) == 8,
+ OffsetOf_VertexAttribPointer_size_not_8);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, type) == 12,
+ OffsetOf_VertexAttribPointer_type_not_12);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, normalized) == 16,
+ OffsetOf_VertexAttribPointer_normalized_not_16);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, stride) == 20,
+ OffsetOf_VertexAttribPointer_stride_not_20);
+COMPILE_ASSERT(offsetof(VertexAttribPointer, offset) == 24,
+ OffsetOf_VertexAttribPointer_offset_not_24);
+
+struct Viewport {
+ typedef Viewport ValueType;
+ static const CommandId kCmdId = kViewport;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _x, GLint _y, GLsizei _width, GLsizei _height) {
+ SetHeader();
+ x = _x;
+ y = _y;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(void* cmd, GLint _x, GLint _y, GLsizei _width, GLsizei _height) {
+ static_cast<ValueType*>(cmd)->Init(_x, _y, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(Viewport) == 20,
+ Sizeof_Viewport_is_not_20);
+COMPILE_ASSERT(offsetof(Viewport, header) == 0,
+ OffsetOf_Viewport_header_not_0);
+COMPILE_ASSERT(offsetof(Viewport, x) == 4,
+ OffsetOf_Viewport_x_not_4);
+COMPILE_ASSERT(offsetof(Viewport, y) == 8,
+ OffsetOf_Viewport_y_not_8);
+COMPILE_ASSERT(offsetof(Viewport, width) == 12,
+ OffsetOf_Viewport_width_not_12);
+COMPILE_ASSERT(offsetof(Viewport, height) == 16,
+ OffsetOf_Viewport_height_not_16);
+
+struct BlitFramebufferEXT {
+ typedef BlitFramebufferEXT ValueType;
+ static const CommandId kCmdId = kBlitFramebufferEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLint _srcX0, GLint _srcY0, GLint _srcX1, GLint _srcY1, GLint _dstX0,
+ GLint _dstY0, GLint _dstX1, GLint _dstY1, GLbitfield _mask,
+ GLenum _filter) {
+ SetHeader();
+ srcX0 = _srcX0;
+ srcY0 = _srcY0;
+ srcX1 = _srcX1;
+ srcY1 = _srcY1;
+ dstX0 = _dstX0;
+ dstY0 = _dstY0;
+ dstX1 = _dstX1;
+ dstY1 = _dstY1;
+ mask = _mask;
+ filter = _filter;
+ }
+
+ void* Set(
+ void* cmd, GLint _srcX0, GLint _srcY0, GLint _srcX1, GLint _srcY1,
+ GLint _dstX0, GLint _dstY0, GLint _dstX1, GLint _dstY1, GLbitfield _mask,
+ GLenum _filter) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _srcX0, _srcY0, _srcX1, _srcY1, _dstX0, _dstY0, _dstX1, _dstY1,
+ _mask, _filter);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 srcX0;
+ int32 srcY0;
+ int32 srcX1;
+ int32 srcY1;
+ int32 dstX0;
+ int32 dstY0;
+ int32 dstX1;
+ int32 dstY1;
+ uint32 mask;
+ uint32 filter;
+};
+
+COMPILE_ASSERT(sizeof(BlitFramebufferEXT) == 44,
+ Sizeof_BlitFramebufferEXT_is_not_44);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, header) == 0,
+ OffsetOf_BlitFramebufferEXT_header_not_0);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, srcX0) == 4,
+ OffsetOf_BlitFramebufferEXT_srcX0_not_4);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, srcY0) == 8,
+ OffsetOf_BlitFramebufferEXT_srcY0_not_8);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, srcX1) == 12,
+ OffsetOf_BlitFramebufferEXT_srcX1_not_12);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, srcY1) == 16,
+ OffsetOf_BlitFramebufferEXT_srcY1_not_16);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, dstX0) == 20,
+ OffsetOf_BlitFramebufferEXT_dstX0_not_20);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, dstY0) == 24,
+ OffsetOf_BlitFramebufferEXT_dstY0_not_24);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, dstX1) == 28,
+ OffsetOf_BlitFramebufferEXT_dstX1_not_28);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, dstY1) == 32,
+ OffsetOf_BlitFramebufferEXT_dstY1_not_32);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, mask) == 36,
+ OffsetOf_BlitFramebufferEXT_mask_not_36);
+COMPILE_ASSERT(offsetof(BlitFramebufferEXT, filter) == 40,
+ OffsetOf_BlitFramebufferEXT_filter_not_40);
+
+struct RenderbufferStorageMultisampleEXT {
+ typedef RenderbufferStorageMultisampleEXT ValueType;
+ static const CommandId kCmdId = kRenderbufferStorageMultisampleEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLsizei _samples, GLenum _internalformat, GLsizei _width,
+ GLsizei _height) {
+ SetHeader();
+ target = _target;
+ samples = _samples;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLsizei _samples, GLenum _internalformat,
+ GLsizei _width, GLsizei _height) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _samples, _internalformat, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 samples;
+ uint32 internalformat;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(RenderbufferStorageMultisampleEXT) == 24,
+ Sizeof_RenderbufferStorageMultisampleEXT_is_not_24);
+COMPILE_ASSERT(offsetof(RenderbufferStorageMultisampleEXT, header) == 0,
+ OffsetOf_RenderbufferStorageMultisampleEXT_header_not_0);
+COMPILE_ASSERT(offsetof(RenderbufferStorageMultisampleEXT, target) == 4,
+ OffsetOf_RenderbufferStorageMultisampleEXT_target_not_4);
+COMPILE_ASSERT(offsetof(RenderbufferStorageMultisampleEXT, samples) == 8,
+ OffsetOf_RenderbufferStorageMultisampleEXT_samples_not_8);
+COMPILE_ASSERT(
+ offsetof(RenderbufferStorageMultisampleEXT, internalformat) == 12,
+ OffsetOf_RenderbufferStorageMultisampleEXT_internalformat_not_12); // NOLINT
+COMPILE_ASSERT(offsetof(RenderbufferStorageMultisampleEXT, width) == 16,
+ OffsetOf_RenderbufferStorageMultisampleEXT_width_not_16);
+COMPILE_ASSERT(offsetof(RenderbufferStorageMultisampleEXT, height) == 20,
+ OffsetOf_RenderbufferStorageMultisampleEXT_height_not_20);
+
+struct FramebufferTexture2DMultisampleEXT {
+ typedef FramebufferTexture2DMultisampleEXT ValueType;
+ static const CommandId kCmdId = kFramebufferTexture2DMultisampleEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _attachment, GLenum _textarget, GLuint _texture,
+ GLint _level, GLsizei _samples) {
+ SetHeader();
+ target = _target;
+ attachment = _attachment;
+ textarget = _textarget;
+ texture = _texture;
+ level = _level;
+ samples = _samples;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _attachment, GLenum _textarget,
+ GLuint _texture, GLint _level, GLsizei _samples) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _attachment, _textarget, _texture, _level, _samples);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 attachment;
+ uint32 textarget;
+ uint32 texture;
+ int32 level;
+ int32 samples;
+};
+
+COMPILE_ASSERT(sizeof(FramebufferTexture2DMultisampleEXT) == 28,
+ Sizeof_FramebufferTexture2DMultisampleEXT_is_not_28);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, header) == 0,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_header_not_0);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, target) == 4,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_target_not_4);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, attachment) == 8,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_attachment_not_8);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, textarget) == 12,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_textarget_not_12);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, texture) == 16,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_texture_not_16);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, level) == 20,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_level_not_20);
+COMPILE_ASSERT(offsetof(FramebufferTexture2DMultisampleEXT, samples) == 24,
+ OffsetOf_FramebufferTexture2DMultisampleEXT_samples_not_24);
+
+struct TexStorage2DEXT {
+ typedef TexStorage2DEXT ValueType;
+ static const CommandId kCmdId = kTexStorage2DEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLsizei _levels, GLenum _internalFormat, GLsizei _width,
+ GLsizei _height) {
+ SetHeader();
+ target = _target;
+ levels = _levels;
+ internalFormat = _internalFormat;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLsizei _levels, GLenum _internalFormat,
+ GLsizei _width, GLsizei _height) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _levels, _internalFormat, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 levels;
+ uint32 internalFormat;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(TexStorage2DEXT) == 24,
+ Sizeof_TexStorage2DEXT_is_not_24);
+COMPILE_ASSERT(offsetof(TexStorage2DEXT, header) == 0,
+ OffsetOf_TexStorage2DEXT_header_not_0);
+COMPILE_ASSERT(offsetof(TexStorage2DEXT, target) == 4,
+ OffsetOf_TexStorage2DEXT_target_not_4);
+COMPILE_ASSERT(offsetof(TexStorage2DEXT, levels) == 8,
+ OffsetOf_TexStorage2DEXT_levels_not_8);
+COMPILE_ASSERT(offsetof(TexStorage2DEXT, internalFormat) == 12,
+ OffsetOf_TexStorage2DEXT_internalFormat_not_12);
+COMPILE_ASSERT(offsetof(TexStorage2DEXT, width) == 16,
+ OffsetOf_TexStorage2DEXT_width_not_16);
+COMPILE_ASSERT(offsetof(TexStorage2DEXT, height) == 20,
+ OffsetOf_TexStorage2DEXT_height_not_20);
+
+struct GenQueriesEXT {
+ typedef GenQueriesEXT ValueType;
+ static const CommandId kCmdId = kGenQueriesEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _queries_shm_id, uint32 _queries_shm_offset) {
+ SetHeader();
+ n = _n;
+ queries_shm_id = _queries_shm_id;
+ queries_shm_offset = _queries_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _queries_shm_id,
+ uint32 _queries_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _queries_shm_id, _queries_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 queries_shm_id;
+ uint32 queries_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenQueriesEXT) == 16,
+ Sizeof_GenQueriesEXT_is_not_16);
+COMPILE_ASSERT(offsetof(GenQueriesEXT, header) == 0,
+ OffsetOf_GenQueriesEXT_header_not_0);
+COMPILE_ASSERT(offsetof(GenQueriesEXT, n) == 4,
+ OffsetOf_GenQueriesEXT_n_not_4);
+COMPILE_ASSERT(offsetof(GenQueriesEXT, queries_shm_id) == 8,
+ OffsetOf_GenQueriesEXT_queries_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenQueriesEXT, queries_shm_offset) == 12,
+ OffsetOf_GenQueriesEXT_queries_shm_offset_not_12);
+
+struct GenQueriesEXTImmediate {
+ typedef GenQueriesEXTImmediate ValueType;
+ static const CommandId kCmdId = kGenQueriesEXTImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _queries) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _queries, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _queries) {
+ static_cast<ValueType*>(cmd)->Init(_n, _queries);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenQueriesEXTImmediate) == 8,
+ Sizeof_GenQueriesEXTImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenQueriesEXTImmediate, header) == 0,
+ OffsetOf_GenQueriesEXTImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenQueriesEXTImmediate, n) == 4,
+ OffsetOf_GenQueriesEXTImmediate_n_not_4);
+
+struct DeleteQueriesEXT {
+ typedef DeleteQueriesEXT ValueType;
+ static const CommandId kCmdId = kDeleteQueriesEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _queries_shm_id, uint32 _queries_shm_offset) {
+ SetHeader();
+ n = _n;
+ queries_shm_id = _queries_shm_id;
+ queries_shm_offset = _queries_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _queries_shm_id,
+ uint32 _queries_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_n, _queries_shm_id, _queries_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 queries_shm_id;
+ uint32 queries_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteQueriesEXT) == 16,
+ Sizeof_DeleteQueriesEXT_is_not_16);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXT, header) == 0,
+ OffsetOf_DeleteQueriesEXT_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXT, n) == 4,
+ OffsetOf_DeleteQueriesEXT_n_not_4);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXT, queries_shm_id) == 8,
+ OffsetOf_DeleteQueriesEXT_queries_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXT, queries_shm_offset) == 12,
+ OffsetOf_DeleteQueriesEXT_queries_shm_offset_not_12);
+
+struct DeleteQueriesEXTImmediate {
+ typedef DeleteQueriesEXTImmediate ValueType;
+ static const CommandId kCmdId = kDeleteQueriesEXTImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _queries) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _queries, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _queries) {
+ static_cast<ValueType*>(cmd)->Init(_n, _queries);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteQueriesEXTImmediate) == 8,
+ Sizeof_DeleteQueriesEXTImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXTImmediate, header) == 0,
+ OffsetOf_DeleteQueriesEXTImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteQueriesEXTImmediate, n) == 4,
+ OffsetOf_DeleteQueriesEXTImmediate_n_not_4);
+
+struct BeginQueryEXT {
+ typedef BeginQueryEXT ValueType;
+ static const CommandId kCmdId = kBeginQueryEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLuint _id, uint32 _sync_data_shm_id,
+ uint32 _sync_data_shm_offset) {
+ SetHeader();
+ target = _target;
+ id = _id;
+ sync_data_shm_id = _sync_data_shm_id;
+ sync_data_shm_offset = _sync_data_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLuint _id, uint32 _sync_data_shm_id,
+ uint32 _sync_data_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _id, _sync_data_shm_id, _sync_data_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 id;
+ uint32 sync_data_shm_id;
+ uint32 sync_data_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(BeginQueryEXT) == 20,
+ Sizeof_BeginQueryEXT_is_not_20);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, header) == 0,
+ OffsetOf_BeginQueryEXT_header_not_0);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, target) == 4,
+ OffsetOf_BeginQueryEXT_target_not_4);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, id) == 8,
+ OffsetOf_BeginQueryEXT_id_not_8);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, sync_data_shm_id) == 12,
+ OffsetOf_BeginQueryEXT_sync_data_shm_id_not_12);
+COMPILE_ASSERT(offsetof(BeginQueryEXT, sync_data_shm_offset) == 16,
+ OffsetOf_BeginQueryEXT_sync_data_shm_offset_not_16);
+
+struct EndQueryEXT {
+ typedef EndQueryEXT ValueType;
+ static const CommandId kCmdId = kEndQueryEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLuint _submit_count) {
+ SetHeader();
+ target = _target;
+ submit_count = _submit_count;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLuint _submit_count) {
+ static_cast<ValueType*>(cmd)->Init(_target, _submit_count);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 submit_count;
+};
+
+COMPILE_ASSERT(sizeof(EndQueryEXT) == 12,
+ Sizeof_EndQueryEXT_is_not_12);
+COMPILE_ASSERT(offsetof(EndQueryEXT, header) == 0,
+ OffsetOf_EndQueryEXT_header_not_0);
+COMPILE_ASSERT(offsetof(EndQueryEXT, target) == 4,
+ OffsetOf_EndQueryEXT_target_not_4);
+COMPILE_ASSERT(offsetof(EndQueryEXT, submit_count) == 8,
+ OffsetOf_EndQueryEXT_submit_count_not_8);
+
+struct InsertEventMarkerEXT {
+ typedef InsertEventMarkerEXT ValueType;
+ static const CommandId kCmdId = kInsertEventMarkerEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _bucket_id) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(InsertEventMarkerEXT) == 8,
+ Sizeof_InsertEventMarkerEXT_is_not_8);
+COMPILE_ASSERT(offsetof(InsertEventMarkerEXT, header) == 0,
+ OffsetOf_InsertEventMarkerEXT_header_not_0);
+COMPILE_ASSERT(offsetof(InsertEventMarkerEXT, bucket_id) == 4,
+ OffsetOf_InsertEventMarkerEXT_bucket_id_not_4);
+
+struct PushGroupMarkerEXT {
+ typedef PushGroupMarkerEXT ValueType;
+ static const CommandId kCmdId = kPushGroupMarkerEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _bucket_id) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(PushGroupMarkerEXT) == 8,
+ Sizeof_PushGroupMarkerEXT_is_not_8);
+COMPILE_ASSERT(offsetof(PushGroupMarkerEXT, header) == 0,
+ OffsetOf_PushGroupMarkerEXT_header_not_0);
+COMPILE_ASSERT(offsetof(PushGroupMarkerEXT, bucket_id) == 4,
+ OffsetOf_PushGroupMarkerEXT_bucket_id_not_4);
+
+struct PopGroupMarkerEXT {
+ typedef PopGroupMarkerEXT ValueType;
+ static const CommandId kCmdId = kPopGroupMarkerEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(PopGroupMarkerEXT) == 4,
+ Sizeof_PopGroupMarkerEXT_is_not_4);
+COMPILE_ASSERT(offsetof(PopGroupMarkerEXT, header) == 0,
+ OffsetOf_PopGroupMarkerEXT_header_not_0);
+
+struct GenVertexArraysOES {
+ typedef GenVertexArraysOES ValueType;
+ static const CommandId kCmdId = kGenVertexArraysOES;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _arrays_shm_id, uint32 _arrays_shm_offset) {
+ SetHeader();
+ n = _n;
+ arrays_shm_id = _arrays_shm_id;
+ arrays_shm_offset = _arrays_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _arrays_shm_id,
+ uint32 _arrays_shm_offset) {
+ static_cast<ValueType*>(cmd)->Init(_n, _arrays_shm_id, _arrays_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 arrays_shm_id;
+ uint32 arrays_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenVertexArraysOES) == 16,
+ Sizeof_GenVertexArraysOES_is_not_16);
+COMPILE_ASSERT(offsetof(GenVertexArraysOES, header) == 0,
+ OffsetOf_GenVertexArraysOES_header_not_0);
+COMPILE_ASSERT(offsetof(GenVertexArraysOES, n) == 4,
+ OffsetOf_GenVertexArraysOES_n_not_4);
+COMPILE_ASSERT(offsetof(GenVertexArraysOES, arrays_shm_id) == 8,
+ OffsetOf_GenVertexArraysOES_arrays_shm_id_not_8);
+COMPILE_ASSERT(offsetof(GenVertexArraysOES, arrays_shm_offset) == 12,
+ OffsetOf_GenVertexArraysOES_arrays_shm_offset_not_12);
+
+struct GenVertexArraysOESImmediate {
+ typedef GenVertexArraysOESImmediate ValueType;
+ static const CommandId kCmdId = kGenVertexArraysOESImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _arrays) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _arrays, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _arrays) {
+ static_cast<ValueType*>(cmd)->Init(_n, _arrays);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(GenVertexArraysOESImmediate) == 8,
+ Sizeof_GenVertexArraysOESImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenVertexArraysOESImmediate, header) == 0,
+ OffsetOf_GenVertexArraysOESImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenVertexArraysOESImmediate, n) == 4,
+ OffsetOf_GenVertexArraysOESImmediate_n_not_4);
+
+struct DeleteVertexArraysOES {
+ typedef DeleteVertexArraysOES ValueType;
+ static const CommandId kCmdId = kDeleteVertexArraysOES;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _n, uint32 _arrays_shm_id, uint32 _arrays_shm_offset) {
+ SetHeader();
+ n = _n;
+ arrays_shm_id = _arrays_shm_id;
+ arrays_shm_offset = _arrays_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _n, uint32 _arrays_shm_id,
+ uint32 _arrays_shm_offset) {
+ static_cast<ValueType*>(cmd)->Init(_n, _arrays_shm_id, _arrays_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+ uint32 arrays_shm_id;
+ uint32 arrays_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteVertexArraysOES) == 16,
+ Sizeof_DeleteVertexArraysOES_is_not_16);
+COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, header) == 0,
+ OffsetOf_DeleteVertexArraysOES_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, n) == 4,
+ OffsetOf_DeleteVertexArraysOES_n_not_4);
+COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, arrays_shm_id) == 8,
+ OffsetOf_DeleteVertexArraysOES_arrays_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DeleteVertexArraysOES, arrays_shm_offset) == 12,
+ OffsetOf_DeleteVertexArraysOES_arrays_shm_offset_not_12);
+
+struct DeleteVertexArraysOESImmediate {
+ typedef DeleteVertexArraysOESImmediate ValueType;
+ static const CommandId kCmdId = kDeleteVertexArraysOESImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei n) {
+ return static_cast<uint32>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei n) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _arrays) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this),
+ _arrays, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _arrays) {
+ static_cast<ValueType*>(cmd)->Init(_n, _arrays);
+ const uint32 size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteVertexArraysOESImmediate) == 8,
+ Sizeof_DeleteVertexArraysOESImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteVertexArraysOESImmediate, header) == 0,
+ OffsetOf_DeleteVertexArraysOESImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteVertexArraysOESImmediate, n) == 4,
+ OffsetOf_DeleteVertexArraysOESImmediate_n_not_4);
+
+struct IsVertexArrayOES {
+ typedef IsVertexArrayOES ValueType;
+ static const CommandId kCmdId = kIsVertexArrayOES;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef uint32 Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _array, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ array = _array;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _array, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_array, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 array;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsVertexArrayOES) == 16,
+ Sizeof_IsVertexArrayOES_is_not_16);
+COMPILE_ASSERT(offsetof(IsVertexArrayOES, header) == 0,
+ OffsetOf_IsVertexArrayOES_header_not_0);
+COMPILE_ASSERT(offsetof(IsVertexArrayOES, array) == 4,
+ OffsetOf_IsVertexArrayOES_array_not_4);
+COMPILE_ASSERT(offsetof(IsVertexArrayOES, result_shm_id) == 8,
+ OffsetOf_IsVertexArrayOES_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsVertexArrayOES, result_shm_offset) == 12,
+ OffsetOf_IsVertexArrayOES_result_shm_offset_not_12);
+
+struct BindVertexArrayOES {
+ typedef BindVertexArrayOES ValueType;
+ static const CommandId kCmdId = kBindVertexArrayOES;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _array) {
+ SetHeader();
+ array = _array;
+ }
+
+ void* Set(void* cmd, GLuint _array) {
+ static_cast<ValueType*>(cmd)->Init(_array);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 array;
+};
+
+COMPILE_ASSERT(sizeof(BindVertexArrayOES) == 8,
+ Sizeof_BindVertexArrayOES_is_not_8);
+COMPILE_ASSERT(offsetof(BindVertexArrayOES, header) == 0,
+ OffsetOf_BindVertexArrayOES_header_not_0);
+COMPILE_ASSERT(offsetof(BindVertexArrayOES, array) == 4,
+ OffsetOf_BindVertexArrayOES_array_not_4);
+
+struct SwapBuffers {
+ typedef SwapBuffers ValueType;
+ static const CommandId kCmdId = kSwapBuffers;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(SwapBuffers) == 4,
+ Sizeof_SwapBuffers_is_not_4);
+COMPILE_ASSERT(offsetof(SwapBuffers, header) == 0,
+ OffsetOf_SwapBuffers_header_not_0);
+
+struct GetMaxValueInBufferCHROMIUM {
+ typedef GetMaxValueInBufferCHROMIUM ValueType;
+ static const CommandId kCmdId = kGetMaxValueInBufferCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLuint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _buffer_id, GLsizei _count, GLenum _type, GLuint _offset,
+ uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ buffer_id = _buffer_id;
+ count = _count;
+ type = _type;
+ offset = _offset;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _buffer_id, GLsizei _count, GLenum _type,
+ GLuint _offset, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _buffer_id, _count, _type, _offset, _result_shm_id,
+ _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 buffer_id;
+ int32 count;
+ uint32 type;
+ uint32 offset;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GetMaxValueInBufferCHROMIUM) == 28,
+ Sizeof_GetMaxValueInBufferCHROMIUM_is_not_28);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, header) == 0,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, buffer_id) == 4,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_buffer_id_not_4);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, count) == 8,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_count_not_8);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, type) == 12,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_type_not_12);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, offset) == 16,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_offset_not_16);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, result_shm_id) == 20,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_result_shm_id_not_20);
+COMPILE_ASSERT(offsetof(GetMaxValueInBufferCHROMIUM, result_shm_offset) == 24,
+ OffsetOf_GetMaxValueInBufferCHROMIUM_result_shm_offset_not_24);
+
+struct GenSharedIdsCHROMIUM {
+ typedef GenSharedIdsCHROMIUM ValueType;
+ static const CommandId kCmdId = kGenSharedIdsCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _namespace_id, GLuint _id_offset, GLsizei _n, uint32 _ids_shm_id,
+ uint32 _ids_shm_offset) {
+ SetHeader();
+ namespace_id = _namespace_id;
+ id_offset = _id_offset;
+ n = _n;
+ ids_shm_id = _ids_shm_id;
+ ids_shm_offset = _ids_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _namespace_id, GLuint _id_offset, GLsizei _n,
+ uint32 _ids_shm_id, uint32 _ids_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _namespace_id, _id_offset, _n, _ids_shm_id, _ids_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 namespace_id;
+ uint32 id_offset;
+ int32 n;
+ uint32 ids_shm_id;
+ uint32 ids_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(GenSharedIdsCHROMIUM) == 24,
+ Sizeof_GenSharedIdsCHROMIUM_is_not_24);
+COMPILE_ASSERT(offsetof(GenSharedIdsCHROMIUM, header) == 0,
+ OffsetOf_GenSharedIdsCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GenSharedIdsCHROMIUM, namespace_id) == 4,
+ OffsetOf_GenSharedIdsCHROMIUM_namespace_id_not_4);
+COMPILE_ASSERT(offsetof(GenSharedIdsCHROMIUM, id_offset) == 8,
+ OffsetOf_GenSharedIdsCHROMIUM_id_offset_not_8);
+COMPILE_ASSERT(offsetof(GenSharedIdsCHROMIUM, n) == 12,
+ OffsetOf_GenSharedIdsCHROMIUM_n_not_12);
+COMPILE_ASSERT(offsetof(GenSharedIdsCHROMIUM, ids_shm_id) == 16,
+ OffsetOf_GenSharedIdsCHROMIUM_ids_shm_id_not_16);
+COMPILE_ASSERT(offsetof(GenSharedIdsCHROMIUM, ids_shm_offset) == 20,
+ OffsetOf_GenSharedIdsCHROMIUM_ids_shm_offset_not_20);
+
+struct DeleteSharedIdsCHROMIUM {
+ typedef DeleteSharedIdsCHROMIUM ValueType;
+ static const CommandId kCmdId = kDeleteSharedIdsCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _namespace_id, GLsizei _n, uint32 _ids_shm_id,
+ uint32 _ids_shm_offset) {
+ SetHeader();
+ namespace_id = _namespace_id;
+ n = _n;
+ ids_shm_id = _ids_shm_id;
+ ids_shm_offset = _ids_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _namespace_id, GLsizei _n, uint32 _ids_shm_id,
+ uint32 _ids_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_namespace_id, _n, _ids_shm_id, _ids_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 namespace_id;
+ int32 n;
+ uint32 ids_shm_id;
+ uint32 ids_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DeleteSharedIdsCHROMIUM) == 20,
+ Sizeof_DeleteSharedIdsCHROMIUM_is_not_20);
+COMPILE_ASSERT(offsetof(DeleteSharedIdsCHROMIUM, header) == 0,
+ OffsetOf_DeleteSharedIdsCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteSharedIdsCHROMIUM, namespace_id) == 4,
+ OffsetOf_DeleteSharedIdsCHROMIUM_namespace_id_not_4);
+COMPILE_ASSERT(offsetof(DeleteSharedIdsCHROMIUM, n) == 8,
+ OffsetOf_DeleteSharedIdsCHROMIUM_n_not_8);
+COMPILE_ASSERT(offsetof(DeleteSharedIdsCHROMIUM, ids_shm_id) == 12,
+ OffsetOf_DeleteSharedIdsCHROMIUM_ids_shm_id_not_12);
+COMPILE_ASSERT(offsetof(DeleteSharedIdsCHROMIUM, ids_shm_offset) == 16,
+ OffsetOf_DeleteSharedIdsCHROMIUM_ids_shm_offset_not_16);
+
+struct RegisterSharedIdsCHROMIUM {
+ typedef RegisterSharedIdsCHROMIUM ValueType;
+ static const CommandId kCmdId = kRegisterSharedIdsCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _namespace_id, GLsizei _n, uint32 _ids_shm_id,
+ uint32 _ids_shm_offset) {
+ SetHeader();
+ namespace_id = _namespace_id;
+ n = _n;
+ ids_shm_id = _ids_shm_id;
+ ids_shm_offset = _ids_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _namespace_id, GLsizei _n, uint32 _ids_shm_id,
+ uint32 _ids_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_namespace_id, _n, _ids_shm_id, _ids_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 namespace_id;
+ int32 n;
+ uint32 ids_shm_id;
+ uint32 ids_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(RegisterSharedIdsCHROMIUM) == 20,
+ Sizeof_RegisterSharedIdsCHROMIUM_is_not_20);
+COMPILE_ASSERT(offsetof(RegisterSharedIdsCHROMIUM, header) == 0,
+ OffsetOf_RegisterSharedIdsCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(RegisterSharedIdsCHROMIUM, namespace_id) == 4,
+ OffsetOf_RegisterSharedIdsCHROMIUM_namespace_id_not_4);
+COMPILE_ASSERT(offsetof(RegisterSharedIdsCHROMIUM, n) == 8,
+ OffsetOf_RegisterSharedIdsCHROMIUM_n_not_8);
+COMPILE_ASSERT(offsetof(RegisterSharedIdsCHROMIUM, ids_shm_id) == 12,
+ OffsetOf_RegisterSharedIdsCHROMIUM_ids_shm_id_not_12);
+COMPILE_ASSERT(offsetof(RegisterSharedIdsCHROMIUM, ids_shm_offset) == 16,
+ OffsetOf_RegisterSharedIdsCHROMIUM_ids_shm_offset_not_16);
+
+struct EnableFeatureCHROMIUM {
+ typedef EnableFeatureCHROMIUM ValueType;
+ static const CommandId kCmdId = kEnableFeatureCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _bucket_id, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _bucket_id, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_bucket_id, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(EnableFeatureCHROMIUM) == 16,
+ Sizeof_EnableFeatureCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(EnableFeatureCHROMIUM, header) == 0,
+ OffsetOf_EnableFeatureCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(EnableFeatureCHROMIUM, bucket_id) == 4,
+ OffsetOf_EnableFeatureCHROMIUM_bucket_id_not_4);
+COMPILE_ASSERT(offsetof(EnableFeatureCHROMIUM, result_shm_id) == 8,
+ OffsetOf_EnableFeatureCHROMIUM_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(EnableFeatureCHROMIUM, result_shm_offset) == 12,
+ OffsetOf_EnableFeatureCHROMIUM_result_shm_offset_not_12);
+
+struct ResizeCHROMIUM {
+ typedef ResizeCHROMIUM ValueType;
+ static const CommandId kCmdId = kResizeCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _width, GLuint _height, GLfloat _scale_factor) {
+ SetHeader();
+ width = _width;
+ height = _height;
+ scale_factor = _scale_factor;
+ }
+
+ void* Set(void* cmd, GLuint _width, GLuint _height, GLfloat _scale_factor) {
+ static_cast<ValueType*>(cmd)->Init(_width, _height, _scale_factor);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 width;
+ uint32 height;
+ float scale_factor;
+};
+
+COMPILE_ASSERT(sizeof(ResizeCHROMIUM) == 16,
+ Sizeof_ResizeCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(ResizeCHROMIUM, header) == 0,
+ OffsetOf_ResizeCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(ResizeCHROMIUM, width) == 4,
+ OffsetOf_ResizeCHROMIUM_width_not_4);
+COMPILE_ASSERT(offsetof(ResizeCHROMIUM, height) == 8,
+ OffsetOf_ResizeCHROMIUM_height_not_8);
+COMPILE_ASSERT(offsetof(ResizeCHROMIUM, scale_factor) == 12,
+ OffsetOf_ResizeCHROMIUM_scale_factor_not_12);
+
+struct GetRequestableExtensionsCHROMIUM {
+ typedef GetRequestableExtensionsCHROMIUM ValueType;
+ static const CommandId kCmdId = kGetRequestableExtensionsCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _bucket_id) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetRequestableExtensionsCHROMIUM) == 8,
+ Sizeof_GetRequestableExtensionsCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(GetRequestableExtensionsCHROMIUM, header) == 0,
+ OffsetOf_GetRequestableExtensionsCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GetRequestableExtensionsCHROMIUM, bucket_id) == 4,
+ OffsetOf_GetRequestableExtensionsCHROMIUM_bucket_id_not_4);
+
+struct RequestExtensionCHROMIUM {
+ typedef RequestExtensionCHROMIUM ValueType;
+ static const CommandId kCmdId = kRequestExtensionCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(uint32 _bucket_id) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(RequestExtensionCHROMIUM) == 8,
+ Sizeof_RequestExtensionCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(RequestExtensionCHROMIUM, header) == 0,
+ OffsetOf_RequestExtensionCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(RequestExtensionCHROMIUM, bucket_id) == 4,
+ OffsetOf_RequestExtensionCHROMIUM_bucket_id_not_4);
+
+struct GetMultipleIntegervCHROMIUM {
+ typedef GetMultipleIntegervCHROMIUM ValueType;
+ static const CommandId kCmdId = kGetMultipleIntegervCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ uint32 _pnames_shm_id, uint32 _pnames_shm_offset, GLuint _count,
+ uint32 _results_shm_id, uint32 _results_shm_offset, GLsizeiptr _size) {
+ SetHeader();
+ pnames_shm_id = _pnames_shm_id;
+ pnames_shm_offset = _pnames_shm_offset;
+ count = _count;
+ results_shm_id = _results_shm_id;
+ results_shm_offset = _results_shm_offset;
+ size = _size;
+ }
+
+ void* Set(
+ void* cmd, uint32 _pnames_shm_id, uint32 _pnames_shm_offset,
+ GLuint _count, uint32 _results_shm_id, uint32 _results_shm_offset,
+ GLsizeiptr _size) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _pnames_shm_id, _pnames_shm_offset, _count, _results_shm_id,
+ _results_shm_offset, _size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 pnames_shm_id;
+ uint32 pnames_shm_offset;
+ uint32 count;
+ uint32 results_shm_id;
+ uint32 results_shm_offset;
+ int32 size;
+};
+
+COMPILE_ASSERT(sizeof(GetMultipleIntegervCHROMIUM) == 28,
+ Sizeof_GetMultipleIntegervCHROMIUM_is_not_28);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, header) == 0,
+ OffsetOf_GetMultipleIntegervCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, pnames_shm_id) == 4,
+ OffsetOf_GetMultipleIntegervCHROMIUM_pnames_shm_id_not_4);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, pnames_shm_offset) == 8,
+ OffsetOf_GetMultipleIntegervCHROMIUM_pnames_shm_offset_not_8);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, count) == 12,
+ OffsetOf_GetMultipleIntegervCHROMIUM_count_not_12);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_id) == 16,
+ OffsetOf_GetMultipleIntegervCHROMIUM_results_shm_id_not_16);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_offset) == 20,
+ OffsetOf_GetMultipleIntegervCHROMIUM_results_shm_offset_not_20);
+COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, size) == 24,
+ OffsetOf_GetMultipleIntegervCHROMIUM_size_not_24);
+
+struct GetProgramInfoCHROMIUM {
+ typedef GetProgramInfoCHROMIUM ValueType;
+ static const CommandId kCmdId = kGetProgramInfoCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ struct Result {
+ uint32 link_status;
+ uint32 num_attribs;
+ uint32 num_uniforms;
+ };
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, uint32 _bucket_id) {
+ SetHeader();
+ program = _program;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _program, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_program, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetProgramInfoCHROMIUM) == 12,
+ Sizeof_GetProgramInfoCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM, header) == 0,
+ OffsetOf_GetProgramInfoCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM, program) == 4,
+ OffsetOf_GetProgramInfoCHROMIUM_program_not_4);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM, bucket_id) == 8,
+ OffsetOf_GetProgramInfoCHROMIUM_bucket_id_not_8);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM::Result, link_status) == 0,
+ OffsetOf_GetProgramInfoCHROMIUM_Result_link_status_not_0);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM::Result, num_attribs) == 4,
+ OffsetOf_GetProgramInfoCHROMIUM_Result_num_attribs_not_4);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM::Result, num_uniforms) == 8,
+ OffsetOf_GetProgramInfoCHROMIUM_Result_num_uniforms_not_8);
+
+struct CreateStreamTextureCHROMIUM {
+ typedef CreateStreamTextureCHROMIUM ValueType;
+ static const CommandId kCmdId = kCreateStreamTextureCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef GLuint Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _client_id, uint32 _result_shm_id, uint32 _result_shm_offset) {
+ SetHeader();
+ client_id = _client_id;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLuint _client_id, uint32 _result_shm_id,
+ uint32 _result_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_client_id, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 client_id;
+ uint32 result_shm_id;
+ uint32 result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(CreateStreamTextureCHROMIUM) == 16,
+ Sizeof_CreateStreamTextureCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(CreateStreamTextureCHROMIUM, header) == 0,
+ OffsetOf_CreateStreamTextureCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(CreateStreamTextureCHROMIUM, client_id) == 4,
+ OffsetOf_CreateStreamTextureCHROMIUM_client_id_not_4);
+COMPILE_ASSERT(offsetof(CreateStreamTextureCHROMIUM, result_shm_id) == 8,
+ OffsetOf_CreateStreamTextureCHROMIUM_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(CreateStreamTextureCHROMIUM, result_shm_offset) == 12,
+ OffsetOf_CreateStreamTextureCHROMIUM_result_shm_offset_not_12);
+
+struct DestroyStreamTextureCHROMIUM {
+ typedef DestroyStreamTextureCHROMIUM ValueType;
+ static const CommandId kCmdId = kDestroyStreamTextureCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _texture) {
+ SetHeader();
+ texture = _texture;
+ }
+
+ void* Set(void* cmd, GLuint _texture) {
+ static_cast<ValueType*>(cmd)->Init(_texture);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 texture;
+};
+
+COMPILE_ASSERT(sizeof(DestroyStreamTextureCHROMIUM) == 8,
+ Sizeof_DestroyStreamTextureCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(DestroyStreamTextureCHROMIUM, header) == 0,
+ OffsetOf_DestroyStreamTextureCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(DestroyStreamTextureCHROMIUM, texture) == 4,
+ OffsetOf_DestroyStreamTextureCHROMIUM_texture_not_4);
+
+struct GetTranslatedShaderSourceANGLE {
+ typedef GetTranslatedShaderSourceANGLE ValueType;
+ static const CommandId kCmdId = kGetTranslatedShaderSourceANGLE;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _shader, uint32 _bucket_id) {
+ SetHeader();
+ shader = _shader;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _shader, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_shader, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 shader;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetTranslatedShaderSourceANGLE) == 12,
+ Sizeof_GetTranslatedShaderSourceANGLE_is_not_12);
+COMPILE_ASSERT(offsetof(GetTranslatedShaderSourceANGLE, header) == 0,
+ OffsetOf_GetTranslatedShaderSourceANGLE_header_not_0);
+COMPILE_ASSERT(offsetof(GetTranslatedShaderSourceANGLE, shader) == 4,
+ OffsetOf_GetTranslatedShaderSourceANGLE_shader_not_4);
+COMPILE_ASSERT(offsetof(GetTranslatedShaderSourceANGLE, bucket_id) == 8,
+ OffsetOf_GetTranslatedShaderSourceANGLE_bucket_id_not_8);
+
+struct PostSubBufferCHROMIUM {
+ typedef PostSubBufferCHROMIUM ValueType;
+ static const CommandId kCmdId = kPostSubBufferCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLint _x, GLint _y, GLint _width, GLint _height) {
+ SetHeader();
+ x = _x;
+ y = _y;
+ width = _width;
+ height = _height;
+ }
+
+ void* Set(void* cmd, GLint _x, GLint _y, GLint _width, GLint _height) {
+ static_cast<ValueType*>(cmd)->Init(_x, _y, _width, _height);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 x;
+ int32 y;
+ int32 width;
+ int32 height;
+};
+
+COMPILE_ASSERT(sizeof(PostSubBufferCHROMIUM) == 20,
+ Sizeof_PostSubBufferCHROMIUM_is_not_20);
+COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, header) == 0,
+ OffsetOf_PostSubBufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, x) == 4,
+ OffsetOf_PostSubBufferCHROMIUM_x_not_4);
+COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, y) == 8,
+ OffsetOf_PostSubBufferCHROMIUM_y_not_8);
+COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, width) == 12,
+ OffsetOf_PostSubBufferCHROMIUM_width_not_12);
+COMPILE_ASSERT(offsetof(PostSubBufferCHROMIUM, height) == 16,
+ OffsetOf_PostSubBufferCHROMIUM_height_not_16);
+
+struct TexImageIOSurface2DCHROMIUM {
+ typedef TexImageIOSurface2DCHROMIUM ValueType;
+ static const CommandId kCmdId = kTexImageIOSurface2DCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLsizei _width, GLsizei _height, GLuint _ioSurfaceId,
+ GLuint _plane) {
+ SetHeader();
+ target = _target;
+ width = _width;
+ height = _height;
+ ioSurfaceId = _ioSurfaceId;
+ plane = _plane;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLsizei _width, GLsizei _height,
+ GLuint _ioSurfaceId, GLuint _plane) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _width, _height, _ioSurfaceId, _plane);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 width;
+ int32 height;
+ uint32 ioSurfaceId;
+ uint32 plane;
+};
+
+COMPILE_ASSERT(sizeof(TexImageIOSurface2DCHROMIUM) == 24,
+ Sizeof_TexImageIOSurface2DCHROMIUM_is_not_24);
+COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, header) == 0,
+ OffsetOf_TexImageIOSurface2DCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, target) == 4,
+ OffsetOf_TexImageIOSurface2DCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, width) == 8,
+ OffsetOf_TexImageIOSurface2DCHROMIUM_width_not_8);
+COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, height) == 12,
+ OffsetOf_TexImageIOSurface2DCHROMIUM_height_not_12);
+COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, ioSurfaceId) == 16,
+ OffsetOf_TexImageIOSurface2DCHROMIUM_ioSurfaceId_not_16);
+COMPILE_ASSERT(offsetof(TexImageIOSurface2DCHROMIUM, plane) == 20,
+ OffsetOf_TexImageIOSurface2DCHROMIUM_plane_not_20);
+
+struct CopyTextureCHROMIUM {
+ typedef CopyTextureCHROMIUM ValueType;
+ static const CommandId kCmdId = kCopyTextureCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLenum _source_id, GLenum _dest_id, GLint _level,
+ GLint _internalformat, GLenum _dest_type) {
+ SetHeader();
+ target = _target;
+ source_id = _source_id;
+ dest_id = _dest_id;
+ level = _level;
+ internalformat = _internalformat;
+ dest_type = _dest_type;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLenum _source_id, GLenum _dest_id,
+ GLint _level, GLint _internalformat, GLenum _dest_type) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _source_id, _dest_id, _level, _internalformat,
+ _dest_type);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 source_id;
+ uint32 dest_id;
+ int32 level;
+ int32 internalformat;
+ uint32 dest_type;
+};
+
+COMPILE_ASSERT(sizeof(CopyTextureCHROMIUM) == 28,
+ Sizeof_CopyTextureCHROMIUM_is_not_28);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, header) == 0,
+ OffsetOf_CopyTextureCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, target) == 4,
+ OffsetOf_CopyTextureCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, source_id) == 8,
+ OffsetOf_CopyTextureCHROMIUM_source_id_not_8);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, dest_id) == 12,
+ OffsetOf_CopyTextureCHROMIUM_dest_id_not_12);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, level) == 16,
+ OffsetOf_CopyTextureCHROMIUM_level_not_16);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, internalformat) == 20,
+ OffsetOf_CopyTextureCHROMIUM_internalformat_not_20);
+COMPILE_ASSERT(offsetof(CopyTextureCHROMIUM, dest_type) == 24,
+ OffsetOf_CopyTextureCHROMIUM_dest_type_not_24);
+
+struct DrawArraysInstancedANGLE {
+ typedef DrawArraysInstancedANGLE ValueType;
+ static const CommandId kCmdId = kDrawArraysInstancedANGLE;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _mode, GLint _first, GLsizei _count, GLsizei _primcount) {
+ SetHeader();
+ mode = _mode;
+ first = _first;
+ count = _count;
+ primcount = _primcount;
+ }
+
+ void* Set(
+ void* cmd, GLenum _mode, GLint _first, GLsizei _count,
+ GLsizei _primcount) {
+ static_cast<ValueType*>(cmd)->Init(_mode, _first, _count, _primcount);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+ int32 first;
+ int32 count;
+ int32 primcount;
+};
+
+COMPILE_ASSERT(sizeof(DrawArraysInstancedANGLE) == 20,
+ Sizeof_DrawArraysInstancedANGLE_is_not_20);
+COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, header) == 0,
+ OffsetOf_DrawArraysInstancedANGLE_header_not_0);
+COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, mode) == 4,
+ OffsetOf_DrawArraysInstancedANGLE_mode_not_4);
+COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, first) == 8,
+ OffsetOf_DrawArraysInstancedANGLE_first_not_8);
+COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, count) == 12,
+ OffsetOf_DrawArraysInstancedANGLE_count_not_12);
+COMPILE_ASSERT(offsetof(DrawArraysInstancedANGLE, primcount) == 16,
+ OffsetOf_DrawArraysInstancedANGLE_primcount_not_16);
+
+struct DrawElementsInstancedANGLE {
+ typedef DrawElementsInstancedANGLE ValueType;
+ static const CommandId kCmdId = kDrawElementsInstancedANGLE;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _mode, GLsizei _count, GLenum _type, GLuint _index_offset,
+ GLsizei _primcount) {
+ SetHeader();
+ mode = _mode;
+ count = _count;
+ type = _type;
+ index_offset = _index_offset;
+ primcount = _primcount;
+ }
+
+ void* Set(
+ void* cmd, GLenum _mode, GLsizei _count, GLenum _type,
+ GLuint _index_offset, GLsizei _primcount) {
+ static_cast<ValueType*>(
+ cmd)->Init(_mode, _count, _type, _index_offset, _primcount);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 mode;
+ int32 count;
+ uint32 type;
+ uint32 index_offset;
+ int32 primcount;
+};
+
+COMPILE_ASSERT(sizeof(DrawElementsInstancedANGLE) == 24,
+ Sizeof_DrawElementsInstancedANGLE_is_not_24);
+COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, header) == 0,
+ OffsetOf_DrawElementsInstancedANGLE_header_not_0);
+COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, mode) == 4,
+ OffsetOf_DrawElementsInstancedANGLE_mode_not_4);
+COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, count) == 8,
+ OffsetOf_DrawElementsInstancedANGLE_count_not_8);
+COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, type) == 12,
+ OffsetOf_DrawElementsInstancedANGLE_type_not_12);
+COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, index_offset) == 16,
+ OffsetOf_DrawElementsInstancedANGLE_index_offset_not_16);
+COMPILE_ASSERT(offsetof(DrawElementsInstancedANGLE, primcount) == 20,
+ OffsetOf_DrawElementsInstancedANGLE_primcount_not_20);
+
+struct VertexAttribDivisorANGLE {
+ typedef VertexAttribDivisorANGLE ValueType;
+ static const CommandId kCmdId = kVertexAttribDivisorANGLE;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _index, GLuint _divisor) {
+ SetHeader();
+ index = _index;
+ divisor = _divisor;
+ }
+
+ void* Set(void* cmd, GLuint _index, GLuint _divisor) {
+ static_cast<ValueType*>(cmd)->Init(_index, _divisor);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 index;
+ uint32 divisor;
+};
+
+COMPILE_ASSERT(sizeof(VertexAttribDivisorANGLE) == 12,
+ Sizeof_VertexAttribDivisorANGLE_is_not_12);
+COMPILE_ASSERT(offsetof(VertexAttribDivisorANGLE, header) == 0,
+ OffsetOf_VertexAttribDivisorANGLE_header_not_0);
+COMPILE_ASSERT(offsetof(VertexAttribDivisorANGLE, index) == 4,
+ OffsetOf_VertexAttribDivisorANGLE_index_not_4);
+COMPILE_ASSERT(offsetof(VertexAttribDivisorANGLE, divisor) == 8,
+ OffsetOf_VertexAttribDivisorANGLE_divisor_not_8);
+
+struct GenMailboxCHROMIUM {
+ typedef GenMailboxCHROMIUM ValueType;
+ static const CommandId kCmdId = kGenMailboxCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ typedef SizedResult<GLint> Result;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _bucket_id) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GenMailboxCHROMIUM) == 8,
+ Sizeof_GenMailboxCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(GenMailboxCHROMIUM, header) == 0,
+ OffsetOf_GenMailboxCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GenMailboxCHROMIUM, bucket_id) == 4,
+ OffsetOf_GenMailboxCHROMIUM_bucket_id_not_4);
+
+struct ProduceTextureCHROMIUM {
+ typedef ProduceTextureCHROMIUM ValueType;
+ static const CommandId kCmdId = kProduceTextureCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, uint32 _mailbox_shm_id, uint32 _mailbox_shm_offset) {
+ SetHeader();
+ target = _target;
+ mailbox_shm_id = _mailbox_shm_id;
+ mailbox_shm_offset = _mailbox_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, uint32 _mailbox_shm_id,
+ uint32 _mailbox_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _mailbox_shm_id, _mailbox_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 mailbox_shm_id;
+ uint32 mailbox_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(ProduceTextureCHROMIUM) == 16,
+ Sizeof_ProduceTextureCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(ProduceTextureCHROMIUM, header) == 0,
+ OffsetOf_ProduceTextureCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(ProduceTextureCHROMIUM, target) == 4,
+ OffsetOf_ProduceTextureCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(ProduceTextureCHROMIUM, mailbox_shm_id) == 8,
+ OffsetOf_ProduceTextureCHROMIUM_mailbox_shm_id_not_8);
+COMPILE_ASSERT(offsetof(ProduceTextureCHROMIUM, mailbox_shm_offset) == 12,
+ OffsetOf_ProduceTextureCHROMIUM_mailbox_shm_offset_not_12);
+
+struct ProduceTextureCHROMIUMImmediate {
+ typedef ProduceTextureCHROMIUMImmediate ValueType;
+ static const CommandId kCmdId = kProduceTextureCHROMIUMImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLbyte) * 64); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLenum _target, const GLbyte* _mailbox) {
+ SetHeader();
+ target = _target;
+ memcpy(ImmediateDataAddress(this),
+ _mailbox, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLenum _target, const GLbyte* _mailbox) {
+ static_cast<ValueType*>(cmd)->Init(_target, _mailbox);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+};
+
+COMPILE_ASSERT(sizeof(ProduceTextureCHROMIUMImmediate) == 8,
+ Sizeof_ProduceTextureCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(ProduceTextureCHROMIUMImmediate, header) == 0,
+ OffsetOf_ProduceTextureCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(ProduceTextureCHROMIUMImmediate, target) == 4,
+ OffsetOf_ProduceTextureCHROMIUMImmediate_target_not_4);
+
+struct ConsumeTextureCHROMIUM {
+ typedef ConsumeTextureCHROMIUM ValueType;
+ static const CommandId kCmdId = kConsumeTextureCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, uint32 _mailbox_shm_id, uint32 _mailbox_shm_offset) {
+ SetHeader();
+ target = _target;
+ mailbox_shm_id = _mailbox_shm_id;
+ mailbox_shm_offset = _mailbox_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, uint32 _mailbox_shm_id,
+ uint32 _mailbox_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(_target, _mailbox_shm_id, _mailbox_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ uint32 mailbox_shm_id;
+ uint32 mailbox_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(ConsumeTextureCHROMIUM) == 16,
+ Sizeof_ConsumeTextureCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(ConsumeTextureCHROMIUM, header) == 0,
+ OffsetOf_ConsumeTextureCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(ConsumeTextureCHROMIUM, target) == 4,
+ OffsetOf_ConsumeTextureCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(ConsumeTextureCHROMIUM, mailbox_shm_id) == 8,
+ OffsetOf_ConsumeTextureCHROMIUM_mailbox_shm_id_not_8);
+COMPILE_ASSERT(offsetof(ConsumeTextureCHROMIUM, mailbox_shm_offset) == 12,
+ OffsetOf_ConsumeTextureCHROMIUM_mailbox_shm_offset_not_12);
+
+struct ConsumeTextureCHROMIUMImmediate {
+ typedef ConsumeTextureCHROMIUMImmediate ValueType;
+ static const CommandId kCmdId = kConsumeTextureCHROMIUMImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize() {
+ return static_cast<uint32>(
+ sizeof(GLbyte) * 64); // NOLINT
+ }
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize()); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize());
+ }
+
+ void Init(GLenum _target, const GLbyte* _mailbox) {
+ SetHeader();
+ target = _target;
+ memcpy(ImmediateDataAddress(this),
+ _mailbox, ComputeDataSize());
+ }
+
+ void* Set(void* cmd, GLenum _target, const GLbyte* _mailbox) {
+ static_cast<ValueType*>(cmd)->Init(_target, _mailbox);
+ const uint32 size = ComputeSize();
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+};
+
+COMPILE_ASSERT(sizeof(ConsumeTextureCHROMIUMImmediate) == 8,
+ Sizeof_ConsumeTextureCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(ConsumeTextureCHROMIUMImmediate, header) == 0,
+ OffsetOf_ConsumeTextureCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(ConsumeTextureCHROMIUMImmediate, target) == 4,
+ OffsetOf_ConsumeTextureCHROMIUMImmediate_target_not_4);
+
+struct BindUniformLocationCHROMIUM {
+ typedef BindUniformLocationCHROMIUM ValueType;
+ static const CommandId kCmdId = kBindUniformLocationCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLuint _program, GLint _location, uint32 _name_shm_id,
+ uint32 _name_shm_offset, uint32 _data_size) {
+ SetHeader();
+ program = _program;
+ location = _location;
+ name_shm_id = _name_shm_id;
+ name_shm_offset = _name_shm_offset;
+ data_size = _data_size;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLint _location, uint32 _name_shm_id,
+ uint32 _name_shm_offset, uint32 _data_size) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _program, _location, _name_shm_id, _name_shm_offset, _data_size);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ int32 location;
+ uint32 name_shm_id;
+ uint32 name_shm_offset;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(BindUniformLocationCHROMIUM) == 24,
+ Sizeof_BindUniformLocationCHROMIUM_is_not_24);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUM, header) == 0,
+ OffsetOf_BindUniformLocationCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUM, program) == 4,
+ OffsetOf_BindUniformLocationCHROMIUM_program_not_4);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUM, location) == 8,
+ OffsetOf_BindUniformLocationCHROMIUM_location_not_8);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUM, name_shm_id) == 12,
+ OffsetOf_BindUniformLocationCHROMIUM_name_shm_id_not_12);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUM, name_shm_offset) == 16,
+ OffsetOf_BindUniformLocationCHROMIUM_name_shm_offset_not_16);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUM, data_size) == 20,
+ OffsetOf_BindUniformLocationCHROMIUM_data_size_not_20);
+
+struct BindUniformLocationCHROMIUMImmediate {
+ typedef BindUniformLocationCHROMIUMImmediate ValueType;
+ static const CommandId kCmdId = kBindUniformLocationCHROMIUMImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeSize(uint32 data_size) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + data_size); // NOLINT
+ }
+
+ void SetHeader(uint32 data_size) {
+ header.SetCmdBySize<ValueType>(data_size);
+ }
+
+ void Init(
+ GLuint _program, GLint _location, const char* _name, uint32 _data_size) {
+ SetHeader(_data_size);
+ program = _program;
+ location = _location;
+ data_size = _data_size;
+ memcpy(ImmediateDataAddress(this), _name, _data_size);
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLint _location, const char* _name,
+ uint32 _data_size) {
+ static_cast<ValueType*>(cmd)->Init(_program, _location, _name, _data_size);
+ return NextImmediateCmdAddress<ValueType>(cmd, _data_size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ int32 location;
+ uint32 data_size;
+};
+
+COMPILE_ASSERT(sizeof(BindUniformLocationCHROMIUMImmediate) == 16,
+ Sizeof_BindUniformLocationCHROMIUMImmediate_is_not_16);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMImmediate, header) == 0,
+ OffsetOf_BindUniformLocationCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMImmediate, program) == 4,
+ OffsetOf_BindUniformLocationCHROMIUMImmediate_program_not_4);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMImmediate, location) == 8,
+ OffsetOf_BindUniformLocationCHROMIUMImmediate_location_not_8);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMImmediate, data_size) == 12,
+ OffsetOf_BindUniformLocationCHROMIUMImmediate_data_size_not_12);
+
+struct BindUniformLocationCHROMIUMBucket {
+ typedef BindUniformLocationCHROMIUMBucket ValueType;
+ static const CommandId kCmdId = kBindUniformLocationCHROMIUMBucket;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, GLint _location, uint32 _name_bucket_id) {
+ SetHeader();
+ program = _program;
+ location = _location;
+ name_bucket_id = _name_bucket_id;
+ }
+
+ void* Set(
+ void* cmd, GLuint _program, GLint _location, uint32 _name_bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_program, _location, _name_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ int32 location;
+ uint32 name_bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(BindUniformLocationCHROMIUMBucket) == 16,
+ Sizeof_BindUniformLocationCHROMIUMBucket_is_not_16);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMBucket, header) == 0,
+ OffsetOf_BindUniformLocationCHROMIUMBucket_header_not_0);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMBucket, program) == 4,
+ OffsetOf_BindUniformLocationCHROMIUMBucket_program_not_4);
+COMPILE_ASSERT(offsetof(BindUniformLocationCHROMIUMBucket, location) == 8,
+ OffsetOf_BindUniformLocationCHROMIUMBucket_location_not_8);
+COMPILE_ASSERT(
+ offsetof(BindUniformLocationCHROMIUMBucket, name_bucket_id) == 12,
+ OffsetOf_BindUniformLocationCHROMIUMBucket_name_bucket_id_not_12); // NOLINT
+
+struct BindTexImage2DCHROMIUM {
+ typedef BindTexImage2DCHROMIUM ValueType;
+ static const CommandId kCmdId = kBindTexImage2DCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLint _imageId) {
+ SetHeader();
+ target = _target;
+ imageId = _imageId;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLint _imageId) {
+ static_cast<ValueType*>(cmd)->Init(_target, _imageId);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 imageId;
+};
+
+COMPILE_ASSERT(sizeof(BindTexImage2DCHROMIUM) == 12,
+ Sizeof_BindTexImage2DCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(BindTexImage2DCHROMIUM, header) == 0,
+ OffsetOf_BindTexImage2DCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(BindTexImage2DCHROMIUM, target) == 4,
+ OffsetOf_BindTexImage2DCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(BindTexImage2DCHROMIUM, imageId) == 8,
+ OffsetOf_BindTexImage2DCHROMIUM_imageId_not_8);
+
+struct ReleaseTexImage2DCHROMIUM {
+ typedef ReleaseTexImage2DCHROMIUM ValueType;
+ static const CommandId kCmdId = kReleaseTexImage2DCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target, GLint _imageId) {
+ SetHeader();
+ target = _target;
+ imageId = _imageId;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLint _imageId) {
+ static_cast<ValueType*>(cmd)->Init(_target, _imageId);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 imageId;
+};
+
+COMPILE_ASSERT(sizeof(ReleaseTexImage2DCHROMIUM) == 12,
+ Sizeof_ReleaseTexImage2DCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(ReleaseTexImage2DCHROMIUM, header) == 0,
+ OffsetOf_ReleaseTexImage2DCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(ReleaseTexImage2DCHROMIUM, target) == 4,
+ OffsetOf_ReleaseTexImage2DCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(ReleaseTexImage2DCHROMIUM, imageId) == 8,
+ OffsetOf_ReleaseTexImage2DCHROMIUM_imageId_not_8);
+
+struct TraceBeginCHROMIUM {
+ typedef TraceBeginCHROMIUM ValueType;
+ static const CommandId kCmdId = kTraceBeginCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _bucket_id) {
+ SetHeader();
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(TraceBeginCHROMIUM) == 8,
+ Sizeof_TraceBeginCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(TraceBeginCHROMIUM, header) == 0,
+ OffsetOf_TraceBeginCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(TraceBeginCHROMIUM, bucket_id) == 4,
+ OffsetOf_TraceBeginCHROMIUM_bucket_id_not_4);
+
+struct TraceEndCHROMIUM {
+ typedef TraceEndCHROMIUM ValueType;
+ static const CommandId kCmdId = kTraceEndCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init() {
+ SetHeader();
+ }
+
+ void* Set(void* cmd) {
+ static_cast<ValueType*>(cmd)->Init();
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+};
+
+COMPILE_ASSERT(sizeof(TraceEndCHROMIUM) == 4,
+ Sizeof_TraceEndCHROMIUM_is_not_4);
+COMPILE_ASSERT(offsetof(TraceEndCHROMIUM, header) == 0,
+ OffsetOf_TraceEndCHROMIUM_header_not_0);
+
+struct AsyncTexSubImage2DCHROMIUM {
+ typedef AsyncTexSubImage2DCHROMIUM ValueType;
+ static const CommandId kCmdId = kAsyncTexSubImage2DCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLenum _type,
+ uint32 _data_shm_id, uint32 _data_shm_offset) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ xoffset = _xoffset;
+ yoffset = _yoffset;
+ width = _width;
+ height = _height;
+ format = _format;
+ type = _type;
+ data_shm_id = _data_shm_id;
+ data_shm_offset = _data_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _xoffset, GLint _yoffset,
+ GLsizei _width, GLsizei _height, GLenum _format, GLenum _type,
+ uint32 _data_shm_id, uint32 _data_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _xoffset, _yoffset, _width, _height, _format,
+ _type, _data_shm_id, _data_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 xoffset;
+ int32 yoffset;
+ int32 width;
+ int32 height;
+ uint32 format;
+ uint32 type;
+ uint32 data_shm_id;
+ uint32 data_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(AsyncTexSubImage2DCHROMIUM) == 44,
+ Sizeof_AsyncTexSubImage2DCHROMIUM_is_not_44);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, header) == 0,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, target) == 4,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, level) == 8,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_level_not_8);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, xoffset) == 12,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_xoffset_not_12);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, yoffset) == 16,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_yoffset_not_16);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, width) == 20,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_width_not_20);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, height) == 24,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_height_not_24);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, format) == 28,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_format_not_28);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, type) == 32,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_type_not_32);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, data_shm_id) == 36,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_data_shm_id_not_36);
+COMPILE_ASSERT(offsetof(AsyncTexSubImage2DCHROMIUM, data_shm_offset) == 40,
+ OffsetOf_AsyncTexSubImage2DCHROMIUM_data_shm_offset_not_40);
+
+struct AsyncTexImage2DCHROMIUM {
+ typedef AsyncTexImage2DCHROMIUM ValueType;
+ static const CommandId kCmdId = kAsyncTexImage2DCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLint _level, GLint _internalformat, GLsizei _width,
+ GLsizei _height, GLint _border, GLenum _format, GLenum _type,
+ uint32 _pixels_shm_id, uint32 _pixels_shm_offset) {
+ SetHeader();
+ target = _target;
+ level = _level;
+ internalformat = _internalformat;
+ width = _width;
+ height = _height;
+ border = _border;
+ format = _format;
+ type = _type;
+ pixels_shm_id = _pixels_shm_id;
+ pixels_shm_offset = _pixels_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLint _level, GLint _internalformat,
+ GLsizei _width, GLsizei _height, GLint _border, GLenum _format,
+ GLenum _type, uint32 _pixels_shm_id, uint32 _pixels_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _level, _internalformat, _width, _height, _border, _format,
+ _type, _pixels_shm_id, _pixels_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 level;
+ int32 internalformat;
+ int32 width;
+ int32 height;
+ int32 border;
+ uint32 format;
+ uint32 type;
+ uint32 pixels_shm_id;
+ uint32 pixels_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(AsyncTexImage2DCHROMIUM) == 44,
+ Sizeof_AsyncTexImage2DCHROMIUM_is_not_44);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, header) == 0,
+ OffsetOf_AsyncTexImage2DCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, target) == 4,
+ OffsetOf_AsyncTexImage2DCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, level) == 8,
+ OffsetOf_AsyncTexImage2DCHROMIUM_level_not_8);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, internalformat) == 12,
+ OffsetOf_AsyncTexImage2DCHROMIUM_internalformat_not_12);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, width) == 16,
+ OffsetOf_AsyncTexImage2DCHROMIUM_width_not_16);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, height) == 20,
+ OffsetOf_AsyncTexImage2DCHROMIUM_height_not_20);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, border) == 24,
+ OffsetOf_AsyncTexImage2DCHROMIUM_border_not_24);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, format) == 28,
+ OffsetOf_AsyncTexImage2DCHROMIUM_format_not_28);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, type) == 32,
+ OffsetOf_AsyncTexImage2DCHROMIUM_type_not_32);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, pixels_shm_id) == 36,
+ OffsetOf_AsyncTexImage2DCHROMIUM_pixels_shm_id_not_36);
+COMPILE_ASSERT(offsetof(AsyncTexImage2DCHROMIUM, pixels_shm_offset) == 40,
+ OffsetOf_AsyncTexImage2DCHROMIUM_pixels_shm_offset_not_40);
+
+struct WaitAsyncTexImage2DCHROMIUM {
+ typedef WaitAsyncTexImage2DCHROMIUM ValueType;
+ static const CommandId kCmdId = kWaitAsyncTexImage2DCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _target) {
+ SetHeader();
+ target = _target;
+ }
+
+ void* Set(void* cmd, GLenum _target) {
+ static_cast<ValueType*>(cmd)->Init(_target);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+};
+
+COMPILE_ASSERT(sizeof(WaitAsyncTexImage2DCHROMIUM) == 8,
+ Sizeof_WaitAsyncTexImage2DCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(WaitAsyncTexImage2DCHROMIUM, header) == 0,
+ OffsetOf_WaitAsyncTexImage2DCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(WaitAsyncTexImage2DCHROMIUM, target) == 4,
+ OffsetOf_WaitAsyncTexImage2DCHROMIUM_target_not_4);
+
+struct DiscardFramebufferEXT {
+ typedef DiscardFramebufferEXT ValueType;
+ static const CommandId kCmdId = kDiscardFramebufferEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(
+ GLenum _target, GLsizei _count, uint32 _attachments_shm_id,
+ uint32 _attachments_shm_offset) {
+ SetHeader();
+ target = _target;
+ count = _count;
+ attachments_shm_id = _attachments_shm_id;
+ attachments_shm_offset = _attachments_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLsizei _count, uint32 _attachments_shm_id,
+ uint32 _attachments_shm_offset) {
+ static_cast<ValueType*>(
+ cmd)->Init(
+ _target, _count, _attachments_shm_id, _attachments_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 count;
+ uint32 attachments_shm_id;
+ uint32 attachments_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DiscardFramebufferEXT) == 20,
+ Sizeof_DiscardFramebufferEXT_is_not_20);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXT, header) == 0,
+ OffsetOf_DiscardFramebufferEXT_header_not_0);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXT, target) == 4,
+ OffsetOf_DiscardFramebufferEXT_target_not_4);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXT, count) == 8,
+ OffsetOf_DiscardFramebufferEXT_count_not_8);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXT, attachments_shm_id) == 12,
+ OffsetOf_DiscardFramebufferEXT_attachments_shm_id_not_12);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXT, attachments_shm_offset) == 16,
+ OffsetOf_DiscardFramebufferEXT_attachments_shm_offset_not_16);
+
+struct DiscardFramebufferEXTImmediate {
+ typedef DiscardFramebufferEXTImmediate ValueType;
+ static const CommandId kCmdId = kDiscardFramebufferEXTImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLenum) * 1 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLenum _target, GLsizei _count, const GLenum* _attachments) {
+ SetHeader(_count);
+ target = _target;
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _attachments, ComputeDataSize(_count));
+ }
+
+ void* Set(
+ void* cmd, GLenum _target, GLsizei _count, const GLenum* _attachments) {
+ static_cast<ValueType*>(cmd)->Init(_target, _count, _attachments);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ uint32 target;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(DiscardFramebufferEXTImmediate) == 12,
+ Sizeof_DiscardFramebufferEXTImmediate_is_not_12);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXTImmediate, header) == 0,
+ OffsetOf_DiscardFramebufferEXTImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXTImmediate, target) == 4,
+ OffsetOf_DiscardFramebufferEXTImmediate_target_not_4);
+COMPILE_ASSERT(offsetof(DiscardFramebufferEXTImmediate, count) == 8,
+ OffsetOf_DiscardFramebufferEXTImmediate_count_not_8);
+
+struct LoseContextCHROMIUM {
+ typedef LoseContextCHROMIUM ValueType;
+ static const CommandId kCmdId = kLoseContextCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLenum _current, GLenum _other) {
+ SetHeader();
+ current = _current;
+ other = _other;
+ }
+
+ void* Set(void* cmd, GLenum _current, GLenum _other) {
+ static_cast<ValueType*>(cmd)->Init(_current, _other);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 current;
+ uint32 other;
+};
+
+COMPILE_ASSERT(sizeof(LoseContextCHROMIUM) == 12,
+ Sizeof_LoseContextCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(LoseContextCHROMIUM, header) == 0,
+ OffsetOf_LoseContextCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(LoseContextCHROMIUM, current) == 4,
+ OffsetOf_LoseContextCHROMIUM_current_not_4);
+COMPILE_ASSERT(offsetof(LoseContextCHROMIUM, other) == 8,
+ OffsetOf_LoseContextCHROMIUM_other_not_8);
+
+struct WaitSyncPointCHROMIUM {
+ typedef WaitSyncPointCHROMIUM ValueType;
+ static const CommandId kCmdId = kWaitSyncPointCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _sync_point) {
+ SetHeader();
+ sync_point = _sync_point;
+ }
+
+ void* Set(void* cmd, GLuint _sync_point) {
+ static_cast<ValueType*>(cmd)->Init(_sync_point);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 sync_point;
+};
+
+COMPILE_ASSERT(sizeof(WaitSyncPointCHROMIUM) == 8,
+ Sizeof_WaitSyncPointCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(WaitSyncPointCHROMIUM, header) == 0,
+ OffsetOf_WaitSyncPointCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(WaitSyncPointCHROMIUM, sync_point) == 4,
+ OffsetOf_WaitSyncPointCHROMIUM_sync_point_not_4);
+
+struct DrawBuffersEXT {
+ typedef DrawBuffersEXT ValueType;
+ static const CommandId kCmdId = kDrawBuffersEXT;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLsizei _count, uint32 _bufs_shm_id, uint32 _bufs_shm_offset) {
+ SetHeader();
+ count = _count;
+ bufs_shm_id = _bufs_shm_id;
+ bufs_shm_offset = _bufs_shm_offset;
+ }
+
+ void* Set(
+ void* cmd, GLsizei _count, uint32 _bufs_shm_id,
+ uint32 _bufs_shm_offset) {
+ static_cast<ValueType*>(cmd)->Init(_count, _bufs_shm_id, _bufs_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32 count;
+ uint32 bufs_shm_id;
+ uint32 bufs_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(DrawBuffersEXT) == 16,
+ Sizeof_DrawBuffersEXT_is_not_16);
+COMPILE_ASSERT(offsetof(DrawBuffersEXT, header) == 0,
+ OffsetOf_DrawBuffersEXT_header_not_0);
+COMPILE_ASSERT(offsetof(DrawBuffersEXT, count) == 4,
+ OffsetOf_DrawBuffersEXT_count_not_4);
+COMPILE_ASSERT(offsetof(DrawBuffersEXT, bufs_shm_id) == 8,
+ OffsetOf_DrawBuffersEXT_bufs_shm_id_not_8);
+COMPILE_ASSERT(offsetof(DrawBuffersEXT, bufs_shm_offset) == 12,
+ OffsetOf_DrawBuffersEXT_bufs_shm_offset_not_12);
+
+struct DrawBuffersEXTImmediate {
+ typedef DrawBuffersEXTImmediate ValueType;
+ static const CommandId kCmdId = kDrawBuffersEXTImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+
+ static uint32 ComputeDataSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(GLenum) * 1 * count); // NOLINT
+ }
+
+ static uint32 ComputeSize(GLsizei count) {
+ return static_cast<uint32>(
+ sizeof(ValueType) + ComputeDataSize(count)); // NOLINT
+ }
+
+ void SetHeader(GLsizei count) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(count));
+ }
+
+ void Init(GLsizei _count, const GLenum* _bufs) {
+ SetHeader(_count);
+ count = _count;
+ memcpy(ImmediateDataAddress(this),
+ _bufs, ComputeDataSize(_count));
+ }
+
+ void* Set(void* cmd, GLsizei _count, const GLenum* _bufs) {
+ static_cast<ValueType*>(cmd)->Init(_count, _bufs);
+ const uint32 size = ComputeSize(_count);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32 count;
+};
+
+COMPILE_ASSERT(sizeof(DrawBuffersEXTImmediate) == 8,
+ Sizeof_DrawBuffersEXTImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DrawBuffersEXTImmediate, header) == 0,
+ OffsetOf_DrawBuffersEXTImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DrawBuffersEXTImmediate, count) == 4,
+ OffsetOf_DrawBuffersEXTImmediate_count_not_4);
+
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_format_test.cc b/chromium/gpu/command_buffer/common/gles2_cmd_format_test.cc
new file mode 100644
index 00000000000..396ccb3e2d7
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_format_test.cc
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains unit tests for gles2 commmands
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2FormatTest : public testing::Test {
+ protected:
+ static const unsigned char kInitialValue = 0xBD;
+
+ virtual void SetUp() {
+ memset(buffer_, kInitialValue, sizeof(buffer_));
+ }
+
+ virtual void TearDown() {
+ }
+
+ template <typename T>
+ T* GetBufferAs() {
+ return static_cast<T*>(static_cast<void*>(&buffer_));
+ }
+
+ void CheckBytesWritten(
+ const void* end, size_t expected_size, size_t written_size) {
+ size_t actual_size = static_cast<const unsigned char*>(end) -
+ GetBufferAs<const unsigned char>();
+ EXPECT_LT(actual_size, sizeof(buffer_));
+ EXPECT_GT(actual_size, 0u);
+ EXPECT_EQ(expected_size, actual_size);
+ EXPECT_EQ(kInitialValue, buffer_[written_size]);
+ EXPECT_NE(kInitialValue, buffer_[written_size - 1]);
+ }
+
+ void CheckBytesWrittenMatchesExpectedSize(
+ const void* end, size_t expected_size) {
+ CheckBytesWritten(end, expected_size, expected_size);
+ }
+
+ private:
+ unsigned char buffer_[1024];
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef _MSC_VER
+const unsigned char GLES2FormatTest::kInitialValue;
+#endif
+
+#include "gpu/command_buffer/common/gles2_cmd_format_test_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/chromium/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
new file mode 100644
index 00000000000..740e6cb82fd
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -0,0 +1,4533 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// This file contains unit tests for gles2 commmands
+// It is included by gles2_cmd_format_test.cc
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
+
+TEST_F(GLES2FormatTest, ActiveTexture) {
+ cmds::ActiveTexture& cmd = *GetBufferAs<cmds::ActiveTexture>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::ActiveTexture::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.texture);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, AttachShader) {
+ cmds::AttachShader& cmd = *GetBufferAs<cmds::AttachShader>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::AttachShader::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.shader);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindAttribLocation) {
+ cmds::BindAttribLocation& cmd = *GetBufferAs<cmds::BindAttribLocation>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindAttribLocation::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.name_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.name_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.data_size);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+
+TEST_F(GLES2FormatTest, BindAttribLocationImmediate) {
+ cmds::BindAttribLocationImmediate& cmd =
+ *GetBufferAs<cmds::BindAttribLocationImmediate>();
+ static const char* const test_str = "test string";
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ test_str,
+ strlen(test_str));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindAttribLocationImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(strlen(test_str)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<char*>(next_cmd),
+ reinterpret_cast<char*>(&cmd) + sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(strlen(test_str)));
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+ EXPECT_EQ(static_cast<uint32>(strlen(test_str)), cmd.data_size);
+ EXPECT_EQ(0, memcmp(test_str, ImmediateDataAddress(&cmd), strlen(test_str)));
+ CheckBytesWritten(
+ next_cmd,
+ sizeof(cmd) + RoundSizeToMultipleOfEntries(strlen(test_str)),
+ sizeof(cmd) + strlen(test_str));
+}
+
+TEST_F(GLES2FormatTest, BindAttribLocationBucket) {
+ cmds::BindAttribLocationBucket& cmd =
+ *GetBufferAs<cmds::BindAttribLocationBucket>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindAttribLocationBucket::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.name_bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindBuffer) {
+ cmds::BindBuffer& cmd = *GetBufferAs<cmds::BindBuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindBuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.buffer);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindFramebuffer) {
+ cmds::BindFramebuffer& cmd = *GetBufferAs<cmds::BindFramebuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindFramebuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.framebuffer);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindRenderbuffer) {
+ cmds::BindRenderbuffer& cmd = *GetBufferAs<cmds::BindRenderbuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindRenderbuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.renderbuffer);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindTexture) {
+ cmds::BindTexture& cmd = *GetBufferAs<cmds::BindTexture>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindTexture::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.texture);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BlendColor) {
+ cmds::BlendColor& cmd = *GetBufferAs<cmds::BlendColor>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLclampf>(11),
+ static_cast<GLclampf>(12),
+ static_cast<GLclampf>(13),
+ static_cast<GLclampf>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::BlendColor::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLclampf>(11), cmd.red);
+ EXPECT_EQ(static_cast<GLclampf>(12), cmd.green);
+ EXPECT_EQ(static_cast<GLclampf>(13), cmd.blue);
+ EXPECT_EQ(static_cast<GLclampf>(14), cmd.alpha);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BlendEquation) {
+ cmds::BlendEquation& cmd = *GetBufferAs<cmds::BlendEquation>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::BlendEquation::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BlendEquationSeparate) {
+ cmds::BlendEquationSeparate& cmd =
+ *GetBufferAs<cmds::BlendEquationSeparate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BlendEquationSeparate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.modeRGB);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.modeAlpha);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BlendFunc) {
+ cmds::BlendFunc& cmd = *GetBufferAs<cmds::BlendFunc>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BlendFunc::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.sfactor);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.dfactor);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BlendFuncSeparate) {
+ cmds::BlendFuncSeparate& cmd = *GetBufferAs<cmds::BlendFuncSeparate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLenum>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::BlendFuncSeparate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.srcRGB);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.dstRGB);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.srcAlpha);
+ EXPECT_EQ(static_cast<GLenum>(14), cmd.dstAlpha);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BufferData) {
+ cmds::BufferData& cmd = *GetBufferAs<cmds::BufferData>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizeiptr>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14),
+ static_cast<GLenum>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::BufferData::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLsizeiptr>(12), cmd.size);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.data_shm_offset);
+ EXPECT_EQ(static_cast<GLenum>(15), cmd.usage);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for BufferDataImmediate
+TEST_F(GLES2FormatTest, BufferSubData) {
+ cmds::BufferSubData& cmd = *GetBufferAs<cmds::BufferSubData>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLintptr>(12),
+ static_cast<GLsizeiptr>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::BufferSubData::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLintptr>(12), cmd.offset);
+ EXPECT_EQ(static_cast<GLsizeiptr>(13), cmd.size);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.data_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for BufferSubDataImmediate
+TEST_F(GLES2FormatTest, CheckFramebufferStatus) {
+ cmds::CheckFramebufferStatus& cmd =
+ *GetBufferAs<cmds::CheckFramebufferStatus>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::CheckFramebufferStatus::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Clear) {
+ cmds::Clear& cmd = *GetBufferAs<cmds::Clear>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLbitfield>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::Clear::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLbitfield>(11), cmd.mask);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ClearColor) {
+ cmds::ClearColor& cmd = *GetBufferAs<cmds::ClearColor>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLclampf>(11),
+ static_cast<GLclampf>(12),
+ static_cast<GLclampf>(13),
+ static_cast<GLclampf>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::ClearColor::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLclampf>(11), cmd.red);
+ EXPECT_EQ(static_cast<GLclampf>(12), cmd.green);
+ EXPECT_EQ(static_cast<GLclampf>(13), cmd.blue);
+ EXPECT_EQ(static_cast<GLclampf>(14), cmd.alpha);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ClearDepthf) {
+ cmds::ClearDepthf& cmd = *GetBufferAs<cmds::ClearDepthf>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLclampf>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::ClearDepthf::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLclampf>(11), cmd.depth);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ClearStencil) {
+ cmds::ClearStencil& cmd = *GetBufferAs<cmds::ClearStencil>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::ClearStencil::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.s);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ColorMask) {
+ cmds::ColorMask& cmd = *GetBufferAs<cmds::ColorMask>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLboolean>(11),
+ static_cast<GLboolean>(12),
+ static_cast<GLboolean>(13),
+ static_cast<GLboolean>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::ColorMask::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLboolean>(11), cmd.red);
+ EXPECT_EQ(static_cast<GLboolean>(12), cmd.green);
+ EXPECT_EQ(static_cast<GLboolean>(13), cmd.blue);
+ EXPECT_EQ(static_cast<GLboolean>(14), cmd.alpha);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CompileShader) {
+ cmds::CompileShader& cmd = *GetBufferAs<cmds::CompileShader>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::CompileShader::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CompressedTexImage2D) {
+ cmds::CompressedTexImage2D& cmd = *GetBufferAs<cmds::CompressedTexImage2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLint>(16),
+ static_cast<GLsizei>(17),
+ static_cast<uint32>(18),
+ static_cast<uint32>(19));
+ EXPECT_EQ(static_cast<uint32>(cmds::CompressedTexImage2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+ EXPECT_EQ(static_cast<GLint>(16), cmd.border);
+ EXPECT_EQ(static_cast<GLsizei>(17), cmd.imageSize);
+ EXPECT_EQ(static_cast<uint32>(18), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.data_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for CompressedTexImage2DImmediate
+TEST_F(GLES2FormatTest, CompressedTexImage2DBucket) {
+ cmds::CompressedTexImage2DBucket& cmd =
+ *GetBufferAs<cmds::CompressedTexImage2DBucket>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLint>(16),
+ static_cast<GLuint>(17));
+ EXPECT_EQ(static_cast<uint32>(cmds::CompressedTexImage2DBucket::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+ EXPECT_EQ(static_cast<GLint>(16), cmd.border);
+ EXPECT_EQ(static_cast<GLuint>(17), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CompressedTexSubImage2D) {
+ cmds::CompressedTexSubImage2D& cmd =
+ *GetBufferAs<cmds::CompressedTexSubImage2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLsizei>(16),
+ static_cast<GLenum>(17),
+ static_cast<GLsizei>(18),
+ static_cast<uint32>(19),
+ static_cast<uint32>(20));
+ EXPECT_EQ(static_cast<uint32>(cmds::CompressedTexSubImage2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(16), cmd.height);
+ EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+ EXPECT_EQ(static_cast<GLsizei>(18), cmd.imageSize);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(20), cmd.data_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for CompressedTexSubImage2DImmediate
+TEST_F(GLES2FormatTest, CompressedTexSubImage2DBucket) {
+ cmds::CompressedTexSubImage2DBucket& cmd =
+ *GetBufferAs<cmds::CompressedTexSubImage2DBucket>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLsizei>(16),
+ static_cast<GLenum>(17),
+ static_cast<GLuint>(18));
+ EXPECT_EQ(static_cast<uint32>(cmds::CompressedTexSubImage2DBucket::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(16), cmd.height);
+ EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+ EXPECT_EQ(static_cast<GLuint>(18), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CopyTexImage2D) {
+ cmds::CopyTexImage2D& cmd = *GetBufferAs<cmds::CopyTexImage2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLint>(14),
+ static_cast<GLint>(15),
+ static_cast<GLsizei>(16),
+ static_cast<GLsizei>(17),
+ static_cast<GLint>(18));
+ EXPECT_EQ(static_cast<uint32>(cmds::CopyTexImage2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.y);
+ EXPECT_EQ(static_cast<GLsizei>(16), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(17), cmd.height);
+ EXPECT_EQ(static_cast<GLint>(18), cmd.border);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CopyTexSubImage2D) {
+ cmds::CopyTexSubImage2D& cmd = *GetBufferAs<cmds::CopyTexSubImage2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLint>(15),
+ static_cast<GLint>(16),
+ static_cast<GLsizei>(17),
+ static_cast<GLsizei>(18));
+ EXPECT_EQ(static_cast<uint32>(cmds::CopyTexSubImage2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(16), cmd.y);
+ EXPECT_EQ(static_cast<GLsizei>(17), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(18), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CreateProgram) {
+ cmds::CreateProgram& cmd = *GetBufferAs<cmds::CreateProgram>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<uint32>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::CreateProgram::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<uint32>(11), cmd.client_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CreateShader) {
+ cmds::CreateShader& cmd = *GetBufferAs<cmds::CreateShader>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::CreateShader::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.type);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.client_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CullFace) {
+ cmds::CullFace& cmd = *GetBufferAs<cmds::CullFace>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::CullFace::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteBuffers) {
+ cmds::DeleteBuffers& cmd = *GetBufferAs<cmds::DeleteBuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteBuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.buffers_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.buffers_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteBuffersImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::DeleteBuffersImmediate& cmd =
+ *GetBufferAs<cmds::DeleteBuffersImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteBuffersImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteFramebuffers) {
+ cmds::DeleteFramebuffers& cmd = *GetBufferAs<cmds::DeleteFramebuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteFramebuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.framebuffers_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.framebuffers_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteFramebuffersImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::DeleteFramebuffersImmediate& cmd =
+ *GetBufferAs<cmds::DeleteFramebuffersImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteFramebuffersImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteProgram) {
+ cmds::DeleteProgram& cmd = *GetBufferAs<cmds::DeleteProgram>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteProgram::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteRenderbuffers) {
+ cmds::DeleteRenderbuffers& cmd = *GetBufferAs<cmds::DeleteRenderbuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteRenderbuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.renderbuffers_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.renderbuffers_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteRenderbuffersImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::DeleteRenderbuffersImmediate& cmd =
+ *GetBufferAs<cmds::DeleteRenderbuffersImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteRenderbuffersImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteShader) {
+ cmds::DeleteShader& cmd = *GetBufferAs<cmds::DeleteShader>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteShader::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteTextures) {
+ cmds::DeleteTextures& cmd = *GetBufferAs<cmds::DeleteTextures>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteTextures::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.textures_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.textures_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteTexturesImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::DeleteTexturesImmediate& cmd =
+ *GetBufferAs<cmds::DeleteTexturesImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteTexturesImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DepthFunc) {
+ cmds::DepthFunc& cmd = *GetBufferAs<cmds::DepthFunc>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::DepthFunc::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.func);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DepthMask) {
+ cmds::DepthMask& cmd = *GetBufferAs<cmds::DepthMask>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLboolean>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::DepthMask::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLboolean>(11), cmd.flag);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DepthRangef) {
+ cmds::DepthRangef& cmd = *GetBufferAs<cmds::DepthRangef>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLclampf>(11),
+ static_cast<GLclampf>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::DepthRangef::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLclampf>(11), cmd.zNear);
+ EXPECT_EQ(static_cast<GLclampf>(12), cmd.zFar);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DetachShader) {
+ cmds::DetachShader& cmd = *GetBufferAs<cmds::DetachShader>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::DetachShader::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.shader);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Disable) {
+ cmds::Disable& cmd = *GetBufferAs<cmds::Disable>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::Disable::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.cap);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DisableVertexAttribArray) {
+ cmds::DisableVertexAttribArray& cmd =
+ *GetBufferAs<cmds::DisableVertexAttribArray>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::DisableVertexAttribArray::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.index);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DrawArrays) {
+ cmds::DrawArrays& cmd = *GetBufferAs<cmds::DrawArrays>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLsizei>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DrawArrays::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.first);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DrawElements) {
+ cmds::DrawElements& cmd = *GetBufferAs<cmds::DrawElements>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLuint>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::DrawElements::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.type);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.index_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Enable) {
+ cmds::Enable& cmd = *GetBufferAs<cmds::Enable>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::Enable::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.cap);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, EnableVertexAttribArray) {
+ cmds::EnableVertexAttribArray& cmd =
+ *GetBufferAs<cmds::EnableVertexAttribArray>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::EnableVertexAttribArray::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.index);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Finish) {
+ cmds::Finish& cmd = *GetBufferAs<cmds::Finish>();
+ void* next_cmd = cmd.Set(
+ &cmd);
+ EXPECT_EQ(static_cast<uint32>(cmds::Finish::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Flush) {
+ cmds::Flush& cmd = *GetBufferAs<cmds::Flush>();
+ void* next_cmd = cmd.Set(
+ &cmd);
+ EXPECT_EQ(static_cast<uint32>(cmds::Flush::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, FramebufferRenderbuffer) {
+ cmds::FramebufferRenderbuffer& cmd =
+ *GetBufferAs<cmds::FramebufferRenderbuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLuint>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::FramebufferRenderbuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.attachment);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.renderbuffertarget);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.renderbuffer);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, FramebufferTexture2D) {
+ cmds::FramebufferTexture2D& cmd = *GetBufferAs<cmds::FramebufferTexture2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLuint>(14),
+ static_cast<GLint>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::FramebufferTexture2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.attachment);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.textarget);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.texture);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.level);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, FrontFace) {
+ cmds::FrontFace& cmd = *GetBufferAs<cmds::FrontFace>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::FrontFace::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenBuffers) {
+ cmds::GenBuffers& cmd = *GetBufferAs<cmds::GenBuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenBuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.buffers_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.buffers_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenBuffersImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::GenBuffersImmediate& cmd = *GetBufferAs<cmds::GenBuffersImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::GenBuffersImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, GenerateMipmap) {
+ cmds::GenerateMipmap& cmd = *GetBufferAs<cmds::GenerateMipmap>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenerateMipmap::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenFramebuffers) {
+ cmds::GenFramebuffers& cmd = *GetBufferAs<cmds::GenFramebuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenFramebuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.framebuffers_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.framebuffers_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenFramebuffersImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::GenFramebuffersImmediate& cmd =
+ *GetBufferAs<cmds::GenFramebuffersImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::GenFramebuffersImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, GenRenderbuffers) {
+ cmds::GenRenderbuffers& cmd = *GetBufferAs<cmds::GenRenderbuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenRenderbuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.renderbuffers_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.renderbuffers_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenRenderbuffersImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::GenRenderbuffersImmediate& cmd =
+ *GetBufferAs<cmds::GenRenderbuffersImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::GenRenderbuffersImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, GenTextures) {
+ cmds::GenTextures& cmd = *GetBufferAs<cmds::GenTextures>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenTextures::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.textures_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.textures_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenTexturesImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::GenTexturesImmediate& cmd = *GetBufferAs<cmds::GenTexturesImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::GenTexturesImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, GetActiveAttrib) {
+ cmds::GetActiveAttrib& cmd = *GetBufferAs<cmds::GetActiveAttrib>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetActiveAttrib::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.name_bucket_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetActiveUniform) {
+ cmds::GetActiveUniform& cmd = *GetBufferAs<cmds::GetActiveUniform>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetActiveUniform::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.index);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.name_bucket_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetAttachedShaders) {
+ cmds::GetAttachedShaders& cmd = *GetBufferAs<cmds::GetAttachedShaders>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetAttachedShaders::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.result_size);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Write test for GetAttribLocation
+// TODO(gman): Write test for GetAttribLocationImmediate
+// TODO(gman): Write test for GetAttribLocationBucket
+TEST_F(GLES2FormatTest, GetBooleanv) {
+ cmds::GetBooleanv& cmd = *GetBufferAs<cmds::GetBooleanv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetBooleanv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetBufferParameteriv) {
+ cmds::GetBufferParameteriv& cmd = *GetBufferAs<cmds::GetBufferParameteriv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetBufferParameteriv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetError) {
+ cmds::GetError& cmd = *GetBufferAs<cmds::GetError>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<uint32>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetError::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<uint32>(11), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetFloatv) {
+ cmds::GetFloatv& cmd = *GetBufferAs<cmds::GetFloatv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetFloatv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetFramebufferAttachmentParameteriv) {
+ cmds::GetFramebufferAttachmentParameteriv& cmd =
+ *GetBufferAs<cmds::GetFramebufferAttachmentParameteriv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(
+ static_cast<uint32>(cmds::GetFramebufferAttachmentParameteriv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.attachment);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetIntegerv) {
+ cmds::GetIntegerv& cmd = *GetBufferAs<cmds::GetIntegerv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetIntegerv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetProgramiv) {
+ cmds::GetProgramiv& cmd = *GetBufferAs<cmds::GetProgramiv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetProgramiv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetProgramInfoLog) {
+ cmds::GetProgramInfoLog& cmd = *GetBufferAs<cmds::GetProgramInfoLog>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetProgramInfoLog::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetRenderbufferParameteriv) {
+ cmds::GetRenderbufferParameteriv& cmd =
+ *GetBufferAs<cmds::GetRenderbufferParameteriv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetRenderbufferParameteriv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetShaderiv) {
+ cmds::GetShaderiv& cmd = *GetBufferAs<cmds::GetShaderiv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetShaderiv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetShaderInfoLog) {
+ cmds::GetShaderInfoLog& cmd = *GetBufferAs<cmds::GetShaderInfoLog>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetShaderInfoLog::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetShaderPrecisionFormat) {
+ cmds::GetShaderPrecisionFormat& cmd =
+ *GetBufferAs<cmds::GetShaderPrecisionFormat>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetShaderPrecisionFormat::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.shadertype);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.precisiontype);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetShaderSource) {
+ cmds::GetShaderSource& cmd = *GetBufferAs<cmds::GetShaderSource>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetShaderSource::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetString) {
+ cmds::GetString& cmd = *GetBufferAs<cmds::GetString>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetString::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.name);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetTexParameterfv) {
+ cmds::GetTexParameterfv& cmd = *GetBufferAs<cmds::GetTexParameterfv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetTexParameterfv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetTexParameteriv) {
+ cmds::GetTexParameteriv& cmd = *GetBufferAs<cmds::GetTexParameteriv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetTexParameteriv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetUniformfv) {
+ cmds::GetUniformfv& cmd = *GetBufferAs<cmds::GetUniformfv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetUniformfv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.location);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetUniformiv) {
+ cmds::GetUniformiv& cmd = *GetBufferAs<cmds::GetUniformiv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetUniformiv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.location);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Write test for GetUniformLocation
+// TODO(gman): Write test for GetUniformLocationImmediate
+// TODO(gman): Write test for GetUniformLocationBucket
+TEST_F(GLES2FormatTest, GetVertexAttribfv) {
+ cmds::GetVertexAttribfv& cmd = *GetBufferAs<cmds::GetVertexAttribfv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetVertexAttribfv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.index);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetVertexAttribiv) {
+ cmds::GetVertexAttribiv& cmd = *GetBufferAs<cmds::GetVertexAttribiv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetVertexAttribiv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.index);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetVertexAttribPointerv) {
+ cmds::GetVertexAttribPointerv& cmd =
+ *GetBufferAs<cmds::GetVertexAttribPointerv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetVertexAttribPointerv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.index);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.pointer_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.pointer_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Hint) {
+ cmds::Hint& cmd = *GetBufferAs<cmds::Hint>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::Hint::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.mode);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsBuffer) {
+ cmds::IsBuffer& cmd = *GetBufferAs<cmds::IsBuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsBuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.buffer);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsEnabled) {
+ cmds::IsEnabled& cmd = *GetBufferAs<cmds::IsEnabled>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsEnabled::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.cap);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsFramebuffer) {
+ cmds::IsFramebuffer& cmd = *GetBufferAs<cmds::IsFramebuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsFramebuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.framebuffer);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsProgram) {
+ cmds::IsProgram& cmd = *GetBufferAs<cmds::IsProgram>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsProgram::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsRenderbuffer) {
+ cmds::IsRenderbuffer& cmd = *GetBufferAs<cmds::IsRenderbuffer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsRenderbuffer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.renderbuffer);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsShader) {
+ cmds::IsShader& cmd = *GetBufferAs<cmds::IsShader>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsShader::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, IsTexture) {
+ cmds::IsTexture& cmd = *GetBufferAs<cmds::IsTexture>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsTexture::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.texture);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, LineWidth) {
+ cmds::LineWidth& cmd = *GetBufferAs<cmds::LineWidth>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLfloat>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::LineWidth::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLfloat>(11), cmd.width);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, LinkProgram) {
+ cmds::LinkProgram& cmd = *GetBufferAs<cmds::LinkProgram>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::LinkProgram::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PixelStorei) {
+ cmds::PixelStorei& cmd = *GetBufferAs<cmds::PixelStorei>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::PixelStorei::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.pname);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.param);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PolygonOffset) {
+ cmds::PolygonOffset& cmd = *GetBufferAs<cmds::PolygonOffset>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLfloat>(11),
+ static_cast<GLfloat>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::PolygonOffset::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLfloat>(11), cmd.factor);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.units);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ReadPixels) {
+ cmds::ReadPixels& cmd = *GetBufferAs<cmds::ReadPixels>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLsizei>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLenum>(15),
+ static_cast<GLenum>(16),
+ static_cast<uint32>(17),
+ static_cast<uint32>(18),
+ static_cast<uint32>(19),
+ static_cast<uint32>(20),
+ static_cast<GLboolean>(21));
+ EXPECT_EQ(static_cast<uint32>(cmds::ReadPixels::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.y);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.height);
+ EXPECT_EQ(static_cast<GLenum>(15), cmd.format);
+ EXPECT_EQ(static_cast<GLenum>(16), cmd.type);
+ EXPECT_EQ(static_cast<uint32>(17), cmd.pixels_shm_id);
+ EXPECT_EQ(static_cast<uint32>(18), cmd.pixels_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(20), cmd.result_shm_offset);
+ EXPECT_EQ(static_cast<GLboolean>(21), cmd.async);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ReleaseShaderCompiler) {
+ cmds::ReleaseShaderCompiler& cmd =
+ *GetBufferAs<cmds::ReleaseShaderCompiler>();
+ void* next_cmd = cmd.Set(
+ &cmd);
+ EXPECT_EQ(static_cast<uint32>(cmds::ReleaseShaderCompiler::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, RenderbufferStorage) {
+ cmds::RenderbufferStorage& cmd = *GetBufferAs<cmds::RenderbufferStorage>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLsizei>(13),
+ static_cast<GLsizei>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::RenderbufferStorage::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SampleCoverage) {
+ cmds::SampleCoverage& cmd = *GetBufferAs<cmds::SampleCoverage>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLclampf>(11),
+ static_cast<GLboolean>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::SampleCoverage::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLclampf>(11), cmd.value);
+ EXPECT_EQ(static_cast<GLboolean>(12), cmd.invert);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Scissor) {
+ cmds::Scissor& cmd = *GetBufferAs<cmds::Scissor>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLsizei>(13),
+ static_cast<GLsizei>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Scissor::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.y);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ShaderBinary) {
+ cmds::ShaderBinary& cmd = *GetBufferAs<cmds::ShaderBinary>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13),
+ static_cast<GLenum>(14),
+ static_cast<uint32>(15),
+ static_cast<uint32>(16),
+ static_cast<GLsizei>(17));
+ EXPECT_EQ(static_cast<uint32>(cmds::ShaderBinary::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.shaders_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.shaders_shm_offset);
+ EXPECT_EQ(static_cast<GLenum>(14), cmd.binaryformat);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.binary_shm_id);
+ EXPECT_EQ(static_cast<uint32>(16), cmd.binary_shm_offset);
+ EXPECT_EQ(static_cast<GLsizei>(17), cmd.length);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ShaderSource) {
+ cmds::ShaderSource& cmd = *GetBufferAs<cmds::ShaderSource>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::ShaderSource::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.data_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.data_size);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for ShaderSourceImmediate
+TEST_F(GLES2FormatTest, ShaderSourceBucket) {
+ cmds::ShaderSourceBucket& cmd = *GetBufferAs<cmds::ShaderSourceBucket>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::ShaderSourceBucket::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.data_bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, StencilFunc) {
+ cmds::StencilFunc& cmd = *GetBufferAs<cmds::StencilFunc>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLuint>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::StencilFunc::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.func);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.ref);
+ EXPECT_EQ(static_cast<GLuint>(13), cmd.mask);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, StencilFuncSeparate) {
+ cmds::StencilFuncSeparate& cmd = *GetBufferAs<cmds::StencilFuncSeparate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLint>(13),
+ static_cast<GLuint>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::StencilFuncSeparate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.face);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.func);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.ref);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.mask);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, StencilMask) {
+ cmds::StencilMask& cmd = *GetBufferAs<cmds::StencilMask>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::StencilMask::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.mask);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, StencilMaskSeparate) {
+ cmds::StencilMaskSeparate& cmd = *GetBufferAs<cmds::StencilMaskSeparate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::StencilMaskSeparate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.face);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.mask);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, StencilOp) {
+ cmds::StencilOp& cmd = *GetBufferAs<cmds::StencilOp>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::StencilOp::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.fail);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.zfail);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.zpass);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, StencilOpSeparate) {
+ cmds::StencilOpSeparate& cmd = *GetBufferAs<cmds::StencilOpSeparate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLenum>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::StencilOpSeparate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.face);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.fail);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.zfail);
+ EXPECT_EQ(static_cast<GLenum>(14), cmd.zpass);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexImage2D) {
+ cmds::TexImage2D& cmd = *GetBufferAs<cmds::TexImage2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLint>(16),
+ static_cast<GLenum>(17),
+ static_cast<GLenum>(18),
+ static_cast<uint32>(19),
+ static_cast<uint32>(20));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexImage2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+ EXPECT_EQ(static_cast<GLint>(16), cmd.border);
+ EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+ EXPECT_EQ(static_cast<GLenum>(18), cmd.type);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.pixels_shm_id);
+ EXPECT_EQ(static_cast<uint32>(20), cmd.pixels_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for TexImage2DImmediate
+TEST_F(GLES2FormatTest, TexParameterf) {
+ cmds::TexParameterf& cmd = *GetBufferAs<cmds::TexParameterf>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLfloat>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexParameterf::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.param);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexParameterfv) {
+ cmds::TexParameterfv& cmd = *GetBufferAs<cmds::TexParameterfv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexParameterfv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexParameterfvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ };
+ cmds::TexParameterfvImmediate& cmd =
+ *GetBufferAs<cmds::TexParameterfvImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::TexParameterfvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, TexParameteri) {
+ cmds::TexParameteri& cmd = *GetBufferAs<cmds::TexParameteri>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLint>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexParameteri::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.param);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexParameteriv) {
+ cmds::TexParameteriv& cmd = *GetBufferAs<cmds::TexParameteriv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexParameteriv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.params_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.params_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexParameterivImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLint data[] = {
+ static_cast<GLint>(kSomeBaseValueToTestWith + 0),
+ };
+ cmds::TexParameterivImmediate& cmd =
+ *GetBufferAs<cmds::TexParameterivImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::TexParameterivImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.pname);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, TexSubImage2D) {
+ cmds::TexSubImage2D& cmd = *GetBufferAs<cmds::TexSubImage2D>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLsizei>(16),
+ static_cast<GLenum>(17),
+ static_cast<GLenum>(18),
+ static_cast<uint32>(19),
+ static_cast<uint32>(20),
+ static_cast<GLboolean>(21));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexSubImage2D::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(16), cmd.height);
+ EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+ EXPECT_EQ(static_cast<GLenum>(18), cmd.type);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.pixels_shm_id);
+ EXPECT_EQ(static_cast<uint32>(20), cmd.pixels_shm_offset);
+ EXPECT_EQ(static_cast<GLboolean>(21), cmd.internal);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Implement test for TexSubImage2DImmediate
+TEST_F(GLES2FormatTest, Uniform1f) {
+ cmds::Uniform1f& cmd = *GetBufferAs<cmds::Uniform1f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLfloat>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform1f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform1fv) {
+ cmds::Uniform1fv& cmd = *GetBufferAs<cmds::Uniform1fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform1fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform1fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ };
+ cmds::Uniform1fvImmediate& cmd = *GetBufferAs<cmds::Uniform1fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 1;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform1fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform1i) {
+ cmds::Uniform1i& cmd = *GetBufferAs<cmds::Uniform1i>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform1i::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.x);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform1iv) {
+ cmds::Uniform1iv& cmd = *GetBufferAs<cmds::Uniform1iv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform1iv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform1ivImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLint data[] = {
+ static_cast<GLint>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 1),
+ };
+ cmds::Uniform1ivImmediate& cmd = *GetBufferAs<cmds::Uniform1ivImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLint) * 1;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform1ivImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform2f) {
+ cmds::Uniform2f& cmd = *GetBufferAs<cmds::Uniform2f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLfloat>(12),
+ static_cast<GLfloat>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform2f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.y);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform2fv) {
+ cmds::Uniform2fv& cmd = *GetBufferAs<cmds::Uniform2fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform2fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform2fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ };
+ cmds::Uniform2fvImmediate& cmd = *GetBufferAs<cmds::Uniform2fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 2;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform2fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform2i) {
+ cmds::Uniform2i& cmd = *GetBufferAs<cmds::Uniform2i>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform2i::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.y);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform2iv) {
+ cmds::Uniform2iv& cmd = *GetBufferAs<cmds::Uniform2iv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform2iv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform2ivImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLint data[] = {
+ static_cast<GLint>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 3),
+ };
+ cmds::Uniform2ivImmediate& cmd = *GetBufferAs<cmds::Uniform2ivImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLint) * 2;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform2ivImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform3f) {
+ cmds::Uniform3f& cmd = *GetBufferAs<cmds::Uniform3f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLfloat>(12),
+ static_cast<GLfloat>(13),
+ static_cast<GLfloat>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform3f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.y);
+ EXPECT_EQ(static_cast<GLfloat>(14), cmd.z);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform3fv) {
+ cmds::Uniform3fv& cmd = *GetBufferAs<cmds::Uniform3fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform3fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform3fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 5),
+ };
+ cmds::Uniform3fvImmediate& cmd = *GetBufferAs<cmds::Uniform3fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 3;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform3fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform3i) {
+ cmds::Uniform3i& cmd = *GetBufferAs<cmds::Uniform3i>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform3i::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.y);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.z);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform3iv) {
+ cmds::Uniform3iv& cmd = *GetBufferAs<cmds::Uniform3iv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform3iv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform3ivImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLint data[] = {
+ static_cast<GLint>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 5),
+ };
+ cmds::Uniform3ivImmediate& cmd = *GetBufferAs<cmds::Uniform3ivImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLint) * 3;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform3ivImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform4f) {
+ cmds::Uniform4f& cmd = *GetBufferAs<cmds::Uniform4f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLfloat>(12),
+ static_cast<GLfloat>(13),
+ static_cast<GLfloat>(14),
+ static_cast<GLfloat>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform4f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.y);
+ EXPECT_EQ(static_cast<GLfloat>(14), cmd.z);
+ EXPECT_EQ(static_cast<GLfloat>(15), cmd.w);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform4fv) {
+ cmds::Uniform4fv& cmd = *GetBufferAs<cmds::Uniform4fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform4fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform4fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 7),
+ };
+ cmds::Uniform4fvImmediate& cmd = *GetBufferAs<cmds::Uniform4fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 4;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform4fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, Uniform4i) {
+ cmds::Uniform4i& cmd = *GetBufferAs<cmds::Uniform4i>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLint>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform4i::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.y);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.z);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.w);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform4iv) {
+ cmds::Uniform4iv& cmd = *GetBufferAs<cmds::Uniform4iv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform4iv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.v_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.v_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Uniform4ivImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLint data[] = {
+ static_cast<GLint>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLint>(kSomeBaseValueToTestWith + 7),
+ };
+ cmds::Uniform4ivImmediate& cmd = *GetBufferAs<cmds::Uniform4ivImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLint) * 4;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::Uniform4ivImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, UniformMatrix2fv) {
+ cmds::UniformMatrix2fv& cmd = *GetBufferAs<cmds::UniformMatrix2fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLboolean>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::UniformMatrix2fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<GLboolean>(13), cmd.transpose);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.value_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.value_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, UniformMatrix2fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 7),
+ };
+ cmds::UniformMatrix2fvImmediate& cmd =
+ *GetBufferAs<cmds::UniformMatrix2fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 4;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ static_cast<GLboolean>(3),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::UniformMatrix2fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ EXPECT_EQ(static_cast<GLboolean>(3), cmd.transpose);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, UniformMatrix3fv) {
+ cmds::UniformMatrix3fv& cmd = *GetBufferAs<cmds::UniformMatrix3fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLboolean>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::UniformMatrix3fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<GLboolean>(13), cmd.transpose);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.value_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.value_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, UniformMatrix3fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 7),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 8),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 9),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 10),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 11),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 12),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 13),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 14),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 15),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 16),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 17),
+ };
+ cmds::UniformMatrix3fvImmediate& cmd =
+ *GetBufferAs<cmds::UniformMatrix3fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 9;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ static_cast<GLboolean>(3),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::UniformMatrix3fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ EXPECT_EQ(static_cast<GLboolean>(3), cmd.transpose);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, UniformMatrix4fv) {
+ cmds::UniformMatrix4fv& cmd = *GetBufferAs<cmds::UniformMatrix4fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLboolean>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::UniformMatrix4fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<GLboolean>(13), cmd.transpose);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.value_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.value_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, UniformMatrix4fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 7),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 8),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 9),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 10),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 11),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 12),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 13),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 14),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 15),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 16),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 17),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 18),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 19),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 20),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 21),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 22),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 23),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 24),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 25),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 26),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 27),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 28),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 29),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 30),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 31),
+ };
+ cmds::UniformMatrix4fvImmediate& cmd =
+ *GetBufferAs<cmds::UniformMatrix4fvImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLfloat) * 16;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(1),
+ static_cast<GLsizei>(2),
+ static_cast<GLboolean>(3),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::UniformMatrix4fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(1), cmd.location);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ EXPECT_EQ(static_cast<GLboolean>(3), cmd.transpose);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, UseProgram) {
+ cmds::UseProgram& cmd = *GetBufferAs<cmds::UseProgram>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::UseProgram::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ValidateProgram) {
+ cmds::ValidateProgram& cmd = *GetBufferAs<cmds::ValidateProgram>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::ValidateProgram::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib1f) {
+ cmds::VertexAttrib1f& cmd = *GetBufferAs<cmds::VertexAttrib1f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLfloat>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib1f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib1fv) {
+ cmds::VertexAttrib1fv& cmd = *GetBufferAs<cmds::VertexAttrib1fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib1fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.values_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.values_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib1fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ };
+ cmds::VertexAttrib1fvImmediate& cmd =
+ *GetBufferAs<cmds::VertexAttrib1fvImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib1fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib2f) {
+ cmds::VertexAttrib2f& cmd = *GetBufferAs<cmds::VertexAttrib2f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLfloat>(12),
+ static_cast<GLfloat>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib2f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.y);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib2fv) {
+ cmds::VertexAttrib2fv& cmd = *GetBufferAs<cmds::VertexAttrib2fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib2fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.values_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.values_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib2fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ };
+ cmds::VertexAttrib2fvImmediate& cmd =
+ *GetBufferAs<cmds::VertexAttrib2fvImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib2fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib3f) {
+ cmds::VertexAttrib3f& cmd = *GetBufferAs<cmds::VertexAttrib3f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLfloat>(12),
+ static_cast<GLfloat>(13),
+ static_cast<GLfloat>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib3f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.y);
+ EXPECT_EQ(static_cast<GLfloat>(14), cmd.z);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib3fv) {
+ cmds::VertexAttrib3fv& cmd = *GetBufferAs<cmds::VertexAttrib3fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib3fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.values_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.values_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib3fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ };
+ cmds::VertexAttrib3fvImmediate& cmd =
+ *GetBufferAs<cmds::VertexAttrib3fvImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib3fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib4f) {
+ cmds::VertexAttrib4f& cmd = *GetBufferAs<cmds::VertexAttrib4f>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLfloat>(12),
+ static_cast<GLfloat>(13),
+ static_cast<GLfloat>(14),
+ static_cast<GLfloat>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib4f::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<GLfloat>(12), cmd.x);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.y);
+ EXPECT_EQ(static_cast<GLfloat>(14), cmd.z);
+ EXPECT_EQ(static_cast<GLfloat>(15), cmd.w);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib4fv) {
+ cmds::VertexAttrib4fv& cmd = *GetBufferAs<cmds::VertexAttrib4fv>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib4fv::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.values_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.values_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttrib4fvImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLfloat data[] = {
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLfloat>(kSomeBaseValueToTestWith + 3),
+ };
+ cmds::VertexAttrib4fvImmediate& cmd =
+ *GetBufferAs<cmds::VertexAttrib4fvImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttrib4fvImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, VertexAttribPointer) {
+ cmds::VertexAttribPointer& cmd = *GetBufferAs<cmds::VertexAttribPointer>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLboolean>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLuint>(16));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttribPointer::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.indx);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.size);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.type);
+ EXPECT_EQ(static_cast<GLboolean>(14), cmd.normalized);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.stride);
+ EXPECT_EQ(static_cast<GLuint>(16), cmd.offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, Viewport) {
+ cmds::Viewport& cmd = *GetBufferAs<cmds::Viewport>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLsizei>(13),
+ static_cast<GLsizei>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::Viewport::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.y);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BlitFramebufferEXT) {
+ cmds::BlitFramebufferEXT& cmd = *GetBufferAs<cmds::BlitFramebufferEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLint>(15),
+ static_cast<GLint>(16),
+ static_cast<GLint>(17),
+ static_cast<GLint>(18),
+ static_cast<GLbitfield>(19),
+ static_cast<GLenum>(20));
+ EXPECT_EQ(static_cast<uint32>(cmds::BlitFramebufferEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.srcX0);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.srcY0);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.srcX1);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.srcY1);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.dstX0);
+ EXPECT_EQ(static_cast<GLint>(16), cmd.dstY0);
+ EXPECT_EQ(static_cast<GLint>(17), cmd.dstX1);
+ EXPECT_EQ(static_cast<GLint>(18), cmd.dstY1);
+ EXPECT_EQ(static_cast<GLbitfield>(19), cmd.mask);
+ EXPECT_EQ(static_cast<GLenum>(20), cmd.filter);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, RenderbufferStorageMultisampleEXT) {
+ cmds::RenderbufferStorageMultisampleEXT& cmd =
+ *GetBufferAs<cmds::RenderbufferStorageMultisampleEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLsizei>(15));
+ EXPECT_EQ(
+ static_cast<uint32>(cmds::RenderbufferStorageMultisampleEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.samples);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, FramebufferTexture2DMultisampleEXT) {
+ cmds::FramebufferTexture2DMultisampleEXT& cmd =
+ *GetBufferAs<cmds::FramebufferTexture2DMultisampleEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLuint>(14),
+ static_cast<GLint>(15),
+ static_cast<GLsizei>(16));
+ EXPECT_EQ(
+ static_cast<uint32>(cmds::FramebufferTexture2DMultisampleEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.attachment);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.textarget);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.texture);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.level);
+ EXPECT_EQ(static_cast<GLsizei>(16), cmd.samples);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexStorage2DEXT) {
+ cmds::TexStorage2DEXT& cmd = *GetBufferAs<cmds::TexStorage2DEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLsizei>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexStorage2DEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.levels);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.internalFormat);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenQueriesEXT) {
+ cmds::GenQueriesEXT& cmd = *GetBufferAs<cmds::GenQueriesEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenQueriesEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.queries_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.queries_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenQueriesEXTImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::GenQueriesEXTImmediate& cmd =
+ *GetBufferAs<cmds::GenQueriesEXTImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::GenQueriesEXTImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteQueriesEXT) {
+ cmds::DeleteQueriesEXT& cmd = *GetBufferAs<cmds::DeleteQueriesEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteQueriesEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.queries_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.queries_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteQueriesEXTImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::DeleteQueriesEXTImmediate& cmd =
+ *GetBufferAs<cmds::DeleteQueriesEXTImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteQueriesEXTImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, BeginQueryEXT) {
+ cmds::BeginQueryEXT& cmd = *GetBufferAs<cmds::BeginQueryEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::BeginQueryEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.sync_data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.sync_data_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, EndQueryEXT) {
+ cmds::EndQueryEXT& cmd = *GetBufferAs<cmds::EndQueryEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::EndQueryEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.submit_count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, InsertEventMarkerEXT) {
+ cmds::InsertEventMarkerEXT& cmd = *GetBufferAs<cmds::InsertEventMarkerEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::InsertEventMarkerEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PushGroupMarkerEXT) {
+ cmds::PushGroupMarkerEXT& cmd = *GetBufferAs<cmds::PushGroupMarkerEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::PushGroupMarkerEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PopGroupMarkerEXT) {
+ cmds::PopGroupMarkerEXT& cmd = *GetBufferAs<cmds::PopGroupMarkerEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd);
+ EXPECT_EQ(static_cast<uint32>(cmds::PopGroupMarkerEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenVertexArraysOES) {
+ cmds::GenVertexArraysOES& cmd = *GetBufferAs<cmds::GenVertexArraysOES>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenVertexArraysOES::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.arrays_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.arrays_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenVertexArraysOESImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::GenVertexArraysOESImmediate& cmd =
+ *GetBufferAs<cmds::GenVertexArraysOESImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::GenVertexArraysOESImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteVertexArraysOES) {
+ cmds::DeleteVertexArraysOES& cmd =
+ *GetBufferAs<cmds::DeleteVertexArraysOES>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteVertexArraysOES::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.arrays_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.arrays_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteVertexArraysOESImmediate) {
+ static GLuint ids[] = { 12, 23, 34, };
+ cmds::DeleteVertexArraysOESImmediate& cmd =
+ *GetBufferAs<cmds::DeleteVertexArraysOESImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteVertexArraysOESImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, IsVertexArrayOES) {
+ cmds::IsVertexArrayOES& cmd = *GetBufferAs<cmds::IsVertexArrayOES>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::IsVertexArrayOES::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.array);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindVertexArrayOES) {
+ cmds::BindVertexArrayOES& cmd = *GetBufferAs<cmds::BindVertexArrayOES>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindVertexArrayOES::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.array);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SwapBuffers) {
+ cmds::SwapBuffers& cmd = *GetBufferAs<cmds::SwapBuffers>();
+ void* next_cmd = cmd.Set(
+ &cmd);
+ EXPECT_EQ(static_cast<uint32>(cmds::SwapBuffers::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetMaxValueInBufferCHROMIUM) {
+ cmds::GetMaxValueInBufferCHROMIUM& cmd =
+ *GetBufferAs<cmds::GetMaxValueInBufferCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLuint>(14),
+ static_cast<uint32>(15),
+ static_cast<uint32>(16));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetMaxValueInBufferCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.buffer_id);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.type);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.offset);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(16), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenSharedIdsCHROMIUM) {
+ cmds::GenSharedIdsCHROMIUM& cmd = *GetBufferAs<cmds::GenSharedIdsCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ static_cast<GLsizei>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenSharedIdsCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.namespace_id);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.id_offset);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.ids_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.ids_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DeleteSharedIdsCHROMIUM) {
+ cmds::DeleteSharedIdsCHROMIUM& cmd =
+ *GetBufferAs<cmds::DeleteSharedIdsCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::DeleteSharedIdsCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.namespace_id);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.ids_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.ids_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, RegisterSharedIdsCHROMIUM) {
+ cmds::RegisterSharedIdsCHROMIUM& cmd =
+ *GetBufferAs<cmds::RegisterSharedIdsCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::RegisterSharedIdsCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.namespace_id);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.n);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.ids_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.ids_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, EnableFeatureCHROMIUM) {
+ cmds::EnableFeatureCHROMIUM& cmd =
+ *GetBufferAs<cmds::EnableFeatureCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::EnableFeatureCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.bucket_id);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ResizeCHROMIUM) {
+ cmds::ResizeCHROMIUM& cmd = *GetBufferAs<cmds::ResizeCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12),
+ static_cast<GLfloat>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::ResizeCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.width);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.height);
+ EXPECT_EQ(static_cast<GLfloat>(13), cmd.scale_factor);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetRequestableExtensionsCHROMIUM) {
+ cmds::GetRequestableExtensionsCHROMIUM& cmd =
+ *GetBufferAs<cmds::GetRequestableExtensionsCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<uint32>(11));
+ EXPECT_EQ(
+ static_cast<uint32>(cmds::GetRequestableExtensionsCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<uint32>(11), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, RequestExtensionCHROMIUM) {
+ cmds::RequestExtensionCHROMIUM& cmd =
+ *GetBufferAs<cmds::RequestExtensionCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<uint32>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::RequestExtensionCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<uint32>(11), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetMultipleIntegervCHROMIUM) {
+ cmds::GetMultipleIntegervCHROMIUM& cmd =
+ *GetBufferAs<cmds::GetMultipleIntegervCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<uint32>(11),
+ static_cast<uint32>(12),
+ static_cast<GLuint>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15),
+ static_cast<GLsizeiptr>(16));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetMultipleIntegervCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<uint32>(11), cmd.pnames_shm_id);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.pnames_shm_offset);
+ EXPECT_EQ(static_cast<GLuint>(13), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.results_shm_id);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.results_shm_offset);
+ EXPECT_EQ(static_cast<GLsizeiptr>(16), cmd.size);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetProgramInfoCHROMIUM) {
+ cmds::GetProgramInfoCHROMIUM& cmd =
+ *GetBufferAs<cmds::GetProgramInfoCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetProgramInfoCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CreateStreamTextureCHROMIUM) {
+ cmds::CreateStreamTextureCHROMIUM& cmd =
+ *GetBufferAs<cmds::CreateStreamTextureCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::CreateStreamTextureCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.client_id);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DestroyStreamTextureCHROMIUM) {
+ cmds::DestroyStreamTextureCHROMIUM& cmd =
+ *GetBufferAs<cmds::DestroyStreamTextureCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::DestroyStreamTextureCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.texture);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GetTranslatedShaderSourceANGLE) {
+ cmds::GetTranslatedShaderSourceANGLE& cmd =
+ *GetBufferAs<cmds::GetTranslatedShaderSourceANGLE>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::GetTranslatedShaderSourceANGLE::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.shader);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PostSubBufferCHROMIUM) {
+ cmds::PostSubBufferCHROMIUM& cmd =
+ *GetBufferAs<cmds::PostSubBufferCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLint>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::PostSubBufferCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.x);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.y);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.width);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.height);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TexImageIOSurface2DCHROMIUM) {
+ cmds::TexImageIOSurface2DCHROMIUM& cmd =
+ *GetBufferAs<cmds::TexImageIOSurface2DCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLsizei>(13),
+ static_cast<GLuint>(14),
+ static_cast<GLuint>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::TexImageIOSurface2DCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.height);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.ioSurfaceId);
+ EXPECT_EQ(static_cast<GLuint>(15), cmd.plane);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, CopyTextureCHROMIUM) {
+ cmds::CopyTextureCHROMIUM& cmd = *GetBufferAs<cmds::CopyTextureCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLint>(14),
+ static_cast<GLint>(15),
+ static_cast<GLenum>(16));
+ EXPECT_EQ(static_cast<uint32>(cmds::CopyTextureCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.source_id);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.dest_id);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(15), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLenum>(16), cmd.dest_type);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DrawArraysInstancedANGLE) {
+ cmds::DrawArraysInstancedANGLE& cmd =
+ *GetBufferAs<cmds::DrawArraysInstancedANGLE>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLsizei>(13),
+ static_cast<GLsizei>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::DrawArraysInstancedANGLE::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.first);
+ EXPECT_EQ(static_cast<GLsizei>(13), cmd.count);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.primcount);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DrawElementsInstancedANGLE) {
+ cmds::DrawElementsInstancedANGLE& cmd =
+ *GetBufferAs<cmds::DrawElementsInstancedANGLE>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizei>(12),
+ static_cast<GLenum>(13),
+ static_cast<GLuint>(14),
+ static_cast<GLsizei>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::DrawElementsInstancedANGLE::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.mode);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.type);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.index_offset);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.primcount);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, VertexAttribDivisorANGLE) {
+ cmds::VertexAttribDivisorANGLE& cmd =
+ *GetBufferAs<cmds::VertexAttribDivisorANGLE>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::VertexAttribDivisorANGLE::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.index);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.divisor);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, GenMailboxCHROMIUM) {
+ cmds::GenMailboxCHROMIUM& cmd = *GetBufferAs<cmds::GenMailboxCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::GenMailboxCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ProduceTextureCHROMIUM) {
+ cmds::ProduceTextureCHROMIUM& cmd =
+ *GetBufferAs<cmds::ProduceTextureCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::ProduceTextureCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.mailbox_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.mailbox_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ProduceTextureCHROMIUMImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLbyte data[] = {
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 7),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 8),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 9),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 10),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 11),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 12),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 13),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 14),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 15),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 16),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 17),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 18),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 19),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 20),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 21),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 22),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 23),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 24),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 25),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 26),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 27),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 28),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 29),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 30),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 31),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 32),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 33),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 34),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 35),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 36),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 37),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 38),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 39),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 40),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 41),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 42),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 43),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 44),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 45),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 46),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 47),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 48),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 49),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 50),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 51),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 52),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 53),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 54),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 55),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 56),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 57),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 58),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 59),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 60),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 61),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 62),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 63),
+ };
+ cmds::ProduceTextureCHROMIUMImmediate& cmd =
+ *GetBufferAs<cmds::ProduceTextureCHROMIUMImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::ProduceTextureCHROMIUMImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, ConsumeTextureCHROMIUM) {
+ cmds::ConsumeTextureCHROMIUM& cmd =
+ *GetBufferAs<cmds::ConsumeTextureCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::ConsumeTextureCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.mailbox_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.mailbox_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ConsumeTextureCHROMIUMImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLbyte data[] = {
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 1),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 2),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 3),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 4),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 5),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 6),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 7),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 8),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 9),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 10),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 11),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 12),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 13),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 14),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 15),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 16),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 17),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 18),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 19),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 20),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 21),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 22),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 23),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 24),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 25),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 26),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 27),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 28),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 29),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 30),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 31),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 32),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 33),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 34),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 35),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 36),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 37),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 38),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 39),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 40),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 41),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 42),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 43),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 44),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 45),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 46),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 47),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 48),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 49),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 50),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 51),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 52),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 53),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 54),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 55),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 56),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 57),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 58),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 59),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 60),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 61),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 62),
+ static_cast<GLbyte>(kSomeBaseValueToTestWith + 63),
+ };
+ cmds::ConsumeTextureCHROMIUMImmediate& cmd =
+ *GetBufferAs<cmds::ConsumeTextureCHROMIUMImmediate>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::ConsumeTextureCHROMIUMImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, BindUniformLocationCHROMIUM) {
+ cmds::BindUniformLocationCHROMIUM& cmd =
+ *GetBufferAs<cmds::BindUniformLocationCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLint>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14),
+ static_cast<uint32>(15));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindUniformLocationCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.location);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.name_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.name_shm_offset);
+ EXPECT_EQ(static_cast<uint32>(15), cmd.data_size);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+
+TEST_F(GLES2FormatTest, BindUniformLocationCHROMIUMImmediate) {
+ cmds::BindUniformLocationCHROMIUMImmediate& cmd =
+ *GetBufferAs<cmds::BindUniformLocationCHROMIUMImmediate>();
+ static const char* const test_str = "test string";
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLint>(12),
+ test_str,
+ strlen(test_str));
+ EXPECT_EQ(
+ static_cast<uint32>(cmds::BindUniformLocationCHROMIUMImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(strlen(test_str)),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<char*>(next_cmd),
+ reinterpret_cast<char*>(&cmd) + sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(strlen(test_str)));
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.location);
+ EXPECT_EQ(static_cast<uint32>(strlen(test_str)), cmd.data_size);
+ EXPECT_EQ(0, memcmp(test_str, ImmediateDataAddress(&cmd), strlen(test_str)));
+ CheckBytesWritten(
+ next_cmd,
+ sizeof(cmd) + RoundSizeToMultipleOfEntries(strlen(test_str)),
+ sizeof(cmd) + strlen(test_str));
+}
+
+TEST_F(GLES2FormatTest, BindUniformLocationCHROMIUMBucket) {
+ cmds::BindUniformLocationCHROMIUMBucket& cmd =
+ *GetBufferAs<cmds::BindUniformLocationCHROMIUMBucket>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<GLint>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(
+ static_cast<uint32>(cmds::BindUniformLocationCHROMIUMBucket::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.location);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.name_bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindTexImage2DCHROMIUM) {
+ cmds::BindTexImage2DCHROMIUM& cmd =
+ *GetBufferAs<cmds::BindTexImage2DCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::BindTexImage2DCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.imageId);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, ReleaseTexImage2DCHROMIUM) {
+ cmds::ReleaseTexImage2DCHROMIUM& cmd =
+ *GetBufferAs<cmds::ReleaseTexImage2DCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::ReleaseTexImage2DCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.imageId);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TraceBeginCHROMIUM) {
+ cmds::TraceBeginCHROMIUM& cmd = *GetBufferAs<cmds::TraceBeginCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::TraceBeginCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.bucket_id);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, TraceEndCHROMIUM) {
+ cmds::TraceEndCHROMIUM& cmd = *GetBufferAs<cmds::TraceEndCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd);
+ EXPECT_EQ(static_cast<uint32>(cmds::TraceEndCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, AsyncTexSubImage2DCHROMIUM) {
+ cmds::AsyncTexSubImage2DCHROMIUM& cmd =
+ *GetBufferAs<cmds::AsyncTexSubImage2DCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLint>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLsizei>(16),
+ static_cast<GLenum>(17),
+ static_cast<GLenum>(18),
+ static_cast<uint32>(19),
+ static_cast<uint32>(20));
+ EXPECT_EQ(static_cast<uint32>(cmds::AsyncTexSubImage2DCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.xoffset);
+ EXPECT_EQ(static_cast<GLint>(14), cmd.yoffset);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(16), cmd.height);
+ EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+ EXPECT_EQ(static_cast<GLenum>(18), cmd.type);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.data_shm_id);
+ EXPECT_EQ(static_cast<uint32>(20), cmd.data_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, AsyncTexImage2DCHROMIUM) {
+ cmds::AsyncTexImage2DCHROMIUM& cmd =
+ *GetBufferAs<cmds::AsyncTexImage2DCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLint>(12),
+ static_cast<GLint>(13),
+ static_cast<GLsizei>(14),
+ static_cast<GLsizei>(15),
+ static_cast<GLint>(16),
+ static_cast<GLenum>(17),
+ static_cast<GLenum>(18),
+ static_cast<uint32>(19),
+ static_cast<uint32>(20));
+ EXPECT_EQ(static_cast<uint32>(cmds::AsyncTexImage2DCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLint>(12), cmd.level);
+ EXPECT_EQ(static_cast<GLint>(13), cmd.internalformat);
+ EXPECT_EQ(static_cast<GLsizei>(14), cmd.width);
+ EXPECT_EQ(static_cast<GLsizei>(15), cmd.height);
+ EXPECT_EQ(static_cast<GLint>(16), cmd.border);
+ EXPECT_EQ(static_cast<GLenum>(17), cmd.format);
+ EXPECT_EQ(static_cast<GLenum>(18), cmd.type);
+ EXPECT_EQ(static_cast<uint32>(19), cmd.pixels_shm_id);
+ EXPECT_EQ(static_cast<uint32>(20), cmd.pixels_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, WaitAsyncTexImage2DCHROMIUM) {
+ cmds::WaitAsyncTexImage2DCHROMIUM& cmd =
+ *GetBufferAs<cmds::WaitAsyncTexImage2DCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::WaitAsyncTexImage2DCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DiscardFramebufferEXT) {
+ cmds::DiscardFramebufferEXT& cmd =
+ *GetBufferAs<cmds::DiscardFramebufferEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLsizei>(12),
+ static_cast<uint32>(13),
+ static_cast<uint32>(14));
+ EXPECT_EQ(static_cast<uint32>(cmds::DiscardFramebufferEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLsizei>(12), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.attachments_shm_id);
+ EXPECT_EQ(static_cast<uint32>(14), cmd.attachments_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DiscardFramebufferEXTImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLenum data[] = {
+ static_cast<GLenum>(kSomeBaseValueToTestWith + 0),
+ static_cast<GLenum>(kSomeBaseValueToTestWith + 1),
+ };
+ cmds::DiscardFramebufferEXTImmediate& cmd =
+ *GetBufferAs<cmds::DiscardFramebufferEXTImmediate>();
+ const GLsizei kNumElements = 2;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLenum) * 1;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(1),
+ static_cast<GLsizei>(2),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::DiscardFramebufferEXTImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(1), cmd.target);
+ EXPECT_EQ(static_cast<GLsizei>(2), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+TEST_F(GLES2FormatTest, LoseContextCHROMIUM) {
+ cmds::LoseContextCHROMIUM& cmd = *GetBufferAs<cmds::LoseContextCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLenum>(11),
+ static_cast<GLenum>(12));
+ EXPECT_EQ(static_cast<uint32>(cmds::LoseContextCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.current);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.other);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+// TODO(gman): Write test for InsertSyncPointCHROMIUM
+TEST_F(GLES2FormatTest, WaitSyncPointCHROMIUM) {
+ cmds::WaitSyncPointCHROMIUM& cmd =
+ *GetBufferAs<cmds::WaitSyncPointCHROMIUM>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11));
+ EXPECT_EQ(static_cast<uint32>(cmds::WaitSyncPointCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.sync_point);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DrawBuffersEXT) {
+ cmds::DrawBuffersEXT& cmd = *GetBufferAs<cmds::DrawBuffersEXT>();
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(11),
+ static_cast<uint32>(12),
+ static_cast<uint32>(13));
+ EXPECT_EQ(static_cast<uint32>(cmds::DrawBuffersEXT::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(11), cmd.count);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bufs_shm_id);
+ EXPECT_EQ(static_cast<uint32>(13), cmd.bufs_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, DrawBuffersEXTImmediate) {
+ const int kSomeBaseValueToTestWith = 51;
+ static GLenum data[] = {
+ static_cast<GLenum>(kSomeBaseValueToTestWith + 0),
+ };
+ cmds::DrawBuffersEXTImmediate& cmd =
+ *GetBufferAs<cmds::DrawBuffersEXTImmediate>();
+ const GLsizei kNumElements = 1;
+ const size_t kExpectedCmdSize =
+ sizeof(cmd) + kNumElements * sizeof(GLenum) * 1;
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLsizei>(1),
+ data);
+ EXPECT_EQ(static_cast<uint32>(cmds::DrawBuffersEXTImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(kExpectedCmdSize, cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(1), cmd.count);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd, sizeof(cmd) +
+ RoundSizeToMultipleOfEntries(sizeof(data)));
+ // TODO(gman): Check that data was inserted;
+}
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_ids.h b/chromium/gpu/command_buffer/common/gles2_cmd_ids.h
new file mode 100644
index 00000000000..b701c914d05
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_ids.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the GLES2 command buffer commands.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_H_
+
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+
+namespace gpu {
+namespace gles2 {
+
+#include "gpu/command_buffer/common/gles2_cmd_ids_autogen.h"
+
+const char* GetCommandName(CommandId command_id);
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/chromium/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
new file mode 100644
index 00000000000..6fd070975d8
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -0,0 +1,267 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_AUTOGEN_H_
+
+#define GLES2_COMMAND_LIST(OP) \
+ OP(ActiveTexture) /* 256 */ \
+ OP(AttachShader) /* 257 */ \
+ OP(BindAttribLocation) /* 258 */ \
+ OP(BindAttribLocationImmediate) /* 259 */ \
+ OP(BindAttribLocationBucket) /* 260 */ \
+ OP(BindBuffer) /* 261 */ \
+ OP(BindFramebuffer) /* 262 */ \
+ OP(BindRenderbuffer) /* 263 */ \
+ OP(BindTexture) /* 264 */ \
+ OP(BlendColor) /* 265 */ \
+ OP(BlendEquation) /* 266 */ \
+ OP(BlendEquationSeparate) /* 267 */ \
+ OP(BlendFunc) /* 268 */ \
+ OP(BlendFuncSeparate) /* 269 */ \
+ OP(BufferData) /* 270 */ \
+ OP(BufferDataImmediate) /* 271 */ \
+ OP(BufferSubData) /* 272 */ \
+ OP(BufferSubDataImmediate) /* 273 */ \
+ OP(CheckFramebufferStatus) /* 274 */ \
+ OP(Clear) /* 275 */ \
+ OP(ClearColor) /* 276 */ \
+ OP(ClearDepthf) /* 277 */ \
+ OP(ClearStencil) /* 278 */ \
+ OP(ColorMask) /* 279 */ \
+ OP(CompileShader) /* 280 */ \
+ OP(CompressedTexImage2D) /* 281 */ \
+ OP(CompressedTexImage2DImmediate) /* 282 */ \
+ OP(CompressedTexImage2DBucket) /* 283 */ \
+ OP(CompressedTexSubImage2D) /* 284 */ \
+ OP(CompressedTexSubImage2DImmediate) /* 285 */ \
+ OP(CompressedTexSubImage2DBucket) /* 286 */ \
+ OP(CopyTexImage2D) /* 287 */ \
+ OP(CopyTexSubImage2D) /* 288 */ \
+ OP(CreateProgram) /* 289 */ \
+ OP(CreateShader) /* 290 */ \
+ OP(CullFace) /* 291 */ \
+ OP(DeleteBuffers) /* 292 */ \
+ OP(DeleteBuffersImmediate) /* 293 */ \
+ OP(DeleteFramebuffers) /* 294 */ \
+ OP(DeleteFramebuffersImmediate) /* 295 */ \
+ OP(DeleteProgram) /* 296 */ \
+ OP(DeleteRenderbuffers) /* 297 */ \
+ OP(DeleteRenderbuffersImmediate) /* 298 */ \
+ OP(DeleteShader) /* 299 */ \
+ OP(DeleteTextures) /* 300 */ \
+ OP(DeleteTexturesImmediate) /* 301 */ \
+ OP(DepthFunc) /* 302 */ \
+ OP(DepthMask) /* 303 */ \
+ OP(DepthRangef) /* 304 */ \
+ OP(DetachShader) /* 305 */ \
+ OP(Disable) /* 306 */ \
+ OP(DisableVertexAttribArray) /* 307 */ \
+ OP(DrawArrays) /* 308 */ \
+ OP(DrawElements) /* 309 */ \
+ OP(Enable) /* 310 */ \
+ OP(EnableVertexAttribArray) /* 311 */ \
+ OP(Finish) /* 312 */ \
+ OP(Flush) /* 313 */ \
+ OP(FramebufferRenderbuffer) /* 314 */ \
+ OP(FramebufferTexture2D) /* 315 */ \
+ OP(FrontFace) /* 316 */ \
+ OP(GenBuffers) /* 317 */ \
+ OP(GenBuffersImmediate) /* 318 */ \
+ OP(GenerateMipmap) /* 319 */ \
+ OP(GenFramebuffers) /* 320 */ \
+ OP(GenFramebuffersImmediate) /* 321 */ \
+ OP(GenRenderbuffers) /* 322 */ \
+ OP(GenRenderbuffersImmediate) /* 323 */ \
+ OP(GenTextures) /* 324 */ \
+ OP(GenTexturesImmediate) /* 325 */ \
+ OP(GetActiveAttrib) /* 326 */ \
+ OP(GetActiveUniform) /* 327 */ \
+ OP(GetAttachedShaders) /* 328 */ \
+ OP(GetAttribLocation) /* 329 */ \
+ OP(GetAttribLocationImmediate) /* 330 */ \
+ OP(GetAttribLocationBucket) /* 331 */ \
+ OP(GetBooleanv) /* 332 */ \
+ OP(GetBufferParameteriv) /* 333 */ \
+ OP(GetError) /* 334 */ \
+ OP(GetFloatv) /* 335 */ \
+ OP(GetFramebufferAttachmentParameteriv) /* 336 */ \
+ OP(GetIntegerv) /* 337 */ \
+ OP(GetProgramiv) /* 338 */ \
+ OP(GetProgramInfoLog) /* 339 */ \
+ OP(GetRenderbufferParameteriv) /* 340 */ \
+ OP(GetShaderiv) /* 341 */ \
+ OP(GetShaderInfoLog) /* 342 */ \
+ OP(GetShaderPrecisionFormat) /* 343 */ \
+ OP(GetShaderSource) /* 344 */ \
+ OP(GetString) /* 345 */ \
+ OP(GetTexParameterfv) /* 346 */ \
+ OP(GetTexParameteriv) /* 347 */ \
+ OP(GetUniformfv) /* 348 */ \
+ OP(GetUniformiv) /* 349 */ \
+ OP(GetUniformLocation) /* 350 */ \
+ OP(GetUniformLocationImmediate) /* 351 */ \
+ OP(GetUniformLocationBucket) /* 352 */ \
+ OP(GetVertexAttribfv) /* 353 */ \
+ OP(GetVertexAttribiv) /* 354 */ \
+ OP(GetVertexAttribPointerv) /* 355 */ \
+ OP(Hint) /* 356 */ \
+ OP(IsBuffer) /* 357 */ \
+ OP(IsEnabled) /* 358 */ \
+ OP(IsFramebuffer) /* 359 */ \
+ OP(IsProgram) /* 360 */ \
+ OP(IsRenderbuffer) /* 361 */ \
+ OP(IsShader) /* 362 */ \
+ OP(IsTexture) /* 363 */ \
+ OP(LineWidth) /* 364 */ \
+ OP(LinkProgram) /* 365 */ \
+ OP(PixelStorei) /* 366 */ \
+ OP(PolygonOffset) /* 367 */ \
+ OP(ReadPixels) /* 368 */ \
+ OP(ReleaseShaderCompiler) /* 369 */ \
+ OP(RenderbufferStorage) /* 370 */ \
+ OP(SampleCoverage) /* 371 */ \
+ OP(Scissor) /* 372 */ \
+ OP(ShaderBinary) /* 373 */ \
+ OP(ShaderSource) /* 374 */ \
+ OP(ShaderSourceImmediate) /* 375 */ \
+ OP(ShaderSourceBucket) /* 376 */ \
+ OP(StencilFunc) /* 377 */ \
+ OP(StencilFuncSeparate) /* 378 */ \
+ OP(StencilMask) /* 379 */ \
+ OP(StencilMaskSeparate) /* 380 */ \
+ OP(StencilOp) /* 381 */ \
+ OP(StencilOpSeparate) /* 382 */ \
+ OP(TexImage2D) /* 383 */ \
+ OP(TexImage2DImmediate) /* 384 */ \
+ OP(TexParameterf) /* 385 */ \
+ OP(TexParameterfv) /* 386 */ \
+ OP(TexParameterfvImmediate) /* 387 */ \
+ OP(TexParameteri) /* 388 */ \
+ OP(TexParameteriv) /* 389 */ \
+ OP(TexParameterivImmediate) /* 390 */ \
+ OP(TexSubImage2D) /* 391 */ \
+ OP(TexSubImage2DImmediate) /* 392 */ \
+ OP(Uniform1f) /* 393 */ \
+ OP(Uniform1fv) /* 394 */ \
+ OP(Uniform1fvImmediate) /* 395 */ \
+ OP(Uniform1i) /* 396 */ \
+ OP(Uniform1iv) /* 397 */ \
+ OP(Uniform1ivImmediate) /* 398 */ \
+ OP(Uniform2f) /* 399 */ \
+ OP(Uniform2fv) /* 400 */ \
+ OP(Uniform2fvImmediate) /* 401 */ \
+ OP(Uniform2i) /* 402 */ \
+ OP(Uniform2iv) /* 403 */ \
+ OP(Uniform2ivImmediate) /* 404 */ \
+ OP(Uniform3f) /* 405 */ \
+ OP(Uniform3fv) /* 406 */ \
+ OP(Uniform3fvImmediate) /* 407 */ \
+ OP(Uniform3i) /* 408 */ \
+ OP(Uniform3iv) /* 409 */ \
+ OP(Uniform3ivImmediate) /* 410 */ \
+ OP(Uniform4f) /* 411 */ \
+ OP(Uniform4fv) /* 412 */ \
+ OP(Uniform4fvImmediate) /* 413 */ \
+ OP(Uniform4i) /* 414 */ \
+ OP(Uniform4iv) /* 415 */ \
+ OP(Uniform4ivImmediate) /* 416 */ \
+ OP(UniformMatrix2fv) /* 417 */ \
+ OP(UniformMatrix2fvImmediate) /* 418 */ \
+ OP(UniformMatrix3fv) /* 419 */ \
+ OP(UniformMatrix3fvImmediate) /* 420 */ \
+ OP(UniformMatrix4fv) /* 421 */ \
+ OP(UniformMatrix4fvImmediate) /* 422 */ \
+ OP(UseProgram) /* 423 */ \
+ OP(ValidateProgram) /* 424 */ \
+ OP(VertexAttrib1f) /* 425 */ \
+ OP(VertexAttrib1fv) /* 426 */ \
+ OP(VertexAttrib1fvImmediate) /* 427 */ \
+ OP(VertexAttrib2f) /* 428 */ \
+ OP(VertexAttrib2fv) /* 429 */ \
+ OP(VertexAttrib2fvImmediate) /* 430 */ \
+ OP(VertexAttrib3f) /* 431 */ \
+ OP(VertexAttrib3fv) /* 432 */ \
+ OP(VertexAttrib3fvImmediate) /* 433 */ \
+ OP(VertexAttrib4f) /* 434 */ \
+ OP(VertexAttrib4fv) /* 435 */ \
+ OP(VertexAttrib4fvImmediate) /* 436 */ \
+ OP(VertexAttribPointer) /* 437 */ \
+ OP(Viewport) /* 438 */ \
+ OP(BlitFramebufferEXT) /* 439 */ \
+ OP(RenderbufferStorageMultisampleEXT) /* 440 */ \
+ OP(FramebufferTexture2DMultisampleEXT) /* 441 */ \
+ OP(TexStorage2DEXT) /* 442 */ \
+ OP(GenQueriesEXT) /* 443 */ \
+ OP(GenQueriesEXTImmediate) /* 444 */ \
+ OP(DeleteQueriesEXT) /* 445 */ \
+ OP(DeleteQueriesEXTImmediate) /* 446 */ \
+ OP(BeginQueryEXT) /* 447 */ \
+ OP(EndQueryEXT) /* 448 */ \
+ OP(InsertEventMarkerEXT) /* 449 */ \
+ OP(PushGroupMarkerEXT) /* 450 */ \
+ OP(PopGroupMarkerEXT) /* 451 */ \
+ OP(GenVertexArraysOES) /* 452 */ \
+ OP(GenVertexArraysOESImmediate) /* 453 */ \
+ OP(DeleteVertexArraysOES) /* 454 */ \
+ OP(DeleteVertexArraysOESImmediate) /* 455 */ \
+ OP(IsVertexArrayOES) /* 456 */ \
+ OP(BindVertexArrayOES) /* 457 */ \
+ OP(SwapBuffers) /* 458 */ \
+ OP(GetMaxValueInBufferCHROMIUM) /* 459 */ \
+ OP(GenSharedIdsCHROMIUM) /* 460 */ \
+ OP(DeleteSharedIdsCHROMIUM) /* 461 */ \
+ OP(RegisterSharedIdsCHROMIUM) /* 462 */ \
+ OP(EnableFeatureCHROMIUM) /* 463 */ \
+ OP(ResizeCHROMIUM) /* 464 */ \
+ OP(GetRequestableExtensionsCHROMIUM) /* 465 */ \
+ OP(RequestExtensionCHROMIUM) /* 466 */ \
+ OP(GetMultipleIntegervCHROMIUM) /* 467 */ \
+ OP(GetProgramInfoCHROMIUM) /* 468 */ \
+ OP(CreateStreamTextureCHROMIUM) /* 469 */ \
+ OP(DestroyStreamTextureCHROMIUM) /* 470 */ \
+ OP(GetTranslatedShaderSourceANGLE) /* 471 */ \
+ OP(PostSubBufferCHROMIUM) /* 472 */ \
+ OP(TexImageIOSurface2DCHROMIUM) /* 473 */ \
+ OP(CopyTextureCHROMIUM) /* 474 */ \
+ OP(DrawArraysInstancedANGLE) /* 475 */ \
+ OP(DrawElementsInstancedANGLE) /* 476 */ \
+ OP(VertexAttribDivisorANGLE) /* 477 */ \
+ OP(GenMailboxCHROMIUM) /* 478 */ \
+ OP(ProduceTextureCHROMIUM) /* 479 */ \
+ OP(ProduceTextureCHROMIUMImmediate) /* 480 */ \
+ OP(ConsumeTextureCHROMIUM) /* 481 */ \
+ OP(ConsumeTextureCHROMIUMImmediate) /* 482 */ \
+ OP(BindUniformLocationCHROMIUM) /* 483 */ \
+ OP(BindUniformLocationCHROMIUMImmediate) /* 484 */ \
+ OP(BindUniformLocationCHROMIUMBucket) /* 485 */ \
+ OP(BindTexImage2DCHROMIUM) /* 486 */ \
+ OP(ReleaseTexImage2DCHROMIUM) /* 487 */ \
+ OP(TraceBeginCHROMIUM) /* 488 */ \
+ OP(TraceEndCHROMIUM) /* 489 */ \
+ OP(AsyncTexSubImage2DCHROMIUM) /* 490 */ \
+ OP(AsyncTexImage2DCHROMIUM) /* 491 */ \
+ OP(WaitAsyncTexImage2DCHROMIUM) /* 492 */ \
+ OP(DiscardFramebufferEXT) /* 493 */ \
+ OP(DiscardFramebufferEXTImmediate) /* 494 */ \
+ OP(LoseContextCHROMIUM) /* 495 */ \
+ OP(InsertSyncPointCHROMIUM) /* 496 */ \
+ OP(WaitSyncPointCHROMIUM) /* 497 */ \
+ OP(DrawBuffersEXT) /* 498 */ \
+ OP(DrawBuffersEXTImmediate) /* 499 */ \
+
+enum CommandId {
+ kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
+#define GLES2_CMD_OP(name) k ## name,
+ GLES2_COMMAND_LIST(GLES2_CMD_OP)
+#undef GLES2_CMD_OP
+ kNumCommands
+};
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_IDS_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_utils.cc b/chromium/gpu/command_buffer/common/gles2_cmd_utils.cc
new file mode 100644
index 00000000000..25eafcd8a26
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -0,0 +1,813 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is here so other GLES2 related files can have a common set of
+// includes where appropriate.
+
+#include <stdio.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+
+namespace gpu {
+namespace gles2 {
+
+namespace gl_error_bit {
+enum GLErrorBit {
+ kNoError = 0,
+ kInvalidEnum = (1 << 0),
+ kInvalidValue = (1 << 1),
+ kInvalidOperation = (1 << 2),
+ kOutOfMemory = (1 << 3),
+ kInvalidFrameBufferOperation = (1 << 4)
+};
+}
+
+int GLES2Util::GLGetNumValuesReturned(int id) const {
+ switch (id) {
+ // -- glGetBooleanv, glGetFloatv, glGetIntergerv
+ case GL_ACTIVE_TEXTURE:
+ return 1;
+ case GL_ALIASED_LINE_WIDTH_RANGE:
+ return 2;
+ case GL_ALIASED_POINT_SIZE_RANGE:
+ return 2;
+ case GL_ALPHA_BITS:
+ return 1;
+ case GL_ARRAY_BUFFER_BINDING:
+ return 1;
+ case GL_BLEND:
+ return 1;
+ case GL_BLEND_COLOR:
+ return 4;
+ case GL_BLEND_DST_ALPHA:
+ return 1;
+ case GL_BLEND_DST_RGB:
+ return 1;
+ case GL_BLEND_EQUATION_ALPHA:
+ return 1;
+ case GL_BLEND_EQUATION_RGB:
+ return 1;
+ case GL_BLEND_SRC_ALPHA:
+ return 1;
+ case GL_BLEND_SRC_RGB:
+ return 1;
+ case GL_BLUE_BITS:
+ return 1;
+ case GL_COLOR_CLEAR_VALUE:
+ return 4;
+ case GL_COLOR_WRITEMASK:
+ return 4;
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ return num_compressed_texture_formats_;
+ case GL_CULL_FACE:
+ return 1;
+ case GL_CULL_FACE_MODE:
+ return 1;
+ case GL_CURRENT_PROGRAM:
+ return 1;
+ case GL_DEPTH_BITS:
+ return 1;
+ case GL_DEPTH_CLEAR_VALUE:
+ return 1;
+ case GL_DEPTH_FUNC:
+ return 1;
+ case GL_DEPTH_RANGE:
+ return 2;
+ case GL_DEPTH_TEST:
+ return 1;
+ case GL_DEPTH_WRITEMASK:
+ return 1;
+ case GL_DITHER:
+ return 1;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+ return 1;
+ case GL_FRAMEBUFFER_BINDING:
+ return 1;
+ case GL_FRONT_FACE:
+ return 1;
+ case GL_GENERATE_MIPMAP_HINT:
+ return 1;
+ case GL_GREEN_BITS:
+ return 1;
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
+ return 1;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE:
+ return 1;
+ case GL_LINE_WIDTH:
+ return 1;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ return 1;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
+ return 1;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+ return 1;
+ case GL_MAX_RENDERBUFFER_SIZE:
+ return 1;
+ case GL_MAX_TEXTURE_IMAGE_UNITS:
+ return 1;
+ case GL_MAX_TEXTURE_SIZE:
+ return 1;
+ case GL_MAX_VARYING_VECTORS:
+ return 1;
+ case GL_MAX_VERTEX_ATTRIBS:
+ return 1;
+ case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+ return 1;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS:
+ return 1;
+ case GL_MAX_VIEWPORT_DIMS:
+ return 2;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ return 1;
+ case GL_NUM_SHADER_BINARY_FORMATS:
+ return 1;
+ case GL_PACK_ALIGNMENT:
+ return 1;
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
+ return 1;
+ case GL_POLYGON_OFFSET_FACTOR:
+ return 1;
+ case GL_POLYGON_OFFSET_FILL:
+ return 1;
+ case GL_POLYGON_OFFSET_UNITS:
+ return 1;
+ case GL_RED_BITS:
+ return 1;
+ case GL_RENDERBUFFER_BINDING:
+ return 1;
+ case GL_SAMPLE_BUFFERS:
+ return 1;
+ case GL_SAMPLE_COVERAGE_INVERT:
+ return 1;
+ case GL_SAMPLE_COVERAGE_VALUE:
+ return 1;
+ case GL_SAMPLES:
+ return 1;
+ case GL_SCISSOR_BOX:
+ return 4;
+ case GL_SCISSOR_TEST:
+ return 1;
+ case GL_SHADER_BINARY_FORMATS:
+ return num_shader_binary_formats_;
+ case GL_SHADER_COMPILER:
+ return 1;
+ case GL_STENCIL_BACK_FAIL:
+ return 1;
+ case GL_STENCIL_BACK_FUNC:
+ return 1;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
+ return 1;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS:
+ return 1;
+ case GL_STENCIL_BACK_REF:
+ return 1;
+ case GL_STENCIL_BACK_VALUE_MASK:
+ return 1;
+ case GL_STENCIL_BACK_WRITEMASK:
+ return 1;
+ case GL_STENCIL_BITS:
+ return 1;
+ case GL_STENCIL_CLEAR_VALUE:
+ return 1;
+ case GL_STENCIL_FAIL:
+ return 1;
+ case GL_STENCIL_FUNC:
+ return 1;
+ case GL_STENCIL_PASS_DEPTH_FAIL:
+ return 1;
+ case GL_STENCIL_PASS_DEPTH_PASS:
+ return 1;
+ case GL_STENCIL_REF:
+ return 1;
+ case GL_STENCIL_TEST:
+ return 1;
+ case GL_STENCIL_VALUE_MASK:
+ return 1;
+ case GL_STENCIL_WRITEMASK:
+ return 1;
+ case GL_SUBPIXEL_BITS:
+ return 1;
+ case GL_TEXTURE_BINDING_2D:
+ return 1;
+ case GL_TEXTURE_BINDING_CUBE_MAP:
+ return 1;
+ case GL_TEXTURE_BINDING_EXTERNAL_OES:
+ return 1;
+ case GL_TEXTURE_BINDING_RECTANGLE_ARB:
+ return 1;
+ case GL_TEXTURE_IMMUTABLE_FORMAT_EXT:
+ return 1;
+ case GL_UNPACK_ALIGNMENT:
+ return 1;
+ case GL_VIEWPORT:
+ return 4;
+ // -- glGetBooleanv, glGetFloatv, glGetIntergerv with
+ // GL_CHROMIUM_framebuffer_multisample
+ case GL_MAX_SAMPLES_EXT:
+ return 1;
+ case GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
+ return 1;
+
+ // -- glGetBufferParameteriv
+ case GL_BUFFER_SIZE:
+ return 1;
+ case GL_BUFFER_USAGE:
+ return 1;
+
+ // -- glGetFramebufferAttachmentParameteriv
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
+ return 1;
+ case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
+ return 1;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
+ return 1;
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
+ return 1;
+ // -- glGetFramebufferAttachmentParameteriv with
+ // GL_EXT_multisampled_render_to_texture
+ case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT:
+ return 1;
+
+ // -- glGetProgramiv
+ case GL_DELETE_STATUS:
+ return 1;
+ case GL_LINK_STATUS:
+ return 1;
+ case GL_VALIDATE_STATUS:
+ return 1;
+ case GL_INFO_LOG_LENGTH:
+ return 1;
+ case GL_ATTACHED_SHADERS:
+ return 1;
+ case GL_ACTIVE_ATTRIBUTES:
+ return 1;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ return 1;
+ case GL_ACTIVE_UNIFORMS:
+ return 1;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ return 1;
+
+
+ // -- glGetRenderbufferAttachmentParameteriv
+ case GL_RENDERBUFFER_WIDTH:
+ return 1;
+ case GL_RENDERBUFFER_HEIGHT:
+ return 1;
+ case GL_RENDERBUFFER_INTERNAL_FORMAT:
+ return 1;
+ case GL_RENDERBUFFER_RED_SIZE:
+ return 1;
+ case GL_RENDERBUFFER_GREEN_SIZE:
+ return 1;
+ case GL_RENDERBUFFER_BLUE_SIZE:
+ return 1;
+ case GL_RENDERBUFFER_ALPHA_SIZE:
+ return 1;
+ case GL_RENDERBUFFER_DEPTH_SIZE:
+ return 1;
+ case GL_RENDERBUFFER_STENCIL_SIZE:
+ return 1;
+ // -- glGetRenderbufferAttachmentParameteriv with
+ // GL_EXT_multisampled_render_to_texture
+ case GL_RENDERBUFFER_SAMPLES_EXT:
+ return 1;
+
+ // -- glGetShaderiv
+ case GL_SHADER_TYPE:
+ return 1;
+ // Already defined under glGetFramebufferAttachemntParameteriv.
+ // case GL_DELETE_STATUS:
+ // return 1;
+ case GL_COMPILE_STATUS:
+ return 1;
+ // Already defined under glGetFramebufferAttachemntParameteriv.
+ // case GL_INFO_LOG_LENGTH:
+ // return 1;
+ case GL_SHADER_SOURCE_LENGTH:
+ return 1;
+ case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
+ return 1;
+
+ // -- glGetTexParameterfv, glGetTexParameteriv
+ case GL_TEXTURE_MAG_FILTER:
+ return 1;
+ case GL_TEXTURE_MIN_FILTER:
+ return 1;
+ case GL_TEXTURE_WRAP_S:
+ return 1;
+ case GL_TEXTURE_WRAP_T:
+ return 1;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ return 1;
+
+ // -- glGetVertexAttribfv, glGetVertexAttribiv
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+ return 1;
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ return 1;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ return 1;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ return 1;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ return 1;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ return 1;
+ case GL_CURRENT_VERTEX_ATTRIB:
+ return 4;
+
+ // -- glHint with GL_OES_standard_derivatives
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ return 1;
+
+ // bad enum
+ default:
+ return 0;
+ }
+}
+
+namespace {
+
+// Return the number of elements per group of a specified format.
+int ElementsPerGroup(int format, int type) {
+ switch (type) {
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ case GL_UNSIGNED_INT_24_8_OES:
+ return 1;
+ default:
+ break;
+ }
+
+ switch (format) {
+ case GL_RGB:
+ return 3;
+ case GL_LUMINANCE_ALPHA:
+ return 2;
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ return 4;
+ case GL_ALPHA:
+ case GL_LUMINANCE:
+ case GL_DEPTH_COMPONENT:
+ case GL_DEPTH_COMPONENT24_OES:
+ case GL_DEPTH_COMPONENT32_OES:
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH24_STENCIL8_OES:
+ case GL_DEPTH_STENCIL_OES:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+// Return the number of bytes per element, based on the element type.
+int BytesPerElement(int type) {
+ switch (type) {
+ case GL_FLOAT:
+ case GL_UNSIGNED_INT_24_8_OES:
+ case GL_UNSIGNED_INT:
+ return 4;
+ case GL_HALF_FLOAT_OES:
+ case GL_UNSIGNED_SHORT:
+ case GL_SHORT:
+ case GL_UNSIGNED_SHORT_5_6_5:
+ case GL_UNSIGNED_SHORT_4_4_4_4:
+ case GL_UNSIGNED_SHORT_5_5_5_1:
+ return 2;
+ case GL_UNSIGNED_BYTE:
+ case GL_BYTE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+} // anonymous namespace
+
+uint32 GLES2Util::ComputeImageGroupSize(int format, int type) {
+ return BytesPerElement(type) * ElementsPerGroup(format, type);
+}
+
+bool GLES2Util::ComputeImagePaddedRowSize(
+ int width, int format, int type, int unpack_alignment,
+ uint32* padded_row_size) {
+ uint32 bytes_per_group = ComputeImageGroupSize(format, type);
+ uint32 unpadded_row_size;
+ if (!SafeMultiplyUint32(width, bytes_per_group, &unpadded_row_size)) {
+ return false;
+ }
+ uint32 temp;
+ if (!SafeAddUint32(unpadded_row_size, unpack_alignment - 1, &temp)) {
+ return false;
+ }
+ *padded_row_size = (temp / unpack_alignment) * unpack_alignment;
+ return true;
+}
+
+// Returns the amount of data glTexImage2D or glTexSubImage2D will access.
+bool GLES2Util::ComputeImageDataSizes(
+ int width, int height, int format, int type, int unpack_alignment,
+ uint32* size, uint32* ret_unpadded_row_size, uint32* ret_padded_row_size) {
+ uint32 bytes_per_group = ComputeImageGroupSize(format, type);
+ uint32 row_size;
+ if (!SafeMultiplyUint32(width, bytes_per_group, &row_size)) {
+ return false;
+ }
+ if (height > 1) {
+ uint32 temp;
+ if (!SafeAddUint32(row_size, unpack_alignment - 1, &temp)) {
+ return false;
+ }
+ uint32 padded_row_size = (temp / unpack_alignment) * unpack_alignment;
+ uint32 size_of_all_but_last_row;
+ if (!SafeMultiplyUint32((height - 1), padded_row_size,
+ &size_of_all_but_last_row)) {
+ return false;
+ }
+ if (!SafeAddUint32(size_of_all_but_last_row, row_size, size)) {
+ return false;
+ }
+ if (ret_padded_row_size) {
+ *ret_padded_row_size = padded_row_size;
+ }
+ } else {
+ if (!SafeMultiplyUint32(height, row_size, size)) {
+ return false;
+ }
+ if (ret_padded_row_size) {
+ *ret_padded_row_size = row_size;
+ }
+ }
+ if (ret_unpadded_row_size) {
+ *ret_unpadded_row_size = row_size;
+ }
+
+ return true;
+}
+
+size_t GLES2Util::RenderbufferBytesPerPixel(int format) {
+ switch (format) {
+ case GL_STENCIL_INDEX8:
+ return 1;
+ case GL_RGBA4:
+ case GL_RGB565:
+ case GL_RGB5_A1:
+ case GL_DEPTH_COMPONENT16:
+ return 2;
+ case GL_RGB:
+ case GL_RGBA:
+ case GL_DEPTH24_STENCIL8_OES:
+ case GL_RGB8_OES:
+ case GL_RGBA8_OES:
+ case GL_DEPTH_COMPONENT24_OES:
+ return 4;
+ default:
+ return 0;
+ }
+}
+
+uint32 GLES2Util::GetGLDataTypeSizeForUniforms(int type) {
+ switch (type) {
+ case GL_FLOAT:
+ return sizeof(GLfloat); // NOLINT
+ case GL_FLOAT_VEC2:
+ return sizeof(GLfloat) * 2; // NOLINT
+ case GL_FLOAT_VEC3:
+ return sizeof(GLfloat) * 3; // NOLINT
+ case GL_FLOAT_VEC4:
+ return sizeof(GLfloat) * 4; // NOLINT
+ case GL_INT:
+ return sizeof(GLint); // NOLINT
+ case GL_INT_VEC2:
+ return sizeof(GLint) * 2; // NOLINT
+ case GL_INT_VEC3:
+ return sizeof(GLint) * 3; // NOLINT
+ case GL_INT_VEC4:
+ return sizeof(GLint) * 4; // NOLINT
+ case GL_BOOL:
+ return sizeof(GLint); // NOLINT
+ case GL_BOOL_VEC2:
+ return sizeof(GLint) * 2; // NOLINT
+ case GL_BOOL_VEC3:
+ return sizeof(GLint) * 3; // NOLINT
+ case GL_BOOL_VEC4:
+ return sizeof(GLint) * 4; // NOLINT
+ case GL_FLOAT_MAT2:
+ return sizeof(GLfloat) * 2 * 2; // NOLINT
+ case GL_FLOAT_MAT3:
+ return sizeof(GLfloat) * 3 * 3; // NOLINT
+ case GL_FLOAT_MAT4:
+ return sizeof(GLfloat) * 4 * 4; // NOLINT
+ case GL_SAMPLER_2D:
+ return sizeof(GLint); // NOLINT
+ case GL_SAMPLER_2D_RECT_ARB:
+ return sizeof(GLint); // NOLINT
+ case GL_SAMPLER_CUBE:
+ return sizeof(GLint); // NOLINT
+ case GL_SAMPLER_EXTERNAL_OES:
+ return sizeof(GLint); // NOLINT
+ default:
+ return 0;
+ }
+}
+
+size_t GLES2Util::GetGLTypeSizeForTexturesAndBuffers(uint32 type) {
+ switch (type) {
+ case GL_BYTE:
+ return sizeof(GLbyte); // NOLINT
+ case GL_UNSIGNED_BYTE:
+ return sizeof(GLubyte); // NOLINT
+ case GL_SHORT:
+ return sizeof(GLshort); // NOLINT
+ case GL_UNSIGNED_SHORT:
+ return sizeof(GLushort); // NOLINT
+ case GL_INT:
+ return sizeof(GLint); // NOLINT
+ case GL_UNSIGNED_INT:
+ return sizeof(GLuint); // NOLINT
+ case GL_FLOAT:
+ return sizeof(GLfloat); // NOLINT
+ case GL_FIXED:
+ return sizeof(GLfixed); // NOLINT
+ default:
+ return 0;
+ }
+}
+
+uint32 GLES2Util::GLErrorToErrorBit(uint32 error) {
+ switch (error) {
+ case GL_INVALID_ENUM:
+ return gl_error_bit::kInvalidEnum;
+ case GL_INVALID_VALUE:
+ return gl_error_bit::kInvalidValue;
+ case GL_INVALID_OPERATION:
+ return gl_error_bit::kInvalidOperation;
+ case GL_OUT_OF_MEMORY:
+ return gl_error_bit::kOutOfMemory;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ return gl_error_bit::kInvalidFrameBufferOperation;
+ default:
+ GPU_NOTREACHED();
+ return gl_error_bit::kNoError;
+ }
+}
+
+uint32 GLES2Util::GLErrorBitToGLError(uint32 error_bit) {
+ switch (error_bit) {
+ case gl_error_bit::kInvalidEnum:
+ return GL_INVALID_ENUM;
+ case gl_error_bit::kInvalidValue:
+ return GL_INVALID_VALUE;
+ case gl_error_bit::kInvalidOperation:
+ return GL_INVALID_OPERATION;
+ case gl_error_bit::kOutOfMemory:
+ return GL_OUT_OF_MEMORY;
+ case gl_error_bit::kInvalidFrameBufferOperation:
+ return GL_INVALID_FRAMEBUFFER_OPERATION;
+ default:
+ GPU_NOTREACHED();
+ return GL_NO_ERROR;
+ }
+}
+
+uint32 GLES2Util::IndexToGLFaceTarget(int index) {
+ static uint32 faces[] = {
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ };
+ return faces[index];
+}
+
+uint32 GLES2Util::GetChannelsForFormat(int format) {
+ switch (format) {
+ case GL_ALPHA:
+ case GL_ALPHA16F_EXT:
+ case GL_ALPHA32F_EXT:
+ return kAlpha;
+ case GL_LUMINANCE:
+ return kRGB;
+ case GL_LUMINANCE_ALPHA:
+ return kRGBA;
+ case GL_RGB:
+ case GL_RGB8_OES:
+ case GL_RGB565:
+ case GL_RGB16F_EXT:
+ case GL_RGB32F_EXT:
+ return kRGB;
+ case GL_BGRA_EXT:
+ case GL_BGRA8_EXT:
+ case GL_RGBA16F_EXT:
+ case GL_RGBA32F_EXT:
+ case GL_RGBA:
+ case GL_RGBA8_OES:
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ return kRGBA;
+ case GL_DEPTH_COMPONENT32_OES:
+ case GL_DEPTH_COMPONENT24_OES:
+ case GL_DEPTH_COMPONENT16:
+ case GL_DEPTH_COMPONENT:
+ return kDepth;
+ case GL_STENCIL_INDEX8:
+ return kStencil;
+ case GL_DEPTH_STENCIL_OES:
+ case GL_DEPTH24_STENCIL8_OES:
+ return kDepth | kStencil;
+ default:
+ return 0x0000;
+ }
+}
+
+uint32 GLES2Util::GetChannelsNeededForAttachmentType(
+ int type, uint32 max_color_attachments) {
+ switch (type) {
+ case GL_DEPTH_ATTACHMENT:
+ return kDepth;
+ case GL_STENCIL_ATTACHMENT:
+ return kStencil;
+ default:
+ if (type >= GL_COLOR_ATTACHMENT0 &&
+ type < static_cast<int>(
+ GL_COLOR_ATTACHMENT0 + max_color_attachments)) {
+ return kRGBA;
+ }
+ return 0x0000;
+ }
+}
+
+std::string GLES2Util::GetStringEnum(uint32 value) {
+ const EnumToString* entry = enum_to_string_table_;
+ const EnumToString* end = entry + enum_to_string_table_len_;
+ for (;entry < end; ++entry) {
+ if (value == entry->value) {
+ return entry->name;
+ }
+ }
+ char buffer[20];
+ sprintf(buffer, (value < 0x10000) ? "0x%04x" : "0x%08x", value);
+ return buffer;
+}
+
+std::string GLES2Util::GetStringError(uint32 value) {
+ static EnumToString string_table[] = {
+ { GL_NONE, "GL_NONE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringBool(uint32 value) {
+ return value ? "GL_TRUE" : "GL_FALSE";
+}
+
+std::string GLES2Util::GetQualifiedEnumString(
+ const EnumToString* table, size_t count, uint32 value) {
+ for (const EnumToString* end = table + count; table < end; ++table) {
+ if (table->value == value) {
+ return table->name;
+ }
+ }
+ return GetStringEnum(value);
+}
+
+bool GLES2Util::ParseUniformName(
+ const std::string& name,
+ size_t* array_pos,
+ int* element_index,
+ bool* getting_array) {
+ bool getting_array_location = false;
+ size_t open_pos = std::string::npos;
+ int index = 0;
+ if (name[name.size() - 1] == ']') {
+ if (name.size() < 3) {
+ return false;
+ }
+ open_pos = name.find_last_of('[');
+ if (open_pos == std::string::npos ||
+ open_pos >= name.size() - 2) {
+ return false;
+ }
+ size_t last = name.size() - 1;
+ for (size_t pos = open_pos + 1; pos < last; ++pos) {
+ int8 digit = name[pos] - '0';
+ if (digit < 0 || digit > 9) {
+ return false;
+ }
+ index = index * 10 + digit;
+ }
+ getting_array_location = true;
+ }
+ *getting_array = getting_array_location;
+ *element_index = index;
+ *array_pos = open_pos;
+ return true;
+}
+
+ContextCreationAttribParser::ContextCreationAttribParser()
+ : alpha_size_(-1),
+ blue_size_(-1),
+ green_size_(-1),
+ red_size_(-1),
+ depth_size_(-1),
+ stencil_size_(-1),
+ samples_(-1),
+ sample_buffers_(-1),
+ buffer_preserved_(true),
+ share_resources_(false),
+ bind_generates_resource_(true) {
+}
+
+bool ContextCreationAttribParser::Parse(const std::vector<int32>& attribs) {
+ // From <EGL/egl.h>.
+ const int32 EGL_ALPHA_SIZE = 0x3021;
+ const int32 EGL_BLUE_SIZE = 0x3022;
+ const int32 EGL_GREEN_SIZE = 0x3023;
+ const int32 EGL_RED_SIZE = 0x3024;
+ const int32 EGL_DEPTH_SIZE = 0x3025;
+ const int32 EGL_STENCIL_SIZE = 0x3026;
+ const int32 EGL_SAMPLES = 0x3031;
+ const int32 EGL_SAMPLE_BUFFERS = 0x3032;
+ const int32 EGL_NONE = 0x3038;
+ const int32 EGL_SWAP_BEHAVIOR = 0x3093;
+ const int32 EGL_BUFFER_PRESERVED = 0x3094;
+
+ // Chromium only.
+ const int32 SHARE_RESOURCES = 0x10000;
+ const int32 BIND_GENERATES_RESOURCES = 0x10001;
+
+ for (size_t i = 0; i < attribs.size(); i += 2) {
+ const int32 attrib = attribs[i];
+ if (i + 1 >= attribs.size()) {
+ if (attrib == EGL_NONE) {
+ return true;
+ }
+
+ GPU_DLOG(ERROR) << "Missing value after context creation attribute: "
+ << attrib;
+ return false;
+ }
+
+ const int32 value = attribs[i+1];
+ switch (attrib) {
+ case EGL_ALPHA_SIZE:
+ alpha_size_ = value;
+ break;
+ case EGL_BLUE_SIZE:
+ blue_size_ = value;
+ break;
+ case EGL_GREEN_SIZE:
+ green_size_ = value;
+ break;
+ case EGL_RED_SIZE:
+ red_size_ = value;
+ break;
+ case EGL_DEPTH_SIZE:
+ depth_size_ = value;
+ break;
+ case EGL_STENCIL_SIZE:
+ stencil_size_ = value;
+ break;
+ case EGL_SAMPLES:
+ samples_ = value;
+ break;
+ case EGL_SAMPLE_BUFFERS:
+ sample_buffers_ = value;
+ break;
+ case EGL_SWAP_BEHAVIOR:
+ buffer_preserved_ = value == EGL_BUFFER_PRESERVED;
+ break;
+ case SHARE_RESOURCES:
+ share_resources_ = value != 0;
+ break;
+ case BIND_GENERATES_RESOURCES:
+ bind_generates_resource_ = value != 0;
+ break;
+ case EGL_NONE:
+ // Terminate list, even if more attributes.
+ return true;
+ default:
+ GPU_DLOG(ERROR) << "Invalid context creation attribute: " << attrib;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+#include "gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_utils.h b/chromium/gpu/command_buffer/common/gles2_cmd_utils.h
new file mode 100644
index 00000000000..4bc4b1b7fcc
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -0,0 +1,200 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is here so other GLES2 related files can have a common set of
+// includes where appropriate.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_H_
+
+#include <limits>
+#include <string>
+#include <vector>
+
+#include "gpu/command_buffer/common/gles2_utils_export.h"
+#include "gpu/command_buffer/common/types.h"
+
+namespace gpu {
+namespace gles2 {
+
+// Does a multiply and checks for overflow. If the multiply did not overflow
+// returns true.
+
+// Multiplies 2 32 bit unsigned numbers checking for overflow.
+// If there was no overflow returns true.
+inline bool SafeMultiplyUint32(uint32 a, uint32 b, uint32* dst) {
+ if (b == 0) {
+ *dst = 0;
+ return true;
+ }
+ uint32 v = a * b;
+ if (v / b != a) {
+ *dst = 0;
+ return false;
+ }
+ *dst = v;
+ return true;
+}
+
+// Does an add checking for overflow. If there was no overflow returns true.
+inline bool SafeAddUint32(uint32 a, uint32 b, uint32* dst) {
+ if (a + b < a) {
+ *dst = 0;
+ return false;
+ }
+ *dst = a + b;
+ return true;
+}
+
+// Does an add checking for overflow. If there was no overflow returns true.
+inline bool SafeAddInt32(int32 a, int32 b, int32* dst) {
+ int64 sum64 = static_cast<int64>(a) + b;
+ int32 sum32 = static_cast<int32>(sum64);
+ bool safe = sum64 == static_cast<int64>(sum32);
+ *dst = safe ? sum32 : 0;
+ return safe;
+}
+
+// Utilties for GLES2 support.
+class GLES2_UTILS_EXPORT GLES2Util {
+ public:
+ static const int kNumFaces = 6;
+
+ // Bits returned by GetChannelsForFormat
+ enum ChannelBits {
+ kRed = 0x1,
+ kGreen = 0x2,
+ kBlue = 0x4,
+ kAlpha = 0x8,
+ kDepth = 0x10000,
+ kStencil = 0x20000,
+
+ kRGB = kRed | kGreen | kBlue,
+ kRGBA = kRGB | kAlpha
+ };
+
+ struct EnumToString {
+ uint32 value;
+ const char* name;
+ };
+
+ GLES2Util()
+ : num_compressed_texture_formats_(0),
+ num_shader_binary_formats_(0) {
+ }
+
+ int num_compressed_texture_formats() const {
+ return num_compressed_texture_formats_;
+ }
+
+ void set_num_compressed_texture_formats(int num_compressed_texture_formats) {
+ num_compressed_texture_formats_ = num_compressed_texture_formats;
+ }
+
+ int num_shader_binary_formats() const {
+ return num_shader_binary_formats_;
+ }
+
+ void set_num_shader_binary_formats(int num_shader_binary_formats) {
+ num_shader_binary_formats_ = num_shader_binary_formats;
+ }
+
+ // Gets the number of values a particular id will return when a glGet
+ // function is called. If 0 is returned the id is invalid.
+ int GLGetNumValuesReturned(int id) const;
+
+ // Computes the size of a single group of elements from a format and type pair
+ static uint32 ComputeImageGroupSize(int format, int type);
+
+ // Computes the size of an image row including alignment padding
+ static bool ComputeImagePaddedRowSize(
+ int width, int format, int type, int unpack_alignment,
+ uint32* padded_row_size);
+
+ // Computes the size of image data for TexImage2D and TexSubImage2D.
+ // Optionally the unpadded and padded row sizes can be returned. If height < 2
+ // then the padded_row_size will be the same as the unpadded_row_size since
+ // padding is not necessary.
+ static bool ComputeImageDataSizes(
+ int width, int height, int format, int type, int unpack_alignment,
+ uint32* size, uint32* unpadded_row_size, uint32* padded_row_size);
+
+ static size_t RenderbufferBytesPerPixel(int format);
+
+ static uint32 GetGLDataTypeSizeForUniforms(int type);
+
+ static size_t GetGLTypeSizeForTexturesAndBuffers(uint32 type);
+
+ static uint32 GLErrorToErrorBit(uint32 gl_error);
+
+ static uint32 GLErrorBitToGLError(uint32 error_bit);
+
+ static uint32 IndexToGLFaceTarget(int index);
+
+ // Returns a bitmask for the channels the given format supports.
+ // See ChannelBits.
+ static uint32 GetChannelsForFormat(int format);
+
+ // Returns a bitmask for the channels the given attachment type needs.
+ static uint32 GetChannelsNeededForAttachmentType(
+ int type, uint32 max_color_attachments);
+
+ static bool IsNPOT(uint32 value) {
+ return value > 0 && (value & (value - 1)) != 0;
+ }
+
+ static std::string GetStringEnum(uint32 value);
+ static std::string GetStringBool(uint32 value);
+ static std::string GetStringError(uint32 value);
+
+ // Parses a uniform name.
+ // array_pos: the position of the last '[' character in name.
+ // element_index: the index of the array element specifed in the name.
+ // getting_array: True if name refers to array.
+ // returns true of parsing was successful. Returing true does NOT mean
+ // it's a valid uniform name. On the otherhand, returning false does mean
+ // it's an invalid uniform name.
+ static bool ParseUniformName(
+ const std::string& name,
+ size_t* array_pos,
+ int* element_index,
+ bool* getting_array);
+
+ #include "../common/gles2_cmd_utils_autogen.h"
+
+ private:
+ static std::string GetQualifiedEnumString(
+ const EnumToString* table, size_t count, uint32 value);
+
+ static const EnumToString* const enum_to_string_table_;
+ static const size_t enum_to_string_table_len_;
+
+ int num_compressed_texture_formats_;
+ int num_shader_binary_formats_;
+};
+
+class GLES2_UTILS_EXPORT ContextCreationAttribParser {
+ public:
+ ContextCreationAttribParser();
+ bool Parse(const std::vector<int32>& attribs);
+
+ // -1 if invalid or unspecified.
+ int32 alpha_size_;
+ int32 blue_size_;
+ int32 green_size_;
+ int32 red_size_;
+ int32 depth_size_;
+ int32 stencil_size_;
+ int32 samples_;
+ int32 sample_buffers_;
+ bool buffer_preserved_;
+ bool share_resources_;
+ bool bind_generates_resource_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/chromium/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
new file mode 100644
index 00000000000..00e1f0ea072
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_AUTOGEN_H_
+
+static std::string GetStringAttachment(uint32 value);
+static std::string GetStringBackbufferAttachment(uint32 value);
+static std::string GetStringBlitFilter(uint32 value);
+static std::string GetStringBufferParameter(uint32 value);
+static std::string GetStringBufferTarget(uint32 value);
+static std::string GetStringBufferUsage(uint32 value);
+static std::string GetStringCapability(uint32 value);
+static std::string GetStringCmpFunction(uint32 value);
+static std::string GetStringCompressedTextureFormat(uint32 value);
+static std::string GetStringDrawMode(uint32 value);
+static std::string GetStringDstBlendFactor(uint32 value);
+static std::string GetStringEquation(uint32 value);
+static std::string GetStringFaceMode(uint32 value);
+static std::string GetStringFaceType(uint32 value);
+static std::string GetStringFrameBufferParameter(uint32 value);
+static std::string GetStringFrameBufferTarget(uint32 value);
+static std::string GetStringGLState(uint32 value);
+static std::string GetStringGetMaxIndexType(uint32 value);
+static std::string GetStringGetTexParamTarget(uint32 value);
+static std::string GetStringHintMode(uint32 value);
+static std::string GetStringHintTarget(uint32 value);
+static std::string GetStringIndexType(uint32 value);
+static std::string GetStringPixelStore(uint32 value);
+static std::string GetStringPixelType(uint32 value);
+static std::string GetStringProgramParameter(uint32 value);
+static std::string GetStringQueryObjectParameter(uint32 value);
+static std::string GetStringQueryParameter(uint32 value);
+static std::string GetStringQueryTarget(uint32 value);
+static std::string GetStringReadPixelFormat(uint32 value);
+static std::string GetStringReadPixelType(uint32 value);
+static std::string GetStringRenderBufferFormat(uint32 value);
+static std::string GetStringRenderBufferParameter(uint32 value);
+static std::string GetStringRenderBufferTarget(uint32 value);
+static std::string GetStringResetStatus(uint32 value);
+static std::string GetStringShaderBinaryFormat(uint32 value);
+static std::string GetStringShaderParameter(uint32 value);
+static std::string GetStringShaderPrecision(uint32 value);
+static std::string GetStringShaderType(uint32 value);
+static std::string GetStringSrcBlendFactor(uint32 value);
+static std::string GetStringStencilOp(uint32 value);
+static std::string GetStringStringType(uint32 value);
+static std::string GetStringTextureBindTarget(uint32 value);
+static std::string GetStringTextureFormat(uint32 value);
+static std::string GetStringTextureInternalFormat(uint32 value);
+static std::string GetStringTextureInternalFormatStorage(uint32 value);
+static std::string GetStringTextureMagFilterMode(uint32 value);
+static std::string GetStringTextureMinFilterMode(uint32 value);
+static std::string GetStringTextureParameter(uint32 value);
+static std::string GetStringTexturePool(uint32 value);
+static std::string GetStringTextureTarget(uint32 value);
+static std::string GetStringTextureUsage(uint32 value);
+static std::string GetStringTextureWrapMode(uint32 value);
+static std::string GetStringVertexAttribType(uint32 value);
+static std::string GetStringVertexAttribute(uint32 value);
+static std::string GetStringVertexPointer(uint32 value);
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/chromium/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
new file mode 100644
index 00000000000..573aee9d756
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -0,0 +1,1408 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_IMPLEMENTATION_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_IMPLEMENTATION_AUTOGEN_H_
+
+static const GLES2Util::EnumToString enum_to_string_table[] = {
+ { 0x78EC, "GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM", },
+ { 0x8825, "GL_DRAW_BUFFER0_NV", },
+ { 0x0BC1, "GL_ALPHA_TEST_FUNC_QCOM", },
+ { 0x884C, "GL_TEXTURE_COMPARE_MODE_EXT", },
+ { 0x0BC2, "GL_ALPHA_TEST_REF_QCOM", },
+ { 0x78EF, "GL_PIXEL_UNPACK_TRANSFER_BUFFER_BINDING_CHROMIUM", },
+ { 0x884D, "GL_TEXTURE_COMPARE_FUNC_EXT", },
+ { 0x884E, "GL_COMPARE_REF_TO_TEXTURE_EXT", },
+ { 0x93A1, "GL_BGRA8_EXT", },
+ { 0x8826, "GL_DRAW_BUFFER1_NV", },
+ { 0x1E01, "GL_REPLACE", },
+ { 0, "GL_FALSE", },
+ { 0x00400000, "GL_STENCIL_BUFFER_BIT6_QCOM", },
+ { 0x82E6, "GL_SAMPLER", },
+ { 0x1E02, "GL_INCR", },
+ { 0x9130, "GL_SGX_PROGRAM_BINARY_IMG", },
+ { 0x9133, "GL_RENDERBUFFER_SAMPLES_IMG", },
+ { 0x82E0, "GL_BUFFER", },
+ { 0x9135, "GL_MAX_SAMPLES_IMG", },
+ { 0x9134, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG", },
+ { 0x9136, "GL_TEXTURE_SAMPLES_IMG", },
+ { 0x00000020, "GL_COLOR_BUFFER_BIT5_QCOM", },
+ { 0x0008, "GL_MAP_INVALIDATE_BUFFER_BIT_EXT", },
+ { 0x0BC0, "GL_ALPHA_TEST_QCOM", },
+ { 0x0006, "GL_TRIANGLE_FAN", },
+ { 0x0004, "GL_TRIANGLES", },
+ { 0x0005, "GL_TRIANGLE_STRIP", },
+ { 0x0002, "GL_LINE_LOOP", },
+ { 0x0003, "GL_LINE_STRIP", },
+ { 0x0000, "GL_POINTS", },
+ { 0x0001, "GL_LINES", },
+ { 0x78F0, "GL_IMAGE_ROWBYTES_CHROMIUM", },
+ { 0x88B8, "GL_READ_ONLY", },
+ { 0x88B9, "GL_WRITE_ONLY_OES", },
+ { 0x8211, "GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT", },
+ { 0x8210, "GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT", },
+ { 0x8741, "GL_PROGRAM_BINARY_LENGTH_OES", },
+ { 0x8740, "GL_Z400_BINARY_AMD", },
+ { 0x8192, "GL_GENERATE_MIPMAP_HINT", },
+ { 0x87F9, "GL_3DC_X_AMD", },
+ { 0x8A53, "GL_SYNC_OBJECT_APPLE", },
+ { 0x8DF8, "GL_SHADER_BINARY_FORMATS", },
+ { 0x8DF9, "GL_NUM_SHADER_BINARY_FORMATS", },
+ { 0x826D, "GL_DEBUG_GROUP_STACK_DEPTH", },
+ { 0x826B, "GL_DEBUG_SEVERITY_NOTIFICATION", },
+ { 0x826C, "GL_MAX_DEBUG_GROUP_STACK_DEPTH", },
+ { 0x8B59, "GL_BOOL_VEC4", },
+ { 0x8B58, "GL_BOOL_VEC3", },
+ { 0x8B57, "GL_BOOL_VEC2", },
+ { 0x8DF1, "GL_MEDIUM_FLOAT", },
+ { 0x8B55, "GL_INT_VEC4", },
+ { 0x8B54, "GL_INT_VEC3", },
+ { 0x8DF4, "GL_MEDIUM_INT", },
+ { 0x8DF5, "GL_HIGH_INT", },
+ { 0x8DF6, "GL_UNSIGNED_INT_10_10_10_2_OES", },
+ { 0x8B50, "GL_FLOAT_VEC2", },
+ { 0x806F, "GL_TEXTURE_3D_OES", },
+ { 0x92E0, "GL_DEBUG_OUTPUT", },
+ { 0x806A, "GL_TEXTURE_BINDING_3D_OES", },
+ { 0x93D9, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR", },
+ { 0x8CE3, "GL_COLOR_ATTACHMENT3_NV", },
+ { 0x8069, "GL_TEXTURE_BINDING_2D", },
+ { 0x8261, "GL_NO_RESET_NOTIFICATION_EXT", },
+ { 0x8DFA, "GL_SHADER_COMPILER", },
+ { 0x8DFB, "GL_MAX_VERTEX_UNIFORM_VECTORS", },
+ { 0x8DFC, "GL_MAX_VARYING_VECTORS", },
+ { 0x8B5C, "GL_FLOAT_MAT4", },
+ { 0x8B5B, "GL_FLOAT_MAT3", },
+ { 0x8B5A, "GL_FLOAT_MAT2", },
+ { 0x0D05, "GL_PACK_ALIGNMENT", },
+ { 0x87FF, "GL_PROGRAM_BINARY_FORMATS_OES", },
+ { 0x87FE, "GL_NUM_PROGRAM_BINARY_FORMATS_OES", },
+ { 0x2600, "GL_NEAREST", },
+ { 0x2601, "GL_LINEAR", },
+ { 0x8C03, "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG", },
+ { 0x9242, "GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM", },
+ { 0x88BA, "GL_READ_WRITE", },
+ { 0x88BB, "GL_BUFFER_ACCESS_OES", },
+ { 0x88BC, "GL_BUFFER_MAPPED_OES", },
+ { 0x88BD, "GL_BUFFER_MAP_POINTER_OES", },
+ { 0x0C10, "GL_SCISSOR_BOX", },
+ { 0x0C11, "GL_SCISSOR_TEST", },
+ { 0x80000000, "GL_MULTISAMPLE_BUFFER_BIT7_QCOM", },
+ { 0x300E, "GL_CONTEXT_LOST", },
+ { 0x02000000, "GL_MULTISAMPLE_BUFFER_BIT1_QCOM", },
+ { 0x8C2F, "GL_ANY_SAMPLES_PASSED_EXT", },
+ { 0x8BD2, "GL_TEXTURE_WIDTH_QCOM", },
+ { 0x8BD3, "GL_TEXTURE_HEIGHT_QCOM", },
+ { 0x8BD4, "GL_TEXTURE_DEPTH_QCOM", },
+ { 0x8BD5, "GL_TEXTURE_INTERNAL_FORMAT_QCOM", },
+ { 0x8BD6, "GL_TEXTURE_FORMAT_QCOM", },
+ { 0x8BD7, "GL_TEXTURE_TYPE_QCOM", },
+ { 0x8B8D, "GL_CURRENT_PROGRAM", },
+ { 0x8BD9, "GL_TEXTURE_NUM_LEVELS_QCOM", },
+ { 0x8B8A, "GL_ACTIVE_ATTRIBUTE_MAX_LENGTH", },
+ { 0x8B8B, "GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES", },
+ { 0x8B8C, "GL_SHADING_LANGUAGE_VERSION", },
+ { 0x8BDA, "GL_TEXTURE_TARGET_QCOM", },
+ { 0x8BDB, "GL_TEXTURE_OBJECT_VALID_QCOM", },
+ { 0x8BDC, "GL_STATE_RESTORE", },
+ { 0x8B88, "GL_SHADER_SOURCE_LENGTH", },
+ { 0x8B89, "GL_ACTIVE_ATTRIBUTES", },
+ { 0x8B84, "GL_INFO_LOG_LENGTH", },
+ { 0x8B85, "GL_ATTACHED_SHADERS", },
+ { 0x8B86, "GL_ACTIVE_UNIFORMS", },
+ { 0x8B87, "GL_ACTIVE_UNIFORM_MAX_LENGTH", },
+ { 0x8B80, "GL_DELETE_STATUS", },
+ { 0x8B81, "GL_COMPILE_STATUS", },
+ { 0x8B82, "GL_LINK_STATUS", },
+ { 0x8B83, "GL_VALIDATE_STATUS", },
+ { 0x93D2, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR", },
+ { 0x8D48, "GL_STENCIL_INDEX8", },
+ { 0x8D46, "GL_STENCIL_INDEX1_OES", },
+ { 0x8D47, "GL_STENCIL_INDEX4_OES", },
+ { 0x8D44, "GL_RENDERBUFFER_INTERNAL_FORMAT", },
+ { 0x00000100, "GL_DEPTH_BUFFER_BIT", },
+ { 0x8D42, "GL_RENDERBUFFER_WIDTH", },
+ { 0x8D43, "GL_RENDERBUFFER_HEIGHT", },
+ { 0x8D40, "GL_FRAMEBUFFER", },
+ { 0x8D41, "GL_RENDERBUFFER", },
+ { 0x0BD0, "GL_DITHER", },
+ { 0x93D3, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR", },
+ { 0x9144, "GL_MAX_DEBUG_LOGGED_MESSAGES", },
+ { 0x1801, "GL_DEPTH_EXT", },
+ { 0x1800, "GL_COLOR_EXT", },
+ { 0x1802, "GL_STENCIL_EXT", },
+ { 0x0B21, "GL_LINE_WIDTH", },
+ { 0x81A5, "GL_DEPTH_COMPONENT16", },
+ { 0x81A6, "GL_DEPTH_COMPONENT24_OES", },
+ { 0x81A7, "GL_DEPTH_COMPONENT32_OES", },
+ { 0x88FE, "GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE", },
+ { 0x93D0, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", },
+ { 0x9143, "GL_MAX_DEBUG_MESSAGE_LENGTH", },
+ { 0x8DFD, "GL_MAX_FRAGMENT_UNIFORM_VECTORS", },
+ { 0x9145, "GL_DEBUG_LOGGED_MESSAGES", },
+ { 0x9146, "GL_DEBUG_SEVERITY_HIGH", },
+ { 0x9147, "GL_DEBUG_SEVERITY_MEDIUM", },
+ { 0x9148, "GL_DEBUG_SEVERITY_LOW", },
+ { 0x8F60, "GL_MALI_SHADER_BINARY_ARM", },
+ { 0x8F61, "GL_MALI_PROGRAM_BINARY_ARM", },
+ { 0x87EE, "GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD", },
+ { 0x822B, "GL_RG8_EXT", },
+ { 0x93D1, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR", },
+ { 0x822D, "GL_R16F_EXT", },
+ { 0x822E, "GL_R32F_EXT", },
+ { 1, "GL_ES_VERSION_2_0", },
+ { 0x84F9, "GL_DEPTH_STENCIL_OES", },
+ { 0x8368, "GL_UNSIGNED_INT_2_10_10_10_REV_EXT", },
+ { 0x8819, "GL_LUMINANCE_ALPHA32F_EXT", },
+ { 0x8818, "GL_LUMINANCE32F_EXT", },
+ { 0x8363, "GL_UNSIGNED_SHORT_5_6_5", },
+ { 0x8814, "GL_RGBA32F_EXT", },
+ { 0x84F2, "GL_ALL_COMPLETED_NV", },
+ { 0x8816, "GL_ALPHA32F_EXT", },
+ { 0x84F4, "GL_FENCE_CONDITION_NV", },
+ { 0x8366, "GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT", },
+ { 0x8365, "GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT", },
+ { 0x881E, "GL_LUMINANCE16F_EXT", },
+ { 0x84FA, "GL_UNSIGNED_INT_24_8_OES", },
+ { 0x881F, "GL_LUMINANCE_ALPHA16F_EXT", },
+ { 0x881A, "GL_RGBA16F_EXT", },
+ { 0x84FE, "GL_TEXTURE_MAX_ANISOTROPY_EXT", },
+ { 0x0901, "GL_CCW", },
+ { 0x0900, "GL_CW", },
+ { 0x8229, "GL_R8_EXT", },
+ { 0x8227, "GL_RG_EXT", },
+ { 0x8B62, "GL_SAMPLER_2D_SHADOW_EXT", },
+ { 0x8B63, "GL_SAMPLER_2D_RECT_ARB", },
+ { 0x8B60, "GL_SAMPLER_CUBE", },
+ { 0x93D7, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR", },
+ { 0x00001000, "GL_DEPTH_BUFFER_BIT4_QCOM", },
+ { 0x83F0, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", },
+ { 0x00000080, "GL_COLOR_BUFFER_BIT7_QCOM", },
+ { 0x88F0, "GL_DEPTH24_STENCIL8_OES", },
+ { 0x80A0, "GL_SAMPLE_COVERAGE", },
+ { 0x93D4, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR", },
+ { 0x822F, "GL_RG16F_EXT", },
+ { 0x80A9, "GL_SAMPLES", },
+ { 0x80A8, "GL_SAMPLE_BUFFERS", },
+ { 0x0D55, "GL_ALPHA_BITS", },
+ { 0x0D54, "GL_BLUE_BITS", },
+ { 0x0D57, "GL_STENCIL_BITS", },
+ { 0x0D56, "GL_DEPTH_BITS", },
+ { 0x8CD5, "GL_FRAMEBUFFER_COMPLETE", },
+ { 0x0D50, "GL_SUBPIXEL_BITS", },
+ { 0x0D53, "GL_GREEN_BITS", },
+ { 0x0D52, "GL_RED_BITS", },
+ { 0x8037, "GL_POLYGON_OFFSET_FILL", },
+ { 0x8034, "GL_UNSIGNED_SHORT_5_5_5_1", },
+ { 0x8033, "GL_UNSIGNED_SHORT_4_4_4_4", },
+ { 0x0305, "GL_ONE_MINUS_DST_ALPHA", },
+ { 0x0304, "GL_DST_ALPHA", },
+ { 0x0307, "GL_ONE_MINUS_DST_COLOR", },
+ { 0x0306, "GL_DST_COLOR", },
+ { 0x0301, "GL_ONE_MINUS_SRC_COLOR", },
+ { 0x0300, "GL_SRC_COLOR", },
+ { 0x0303, "GL_ONE_MINUS_SRC_ALPHA", },
+ { 0x0302, "GL_SRC_ALPHA", },
+ { 0x0308, "GL_SRC_ALPHA_SATURATE", },
+ { 0x2A00, "GL_POLYGON_OFFSET_UNITS", },
+ { 0xFFFFFFFF, "GL_ALL_SHADER_BITS_EXT", },
+ { 0x00800000, "GL_STENCIL_BUFFER_BIT7_QCOM", },
+ { 0x00020000, "GL_STENCIL_BUFFER_BIT1_QCOM", },
+ { 0x8D00, "GL_DEPTH_ATTACHMENT", },
+ { 0x8FA0, "GL_PERFMON_GLOBAL_MODE_QCOM", },
+ { 0x8815, "GL_RGB32F_EXT", },
+ { 0x813D, "GL_TEXTURE_MAX_LEVEL_APPLE", },
+ { 0x84F3, "GL_FENCE_STATUS_NV", },
+ { 0x8CDD, "GL_FRAMEBUFFER_UNSUPPORTED", },
+ { 0x8CDF, "GL_MAX_COLOR_ATTACHMENTS_NV", },
+ { 0x90F3, "GL_CONTEXT_ROBUST_ACCESS_EXT", },
+ { 0x90F2, "GL_MAX_MULTIVIEW_BUFFERS_EXT", },
+ { 0x90F1, "GL_MULTIVIEW_EXT", },
+ { 0x90F0, "GL_COLOR_ATTACHMENT_EXT", },
+ { 0x803C, "GL_ALPHA8_OES", },
+ { 0x84F5, "GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM", },
+ { 0x882A, "GL_DRAW_BUFFER5_NV", },
+ { 0x80AA, "GL_SAMPLE_COVERAGE_VALUE", },
+ { 0x84F6, "GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM", },
+ { 0x80AB, "GL_SAMPLE_COVERAGE_INVERT", },
+ { 0x8FC4, "GL_SHADER_BINARY_VIV", },
+ { 0x882B, "GL_DRAW_BUFFER6_NV", },
+ { 0x8C17, "GL_UNSIGNED_NORMALIZED_EXT", },
+ { 0x8A4F, "GL_PROGRAM_PIPELINE_OBJECT_EXT", },
+ { 0x882C, "GL_DRAW_BUFFER7_NV", },
+ { 0x0010, "GL_MAP_FLUSH_EXPLICIT_BIT_EXT", },
+ { 0x882D, "GL_DRAW_BUFFER8_NV", },
+ { 0x84FF, "GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT", },
+ { 0x0B74, "GL_DEPTH_FUNC", },
+ { 0x881B, "GL_RGB16F_EXT", },
+ { 0x0B71, "GL_DEPTH_TEST", },
+ { 0x0B70, "GL_DEPTH_RANGE", },
+ { 0x0B73, "GL_DEPTH_CLEAR_VALUE", },
+ { 0x0B72, "GL_DEPTH_WRITEMASK", },
+ { 0x85BA, "GL_UNSIGNED_SHORT_8_8_APPLE", },
+ { 0x882E, "GL_DRAW_BUFFER9_NV", },
+ { 0x8073, "GL_MAX_3D_TEXTURE_SIZE_OES", },
+ { 0x8072, "GL_TEXTURE_WRAP_R_OES", },
+ { 0x882F, "GL_DRAW_BUFFER10_NV", },
+ { 0x80E1, "GL_BGRA_EXT", },
+ { 0x8ED7, "GL_COVERAGE_AUTOMATIC_NV", },
+ { 0x8ED6, "GL_COVERAGE_EDGE_FRAGMENTS_NV", },
+ { 0x8ED5, "GL_COVERAGE_ALL_FRAGMENTS_NV", },
+ { 0x8ED4, "GL_COVERAGE_SAMPLES_NV", },
+ { 0x8ED3, "GL_COVERAGE_BUFFERS_NV", },
+ { 0x8ED2, "GL_COVERAGE_ATTACHMENT_NV", },
+ { 0x8ED1, "GL_COVERAGE_COMPONENT4_NV", },
+ { 0x8ED0, "GL_COVERAGE_COMPONENT_NV", },
+ { 0x800B, "GL_FUNC_REVERSE_SUBTRACT", },
+ { 0x00000400, "GL_STENCIL_BUFFER_BIT", },
+ { 0x800A, "GL_FUNC_SUBTRACT", },
+ { 0x8E2C, "GL_DEPTH_COMPONENT16_NONLINEAR_NV", },
+ { 0x889F, "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING", },
+ { 0x8219, "GL_FRAMEBUFFER_UNDEFINED_OES", },
+ { 0x8006, "GL_FUNC_ADD", },
+ { 0x8007, "GL_MIN_EXT", },
+ { 0x8004, "GL_ONE_MINUS_CONSTANT_ALPHA", },
+ { 0x8005, "GL_BLEND_COLOR", },
+ { 0x8002, "GL_ONE_MINUS_CONSTANT_COLOR", },
+ { 0x8003, "GL_CONSTANT_ALPHA", },
+ { 0x8000, "GL_COVERAGE_BUFFER_BIT_NV", },
+ { 0x8001, "GL_CONSTANT_COLOR", },
+ { 0x0204, "GL_GREATER", },
+ { 0x0205, "GL_NOTEQUAL", },
+ { 0x0206, "GL_GEQUAL", },
+ { 0x0207, "GL_ALWAYS", },
+ { 0x0200, "GL_NEVER", },
+ { 0x0201, "GL_LESS", },
+ { 0x0202, "GL_EQUAL", },
+ { 0x0203, "GL_LEQUAL", },
+ { 0x2901, "GL_REPEAT", },
+ { 0x8B99, "GL_PALETTE8_RGB5_A1_OES", },
+ { 0x8B98, "GL_PALETTE8_RGBA4_OES", },
+ { 0x8FB2, "GL_GPU_OPTIMIZED_QCOM", },
+ { 0x190A, "GL_LUMINANCE_ALPHA", },
+ { 0x8FB0, "GL_BINNING_CONTROL_HINT_QCOM", },
+ { 0x8FB1, "GL_CPU_OPTIMIZED_QCOM", },
+ { 0x8B93, "GL_PALETTE4_RGBA4_OES", },
+ { 0x8B92, "GL_PALETTE4_R5_G6_B5_OES", },
+ { 0x8B91, "GL_PALETTE4_RGBA8_OES", },
+ { 0x8B90, "GL_PALETTE4_RGB8_OES", },
+ { 0x8B97, "GL_PALETTE8_R5_G6_B5_OES", },
+ { 0x8B96, "GL_PALETTE8_RGBA8_OES", },
+ { 0x8B95, "GL_PALETTE8_RGB8_OES", },
+ { 0x8B94, "GL_PALETTE4_RGB5_A1_OES", },
+ { 0x0BE2, "GL_BLEND", },
+ { 0x84CB, "GL_TEXTURE11", },
+ { 0x8D55, "GL_RENDERBUFFER_STENCIL_SIZE", },
+ { 0x8D54, "GL_RENDERBUFFER_DEPTH_SIZE", },
+ { 0x8D57, "GL_MAX_SAMPLES_ANGLE", },
+ { 0x8D56, "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE", },
+ { 0x8D51, "GL_RENDERBUFFER_GREEN_SIZE", },
+ { 0x8D50, "GL_RENDERBUFFER_RED_SIZE", },
+ { 0x8D53, "GL_RENDERBUFFER_ALPHA_SIZE", },
+ { 0x8D52, "GL_RENDERBUFFER_BLUE_SIZE", },
+ { 0x00080000, "GL_STENCIL_BUFFER_BIT3_QCOM", },
+ { 0x886A, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED", },
+ { 0x0C01, "GL_DRAW_BUFFER_EXT", },
+ { 0x9250, "GL_SHADER_BINARY_DMP", },
+ { 0x10000000, "GL_MULTISAMPLE_BUFFER_BIT4_QCOM", },
+ { 0x8C92, "GL_ATC_RGB_AMD", },
+ { 0x9154, "GL_VERTEX_ARRAY_OBJECT_EXT", },
+ { 0x9153, "GL_QUERY_OBJECT_EXT", },
+ { 0x9151, "GL_BUFFER_OBJECT_EXT", },
+ { 0x8C93, "GL_ATC_RGBA_EXPLICIT_ALPHA_AMD", },
+ { 0x00000002, "GL_CONTEXT_FLAG_DEBUG_BIT", },
+ { 0x00000001, "GL_SYNC_FLUSH_COMMANDS_BIT_APPLE", },
+ { 0x00000004, "GL_COLOR_BUFFER_BIT2_QCOM", },
+ { 0x1702, "GL_TEXTURE", },
+ { 0x00000008, "GL_COLOR_BUFFER_BIT3_QCOM", },
+ { 0x826A, "GL_DEBUG_TYPE_POP_GROUP", },
+ { 0x8828, "GL_DRAW_BUFFER3_NV", },
+ { 0x8DF0, "GL_LOW_FLOAT", },
+ { 0x1906, "GL_ALPHA", },
+ { 0x1907, "GL_RGB", },
+ { 0x1902, "GL_DEPTH_COMPONENT", },
+ { 0x8B56, "GL_BOOL", },
+ { 0x93DB, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR", },
+ { 0x8B9B, "GL_IMPLEMENTATION_COLOR_READ_FORMAT", },
+ { 0x8B9A, "GL_IMPLEMENTATION_COLOR_READ_TYPE", },
+ { 0x93DA, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR", },
+ { 0x1908, "GL_RGBA", },
+ { 0x8DF2, "GL_HIGH_FLOAT", },
+ { 0x93DD, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR", },
+ { 0x8827, "GL_DRAW_BUFFER2_NV", },
+ { 0x9243, "GL_UNPACK_COLORSPACE_CONVERSION_CHROMIUM", },
+ { 0x8DF3, "GL_LOW_INT", },
+ { 0x82E8, "GL_MAX_LABEL_LENGTH", },
+ { 0x8B53, "GL_INT_VEC2", },
+ { 0x0C02, "GL_READ_BUFFER_EXT", },
+ { 0x82E3, "GL_QUERY", },
+ { 0x82E2, "GL_PROGRAM", },
+ { 0x82E1, "GL_SHADER", },
+ { 0x8B52, "GL_FLOAT_VEC4", },
+ { 0x9240, "GL_UNPACK_FLIP_Y_CHROMIUM", },
+ { 0x8B51, "GL_FLOAT_VEC3", },
+ { 0x8230, "GL_RG32F_EXT", },
+ { 0x8DF7, "GL_INT_10_10_10_2_OES", },
+ { 0x812F, "GL_CLAMP_TO_EDGE", },
+ { 0x86A3, "GL_COMPRESSED_TEXTURE_FORMATS", },
+ { 0x86A2, "GL_NUM_COMPRESSED_TEXTURE_FORMATS", },
+ { 0x0CF3, "GL_UNPACK_SKIP_ROWS", },
+ { 0x0CF2, "GL_UNPACK_ROW_LENGTH", },
+ { 0x140C, "GL_FIXED", },
+ { 0x8008, "GL_MAX_EXT", },
+ { 0x0CF5, "GL_UNPACK_ALIGNMENT", },
+ { 0x0CF4, "GL_UNPACK_SKIP_PIXELS", },
+ { 0x8009, "GL_BLEND_EQUATION", },
+ { 0x1401, "GL_UNSIGNED_BYTE", },
+ { 0x1400, "GL_BYTE", },
+ { 0x1403, "GL_UNSIGNED_SHORT", },
+ { 0x1402, "GL_SHORT", },
+ { 0x1405, "GL_UNSIGNED_INT", },
+ { 0x1404, "GL_INT", },
+ { 0x1406, "GL_FLOAT", },
+ { 0x8043, "GL_LUMINANCE4_ALPHA4_OES", },
+ { 0x8040, "GL_LUMINANCE8_OES", },
+ { 0x8045, "GL_LUMINANCE8_ALPHA8_OES", },
+ { 0x8CD1, "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME", },
+ { 0x00040000, "GL_STENCIL_BUFFER_BIT2_QCOM", },
+ { 0x8CD0, "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", },
+ { 0x8CE4, "GL_COLOR_ATTACHMENT4_NV", },
+ { 0x8CD3, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE", },
+ { 0x0B90, "GL_STENCIL_TEST", },
+ { 0x8CD2, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL", },
+ { 0x881C, "GL_ALPHA16F_EXT", },
+ { 0x8CD4, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES", },
+ { 0x8CD7, "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT", },
+ { 0x9112, "GL_OBJECT_TYPE_APPLE", },
+ { 0x8038, "GL_POLYGON_OFFSET_FACTOR", },
+ { 0x851A, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z", },
+ { 0x851C, "GL_MAX_CUBE_MAP_TEXTURE_SIZE", },
+ { 0x8CD9, "GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS", },
+ { 0x84CC, "GL_TEXTURE12", },
+ { 0x0BA2, "GL_VIEWPORT", },
+ { 0x84CA, "GL_TEXTURE10", },
+ { 0x84CF, "GL_TEXTURE15", },
+ { 0x84CE, "GL_TEXTURE14", },
+ { 0x84CD, "GL_TEXTURE13", },
+ { 0x9115, "GL_SYNC_FLAGS_APPLE", },
+ { 0x83F3, "GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE", },
+ { 0x83F2, "GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE", },
+ { 0x83F1, "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT", },
+ { 0x9114, "GL_SYNC_STATUS_APPLE", },
+ { 0x8C0A, "GL_SGX_BINARY_IMG", },
+ { 0x911C, "GL_CONDITION_SATISFIED_APPLE", },
+ { 0x911B, "GL_TIMEOUT_EXPIRED_APPLE", },
+ { 0x911A, "GL_ALREADY_SIGNALED_APPLE", },
+ { 0x911D, "GL_WAIT_FAILED_APPLE", },
+ { 0x846D, "GL_ALIASED_POINT_SIZE_RANGE", },
+ { 0x846E, "GL_ALIASED_LINE_WIDTH_RANGE", },
+ { 0x9113, "GL_SYNC_CONDITION_APPLE", },
+ { 0x93A4, "GL_PACK_REVERSE_ROW_ORDER_ANGLE", },
+ { 0x9111, "GL_MAX_SERVER_WAIT_TIMEOUT_APPLE", },
+ { 0x9117, "GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE", },
+ { 0x93A0, "GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE", },
+ { 0x93A3, "GL_FRAMEBUFFER_ATTACHMENT_ANGLE", },
+ { 0x93A2, "GL_TEXTURE_USAGE_ANGLE", },
+ { 0x8802, "GL_STENCIL_BACK_PASS_DEPTH_FAIL", },
+ { 0x9119, "GL_SIGNALED_APPLE", },
+ { 0x9118, "GL_UNSIGNALED_APPLE", },
+ { 0x8C01, "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG", },
+ { 0x8C00, "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG", },
+ { 0x8A52, "GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT", },
+ { 0x8C02, "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG", },
+ { 0x84C9, "GL_TEXTURE9", },
+ { 0x84C8, "GL_TEXTURE8", },
+ { 0x8869, "GL_MAX_VERTEX_ATTRIBS", },
+ { 0x84C3, "GL_TEXTURE3", },
+ { 0x84C2, "GL_TEXTURE2", },
+ { 0x84C1, "GL_TEXTURE1", },
+ { 0x84C0, "GL_TEXTURE0", },
+ { 0x84C7, "GL_TEXTURE7", },
+ { 0x84C6, "GL_TEXTURE6", },
+ { 0x84C5, "GL_TEXTURE5", },
+ { 0x8803, "GL_STENCIL_BACK_PASS_DEPTH_PASS", },
+ { 0x8518, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y", },
+ { 0x8519, "GL_TEXTURE_CUBE_MAP_POSITIVE_Z", },
+ { 0x8514, "GL_TEXTURE_BINDING_CUBE_MAP", },
+ { 0x8515, "GL_TEXTURE_CUBE_MAP_POSITIVE_X", },
+ { 0x8516, "GL_TEXTURE_CUBE_MAP_NEGATIVE_X", },
+ { 0x8517, "GL_TEXTURE_CUBE_MAP_POSITIVE_Y", },
+ { 0x8513, "GL_TEXTURE_CUBE_MAP", },
+ { 0x8626, "GL_CURRENT_VERTEX_ATTRIB", },
+ { 0x8765, "GL_BUFFER_USAGE", },
+ { 0x8764, "GL_BUFFER_SIZE", },
+ { 0x93D8, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR", },
+ { 0x0503, "GL_STACK_OVERFLOW", },
+ { 0x0502, "GL_INVALID_OPERATION", },
+ { 0x0501, "GL_INVALID_VALUE", },
+ { 0x0500, "GL_INVALID_ENUM", },
+ { 64, "GL_MAILBOX_SIZE_CHROMIUM", },
+ { 0x0506, "GL_INVALID_FRAMEBUFFER_OPERATION", },
+ { 0x0505, "GL_OUT_OF_MEMORY", },
+ { 0x8B5F, "GL_SAMPLER_3D_OES", },
+ { 0x0B44, "GL_CULL_FACE", },
+ { 0x8B5E, "GL_SAMPLER_2D", },
+ { 0x0B46, "GL_FRONT_FACE", },
+ { 0x8FB3, "GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM", },
+ { 0x824A, "GL_DEBUG_SOURCE_APPLICATION", },
+ { 0x824B, "GL_DEBUG_SOURCE_OTHER", },
+ { 0x824C, "GL_DEBUG_TYPE_ERROR", },
+ { 0x824D, "GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR", },
+ { 0x824E, "GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR", },
+ { 0x824F, "GL_DEBUG_TYPE_PORTABILITY", },
+ { 0x8B31, "GL_VERTEX_SHADER", },
+ { 0x8B30, "GL_FRAGMENT_SHADER", },
+ { 0x1E00, "GL_KEEP", },
+ { 0x8268, "GL_DEBUG_TYPE_MARKER", },
+ { 0x84D8, "GL_TEXTURE24", },
+ { 0x84D9, "GL_TEXTURE25", },
+ { 0x84D6, "GL_TEXTURE22", },
+ { 0x84D7, "GL_TEXTURE23", },
+ { 0x84D4, "GL_TEXTURE20", },
+ { 0x84D5, "GL_TEXTURE21", },
+ { 0x84D2, "GL_TEXTURE18", },
+ { 0x84D3, "GL_TEXTURE19", },
+ { 0x84D0, "GL_TEXTURE16", },
+ { 0x84D1, "GL_TEXTURE17", },
+ { 0x1E03, "GL_DECR", },
+ { 0x84DF, "GL_TEXTURE31", },
+ { 0x93D6, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR", },
+ { 0x84DD, "GL_TEXTURE29", },
+ { 0x84DE, "GL_TEXTURE30", },
+ { 0x84DB, "GL_TEXTURE27", },
+ { 0x84DC, "GL_TEXTURE28", },
+ { 0x6002, "GL_TEXTURE_POOL_UNMANAGED_CHROMIUM", },
+ { 0x84DA, "GL_TEXTURE26", },
+ { 0x8242, "GL_DEBUG_OUTPUT_SYNCHRONOUS", },
+ { 0x8243, "GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH", },
+ { 0x8244, "GL_DEBUG_CALLBACK_FUNCTION", },
+ { 0x8245, "GL_DEBUG_CALLBACK_USER_PARAM", },
+ { 0x8246, "GL_DEBUG_SOURCE_API", },
+ { 0x8247, "GL_DEBUG_SOURCE_WINDOW_SYSTEM", },
+ { 0x8248, "GL_DEBUG_SOURCE_SHADER_COMPILER", },
+ { 0x8249, "GL_DEBUG_SOURCE_THIRD_PARTY", },
+ { 0x93D5, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR", },
+ { 0x00000040, "GL_COLOR_BUFFER_BIT6_QCOM", },
+ { 0x8645, "GL_VERTEX_ATTRIB_ARRAY_POINTER", },
+ { 0x8865, "GL_CURRENT_QUERY_EXT", },
+ { 0x8866, "GL_QUERY_RESULT_EXT", },
+ { 0x8867, "GL_QUERY_RESULT_AVAILABLE_EXT", },
+ { 0x08000000, "GL_MULTISAMPLE_BUFFER_BIT3_QCOM", },
+ { 0x87FA, "GL_3DC_XY_AMD", },
+ { 0x84C4, "GL_TEXTURE4", },
+ { 0x85B5, "GL_VERTEX_ARRAY_BINDING_OES", },
+ { 0x8D6A, "GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT", },
+ { 0x8D6C, "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT", },
+ { 0x8252, "GL_LOSE_CONTEXT_ON_RESET_EXT", },
+ { 0x8251, "GL_DEBUG_TYPE_OTHER", },
+ { 0x8C40, "GL_SRGB_EXT", },
+ { 0x8C43, "GL_SRGB8_ALPHA8_EXT", },
+ { 0x8C42, "GL_SRGB_ALPHA_EXT", },
+ { 0x00200000, "GL_STENCIL_BUFFER_BIT5_QCOM", },
+ { 0x8D68, "GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES", },
+ { 0x85BB, "GL_UNSIGNED_SHORT_8_8_REV_APPLE", },
+ { 0x8D61, "GL_HALF_FLOAT_OES", },
+ { 0x8D62, "GL_RGB565", },
+ { 0x8D64, "GL_ETC1_RGB8_OES", },
+ { 0x8D65, "GL_TEXTURE_EXTERNAL_OES", },
+ { 0x8D66, "GL_SAMPLER_EXTERNAL_OES", },
+ { 0x8D67, "GL_TEXTURE_BINDING_EXTERNAL_OES", },
+ { 0x04000000, "GL_MULTISAMPLE_BUFFER_BIT2_QCOM", },
+ { 0x8CEE, "GL_COLOR_ATTACHMENT14_NV", },
+ { 0x2800, "GL_TEXTURE_MAG_FILTER", },
+ { 0x2801, "GL_TEXTURE_MIN_FILTER", },
+ { 0x2802, "GL_TEXTURE_WRAP_S", },
+ { 0x2803, "GL_TEXTURE_WRAP_T", },
+ { 0x2703, "GL_LINEAR_MIPMAP_LINEAR", },
+ { 0x2702, "GL_NEAREST_MIPMAP_LINEAR", },
+ { 0x1F03, "GL_EXTENSIONS", },
+ { 0x1F02, "GL_VERSION", },
+ { 0x1F01, "GL_RENDERER", },
+ { 0x1F00, "GL_VENDOR", },
+ { 0x2701, "GL_LINEAR_MIPMAP_NEAREST", },
+ { 0x0B94, "GL_STENCIL_FAIL", },
+ { 0x8B4C, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS", },
+ { 0x8B4D, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS", },
+ { 0x8B4F, "GL_SHADER_TYPE", },
+ { 0x00004000, "GL_COLOR_BUFFER_BIT", },
+ { 0x00000010, "GL_COLOR_BUFFER_BIT4_QCOM", },
+ { 0x8834, "GL_DRAW_BUFFER15_NV", },
+ { 0x8833, "GL_DRAW_BUFFER14_NV", },
+ { 0x8832, "GL_DRAW_BUFFER13_NV", },
+ { 0x8831, "GL_DRAW_BUFFER12_NV", },
+ { 0x8830, "GL_DRAW_BUFFER11_NV", },
+ { 0x93B8, "GL_COMPRESSED_RGBA_ASTC_10x5_KHR", },
+ { 0x9241, "GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM", },
+ { 0x00010000, "GL_STENCIL_BUFFER_BIT0_QCOM", },
+ { 0x0B93, "GL_STENCIL_VALUE_MASK", },
+ { 0x0B92, "GL_STENCIL_FUNC", },
+ { 0x0B91, "GL_STENCIL_CLEAR_VALUE", },
+ { 0x883D, "GL_BLEND_EQUATION_ALPHA", },
+ { 0x0B97, "GL_STENCIL_REF", },
+ { 0x0B96, "GL_STENCIL_PASS_DEPTH_PASS", },
+ { 0x0B95, "GL_STENCIL_PASS_DEPTH_FAIL", },
+ { 0x2700, "GL_NEAREST_MIPMAP_NEAREST", },
+ { 0x0B98, "GL_STENCIL_WRITEMASK", },
+ { 0x8B40, "GL_PROGRAM_OBJECT_EXT", },
+ { 0x8B48, "GL_SHADER_OBJECT_EXT", },
+ { 0x912F, "GL_TEXTURE_IMMUTABLE_FORMAT_EXT", },
+ { 0x20000000, "GL_MULTISAMPLE_BUFFER_BIT5_QCOM", },
+ { 0x0DE1, "GL_TEXTURE_2D", },
+ { 0x80C9, "GL_BLEND_SRC_RGB", },
+ { 0x80C8, "GL_BLEND_DST_RGB", },
+ { 0x0504, "GL_STACK_UNDERFLOW", },
+ { 0x8059, "GL_RGB10_A2_EXT", },
+ { 0x8058, "GL_RGBA8_OES", },
+ { 0x00002000, "GL_DEPTH_BUFFER_BIT5_QCOM", },
+ { 0x8051, "GL_RGB8_OES", },
+ { 0x8052, "GL_RGB10_EXT", },
+ { 0x8CAB, "GL_RENDERBUFFER_SAMPLES_ANGLE", },
+ { 0x8057, "GL_RGB5_A1", },
+ { 0x8056, "GL_RGBA4", },
+ { 0x150A, "GL_INVERT", },
+ { 0x01000000, "GL_MULTISAMPLE_BUFFER_BIT0_QCOM", },
+ { 0x78ED, "GL_PIXEL_PACK_TRANSFER_BUFFER_CHROMIUM", },
+ { 0x78EE, "GL_PIXEL_PACK_TRANSFER_BUFFER_BINDING_CHROMIUM", },
+ { 0x8269, "GL_DEBUG_TYPE_PUSH_GROUP", },
+ { 0x0B45, "GL_CULL_FACE_MODE", },
+ { 0x00100000, "GL_STENCIL_BUFFER_BIT4_QCOM", },
+ { 0x8D20, "GL_STENCIL_ATTACHMENT", },
+ { 0x00000200, "GL_DEPTH_BUFFER_BIT1_QCOM", },
+ { 0x00008000, "GL_DEPTH_BUFFER_BIT7_QCOM", },
+ { 0x8CA8, "GL_READ_FRAMEBUFFER_ANGLE", },
+ { 0x8CA9, "GL_DRAW_FRAMEBUFFER_ANGLE", },
+ { 0x8CA6, "GL_FRAMEBUFFER_BINDING", },
+ { 0x8CA7, "GL_RENDERBUFFER_BINDING", },
+ { 0x8CA4, "GL_STENCIL_BACK_VALUE_MASK", },
+ { 0x8CA5, "GL_STENCIL_BACK_WRITEMASK", },
+ { 0x8CA3, "GL_STENCIL_BACK_REF", },
+ { 0x80CB, "GL_BLEND_SRC_ALPHA", },
+ { 0x80CA, "GL_BLEND_DST_ALPHA", },
+ { 0x93B0, "GL_COMPRESSED_RGBA_ASTC_4x4_KHR", },
+ { 0x93B1, "GL_COMPRESSED_RGBA_ASTC_5x4_KHR", },
+ { 0x93B2, "GL_COMPRESSED_RGBA_ASTC_5x5_KHR", },
+ { 0x93B3, "GL_COMPRESSED_RGBA_ASTC_6x5_KHR", },
+ { 0x93B4, "GL_COMPRESSED_RGBA_ASTC_6x6_KHR", },
+ { 0x93B5, "GL_COMPRESSED_RGBA_ASTC_8x5_KHR", },
+ { 0x93B6, "GL_COMPRESSED_RGBA_ASTC_8x6_KHR", },
+ { 0x93B7, "GL_COMPRESSED_RGBA_ASTC_8x8_KHR", },
+ { 0x8CD6, "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT", },
+ { 0x93B9, "GL_COMPRESSED_RGBA_ASTC_10x6_KHR", },
+ { 0x8253, "GL_GUILTY_CONTEXT_RESET_EXT", },
+ { 0x8CE5, "GL_COLOR_ATTACHMENT5_NV", },
+ { 0x8872, "GL_MAX_TEXTURE_IMAGE_UNITS", },
+ { 0x8508, "GL_DECR_WRAP", },
+ { 0x8507, "GL_INCR_WRAP", },
+ { 0x8895, "GL_ELEMENT_ARRAY_BUFFER_BINDING", },
+ { 0x8894, "GL_ARRAY_BUFFER_BINDING", },
+ { 0x8893, "GL_ELEMENT_ARRAY_BUFFER", },
+ { 0x8892, "GL_ARRAY_BUFFER", },
+ { 0x8BD8, "GL_TEXTURE_IMAGE_VALID_QCOM", },
+ { 0x93BA, "GL_COMPRESSED_RGBA_ASTC_10x8_KHR", },
+ { 0x93BB, "GL_COMPRESSED_RGBA_ASTC_10x10_KHR", },
+ { 0x93BC, "GL_COMPRESSED_RGBA_ASTC_12x10_KHR", },
+ { 0x93BD, "GL_COMPRESSED_RGBA_ASTC_12x12_KHR", },
+ { 0x84E8, "GL_MAX_RENDERBUFFER_SIZE", },
+ { 0x8370, "GL_MIRRORED_REPEAT", },
+ { 0x84E0, "GL_ACTIVE_TEXTURE", },
+ { 0x8800, "GL_STENCIL_BACK_FUNC", },
+ { 0x8801, "GL_STENCIL_BACK_FAIL", },
+ { 0x0D33, "GL_MAX_TEXTURE_SIZE", },
+ { 0x8624, "GL_VERTEX_ATTRIB_ARRAY_STRIDE", },
+ { 0x8625, "GL_VERTEX_ATTRIB_ARRAY_TYPE", },
+ { 0x8622, "GL_VERTEX_ATTRIB_ARRAY_ENABLED", },
+ { 0x8623, "GL_VERTEX_ATTRIB_ARRAY_SIZE", },
+ { 0x8259, "GL_ACTIVE_PROGRAM_EXT", },
+ { 0x8258, "GL_PROGRAM_SEPARABLE_EXT", },
+ { 0x8256, "GL_RESET_NOTIFICATION_STRATEGY_EXT", },
+ { 0x8255, "GL_UNKNOWN_CONTEXT_RESET_EXT", },
+ { 0x8254, "GL_INNOCENT_CONTEXT_RESET_EXT", },
+ { 0x1100, "GL_DONT_CARE", },
+ { 0x1101, "GL_FASTEST", },
+ { 0x1102, "GL_NICEST", },
+ { 0x8250, "GL_DEBUG_TYPE_PERFORMANCE", },
+ { 0x8CEB, "GL_COLOR_ATTACHMENT11_NV", },
+ { 0x8CEC, "GL_COLOR_ATTACHMENT12_NV", },
+ { 0x0408, "GL_FRONT_AND_BACK", },
+ { 0x8CEA, "GL_COLOR_ATTACHMENT10_NV", },
+ { 0x8CEF, "GL_COLOR_ATTACHMENT15_NV", },
+ { 0x8CED, "GL_COLOR_ATTACHMENT13_NV", },
+ { 0x8829, "GL_DRAW_BUFFER4_NV", },
+ { 0x0404, "GL_FRONT", },
+ { 0x0405, "GL_BACK", },
+ { 0x88E1, "GL_STREAM_READ", },
+ { 0x88E0, "GL_STREAM_DRAW", },
+ { 0x88E4, "GL_STATIC_DRAW", },
+ { 0x88E8, "GL_DYNAMIC_DRAW", },
+ { 0x8CAA, "GL_READ_FRAMEBUFFER_BINDING_ANGLE", },
+ { 0x40000000, "GL_MULTISAMPLE_BUFFER_BIT6_QCOM", },
+ { 0x9116, "GL_SYNC_FENCE_APPLE", },
+ { 0x6000, "GL_TEXTURE_POOL_CHROMIUM", },
+ { 0x00000800, "GL_DEPTH_BUFFER_BIT3_QCOM", },
+ { 0x1903, "GL_RED_EXT", },
+ { 0x6001, "GL_TEXTURE_POOL_MANAGED_CHROMIUM", },
+ { 0x8CE2, "GL_COLOR_ATTACHMENT2_NV", },
+ { 0x8BC1, "GL_COUNTER_RANGE_AMD", },
+ { 0x8CE0, "GL_COLOR_ATTACHMENT0", },
+ { 0x8CE1, "GL_COLOR_ATTACHMENT1_NV", },
+ { 0x8CE6, "GL_COLOR_ATTACHMENT6_NV", },
+ { 0x8CE7, "GL_COLOR_ATTACHMENT7_NV", },
+ { 0x8A1F, "GL_RGB_422_APPLE", },
+ { 0x93DC, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR", },
+ { 0x8CE8, "GL_COLOR_ATTACHMENT8_NV", },
+ { 0x8CE9, "GL_COLOR_ATTACHMENT9_NV", },
+ { 0x0C23, "GL_COLOR_WRITEMASK", },
+ { 0x0C22, "GL_COLOR_CLEAR_VALUE", },
+ { 0x8823, "GL_WRITEONLY_RENDERING_QCOM", },
+ { 0x8824, "GL_MAX_DRAW_BUFFERS_NV", },
+ { 0x825A, "GL_PROGRAM_PIPELINE_BINDING_EXT", },
+ { 0x1909, "GL_LUMINANCE", },
+ { 0x0D3A, "GL_MAX_VIEWPORT_DIMS", },
+ { 0x0020, "GL_MAP_UNSYNCHRONIZED_BIT_EXT", },
+ { 0x809E, "GL_SAMPLE_ALPHA_TO_COVERAGE", },
+ { 0x8BC0, "GL_COUNTER_TYPE_AMD", },
+ { 0x8BC3, "GL_PERCENTAGE_AMD", },
+ { 0x8BC2, "GL_UNSIGNED_INT64_AMD", },
+ { 0x8BC5, "GL_PERFMON_RESULT_SIZE_AMD", },
+ { 0x8BC4, "GL_PERFMON_RESULT_AVAILABLE_AMD", },
+ { 0x8BC6, "GL_PERFMON_RESULT_AMD", },
+};
+
+const GLES2Util::EnumToString* const GLES2Util::enum_to_string_table_ =
+ enum_to_string_table;
+const size_t GLES2Util::enum_to_string_table_len_ =
+ sizeof(enum_to_string_table) / sizeof(enum_to_string_table[0]);
+
+std::string GLES2Util::GetStringAttachment(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_COLOR_ATTACHMENT0, "GL_COLOR_ATTACHMENT0" },
+ { GL_DEPTH_ATTACHMENT, "GL_DEPTH_ATTACHMENT" },
+ { GL_STENCIL_ATTACHMENT, "GL_STENCIL_ATTACHMENT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringBackbufferAttachment(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_COLOR_EXT, "GL_COLOR_EXT" },
+ { GL_DEPTH_EXT, "GL_DEPTH_EXT" },
+ { GL_STENCIL_EXT, "GL_STENCIL_EXT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringBlitFilter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_NEAREST, "GL_NEAREST" },
+ { GL_LINEAR, "GL_LINEAR" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringBufferParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_BUFFER_SIZE, "GL_BUFFER_SIZE" },
+ { GL_BUFFER_USAGE, "GL_BUFFER_USAGE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringBufferTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ARRAY_BUFFER, "GL_ARRAY_BUFFER" },
+ { GL_ELEMENT_ARRAY_BUFFER, "GL_ELEMENT_ARRAY_BUFFER" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringBufferUsage(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_STREAM_DRAW, "GL_STREAM_DRAW" },
+ { GL_STATIC_DRAW, "GL_STATIC_DRAW" },
+ { GL_DYNAMIC_DRAW, "GL_DYNAMIC_DRAW" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringCapability(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_BLEND, "GL_BLEND" },
+ { GL_CULL_FACE, "GL_CULL_FACE" },
+ { GL_DEPTH_TEST, "GL_DEPTH_TEST" },
+ { GL_DITHER, "GL_DITHER" },
+ { GL_POLYGON_OFFSET_FILL, "GL_POLYGON_OFFSET_FILL" },
+ { GL_SAMPLE_ALPHA_TO_COVERAGE, "GL_SAMPLE_ALPHA_TO_COVERAGE" },
+ { GL_SAMPLE_COVERAGE, "GL_SAMPLE_COVERAGE" },
+ { GL_SCISSOR_TEST, "GL_SCISSOR_TEST" },
+ { GL_STENCIL_TEST, "GL_STENCIL_TEST" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringCmpFunction(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_NEVER, "GL_NEVER" },
+ { GL_LESS, "GL_LESS" },
+ { GL_EQUAL, "GL_EQUAL" },
+ { GL_LEQUAL, "GL_LEQUAL" },
+ { GL_GREATER, "GL_GREATER" },
+ { GL_NOTEQUAL, "GL_NOTEQUAL" },
+ { GL_GEQUAL, "GL_GEQUAL" },
+ { GL_ALWAYS, "GL_ALWAYS" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringCompressedTextureFormat(uint32 value) {
+ return GLES2Util::GetQualifiedEnumString(
+ NULL, 0, value);
+}
+
+std::string GLES2Util::GetStringDrawMode(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_POINTS, "GL_POINTS" },
+ { GL_LINE_STRIP, "GL_LINE_STRIP" },
+ { GL_LINE_LOOP, "GL_LINE_LOOP" },
+ { GL_LINES, "GL_LINES" },
+ { GL_TRIANGLE_STRIP, "GL_TRIANGLE_STRIP" },
+ { GL_TRIANGLE_FAN, "GL_TRIANGLE_FAN" },
+ { GL_TRIANGLES, "GL_TRIANGLES" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringDstBlendFactor(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ZERO, "GL_ZERO" },
+ { GL_ONE, "GL_ONE" },
+ { GL_SRC_COLOR, "GL_SRC_COLOR" },
+ { GL_ONE_MINUS_SRC_COLOR, "GL_ONE_MINUS_SRC_COLOR" },
+ { GL_DST_COLOR, "GL_DST_COLOR" },
+ { GL_ONE_MINUS_DST_COLOR, "GL_ONE_MINUS_DST_COLOR" },
+ { GL_SRC_ALPHA, "GL_SRC_ALPHA" },
+ { GL_ONE_MINUS_SRC_ALPHA, "GL_ONE_MINUS_SRC_ALPHA" },
+ { GL_DST_ALPHA, "GL_DST_ALPHA" },
+ { GL_ONE_MINUS_DST_ALPHA, "GL_ONE_MINUS_DST_ALPHA" },
+ { GL_CONSTANT_COLOR, "GL_CONSTANT_COLOR" },
+ { GL_ONE_MINUS_CONSTANT_COLOR, "GL_ONE_MINUS_CONSTANT_COLOR" },
+ { GL_CONSTANT_ALPHA, "GL_CONSTANT_ALPHA" },
+ { GL_ONE_MINUS_CONSTANT_ALPHA, "GL_ONE_MINUS_CONSTANT_ALPHA" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringEquation(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_FUNC_ADD, "GL_FUNC_ADD" },
+ { GL_FUNC_SUBTRACT, "GL_FUNC_SUBTRACT" },
+ { GL_FUNC_REVERSE_SUBTRACT, "GL_FUNC_REVERSE_SUBTRACT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringFaceMode(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_CW, "GL_CW" },
+ { GL_CCW, "GL_CCW" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringFaceType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_FRONT, "GL_FRONT" },
+ { GL_BACK, "GL_BACK" },
+ { GL_FRONT_AND_BACK, "GL_FRONT_AND_BACK" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringFrameBufferParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE" },
+ { GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ "GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME" },
+ { GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
+ "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL" },
+ { GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE,
+ "GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringFrameBufferTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_FRAMEBUFFER, "GL_FRAMEBUFFER" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringGLState(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ACTIVE_TEXTURE, "GL_ACTIVE_TEXTURE" },
+ { GL_ALIASED_LINE_WIDTH_RANGE, "GL_ALIASED_LINE_WIDTH_RANGE" },
+ { GL_ALIASED_POINT_SIZE_RANGE, "GL_ALIASED_POINT_SIZE_RANGE" },
+ { GL_ALPHA_BITS, "GL_ALPHA_BITS" },
+ { GL_ARRAY_BUFFER_BINDING, "GL_ARRAY_BUFFER_BINDING" },
+ { GL_BLUE_BITS, "GL_BLUE_BITS" },
+ { GL_COMPRESSED_TEXTURE_FORMATS, "GL_COMPRESSED_TEXTURE_FORMATS" },
+ { GL_CURRENT_PROGRAM, "GL_CURRENT_PROGRAM" },
+ { GL_DEPTH_BITS, "GL_DEPTH_BITS" },
+ { GL_DEPTH_RANGE, "GL_DEPTH_RANGE" },
+ { GL_ELEMENT_ARRAY_BUFFER_BINDING, "GL_ELEMENT_ARRAY_BUFFER_BINDING" },
+ { GL_FRAMEBUFFER_BINDING, "GL_FRAMEBUFFER_BINDING" },
+ { GL_GENERATE_MIPMAP_HINT, "GL_GENERATE_MIPMAP_HINT" },
+ { GL_GREEN_BITS, "GL_GREEN_BITS" },
+ { GL_IMPLEMENTATION_COLOR_READ_FORMAT,
+ "GL_IMPLEMENTATION_COLOR_READ_FORMAT" },
+ { GL_IMPLEMENTATION_COLOR_READ_TYPE, "GL_IMPLEMENTATION_COLOR_READ_TYPE" },
+ { GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
+ "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS" },
+ { GL_MAX_CUBE_MAP_TEXTURE_SIZE, "GL_MAX_CUBE_MAP_TEXTURE_SIZE" },
+ { GL_MAX_FRAGMENT_UNIFORM_VECTORS, "GL_MAX_FRAGMENT_UNIFORM_VECTORS" },
+ { GL_MAX_RENDERBUFFER_SIZE, "GL_MAX_RENDERBUFFER_SIZE" },
+ { GL_MAX_TEXTURE_IMAGE_UNITS, "GL_MAX_TEXTURE_IMAGE_UNITS" },
+ { GL_MAX_TEXTURE_SIZE, "GL_MAX_TEXTURE_SIZE" },
+ { GL_MAX_VARYING_VECTORS, "GL_MAX_VARYING_VECTORS" },
+ { GL_MAX_VERTEX_ATTRIBS, "GL_MAX_VERTEX_ATTRIBS" },
+ { GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS" },
+ { GL_MAX_VERTEX_UNIFORM_VECTORS, "GL_MAX_VERTEX_UNIFORM_VECTORS" },
+ { GL_MAX_VIEWPORT_DIMS, "GL_MAX_VIEWPORT_DIMS" },
+ { GL_NUM_COMPRESSED_TEXTURE_FORMATS, "GL_NUM_COMPRESSED_TEXTURE_FORMATS" },
+ { GL_NUM_SHADER_BINARY_FORMATS, "GL_NUM_SHADER_BINARY_FORMATS" },
+ { GL_PACK_ALIGNMENT, "GL_PACK_ALIGNMENT" },
+ { GL_RED_BITS, "GL_RED_BITS" },
+ { GL_RENDERBUFFER_BINDING, "GL_RENDERBUFFER_BINDING" },
+ { GL_SAMPLE_BUFFERS, "GL_SAMPLE_BUFFERS" },
+ { GL_SAMPLE_COVERAGE_INVERT, "GL_SAMPLE_COVERAGE_INVERT" },
+ { GL_SAMPLE_COVERAGE_VALUE, "GL_SAMPLE_COVERAGE_VALUE" },
+ { GL_SAMPLES, "GL_SAMPLES" },
+ { GL_SCISSOR_BOX, "GL_SCISSOR_BOX" },
+ { GL_SHADER_BINARY_FORMATS, "GL_SHADER_BINARY_FORMATS" },
+ { GL_SHADER_COMPILER, "GL_SHADER_COMPILER" },
+ { GL_SUBPIXEL_BITS, "GL_SUBPIXEL_BITS" },
+ { GL_STENCIL_BITS, "GL_STENCIL_BITS" },
+ { GL_TEXTURE_BINDING_2D, "GL_TEXTURE_BINDING_2D" },
+ { GL_TEXTURE_BINDING_CUBE_MAP, "GL_TEXTURE_BINDING_CUBE_MAP" },
+ { GL_UNPACK_ALIGNMENT, "GL_UNPACK_ALIGNMENT" },
+ { GL_UNPACK_FLIP_Y_CHROMIUM, "GL_UNPACK_FLIP_Y_CHROMIUM" },
+ { GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
+ "GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM" },
+ { GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM,
+ "GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM" },
+ { GL_VERTEX_ARRAY_BINDING_OES, "GL_VERTEX_ARRAY_BINDING_OES" },
+ { GL_VIEWPORT, "GL_VIEWPORT" },
+ { GL_BLEND_COLOR, "GL_BLEND_COLOR" },
+ { GL_BLEND_EQUATION_RGB, "GL_BLEND_EQUATION_RGB" },
+ { GL_BLEND_EQUATION_ALPHA, "GL_BLEND_EQUATION_ALPHA" },
+ { GL_BLEND_SRC_RGB, "GL_BLEND_SRC_RGB" },
+ { GL_BLEND_DST_RGB, "GL_BLEND_DST_RGB" },
+ { GL_BLEND_SRC_ALPHA, "GL_BLEND_SRC_ALPHA" },
+ { GL_BLEND_DST_ALPHA, "GL_BLEND_DST_ALPHA" },
+ { GL_COLOR_CLEAR_VALUE, "GL_COLOR_CLEAR_VALUE" },
+ { GL_DEPTH_CLEAR_VALUE, "GL_DEPTH_CLEAR_VALUE" },
+ { GL_STENCIL_CLEAR_VALUE, "GL_STENCIL_CLEAR_VALUE" },
+ { GL_COLOR_WRITEMASK, "GL_COLOR_WRITEMASK" },
+ { GL_CULL_FACE_MODE, "GL_CULL_FACE_MODE" },
+ { GL_DEPTH_FUNC, "GL_DEPTH_FUNC" },
+ { GL_DEPTH_WRITEMASK, "GL_DEPTH_WRITEMASK" },
+ { GL_DEPTH_RANGE, "GL_DEPTH_RANGE" },
+ { GL_FRONT_FACE, "GL_FRONT_FACE" },
+ { GL_GENERATE_MIPMAP_HINT, "GL_GENERATE_MIPMAP_HINT" },
+ { GL_LINE_WIDTH, "GL_LINE_WIDTH" },
+ { GL_PACK_ALIGNMENT, "GL_PACK_ALIGNMENT" },
+ { GL_UNPACK_ALIGNMENT, "GL_UNPACK_ALIGNMENT" },
+ { GL_POLYGON_OFFSET_FACTOR, "GL_POLYGON_OFFSET_FACTOR" },
+ { GL_POLYGON_OFFSET_UNITS, "GL_POLYGON_OFFSET_UNITS" },
+ { GL_SAMPLE_COVERAGE_VALUE, "GL_SAMPLE_COVERAGE_VALUE" },
+ { GL_SAMPLE_COVERAGE_INVERT, "GL_SAMPLE_COVERAGE_INVERT" },
+ { GL_SCISSOR_BOX, "GL_SCISSOR_BOX" },
+ { GL_STENCIL_FUNC, "GL_STENCIL_FUNC" },
+ { GL_STENCIL_REF, "GL_STENCIL_REF" },
+ { GL_STENCIL_VALUE_MASK, "GL_STENCIL_VALUE_MASK" },
+ { GL_STENCIL_BACK_FUNC, "GL_STENCIL_BACK_FUNC" },
+ { GL_STENCIL_BACK_REF, "GL_STENCIL_BACK_REF" },
+ { GL_STENCIL_BACK_VALUE_MASK, "GL_STENCIL_BACK_VALUE_MASK" },
+ { GL_STENCIL_WRITEMASK, "GL_STENCIL_WRITEMASK" },
+ { GL_STENCIL_BACK_WRITEMASK, "GL_STENCIL_BACK_WRITEMASK" },
+ { GL_STENCIL_FAIL, "GL_STENCIL_FAIL" },
+ { GL_STENCIL_PASS_DEPTH_FAIL, "GL_STENCIL_PASS_DEPTH_FAIL" },
+ { GL_STENCIL_PASS_DEPTH_PASS, "GL_STENCIL_PASS_DEPTH_PASS" },
+ { GL_STENCIL_BACK_FAIL, "GL_STENCIL_BACK_FAIL" },
+ { GL_STENCIL_BACK_PASS_DEPTH_FAIL, "GL_STENCIL_BACK_PASS_DEPTH_FAIL" },
+ { GL_STENCIL_BACK_PASS_DEPTH_PASS, "GL_STENCIL_BACK_PASS_DEPTH_PASS" },
+ { GL_VIEWPORT, "GL_VIEWPORT" },
+ { GL_BLEND, "GL_BLEND" },
+ { GL_CULL_FACE, "GL_CULL_FACE" },
+ { GL_DEPTH_TEST, "GL_DEPTH_TEST" },
+ { GL_DITHER, "GL_DITHER" },
+ { GL_POLYGON_OFFSET_FILL, "GL_POLYGON_OFFSET_FILL" },
+ { GL_SAMPLE_ALPHA_TO_COVERAGE, "GL_SAMPLE_ALPHA_TO_COVERAGE" },
+ { GL_SAMPLE_COVERAGE, "GL_SAMPLE_COVERAGE" },
+ { GL_SCISSOR_TEST, "GL_SCISSOR_TEST" },
+ { GL_STENCIL_TEST, "GL_STENCIL_TEST" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringGetMaxIndexType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
+ { GL_UNSIGNED_SHORT, "GL_UNSIGNED_SHORT" },
+ { GL_UNSIGNED_INT, "GL_UNSIGNED_INT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringGetTexParamTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
+ { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringHintMode(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_FASTEST, "GL_FASTEST" },
+ { GL_NICEST, "GL_NICEST" },
+ { GL_DONT_CARE, "GL_DONT_CARE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringHintTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_GENERATE_MIPMAP_HINT, "GL_GENERATE_MIPMAP_HINT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringIndexType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
+ { GL_UNSIGNED_SHORT, "GL_UNSIGNED_SHORT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringPixelStore(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_PACK_ALIGNMENT, "GL_PACK_ALIGNMENT" },
+ { GL_UNPACK_ALIGNMENT, "GL_UNPACK_ALIGNMENT" },
+ { GL_UNPACK_FLIP_Y_CHROMIUM, "GL_UNPACK_FLIP_Y_CHROMIUM" },
+ { GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
+ "GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM" },
+ { GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM,
+ "GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringPixelType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
+ { GL_UNSIGNED_SHORT_5_6_5, "GL_UNSIGNED_SHORT_5_6_5" },
+ { GL_UNSIGNED_SHORT_4_4_4_4, "GL_UNSIGNED_SHORT_4_4_4_4" },
+ { GL_UNSIGNED_SHORT_5_5_5_1, "GL_UNSIGNED_SHORT_5_5_5_1" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringProgramParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_DELETE_STATUS, "GL_DELETE_STATUS" },
+ { GL_LINK_STATUS, "GL_LINK_STATUS" },
+ { GL_VALIDATE_STATUS, "GL_VALIDATE_STATUS" },
+ { GL_INFO_LOG_LENGTH, "GL_INFO_LOG_LENGTH" },
+ { GL_ATTACHED_SHADERS, "GL_ATTACHED_SHADERS" },
+ { GL_ACTIVE_ATTRIBUTES, "GL_ACTIVE_ATTRIBUTES" },
+ { GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, "GL_ACTIVE_ATTRIBUTE_MAX_LENGTH" },
+ { GL_ACTIVE_UNIFORMS, "GL_ACTIVE_UNIFORMS" },
+ { GL_ACTIVE_UNIFORM_MAX_LENGTH, "GL_ACTIVE_UNIFORM_MAX_LENGTH" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringQueryObjectParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_QUERY_RESULT_EXT, "GL_QUERY_RESULT_EXT" },
+ { GL_QUERY_RESULT_AVAILABLE_EXT, "GL_QUERY_RESULT_AVAILABLE_EXT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringQueryParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_CURRENT_QUERY_EXT, "GL_CURRENT_QUERY_EXT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringQueryTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ANY_SAMPLES_PASSED_EXT, "GL_ANY_SAMPLES_PASSED_EXT" },
+ { GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
+ "GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT" },
+ { GL_COMMANDS_ISSUED_CHROMIUM, "GL_COMMANDS_ISSUED_CHROMIUM" },
+ { GL_LATENCY_QUERY_CHROMIUM, "GL_LATENCY_QUERY_CHROMIUM" },
+ { GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
+ "GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM" },
+ { GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM,
+ "GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringReadPixelFormat(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ALPHA, "GL_ALPHA" },
+ { GL_RGB, "GL_RGB" },
+ { GL_RGBA, "GL_RGBA" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringReadPixelType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
+ { GL_UNSIGNED_SHORT_5_6_5, "GL_UNSIGNED_SHORT_5_6_5" },
+ { GL_UNSIGNED_SHORT_4_4_4_4, "GL_UNSIGNED_SHORT_4_4_4_4" },
+ { GL_UNSIGNED_SHORT_5_5_5_1, "GL_UNSIGNED_SHORT_5_5_5_1" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringRenderBufferFormat(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_RGBA4, "GL_RGBA4" },
+ { GL_RGB565, "GL_RGB565" },
+ { GL_RGB5_A1, "GL_RGB5_A1" },
+ { GL_DEPTH_COMPONENT16, "GL_DEPTH_COMPONENT16" },
+ { GL_STENCIL_INDEX8, "GL_STENCIL_INDEX8" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringRenderBufferParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_RENDERBUFFER_RED_SIZE, "GL_RENDERBUFFER_RED_SIZE" },
+ { GL_RENDERBUFFER_GREEN_SIZE, "GL_RENDERBUFFER_GREEN_SIZE" },
+ { GL_RENDERBUFFER_BLUE_SIZE, "GL_RENDERBUFFER_BLUE_SIZE" },
+ { GL_RENDERBUFFER_ALPHA_SIZE, "GL_RENDERBUFFER_ALPHA_SIZE" },
+ { GL_RENDERBUFFER_DEPTH_SIZE, "GL_RENDERBUFFER_DEPTH_SIZE" },
+ { GL_RENDERBUFFER_STENCIL_SIZE, "GL_RENDERBUFFER_STENCIL_SIZE" },
+ { GL_RENDERBUFFER_WIDTH, "GL_RENDERBUFFER_WIDTH" },
+ { GL_RENDERBUFFER_HEIGHT, "GL_RENDERBUFFER_HEIGHT" },
+ { GL_RENDERBUFFER_INTERNAL_FORMAT, "GL_RENDERBUFFER_INTERNAL_FORMAT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringRenderBufferTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_RENDERBUFFER, "GL_RENDERBUFFER" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringResetStatus(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_GUILTY_CONTEXT_RESET_ARB, "GL_GUILTY_CONTEXT_RESET_ARB" },
+ { GL_INNOCENT_CONTEXT_RESET_ARB, "GL_INNOCENT_CONTEXT_RESET_ARB" },
+ { GL_UNKNOWN_CONTEXT_RESET_ARB, "GL_UNKNOWN_CONTEXT_RESET_ARB" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringShaderBinaryFormat(uint32 value) {
+ return GLES2Util::GetQualifiedEnumString(
+ NULL, 0, value);
+}
+
+std::string GLES2Util::GetStringShaderParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_SHADER_TYPE, "GL_SHADER_TYPE" },
+ { GL_DELETE_STATUS, "GL_DELETE_STATUS" },
+ { GL_COMPILE_STATUS, "GL_COMPILE_STATUS" },
+ { GL_INFO_LOG_LENGTH, "GL_INFO_LOG_LENGTH" },
+ { GL_SHADER_SOURCE_LENGTH, "GL_SHADER_SOURCE_LENGTH" },
+ { GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
+ "GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringShaderPrecision(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_LOW_FLOAT, "GL_LOW_FLOAT" },
+ { GL_MEDIUM_FLOAT, "GL_MEDIUM_FLOAT" },
+ { GL_HIGH_FLOAT, "GL_HIGH_FLOAT" },
+ { GL_LOW_INT, "GL_LOW_INT" },
+ { GL_MEDIUM_INT, "GL_MEDIUM_INT" },
+ { GL_HIGH_INT, "GL_HIGH_INT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringShaderType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_VERTEX_SHADER, "GL_VERTEX_SHADER" },
+ { GL_FRAGMENT_SHADER, "GL_FRAGMENT_SHADER" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringSrcBlendFactor(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ZERO, "GL_ZERO" },
+ { GL_ONE, "GL_ONE" },
+ { GL_SRC_COLOR, "GL_SRC_COLOR" },
+ { GL_ONE_MINUS_SRC_COLOR, "GL_ONE_MINUS_SRC_COLOR" },
+ { GL_DST_COLOR, "GL_DST_COLOR" },
+ { GL_ONE_MINUS_DST_COLOR, "GL_ONE_MINUS_DST_COLOR" },
+ { GL_SRC_ALPHA, "GL_SRC_ALPHA" },
+ { GL_ONE_MINUS_SRC_ALPHA, "GL_ONE_MINUS_SRC_ALPHA" },
+ { GL_DST_ALPHA, "GL_DST_ALPHA" },
+ { GL_ONE_MINUS_DST_ALPHA, "GL_ONE_MINUS_DST_ALPHA" },
+ { GL_CONSTANT_COLOR, "GL_CONSTANT_COLOR" },
+ { GL_ONE_MINUS_CONSTANT_COLOR, "GL_ONE_MINUS_CONSTANT_COLOR" },
+ { GL_CONSTANT_ALPHA, "GL_CONSTANT_ALPHA" },
+ { GL_ONE_MINUS_CONSTANT_ALPHA, "GL_ONE_MINUS_CONSTANT_ALPHA" },
+ { GL_SRC_ALPHA_SATURATE, "GL_SRC_ALPHA_SATURATE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringStencilOp(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_KEEP, "GL_KEEP" },
+ { GL_ZERO, "GL_ZERO" },
+ { GL_REPLACE, "GL_REPLACE" },
+ { GL_INCR, "GL_INCR" },
+ { GL_INCR_WRAP, "GL_INCR_WRAP" },
+ { GL_DECR, "GL_DECR" },
+ { GL_DECR_WRAP, "GL_DECR_WRAP" },
+ { GL_INVERT, "GL_INVERT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringStringType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_VENDOR, "GL_VENDOR" },
+ { GL_RENDERER, "GL_RENDERER" },
+ { GL_VERSION, "GL_VERSION" },
+ { GL_SHADING_LANGUAGE_VERSION, "GL_SHADING_LANGUAGE_VERSION" },
+ { GL_EXTENSIONS, "GL_EXTENSIONS" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureBindTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
+ { GL_TEXTURE_CUBE_MAP, "GL_TEXTURE_CUBE_MAP" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureFormat(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ALPHA, "GL_ALPHA" },
+ { GL_LUMINANCE, "GL_LUMINANCE" },
+ { GL_LUMINANCE_ALPHA, "GL_LUMINANCE_ALPHA" },
+ { GL_RGB, "GL_RGB" },
+ { GL_RGBA, "GL_RGBA" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureInternalFormat(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_ALPHA, "GL_ALPHA" },
+ { GL_LUMINANCE, "GL_LUMINANCE" },
+ { GL_LUMINANCE_ALPHA, "GL_LUMINANCE_ALPHA" },
+ { GL_RGB, "GL_RGB" },
+ { GL_RGBA, "GL_RGBA" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureInternalFormatStorage(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_RGB565, "GL_RGB565" },
+ { GL_RGBA4, "GL_RGBA4" },
+ { GL_RGB5_A1, "GL_RGB5_A1" },
+ { GL_ALPHA8_EXT, "GL_ALPHA8_EXT" },
+ { GL_LUMINANCE8_EXT, "GL_LUMINANCE8_EXT" },
+ { GL_LUMINANCE8_ALPHA8_EXT, "GL_LUMINANCE8_ALPHA8_EXT" },
+ { GL_RGB8_OES, "GL_RGB8_OES" },
+ { GL_RGBA8_OES, "GL_RGBA8_OES" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureMagFilterMode(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_NEAREST, "GL_NEAREST" },
+ { GL_LINEAR, "GL_LINEAR" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureMinFilterMode(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_NEAREST, "GL_NEAREST" },
+ { GL_LINEAR, "GL_LINEAR" },
+ { GL_NEAREST_MIPMAP_NEAREST, "GL_NEAREST_MIPMAP_NEAREST" },
+ { GL_LINEAR_MIPMAP_NEAREST, "GL_LINEAR_MIPMAP_NEAREST" },
+ { GL_NEAREST_MIPMAP_LINEAR, "GL_NEAREST_MIPMAP_LINEAR" },
+ { GL_LINEAR_MIPMAP_LINEAR, "GL_LINEAR_MIPMAP_LINEAR" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureParameter(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_TEXTURE_MAG_FILTER, "GL_TEXTURE_MAG_FILTER" },
+ { GL_TEXTURE_MIN_FILTER, "GL_TEXTURE_MIN_FILTER" },
+ { GL_TEXTURE_POOL_CHROMIUM, "GL_TEXTURE_POOL_CHROMIUM" },
+ { GL_TEXTURE_WRAP_S, "GL_TEXTURE_WRAP_S" },
+ { GL_TEXTURE_WRAP_T, "GL_TEXTURE_WRAP_T" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTexturePool(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_TEXTURE_POOL_MANAGED_CHROMIUM, "GL_TEXTURE_POOL_MANAGED_CHROMIUM" },
+ { GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
+ "GL_TEXTURE_POOL_UNMANAGED_CHROMIUM" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureTarget(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_TEXTURE_2D, "GL_TEXTURE_2D" },
+ { GL_TEXTURE_CUBE_MAP_POSITIVE_X, "GL_TEXTURE_CUBE_MAP_POSITIVE_X" },
+ { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, "GL_TEXTURE_CUBE_MAP_NEGATIVE_X" },
+ { GL_TEXTURE_CUBE_MAP_POSITIVE_Y, "GL_TEXTURE_CUBE_MAP_POSITIVE_Y" },
+ { GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Y" },
+ { GL_TEXTURE_CUBE_MAP_POSITIVE_Z, "GL_TEXTURE_CUBE_MAP_POSITIVE_Z" },
+ { GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, "GL_TEXTURE_CUBE_MAP_NEGATIVE_Z" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureUsage(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_NONE, "GL_NONE" },
+ { GL_FRAMEBUFFER_ATTACHMENT_ANGLE, "GL_FRAMEBUFFER_ATTACHMENT_ANGLE" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringTextureWrapMode(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_CLAMP_TO_EDGE, "GL_CLAMP_TO_EDGE" },
+ { GL_MIRRORED_REPEAT, "GL_MIRRORED_REPEAT" },
+ { GL_REPEAT, "GL_REPEAT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringVertexAttribType(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_BYTE, "GL_BYTE" },
+ { GL_UNSIGNED_BYTE, "GL_UNSIGNED_BYTE" },
+ { GL_SHORT, "GL_SHORT" },
+ { GL_UNSIGNED_SHORT, "GL_UNSIGNED_SHORT" },
+ { GL_FLOAT, "GL_FLOAT" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringVertexAttribute(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, "GL_VERTEX_ATTRIB_ARRAY_NORMALIZED" },
+ { GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ "GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING" },
+ { GL_VERTEX_ATTRIB_ARRAY_ENABLED, "GL_VERTEX_ATTRIB_ARRAY_ENABLED" },
+ { GL_VERTEX_ATTRIB_ARRAY_SIZE, "GL_VERTEX_ATTRIB_ARRAY_SIZE" },
+ { GL_VERTEX_ATTRIB_ARRAY_STRIDE, "GL_VERTEX_ATTRIB_ARRAY_STRIDE" },
+ { GL_VERTEX_ATTRIB_ARRAY_TYPE, "GL_VERTEX_ATTRIB_ARRAY_TYPE" },
+ { GL_CURRENT_VERTEX_ATTRIB, "GL_CURRENT_VERTEX_ATTRIB" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+std::string GLES2Util::GetStringVertexPointer(uint32 value) {
+ static const EnumToString string_table[] = {
+ { GL_VERTEX_ATTRIB_ARRAY_POINTER, "GL_VERTEX_ATTRIB_ARRAY_POINTER" },
+ };
+ return GLES2Util::GetQualifiedEnumString(
+ string_table, arraysize(string_table), value);
+}
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_UTILS_IMPLEMENTATION_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc b/chromium/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
new file mode 100644
index 00000000000..864c8811d2a
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
@@ -0,0 +1,293 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+
+#include <limits>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2UtilTest : public testing:: Test {
+ protected:
+ GLES2Util util_;
+};
+
+TEST_F(GLES2UtilTest, SafeMultiplyUint32) {
+ uint32 result = 0;
+ EXPECT_TRUE(SafeMultiplyUint32(2u, 3u, &result));
+ EXPECT_EQ(6u, result);
+ EXPECT_FALSE(SafeMultiplyUint32(0x80000000u, 2u, &result));
+ EXPECT_EQ(0u, result);
+ EXPECT_TRUE(SafeMultiplyUint32(0x2u, 0x7FFFFFFFu, &result));
+ EXPECT_EQ(0xFFFFFFFEu, result);
+ EXPECT_FALSE(SafeMultiplyUint32(2u, 0x80000000u, &result));
+ EXPECT_EQ(0u, result);
+}
+
+TEST_F(GLES2UtilTest, SafeAddUint32) {
+ uint32 result = 0;
+ EXPECT_TRUE(SafeAddUint32(2u, 3u, &result));
+ EXPECT_EQ(5u, result);
+ EXPECT_FALSE(SafeAddUint32(0x80000000u, 0x80000000u, &result));
+ EXPECT_EQ(0u, result);
+ EXPECT_TRUE(SafeAddUint32(0xFFFFFFFEu, 0x1u, &result));
+ EXPECT_EQ(0xFFFFFFFFu, result);
+ EXPECT_FALSE(SafeAddUint32(0xFFFFFFFEu, 0x2u, &result));
+ EXPECT_EQ(0u, result);
+ EXPECT_TRUE(SafeAddUint32(0x1u, 0xFFFFFFFEu, &result));
+ EXPECT_EQ(0xFFFFFFFFu, result);
+ EXPECT_FALSE(SafeAddUint32(0x2u, 0xFFFFFFFEu, &result));
+ EXPECT_EQ(0u, result);
+}
+
+TEST_F(GLES2UtilTest, SafeAddInt32) {
+ int32 result = 0;
+ const int32 kMax = std::numeric_limits<int32>::max();
+ const int32 kMin = std::numeric_limits<int32>::min();
+ EXPECT_TRUE(SafeAddInt32(2, 3, &result));
+ EXPECT_EQ(5, result);
+ EXPECT_FALSE(SafeAddInt32(kMax, 1, &result));
+ EXPECT_EQ(0, result);
+ EXPECT_TRUE(SafeAddInt32(kMin + 1, -1, &result));
+ EXPECT_EQ(kMin, result);
+ EXPECT_FALSE(SafeAddInt32(kMin, -1, &result));
+ EXPECT_EQ(0, result);
+ EXPECT_TRUE(SafeAddInt32(kMax - 1, 1, &result));
+ EXPECT_EQ(kMax, result);
+ EXPECT_FALSE(SafeAddInt32(1, kMax, &result));
+ EXPECT_EQ(0, result);
+ EXPECT_TRUE(SafeAddInt32(-1, kMin + 1, &result));
+ EXPECT_EQ(kMin, result);
+ EXPECT_FALSE(SafeAddInt32(-1, kMin, &result));
+ EXPECT_EQ(0, result);
+ EXPECT_TRUE(SafeAddInt32(1, kMax - 1, &result));
+ EXPECT_EQ(kMax, result);
+}
+
+TEST_F(GLES2UtilTest, GLGetNumValuesReturned) {
+ EXPECT_EQ(0, util_.GLGetNumValuesReturned(GL_COMPRESSED_TEXTURE_FORMATS));
+ EXPECT_EQ(0, util_.GLGetNumValuesReturned(GL_SHADER_BINARY_FORMATS));
+
+ EXPECT_EQ(0, util_.num_compressed_texture_formats());
+ EXPECT_EQ(0, util_.num_shader_binary_formats());
+
+ util_.set_num_compressed_texture_formats(1);
+ util_.set_num_shader_binary_formats(2);
+
+ EXPECT_EQ(1, util_.GLGetNumValuesReturned(GL_COMPRESSED_TEXTURE_FORMATS));
+ EXPECT_EQ(2, util_.GLGetNumValuesReturned(GL_SHADER_BINARY_FORMATS));
+
+ EXPECT_EQ(1, util_.num_compressed_texture_formats());
+ EXPECT_EQ(2, util_.num_shader_binary_formats());
+}
+
+TEST_F(GLES2UtilTest, ComputeImageDataSizesFormats) {
+ const uint32 kWidth = 16;
+ const uint32 kHeight = 12;
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 3, size);
+ EXPECT_EQ(kWidth * 3, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 4, size);
+ EXPECT_EQ(kWidth * 4, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 1, size);
+ EXPECT_EQ(kWidth * 1, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 2, size);
+ EXPECT_EQ(kWidth * 2, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 4, size);
+ EXPECT_EQ(kWidth * 4, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_ALPHA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 1, size);
+ EXPECT_EQ(kWidth * 1, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 2, size);
+ EXPECT_EQ(kWidth * 2, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, 1,
+ &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 4, size);
+ EXPECT_EQ(kWidth * 4, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+}
+
+TEST_F(GLES2UtilTest, ComputeImageDataSizeTypes) {
+ const uint32 kWidth = 16;
+ const uint32 kHeight = 12;
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 4, size);
+ EXPECT_EQ(kWidth * 4, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 2, size);
+ EXPECT_EQ(kWidth * 2, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 2, size);
+ EXPECT_EQ(kWidth * 2, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 2, size);
+ EXPECT_EQ(kWidth * 2, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 1, &size,
+ &unpadded_row_size, &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 4, size);
+ EXPECT_EQ(kWidth * 4, padded_row_size);
+ EXPECT_EQ(padded_row_size, unpadded_row_size);
+}
+
+TEST_F(GLES2UtilTest, ComputeImageDataSizesUnpackAlignment) {
+ const uint32 kWidth = 19;
+ const uint32 kHeight = 12;
+ uint32 size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 1, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ(kWidth * kHeight * 3, size);
+ EXPECT_EQ(kWidth * 3, unpadded_row_size);
+ EXPECT_EQ(kWidth * 3, padded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 2, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ((kWidth * 3 + 1) * (kHeight - 1) +
+ kWidth * 3, size);
+ EXPECT_EQ(kWidth * 3, unpadded_row_size);
+ EXPECT_EQ(kWidth * 3 + 1, padded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 4, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ((kWidth * 3 + 3) * (kHeight - 1) +
+ kWidth * 3, size);
+ EXPECT_EQ(kWidth * 3, unpadded_row_size);
+ EXPECT_EQ(kWidth * 3 + 3, padded_row_size);
+ EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
+ kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, 8, &size, &unpadded_row_size,
+ &padded_row_size));
+ EXPECT_EQ((kWidth * 3 + 7) * (kHeight - 1) +
+ kWidth * 3, size);
+ EXPECT_EQ(kWidth * 3, unpadded_row_size);
+ EXPECT_EQ(kWidth * 3 + 7, padded_row_size);
+}
+
+TEST_F(GLES2UtilTest, RenderbufferBytesPerPixel) {
+ EXPECT_EQ(1u, GLES2Util::RenderbufferBytesPerPixel(GL_STENCIL_INDEX8));
+ EXPECT_EQ(2u, GLES2Util::RenderbufferBytesPerPixel(GL_RGBA4));
+ EXPECT_EQ(2u, GLES2Util::RenderbufferBytesPerPixel(GL_RGB565));
+ EXPECT_EQ(2u, GLES2Util::RenderbufferBytesPerPixel(GL_RGB5_A1));
+ EXPECT_EQ(2u, GLES2Util::RenderbufferBytesPerPixel(GL_DEPTH_COMPONENT16));
+ EXPECT_EQ(4u, GLES2Util::RenderbufferBytesPerPixel(GL_RGB));
+ EXPECT_EQ(4u, GLES2Util::RenderbufferBytesPerPixel(GL_RGBA));
+ EXPECT_EQ(
+ 4u, GLES2Util::RenderbufferBytesPerPixel(GL_DEPTH24_STENCIL8_OES));
+ EXPECT_EQ(4u, GLES2Util::RenderbufferBytesPerPixel(GL_RGB8_OES));
+ EXPECT_EQ(4u, GLES2Util::RenderbufferBytesPerPixel(GL_RGBA8_OES));
+ EXPECT_EQ(
+ 4u, GLES2Util::RenderbufferBytesPerPixel(GL_DEPTH_COMPONENT24_OES));
+ EXPECT_EQ(0u, GLES2Util::RenderbufferBytesPerPixel(-1));
+}
+
+TEST_F(GLES2UtilTest, GetChannelsForCompressedFormat) {
+ EXPECT_EQ(0u, GLES2Util::GetChannelsForFormat(GL_ETC1_RGB8_OES));
+ EXPECT_EQ(0u, GLES2Util::GetChannelsForFormat(
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT));
+ EXPECT_EQ(0u, GLES2Util::GetChannelsForFormat(
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT));
+ EXPECT_EQ(0u, GLES2Util::GetChannelsForFormat(
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT));
+ EXPECT_EQ(0u, GLES2Util::GetChannelsForFormat(
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT));
+}
+
+namespace {
+
+void CheckParseUniformName(
+ const char* name,
+ bool expected_success,
+ size_t expected_array_pos,
+ int expected_index,
+ bool expected_getting_array) {
+ int index = 1234;
+ size_t array_pos = 1244;
+ bool getting_array = false;
+ bool success = GLES2Util::ParseUniformName(
+ name, &array_pos, &index, &getting_array);
+ EXPECT_EQ(expected_success, success);
+ if (success) {
+ EXPECT_EQ(expected_array_pos, array_pos);
+ EXPECT_EQ(expected_index, index);
+ EXPECT_EQ(expected_getting_array, getting_array);
+ }
+}
+
+} // anonymous namespace
+
+TEST_F(GLES2UtilTest, ParseUniformName) {
+ CheckParseUniformName("u_name", true, std::string::npos, 0, false);
+ CheckParseUniformName("u_name[]", false, std::string::npos, 0, false);
+ CheckParseUniformName("u_name]", false, std::string::npos, 0, false);
+ CheckParseUniformName("u_name[0a]", false, std::string::npos, 0, false);
+ CheckParseUniformName("u_name[a0]", false, std::string::npos, 0, false);
+ CheckParseUniformName("u_name[0a0]", false, std::string::npos, 0, false);
+ CheckParseUniformName("u_name[0]", true, 6u, 0, true);
+ CheckParseUniformName("u_name[2]", true, 6u, 2, true);
+ CheckParseUniformName("u_name[02]", true, 6u, 2, true);
+ CheckParseUniformName("u_name[20]", true, 6u, 20, true);
+ CheckParseUniformName("u_name[020]", true, 6u, 20, true);
+ CheckParseUniformName("u_name[0][0]", true, 9u, 0, true);
+ CheckParseUniformName("u_name[3][2]", true, 9u, 2, true);
+ CheckParseUniformName("u_name[03][02]", true, 10u, 2, true);
+ CheckParseUniformName("u_name[30][20]", true, 10u, 20, true);
+ CheckParseUniformName("u_name[030][020]", true, 11u, 20, true);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/gles2_utils_export.h b/chromium/gpu/command_buffer/common/gles2_utils_export.h
new file mode 100644
index 00000000000..ec7da8aa2ce
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/gles2_utils_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_UTILS_EXPORT_H_
+#define GPU_COMMAND_BUFFER_COMMON_GLES2_UTILS_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(GLES2_UTILS_IMPLEMENTATION)
+#define GLES2_UTILS_EXPORT __declspec(dllexport)
+#else
+#define GLES2_UTILS_EXPORT __declspec(dllimport)
+#endif // defined(GLES2_UTILS_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(GLES2_UTILS_IMPLEMENTATION)
+#define GLES2_UTILS_EXPORT __attribute__((visibility("default")))
+#else
+#define GLES2_UTILS_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define GLES2_UTILS_EXPORT
+#endif
+
+#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_UTILS_EXPORT_H_
diff --git a/chromium/gpu/command_buffer/common/id_allocator.cc b/chromium/gpu/command_buffer/common/id_allocator.cc
new file mode 100644
index 00000000000..b881e051a5a
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/id_allocator.cc
@@ -0,0 +1,121 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation of IdAllocator.
+
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+
+IdAllocatorInterface::~IdAllocatorInterface() {
+}
+
+IdAllocator::IdAllocator() {}
+
+IdAllocator::~IdAllocator() {}
+
+ResourceId IdAllocator::AllocateID() {
+ ResourceId id;
+ ResourceIdSet::iterator iter = free_ids_.begin();
+ if (iter != free_ids_.end()) {
+ id = *iter;
+ } else {
+ id = LastUsedId() + 1;
+ if (!id) {
+ // We wrapped around to 0.
+ id = FindFirstUnusedId();
+ }
+ }
+ MarkAsUsed(id);
+ return id;
+}
+
+ResourceId IdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) {
+ ResourceId id;
+ ResourceIdSet::iterator iter = free_ids_.lower_bound(desired_id);
+ if (iter != free_ids_.end()) {
+ id = *iter;
+ } else if (LastUsedId() < desired_id) {
+ id = desired_id;
+ } else {
+ id = LastUsedId() + 1;
+ if (!id) {
+ // We wrapped around to 0.
+ id = FindFirstUnusedId();
+ }
+ }
+ MarkAsUsed(id);
+ return id;
+}
+
+bool IdAllocator::MarkAsUsed(ResourceId id) {
+ GPU_DCHECK(id);
+ free_ids_.erase(id);
+ std::pair<ResourceIdSet::iterator, bool> result = used_ids_.insert(id);
+ return result.second;
+}
+
+void IdAllocator::FreeID(ResourceId id) {
+ if (id) {
+ used_ids_.erase(id);
+ free_ids_.insert(id);
+ }
+}
+
+bool IdAllocator::InUse(ResourceId id) const {
+ return id == kInvalidResource || used_ids_.find(id) != used_ids_.end();
+}
+
+ResourceId IdAllocator::LastUsedId() const {
+ if (used_ids_.empty()) {
+ return 0u;
+ } else {
+ return *used_ids_.rbegin();
+ }
+}
+
+ResourceId IdAllocator::FindFirstUnusedId() const {
+ ResourceId id = 1;
+ for (ResourceIdSet::const_iterator it = used_ids_.begin();
+ it != used_ids_.end(); ++it) {
+ if ((*it) != id) {
+ return id;
+ }
+ ++id;
+ }
+ return id;
+}
+
+NonReusedIdAllocator::NonReusedIdAllocator() : last_id_(0) {
+}
+
+NonReusedIdAllocator::~NonReusedIdAllocator() {
+}
+
+ResourceId NonReusedIdAllocator::AllocateID() {
+ return ++last_id_;
+}
+
+ResourceId NonReusedIdAllocator::AllocateIDAtOrAbove(ResourceId desired_id) {
+ if (desired_id > last_id_)
+ last_id_ = desired_id;
+
+ return ++last_id_;
+}
+
+bool NonReusedIdAllocator::MarkAsUsed(ResourceId id) {
+ GPU_NOTREACHED();
+ return false;
+}
+
+void NonReusedIdAllocator::FreeID(ResourceId id) {
+}
+
+bool NonReusedIdAllocator::InUse(ResourceId id) const {
+ GPU_NOTREACHED();
+ return false;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/id_allocator.h b/chromium/gpu/command_buffer/common/id_allocator.h
new file mode 100644
index 00000000000..46fcd1acf03
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/id_allocator.h
@@ -0,0 +1,98 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the definition of the IdAllocator class.
+
+#ifndef GPU_COMMAND_BUFFER_CLIENT_ID_ALLOCATOR_H_
+#define GPU_COMMAND_BUFFER_CLIENT_ID_ALLOCATOR_H_
+
+#include <set>
+#include <utility>
+
+#include "base/compiler_specific.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+// A resource ID, key to the resource maps.
+typedef uint32 ResourceId;
+// Invalid resource ID.
+static const ResourceId kInvalidResource = 0u;
+
+class GPU_EXPORT IdAllocatorInterface {
+ public:
+ virtual ~IdAllocatorInterface();
+
+ // Allocates a new resource ID.
+ virtual ResourceId AllocateID() = 0;
+
+ // Allocates an Id starting at or above desired_id.
+ // Note: may wrap if it starts near limit.
+ virtual ResourceId AllocateIDAtOrAbove(ResourceId desired_id) = 0;
+
+ // Marks an id as used. Returns false if id was already used.
+ virtual bool MarkAsUsed(ResourceId id) = 0;
+
+ // Frees a resource ID.
+ virtual void FreeID(ResourceId id) = 0;
+
+ // Checks whether or not a resource ID is in use.
+ virtual bool InUse(ResourceId id) const = 0;
+};
+
+// A class to manage the allocation of resource IDs.
+class GPU_EXPORT IdAllocator : public IdAllocatorInterface {
+ public:
+ IdAllocator();
+ virtual ~IdAllocator();
+
+ // Implement IdAllocatorInterface.
+ virtual ResourceId AllocateID() OVERRIDE;
+ virtual ResourceId AllocateIDAtOrAbove(ResourceId desired_id) OVERRIDE;
+ virtual bool MarkAsUsed(ResourceId id) OVERRIDE;
+ virtual void FreeID(ResourceId id) OVERRIDE;
+ virtual bool InUse(ResourceId id) const OVERRIDE;
+
+ private:
+ // TODO(gman): This would work much better with ranges or a hash table.
+ typedef std::set<ResourceId> ResourceIdSet;
+
+ // The highest ID on the used list.
+ ResourceId LastUsedId() const;
+
+ // Lowest ID that isn't on the used list. This is slow, use as a last resort.
+ ResourceId FindFirstUnusedId() const;
+
+ ResourceIdSet used_ids_;
+ ResourceIdSet free_ids_;
+
+ DISALLOW_COPY_AND_ASSIGN(IdAllocator);
+};
+
+// A class to manage the allocation of resource IDs that are never reused. This
+// implementation does not track which IDs are currently used. It is useful for
+// shared and programs which cannot be implicitly created by binding a
+// previously unused ID.
+class NonReusedIdAllocator : public IdAllocatorInterface {
+ public:
+ NonReusedIdAllocator();
+ virtual ~NonReusedIdAllocator();
+
+ // Implement IdAllocatorInterface.
+ virtual ResourceId AllocateID() OVERRIDE;
+ virtual ResourceId AllocateIDAtOrAbove(ResourceId desired_id) OVERRIDE;
+ virtual bool MarkAsUsed(ResourceId id) OVERRIDE;
+ virtual void FreeID(ResourceId id) OVERRIDE;
+ virtual bool InUse(ResourceId id) const OVERRIDE;
+
+ private:
+ ResourceId last_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(NonReusedIdAllocator);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_CLIENT_ID_ALLOCATOR_H_
diff --git a/chromium/gpu/command_buffer/common/id_allocator_test.cc b/chromium/gpu/command_buffer/common/id_allocator_test.cc
new file mode 100644
index 00000000000..624f959b287
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/id_allocator_test.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has the unit tests for the IdAllocator class.
+
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class IdAllocatorTest : public testing::Test {
+ protected:
+ virtual void SetUp() {}
+ virtual void TearDown() {}
+
+ IdAllocator* id_allocator() { return &id_allocator_; }
+
+ private:
+ IdAllocator id_allocator_;
+};
+
+// Checks basic functionality: AllocateID, FreeID, InUse.
+TEST_F(IdAllocatorTest, TestBasic) {
+ IdAllocator *allocator = id_allocator();
+ // Check that resource 1 is not in use
+ EXPECT_FALSE(allocator->InUse(1));
+
+ // Allocate an ID, check that it's in use.
+ ResourceId id1 = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(id1));
+
+ // Allocate another ID, check that it's in use, and different from the first
+ // one.
+ ResourceId id2 = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(id2));
+ EXPECT_NE(id1, id2);
+
+ // Free one of the IDs, check that it's not in use any more.
+ allocator->FreeID(id1);
+ EXPECT_FALSE(allocator->InUse(id1));
+
+ // Frees the other ID, check that it's not in use any more.
+ allocator->FreeID(id2);
+ EXPECT_FALSE(allocator->InUse(id2));
+}
+
+// Checks that the resource IDs are re-used after being freed.
+TEST_F(IdAllocatorTest, TestAdvanced) {
+ IdAllocator *allocator = id_allocator();
+
+ // Allocate the highest possible ID, to make life awkward.
+ allocator->AllocateIDAtOrAbove(-1);
+
+ // Allocate a significant number of resources.
+ const unsigned int kNumResources = 100;
+ ResourceId ids[kNumResources];
+ for (unsigned int i = 0; i < kNumResources; ++i) {
+ ids[i] = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(ids[i]));
+ }
+
+ // Check that a new allocation re-uses the resource we just freed.
+ ResourceId id1 = ids[kNumResources / 2];
+ allocator->FreeID(id1);
+ EXPECT_FALSE(allocator->InUse(id1));
+ ResourceId id2 = allocator->AllocateID();
+ EXPECT_TRUE(allocator->InUse(id2));
+ EXPECT_EQ(id1, id2);
+}
+
+// Checks that we can choose our own ids and they won't be reused.
+TEST_F(IdAllocatorTest, MarkAsUsed) {
+ IdAllocator* allocator = id_allocator();
+ ResourceId id = allocator->AllocateID();
+ allocator->FreeID(id);
+ EXPECT_FALSE(allocator->InUse(id));
+ EXPECT_TRUE(allocator->MarkAsUsed(id));
+ EXPECT_TRUE(allocator->InUse(id));
+ ResourceId id2 = allocator->AllocateID();
+ EXPECT_NE(id, id2);
+ EXPECT_TRUE(allocator->MarkAsUsed(id2 + 1));
+ ResourceId id3 = allocator->AllocateID();
+ // Checks our algorithm. If the algorithm changes this check should be
+ // changed.
+ EXPECT_EQ(id3, id2 + 2);
+}
+
+// Checks AllocateIdAtOrAbove.
+TEST_F(IdAllocatorTest, AllocateIdAtOrAbove) {
+ const ResourceId kOffset = 123456;
+ IdAllocator* allocator = id_allocator();
+ ResourceId id1 = allocator->AllocateIDAtOrAbove(kOffset);
+ EXPECT_EQ(kOffset, id1);
+ ResourceId id2 = allocator->AllocateIDAtOrAbove(kOffset);
+ EXPECT_GT(id2, kOffset);
+ ResourceId id3 = allocator->AllocateIDAtOrAbove(kOffset);
+ EXPECT_GT(id3, kOffset);
+}
+
+// Checks that AllocateIdAtOrAbove wraps around at the maximum 32-bit value.
+TEST_F(IdAllocatorTest, AllocateIdAtOrAboveWrapsAround) {
+ const ResourceId kMaxPossibleOffset = -1;
+ IdAllocator* allocator = id_allocator();
+ ResourceId id1 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset);
+ EXPECT_EQ(kMaxPossibleOffset, id1);
+ ResourceId id2 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset);
+ EXPECT_EQ(1u, id2);
+ ResourceId id3 = allocator->AllocateIDAtOrAbove(kMaxPossibleOffset);
+ EXPECT_EQ(2u, id3);
+}
+
+TEST_F(IdAllocatorTest, RedundantFreeIsIgnored) {
+ IdAllocator* allocator = id_allocator();
+ ResourceId id1 = allocator->AllocateID();
+ allocator->FreeID(0);
+ allocator->FreeID(id1);
+ allocator->FreeID(id1);
+ allocator->FreeID(id1 + 1);
+
+ ResourceId id2 = allocator->AllocateID();
+ ResourceId id3 = allocator->AllocateID();
+ EXPECT_NE(id2, id3);
+ EXPECT_NE(kInvalidResource, id2);
+ EXPECT_NE(kInvalidResource, id3);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/logging.cc b/chromium/gpu/command_buffer/common/logging.cc
new file mode 100644
index 00000000000..4bc35103008
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/logging.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/logging.h"
+
+#include <iostream>
+
+namespace gpu {
+
+std::ostream& Logger::stream() {
+ return std::cerr;
+}
+
+Logger::~Logger() {
+ if (!condition_) {
+ std::cerr << std::endl;
+ std::cerr.flush();
+ if (level_ == FATAL)
+ assert(false);
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/logging.h b/chromium/gpu/command_buffer/common/logging.h
new file mode 100644
index 00000000000..2133a87bc0a
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/logging.h
@@ -0,0 +1,221 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_LOGGING_H_
+#define GPU_COMMAND_BUFFER_COMMON_LOGGING_H_
+
+#include <assert.h>
+
+#include <ostream>
+
+#include "gpu/command_buffer/common/gles2_utils_export.h"
+
+// Windows defines an ERROR macro.
+#ifdef ERROR
+#undef ERROR
+#endif
+
+namespace gpu {
+
+// Members are uppercase instead of kCamelCase for consistency with base log
+// severity enum.
+enum LogLevel {
+ INFO,
+ WARNING,
+ ERROR,
+ FATAL
+};
+
+// This is a very simple logger for use in command buffer code. Common and
+// command buffer code cannot be dependent on base. It just outputs the message
+// to stderr.
+class GLES2_UTILS_EXPORT Logger {
+ public:
+ Logger(bool condition, LogLevel level)
+ : condition_(condition),
+ level_(level) {
+ }
+
+ template <typename X>
+ static Logger CheckTrue(const X& x,
+ const char* file, int line,
+ const char* x_name,
+ const char* check_name) {
+ if (!!x)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << ")) failed. ";
+ }
+
+ template <typename X, typename Y>
+ static Logger CheckEqual(const X& x, const Y& y,
+ const char* file, int line,
+ const char* x_name, const char* y_name,
+ const char* check_name) {
+ if (x == y)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << "), "
+ << y_name << "(" << y << ")) failed. ";
+ }
+
+ template <typename X, typename Y>
+ static Logger CheckNotEqual(const X& x, const Y& y,
+ const char* file, int line,
+ const char* x_name, const char* y_name,
+ const char* check_name) {
+ if (x != y)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << "), "
+ << y_name << "(" << y << ")) failed. ";
+ }
+
+ template <typename X, typename Y>
+ static Logger CheckLessThan(const X& x, const Y& y,
+ const char* file, int line,
+ const char* x_name, const char* y_name,
+ const char* check_name) {
+ if (x < y)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << "), "
+ << y_name << "(" << y << ")) failed. ";
+ }
+
+ template <typename X, typename Y>
+ static Logger CheckGreaterThan(const X& x, const Y& y,
+ const char* file, int line,
+ const char* x_name, const char* y_name,
+ const char* check_name) {
+ if (x > y)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << "), "
+ << y_name << "(" << y << ")) failed. ";
+ }
+
+ template <typename X, typename Y>
+ static Logger CheckLessEqual(const X& x, const Y& y,
+ const char* file, int line,
+ const char* x_name, const char* y_name,
+ const char* check_name) {
+ if (x <= y)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << "), "
+ << y_name << "(" << y << ")) failed. ";
+ }
+
+ template <typename X, typename Y>
+ static Logger CheckGreaterEqual(const X& x, const Y& y,
+ const char* file, int line,
+ const char* x_name, const char* y_name,
+ const char* check_name) {
+ if (x >= y)
+ return Logger(true, FATAL);
+
+ return Logger(false, FATAL)
+ << file << "(" << line << "): " << check_name
+ << "(" << x_name << " (" << x << "), "
+ << y_name << "(" << y << ")) failed. ";
+ }
+
+ // Retrieves the stream that we write to. This header cannot depend on
+ // <iostream> because that will add static initializers to all files that
+ // include this header.
+ std::ostream& stream();
+
+ ~Logger();
+
+ template <typename T>
+ Logger& operator<<(const T& value) {
+ if (!condition_)
+ stream() << value;
+ return *this;
+ }
+
+ private:
+ Logger(const Logger& logger)
+ : condition_(logger.condition_),
+ level_(logger.level_) {
+ }
+
+ const bool condition_;
+ const LogLevel level_;
+};
+
+} // namespace gpu
+
+#define GPU_CHECK(X) ::gpu::Logger::CheckTrue( \
+ (X), __FILE__, __LINE__, #X, "GPU_CHECK")
+#define GPU_CHECK_EQ(X, Y) ::gpu::Logger::CheckEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_CHECK_EQ")
+#define GPU_CHECK_NE(X, Y) ::gpu::Logger::CheckNotEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_CHECK_NE")
+#define GPU_CHECK_GT(X, Y) ::gpu::Logger::CheckGreaterThan( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_CHECK_GT")
+#define GPU_CHECK_LT(X, Y) ::gpu::Logger::CheckLessThan( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_CHECK_LT")
+#define GPU_CHECK_GE(X, Y) ::gpu::Logger::CheckGreaterEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_CHECK_GE")
+#define GPU_CHECK_LE(X, Y) ::gpu::Logger::CheckLessEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_CHECK_LE")
+#define GPU_LOG(LEVEL) ::gpu::Logger(false, LEVEL)
+
+
+#if defined(NDEBUG)
+#define GPU_DEBUG_IS_ON false
+#else
+#define GPU_DEBUG_IS_ON true
+#endif
+
+
+#define GPU_DCHECK(X) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckTrue( \
+ (X), __FILE__, __LINE__, #X, "GPU_DCHECK")
+#define GPU_DCHECK_EQ(X, Y) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_DCHECK_EQ")
+#define GPU_DCHECK_NE(X, Y) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckNotEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_DCHECK_NE")
+#define GPU_DCHECK_GT(X, Y) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckGreaterThan( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_DCHECK_GT")
+#define GPU_DCHECK_LT(X, Y) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckLessThan( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_DCHECK_LT")
+#define GPU_DCHECK_GE(X, Y) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckGreaterEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_DCHECK_GE")
+#define GPU_DCHECK_LE(X, Y) \
+ if (GPU_DEBUG_IS_ON) \
+ ::gpu::Logger::CheckLessEqual( \
+ (X), (Y), __FILE__, __LINE__, #X, #Y, "GPU_DCHECK_LE")
+#define GPU_DLOG(LEVEL) if (GPU_DEBUG_IS_ON) ::gpu::Logger(true, LEVEL)
+
+
+
+#define GPU_NOTREACHED() GPU_DCHECK(false)
+
+#endif // GPU_COMMAND_BUFFER_COMMON_LOGGING_H_
diff --git a/chromium/gpu/command_buffer/common/logging_android.cc b/chromium/gpu/command_buffer/common/logging_android.cc
new file mode 100644
index 00000000000..d660080d4c7
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/logging_android.cc
@@ -0,0 +1,33 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <android/log.h>
+#include <iostream>
+#include <sstream>
+
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+
+namespace {
+std::stringstream* g_log;
+const char* kLogTag = "chromium-gpu";
+}
+
+std::ostream& Logger::stream() {
+ if (!g_log)
+ g_log = new std::stringstream();
+ return *g_log;
+}
+
+Logger::~Logger() {
+ if (!condition_) {
+ __android_log_print(ANDROID_LOG_INFO, kLogTag, "%s", g_log->str().c_str());
+ g_log->str(std::string());
+ if (level_ == FATAL)
+ assert(false);
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/mailbox.cc b/chromium/gpu/command_buffer/common/mailbox.cc
new file mode 100644
index 00000000000..be2bebf9653
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/mailbox.cc
@@ -0,0 +1,34 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/common/mailbox.h"
+
+#include <string.h>
+
+#include "gpu/command_buffer/common/logging.h"
+
+namespace gpu {
+
+Mailbox::Mailbox() {
+ memset(name, 0, sizeof(name));
+}
+
+bool Mailbox::IsZero() const {
+ for (size_t i = 0; i < arraysize(name); ++i) {
+ if (name[i])
+ return false;
+ }
+ return true;
+}
+
+void Mailbox::SetZero() {
+ memset(name, 0, sizeof(name));
+}
+
+void Mailbox::SetName(const int8* n) {
+ GPU_DCHECK(IsZero() || !memcmp(name, n, sizeof(name)));
+ memcpy(name, n, sizeof(name));
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/common/mailbox.h b/chromium/gpu/command_buffer/common/mailbox.h
new file mode 100644
index 00000000000..d0e4c2c9a57
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/mailbox.h
@@ -0,0 +1,24 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_MAILBOX_H_
+#define GPU_COMMAND_BUFFER_MAILBOX_H_
+
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+struct GPU_EXPORT Mailbox {
+ Mailbox();
+ bool IsZero() const;
+ void SetZero();
+ void SetName(const int8* name);
+ int8 name[64];
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_MAILBOX_H_
+
diff --git a/chromium/gpu/command_buffer/common/thread_local.h b/chromium/gpu/command_buffer/common/thread_local.h
new file mode 100644
index 00000000000..bc9ff66b528
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/thread_local.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Functions for allocating and accessing thread local values via key.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_THREAD_LOCAL_H_
+#define GPU_COMMAND_BUFFER_COMMON_THREAD_LOCAL_H_
+
+#if defined(_WIN32)
+#include <windows.h>
+#else
+#include <pthread.h>
+#endif
+
+namespace gpu {
+
+#if defined(_WIN32)
+typedef DWORD ThreadLocalKey;
+#else
+typedef pthread_key_t ThreadLocalKey;
+#endif
+
+inline ThreadLocalKey ThreadLocalAlloc() {
+#if defined(_WIN32)
+ return TlsAlloc();
+#else
+ ThreadLocalKey key;
+ pthread_key_create(&key, NULL);
+ return key;
+#endif
+}
+
+inline void ThreadLocalFree(ThreadLocalKey key) {
+#if defined(_WIN32)
+ TlsFree(key);
+#else
+ pthread_key_delete(key);
+#endif
+}
+
+inline void ThreadLocalSetValue(ThreadLocalKey key, void* value) {
+#if defined(_WIN32)
+ TlsSetValue(key, value);
+#else
+ pthread_setspecific(key, value);
+#endif
+}
+
+inline void* ThreadLocalGetValue(ThreadLocalKey key) {
+#if defined(_WIN32)
+ return TlsGetValue(key);
+#else
+ return pthread_getspecific(key);
+#endif
+}
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_THREAD_LOCAL_H_
diff --git a/chromium/gpu/command_buffer/common/time.h b/chromium/gpu/command_buffer/common/time.h
new file mode 100644
index 00000000000..e4eb9422e7b
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/time.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_TIME_H_
+#define GPU_COMMAND_BUFFER_COMMON_TIME_H_
+
+#if !defined(__native_client__)
+
+#include "base/time/time.h"
+
+namespace gpu {
+
+inline uint64 MicrosecondsSinceOriginOfTime() {
+ return (base::TimeTicks::HighResNow() - base::TimeTicks()).InMicroseconds();
+}
+
+} // namespace gpu
+
+#else
+
+namespace gpu {
+
+inline uint64 MicrosecondsSinceOriginOfTime() {
+ return 0;
+}
+
+} // namespace gpu
+
+#endif // __native_client__
+
+#endif // GPU_COMMAND_BUFFER_COMMON_TIME_H_
diff --git a/chromium/gpu/command_buffer/common/trace_event.h b/chromium/gpu/command_buffer/common/trace_event.h
new file mode 100644
index 00000000000..e63517e5236
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/trace_event.h
@@ -0,0 +1,10 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_TRACE_EVENT_H_
+#define GPU_COMMAND_BUFFER_COMMON_TRACE_EVENT_H_
+
+#include "base/debug/trace_event.h"
+
+#endif // GPU_COMMAND_BUFFER_COMMON_TRACE_EVENT_H_
diff --git a/chromium/gpu/command_buffer/common/types.h b/chromium/gpu/command_buffer/common/types.h
new file mode 100644
index 00000000000..718ecca6763
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/types.h
@@ -0,0 +1,186 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains cross-platform basic type definitions
+
+#ifndef GPU_COMMAND_BUFFER_COMMON_TYPES_H_
+#define GPU_COMMAND_BUFFER_COMMON_TYPES_H_
+
+#if !defined(_MSC_VER)
+#include <stdint.h>
+#endif
+#include <cstddef>
+#include <string>
+
+typedef signed char schar;
+typedef signed char int8;
+// TODO(mbelshe) Remove these type guards. These are
+// temporary to avoid conflicts with npapi.h.
+#ifndef _INT16
+#define _INT16
+typedef short int16;
+#endif
+#ifndef _INT32
+#define _INT32
+typedef int int32;
+#endif
+
+// The NSPR system headers define 64-bit as |long| when possible. In order to
+// not have typedef mismatches, we do the same on LP64.
+#if defined(__LP64__) && !defined(__APPLE__) && !defined(__OpenBSD__)
+typedef long int64;
+#else
+typedef long long int64;
+#endif
+
+// NOTE: unsigned types are DANGEROUS in loops and other arithmetical
+// places. Use the signed types unless your variable represents a bit
+// pattern (eg a hash value) or you really need the extra bit. Do NOT
+// use 'unsigned' to express "this value should always be positive";
+// use assertions for this.
+
+typedef unsigned char uint8;
+// TODO(mbelshe) Remove these type guards. These are
+// temporary to avoid conflicts with npapi.h.
+#ifndef _UINT16
+#define _UINT16
+typedef unsigned short uint16;
+#endif
+#ifndef _UINT32
+#define _UINT32
+typedef unsigned int uint32;
+#endif
+
+// See the comment above about NSPR and 64-bit.
+#if defined(__LP64__) && !defined(__APPLE__) && !defined(__OpenBSD__)
+typedef unsigned long uint64;
+#else
+typedef unsigned long long uint64;
+#endif
+
+// A macro to disallow the copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ TypeName(const TypeName&); \
+ void operator=(const TypeName&)
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName(); \
+ DISALLOW_COPY_AND_ASSIGN(TypeName)
+
+// The arraysize(arr) macro returns the # of elements in an array arr.
+// The expression is a compile-time constant, and therefore can be
+// used in defining new arrays, for example. If you use arraysize on
+// a pointer by mistake, you will get a compile-time error.
+//
+// One caveat is that arraysize() doesn't accept any array of an
+// anonymous type or a type defined inside a function. In these rare
+// cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is
+// due to a limitation in C++'s template system. The limitation might
+// eventually be removed, but it hasn't happened yet.
+
+// This template function declaration is used in defining arraysize.
+// Note that the function doesn't need an implementation, as we only
+// use its type.
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+
+// That gcc wants both of these prototypes seems mysterious. VC, for
+// its part, can't decide which to use (another mystery). Matching of
+// template overloads: the final frontier.
+#if !defined(_MSC_VER)
+template <typename T, size_t N>
+char (&ArraySizeHelper(const T (&array)[N]))[N];
+#endif
+
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+// The COMPILE_ASSERT macro can be used to verify that a compile time
+// expression is true. For example, you could use it to verify the
+// size of a static array:
+//
+// COMPILE_ASSERT(ARRAYSIZE_UNSAFE(content_type_names) == CONTENT_NUM_TYPES,
+// content_type_names_incorrect_size);
+//
+// or to make sure a struct is smaller than a certain size:
+//
+// COMPILE_ASSERT(sizeof(foo) < 128, foo_too_large);
+//
+// The second argument to the macro is the name of the variable. If
+// the expression is false, most compilers will issue a warning/error
+// containing the name of the variable.
+
+template <bool>
+struct GpuCompileAssert {
+};
+
+#undef COMPILE_ASSERT
+#define COMPILE_ASSERT(expr, msg) \
+ typedef GpuCompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1]
+
+// Implementation details of COMPILE_ASSERT:
+//
+// - COMPILE_ASSERT works by defining an array type that has -1
+// elements (and thus is invalid) when the expression is false.
+//
+// - The simpler definition
+//
+// #define COMPILE_ASSERT(expr, msg) typedef char msg[(expr) ? 1 : -1]
+//
+// does not work, as gcc supports variable-length arrays whose sizes
+// are determined at run-time (this is gcc's extension and not part
+// of the C++ standard). As a result, gcc fails to reject the
+// following code with the simple definition:
+//
+// int foo;
+// COMPILE_ASSERT(foo, msg); // not supposed to compile as foo is
+// // not a compile-time constant.
+//
+// - By using the type CompileAssert<(bool(expr))>, we ensures that
+// expr is a compile-time constant. (Template arguments must be
+// determined at compile-time.)
+//
+// - The outter parentheses in CompileAssert<(bool(expr))> are necessary
+// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written
+//
+// CompileAssert<bool(expr)>
+//
+// instead, these compilers will refuse to compile
+//
+// COMPILE_ASSERT(5 > 0, some_message);
+//
+// (They seem to think the ">" in "5 > 0" marks the end of the
+// template argument list.)
+//
+// - The array size is (bool(expr) ? 1 : -1), instead of simply
+//
+// ((expr) ? 1 : -1).
+//
+// This is to avoid running into a bug in MS VC 7.1, which
+// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1.
+
+namespace gpu {
+#if defined(_MSC_VER)
+typedef short Int16;
+typedef unsigned short Uint16;
+typedef int Int32;
+typedef unsigned int Uint32;
+#else
+typedef int16_t Int16;
+typedef uint16_t Uint16;
+typedef int32_t Int32;
+typedef uint32_t Uint32;
+#endif
+
+typedef std::string String;
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_COMMON_TYPES_H_
diff --git a/chromium/gpu/command_buffer/common/unittest_main.cc b/chromium/gpu/command_buffer/common/unittest_main.cc
new file mode 100644
index 00000000000..08c4b348038
--- /dev/null
+++ b/chromium/gpu/command_buffer/common/unittest_main.cc
@@ -0,0 +1,22 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+
+int main(int argc, char** argv) {
+ // On Android, AtExitManager is created in
+ // testing/android/native_test_wrapper.cc before main() is called.
+ // The same thing is also done in base/test/test_suite.cc
+#if !defined(OS_ANDROID)
+ base::AtExitManager exit_manager;
+#endif
+ CommandLine::Init(argc, argv);
+ gfx::InitializeGLBindings(gfx::kGLImplementationMockGL);
+ testing::InitGoogleMock(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/chromium/gpu/command_buffer/docs/gles2_cmd_format_docs.txt b/chromium/gpu/command_buffer/docs/gles2_cmd_format_docs.txt
new file mode 100644
index 00000000000..67306abe2db
--- /dev/null
+++ b/chromium/gpu/command_buffer/docs/gles2_cmd_format_docs.txt
@@ -0,0 +1,2262 @@
+//! \file
+//!
+//! The public interface for 3D graphics is based on a command buffer.
+//!
+//! This was chosen because it provides an easy way to separate the process of
+//! writing commands from the process of reading those commands without
+//! requiring too much overhead to keep the two processes in sync.
+//!
+//! You can use this info to write commands yourself. Most developers will use
+//! the provided OpenGL ES 2.0 implementation that issues these commands for
+//! them.
+//!
+//! Each command starts with a header. The header is 32 bits, where the first 21
+//! bits define the number of 32 bit entries, including the header, the command
+//! represents. The last 11 bits specify the command.
+//!
+//! Commands that send a variable amount of data have 1 to 3 ways to send that
+//! data.
+//!
+//! Many commands can send their data in shared memory. The command will take
+//! an id of the shared memory and an offset into that shared memory of where
+//! the data lives. Commands are executed asynchronously, so the client
+//! program must be careful to leave the data available until the command has
+//! executed.
+//!
+//! Some commands have an 'immediate' version where the data appears directly
+//! after the command in memory.
+//!
+//! A 3rd way of passing data is through Buckets. Buckets are identified by
+//! number. You create a bucket with the command SetBucketSize, you can then
+//! fill the bucket with SetBucketData commands. Once you've sent all your
+//! data you can then issue a command that uses the bucket and takes a bucket
+//! id for which bucket to use.
+//!
+//! Receiving data works similarly. Some commands return their data to shared
+//! memory. Other commands return their data through buckets which can then be
+//! queried with the GetBucketSize and GetBucketData commands. In either case
+//! the data will not be available until the command executes.
+//!
+//! All commands and arguments are validated. If a command fails validation the
+//! service will stop processing commands. It is the responsibility of the
+//! client to never issue an invalid command.
+//!
+//! Examples of invalid commands.
+//! - A command's size does not match the command.
+//! - A command's size would address memory outside the command buffer
+//! - A shared memory id is invalid
+//! - A shared memory offset is out of range for the given shared memory
+//! - The size of the data a command would access in shared memory is out of
+//! range for the given shared memory buffer.
+//! - A result (in the transfer buffer) is not initialized to the
+//! failure case. For example, any command that returns a SizedResult
+//! will take a shared memory id and offset to where to store the result.
+//! That size field of the result must be set to 0 before issuing the
+//! the command. That way, if the command buffer service fails the
+//! client will see a 0 size.
+//!
+//! The docs are a little terse. For any command that corresponds to an OpenGL
+//! ES 2.0 function the arguments should be clear by looking at the OpenGL ES
+//! 2.0 documentation with minor caveats.
+//!
+//! - Client side arrays are not supported at the command buffer level
+//! so DrawArrays and VertexAttribPointer only take offsets into buffers.
+//! - The commands GenBuffers, GetTextures, CreateProgram, CreateShader, etc
+//! take client side ids and register them with the service. It's up to the
+//! client to make up the ids.
+//! - For shared resources, it's still up to the client to make up ids.
+//! but to help keep them in sync with other threads the commands
+//! GenSharedIds, RegisterSharedIds and DeleteSharedIds can be used.
+//!
+
+//! The command header.
+struct CommandHeader {
+ Uint32 size:21;
+ Uint32 command:11;
+};
+
+
+//! Used for some glGetXXX commands that return a result through a pointer. We
+//! need to know if the command succeeded or not and the size of the result. If
+//! the command failed its result size will 0. You must set the size to 0
+//! before issuing the command.
+//!
+//! To retrieve the data you might do something like this pseudo code:
+//!
+//! GetAttachedShaders::Result* result = address-of-shared-memory
+//! int num_results = result->size / sizeof(GLuint); // the type returned
+//! GLuint* results = &result->data;
+//! for (int ii = 0; ii < num_results; ++ii) {
+//! printf("%d\n", results[ii]);
+//! }
+//!
+template <typename T>
+struct SizedResult {
+ uint32 size; // in bytes.
+ T data; // this is just here to get an offset.
+};
+
+
+//! A Noop command.
+struct Noop {
+ static const CommandId kCmdId = 0;
+
+ CommandHeader header;
+};
+
+//! The SetToken command puts a token in the command stream that you can
+//! use to check if that token has been passed in the command stream.
+struct SetToken {
+ static const CommandId kCmdId = 1;
+
+ CommandHeader header;
+ uint32 token;
+};
+
+//! The Jump command jumps to another place in the command buffer.
+struct Jump {
+ static const CommandId kCmdId = 3;
+
+ CommandHeader header;
+ uint32 offset;
+};
+
+//! The JumpRelative command jumps to another place in the command buffer
+//! relative to the end of this command. In other words. JumpRelative with an
+//! offset of zero is effectively a no-op.
+struct JumpRelative {
+ static const CommandId kCmdId = 4;
+
+ CommandHeader header;
+ int32 offset;
+};
+
+//! The Call command jumps to a subroutine which can be returned from with the
+//! Return command.
+struct Call {
+ static const CommandId kCmdId = 5;
+
+ CommandHeader header;
+ uint32 offset;
+};
+
+//! The CallRelative command jumps to a subroutine using a relative offset. The
+//! offset is relative to the end of this command..
+struct CallRelative {
+ static const CommandId kCmdId = 6;
+
+ CommandHeader header;
+ int32 offset;
+};
+
+//! Returns from a subroutine called by the Call or CallRelative commands.
+struct Return {
+ static const CommandId kCmdId = 7;
+
+ CommandHeader header;
+};
+
+//! Sets the size of a bucket for collecting data on the service side.
+//! This is a utility for gathering data on the service side so it can be used
+//! all at once when some service side API is called. It removes the need to
+//! add special commands just to support a particular API. For example, any API
+//! command that needs a string needs a way to send that string to the API over
+//! the command buffers. While you can require that the command buffer or
+//! transfer buffer be large enough to hold the largest string you can send,
+//! using this command removes that restriction by letting you send smaller
+//! pieces over and build up the data on the service side.
+//!
+//! You can clear a bucket on the service side and thereby free memory by
+//! sending a size of 0.
+struct SetBucketSize {
+ static const CommandId kCmdId = 8;
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 size;
+};
+
+//! Sets the contents of a portion of a bucket on the service side from data in
+//! shared memory.
+//! See SetBucketSize.
+struct SetBucketData {
+ static const CommandId kCmdId = 9;
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 offset;
+ uint32 size;
+ uint32 shared_memory_id;
+ uint32 shared_memory_offset;
+};
+
+//! Sets the contents of a portion of a bucket on the service side from data in
+//! the command buffer.
+//! See SetBucketSize.
+struct SetBucketDataImmediate {
+ static const CommandId kCmdId = 10;
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 offset;
+ uint32 size;
+};
+
+//! Gets the size of a bucket the service has available. Sending a variable
+//! size result back to the client, for example any API that returns a string,
+//! is problematic since the largest thing you can send back is the size of
+//! your shared memory. This command along with GetBucketData implements a way
+//! to get a result a piece at a time to help solve that problem in a generic
+//! way.
+struct GetBucketSize {
+ static const CommandId kCmdId = 11;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 shared_memory_id;
+ uint32 shared_memory_offset;
+};
+
+//! Gets a piece of a result the service has available.
+//! See GetBucketSize.
+struct GetBucketData {
+ static const CommandId kCmdId = 12;
+
+ CommandHeader header;
+ uint32 bucket_id;
+ uint32 offset;
+ uint32 size;
+ uint32 shared_memory_id;
+ uint32 shared_memory_offset;
+};
+
+// OpenGL ES 2.0 related commands.
+
+//! Command that corresponds to glActiveTexture.
+struct ActiveTexture {
+ static const CommandId kCmdId = 256;
+
+ CommandHeader header;
+ uint32 texture; //!< GLenum
+};
+
+//! Command that corresponds to glAttachShader.
+struct AttachShader {
+ static const CommandId kCmdId = 257;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 shader; //!< GLuint
+};
+
+//! Command that corresponds to glBindAttribLocation.
+struct BindAttribLocation {
+ static const CommandId kCmdId = 258;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 index; //!< GLuint
+ uint32 name_shm_id; //!< uint32
+ uint32 name_shm_offset; //!< uint32
+ uint32 data_size; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glBindAttribLocation.
+struct BindAttribLocationImmediate {
+ static const CommandId kCmdId = 259;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 index; //!< GLuint
+ uint32 data_size; //!< uint32
+};
+
+//! Bucket version of command that corresponds to glBindAttribLocation.
+struct BindAttribLocationBucket {
+ static const CommandId kCmdId = 432;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 index; //!< GLuint
+ uint32 name_bucket_id; //!< uint32
+};
+
+//! Command that corresponds to glBindBuffer.
+struct BindBuffer {
+ static const CommandId kCmdId = 260;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 buffer; //!< GLuint
+};
+
+//! Command that corresponds to glBindFramebuffer.
+struct BindFramebuffer {
+ static const CommandId kCmdId = 261;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 framebuffer; //!< GLuint
+};
+
+//! Command that corresponds to glBindRenderbuffer.
+struct BindRenderbuffer {
+ static const CommandId kCmdId = 262;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 renderbuffer; //!< GLuint
+};
+
+//! Command that corresponds to glBindTexture.
+struct BindTexture {
+ static const CommandId kCmdId = 263;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 texture; //!< GLuint
+};
+
+//! Command that corresponds to glBlendColor.
+struct BlendColor {
+ static const CommandId kCmdId = 264;
+
+ CommandHeader header;
+ float red; //!< GLclampf
+ float green; //!< GLclampf
+ float blue; //!< GLclampf
+ float alpha; //!< GLclampf
+};
+
+//! Command that corresponds to glBlendEquation.
+struct BlendEquation {
+ static const CommandId kCmdId = 265;
+
+ CommandHeader header;
+ uint32 mode; //!< GLenum
+};
+
+//! Command that corresponds to glBlendEquationSeparate.
+struct BlendEquationSeparate {
+ static const CommandId kCmdId = 266;
+
+ CommandHeader header;
+ uint32 modeRGB; //!< GLenum
+ uint32 modeAlpha; //!< GLenum
+};
+
+//! Command that corresponds to glBlendFunc.
+struct BlendFunc {
+ static const CommandId kCmdId = 267;
+
+ CommandHeader header;
+ uint32 sfactor; //!< GLenum
+ uint32 dfactor; //!< GLenum
+};
+
+//! Command that corresponds to glBlendFuncSeparate.
+struct BlendFuncSeparate {
+ static const CommandId kCmdId = 268;
+
+ CommandHeader header;
+ uint32 srcRGB; //!< GLenum
+ uint32 dstRGB; //!< GLenum
+ uint32 srcAlpha; //!< GLenum
+ uint32 dstAlpha; //!< GLenum
+};
+
+//! Command that corresponds to glBufferData.
+struct BufferData {
+ static const CommandId kCmdId = 269;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 size; //!< GLsizeiptr
+ uint32 data_shm_id; //!< uint32
+ uint32 data_shm_offset; //!< uint32
+ uint32 usage; //!< GLenum
+};
+
+//! Immediate version of command that corresponds to glBufferData.
+struct BufferDataImmediate {
+ static const CommandId kCmdId = 270;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 size; //!< GLsizeiptr
+ uint32 usage; //!< GLenum
+};
+
+//! Command that corresponds to glBufferSubData.
+struct BufferSubData {
+ static const CommandId kCmdId = 271;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 offset; //!< GLintptr
+ int32 size; //!< GLsizeiptr
+ uint32 data_shm_id; //!< uint32
+ uint32 data_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glBufferSubData.
+struct BufferSubDataImmediate {
+ static const CommandId kCmdId = 272;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 offset; //!< GLintptr
+ int32 size; //!< GLsizeiptr
+};
+
+//! Command that corresponds to glCheckFramebufferStatus.
+struct CheckFramebufferStatus {
+ static const CommandId kCmdId = 273;
+
+ typedef GLenum Result;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glClear.
+struct Clear {
+ static const CommandId kCmdId = 274;
+
+ CommandHeader header;
+ uint32 mask; //!< GLbitfield
+};
+
+//! Command that corresponds to glClearColor.
+struct ClearColor {
+ static const CommandId kCmdId = 275;
+
+ CommandHeader header;
+ float red; //!< GLclampf
+ float green; //!< GLclampf
+ float blue; //!< GLclampf
+ float alpha; //!< GLclampf
+};
+
+//! Command that corresponds to glClearDepthf.
+struct ClearDepthf {
+ static const CommandId kCmdId = 276;
+
+ CommandHeader header;
+ float depth; //!< GLclampf
+};
+
+//! Command that corresponds to glClearStencil.
+struct ClearStencil {
+ static const CommandId kCmdId = 277;
+
+ CommandHeader header;
+ int32 s; //!< GLint
+};
+
+//! Command that corresponds to glColorMask.
+struct ColorMask {
+ static const CommandId kCmdId = 278;
+
+ CommandHeader header;
+ uint32 red; //!< GLboolean
+ uint32 green; //!< GLboolean
+ uint32 blue; //!< GLboolean
+ uint32 alpha; //!< GLboolean
+};
+
+//! Command that corresponds to glCompileShader.
+struct CompileShader {
+ static const CommandId kCmdId = 279;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+};
+
+//! Command that corresponds to glCompressedTexImage2D.
+struct CompressedTexImage2D {
+ static const CommandId kCmdId = 280;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ uint32 internalformat; //!< GLenum
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ int32 border; //!< GLint
+ int32 imageSize; //!< GLsizei
+ uint32 data_shm_id; //!< uint32
+ uint32 data_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glCompressedTexImage2D.
+struct CompressedTexImage2DImmediate {
+ static const CommandId kCmdId = 281;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ uint32 internalformat; //!< GLenum
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ int32 border; //!< GLint
+ int32 imageSize; //!< GLsizei
+};
+
+//! Bucket version of command that corresponds to glCompressedTexImage2D.
+struct CompressedTexImage2DBucket {
+ static const CommandId kCmdId = 443;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ uint32 internalformat; //!< GLenum
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ int32 border; //!< GLint
+ uint32 bucket_id; //!< GLuint
+};
+
+//! Command that corresponds to glCompressedTexSubImage2D.
+struct CompressedTexSubImage2D {
+ static const CommandId kCmdId = 282;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 xoffset; //!< GLint
+ int32 yoffset; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ uint32 format; //!< GLenum
+ int32 imageSize; //!< GLsizei
+ uint32 data_shm_id; //!< uint32
+ uint32 data_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glCompressedTexSubImage2D.
+struct CompressedTexSubImage2DImmediate {
+ static const CommandId kCmdId = 283;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 xoffset; //!< GLint
+ int32 yoffset; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ uint32 format; //!< GLenum
+ int32 imageSize; //!< GLsizei
+};
+
+//! Bucket version of command that corresponds to glCompressedTexSubImage2D.
+struct CompressedTexSubImage2DBucket {
+ static const CommandId kCmdId = 444;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 xoffset; //!< GLint
+ int32 yoffset; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ uint32 format; //!< GLenum
+ uint32 bucket_id; //!< GLuint
+};
+
+//! Command that corresponds to glCopyTexImage2D.
+struct CopyTexImage2D {
+ static const CommandId kCmdId = 284;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ uint32 internalformat; //!< GLenum
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ int32 border; //!< GLint
+};
+
+//! Command that corresponds to glCopyTexSubImage2D.
+struct CopyTexSubImage2D {
+ static const CommandId kCmdId = 285;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 xoffset; //!< GLint
+ int32 yoffset; //!< GLint
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+};
+
+//! Command that corresponds to glCreateProgram.
+struct CreateProgram {
+ static const CommandId kCmdId = 286;
+
+ CommandHeader header;
+ uint32 client_id; //!< uint32
+};
+
+//! Command that corresponds to glCreateShader.
+struct CreateShader {
+ static const CommandId kCmdId = 287;
+
+ CommandHeader header;
+ uint32 type; //!< GLenum
+ uint32 client_id; //!< uint32
+};
+
+//! Command that corresponds to glCullFace.
+struct CullFace {
+ static const CommandId kCmdId = 288;
+
+ CommandHeader header;
+ uint32 mode; //!< GLenum
+};
+
+//! Command that corresponds to glDeleteBuffers.
+struct DeleteBuffers {
+ static const CommandId kCmdId = 289;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 buffers_shm_id; //!< uint32
+ uint32 buffers_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glDeleteBuffers.
+struct DeleteBuffersImmediate {
+ static const CommandId kCmdId = 290;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glDeleteFramebuffers.
+struct DeleteFramebuffers {
+ static const CommandId kCmdId = 291;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 framebuffers_shm_id; //!< uint32
+ uint32 framebuffers_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glDeleteFramebuffers.
+struct DeleteFramebuffersImmediate {
+ static const CommandId kCmdId = 292;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glDeleteProgram.
+struct DeleteProgram {
+ static const CommandId kCmdId = 293;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+};
+
+//! Command that corresponds to glDeleteRenderbuffers.
+struct DeleteRenderbuffers {
+ static const CommandId kCmdId = 294;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 renderbuffers_shm_id; //!< uint32
+ uint32 renderbuffers_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glDeleteRenderbuffers.
+struct DeleteRenderbuffersImmediate {
+ static const CommandId kCmdId = 295;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glDeleteShader.
+struct DeleteShader {
+ static const CommandId kCmdId = 296;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+};
+
+//! Command that corresponds to glDeleteTextures.
+struct DeleteTextures {
+ static const CommandId kCmdId = 297;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 textures_shm_id; //!< uint32
+ uint32 textures_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glDeleteTextures.
+struct DeleteTexturesImmediate {
+ static const CommandId kCmdId = 298;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glDepthFunc.
+struct DepthFunc {
+ static const CommandId kCmdId = 299;
+
+ CommandHeader header;
+ uint32 func; //!< GLenum
+};
+
+//! Command that corresponds to glDepthMask.
+struct DepthMask {
+ static const CommandId kCmdId = 300;
+
+ CommandHeader header;
+ uint32 flag; //!< GLboolean
+};
+
+//! Command that corresponds to glDepthRangef.
+struct DepthRangef {
+ static const CommandId kCmdId = 301;
+
+ CommandHeader header;
+ float zNear; //!< GLclampf
+ float zFar; //!< GLclampf
+};
+
+//! Command that corresponds to glDetachShader.
+struct DetachShader {
+ static const CommandId kCmdId = 302;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 shader; //!< GLuint
+};
+
+//! Command that corresponds to glDisable.
+struct Disable {
+ static const CommandId kCmdId = 303;
+
+ CommandHeader header;
+ uint32 cap; //!< GLenum
+};
+
+//! Command that corresponds to glDisableVertexAttribArray.
+struct DisableVertexAttribArray {
+ static const CommandId kCmdId = 304;
+
+ CommandHeader header;
+ uint32 index; //!< GLuint
+};
+
+//! Command that corresponds to glDrawArrays.
+struct DrawArrays {
+ static const CommandId kCmdId = 305;
+
+ CommandHeader header;
+ uint32 mode; //!< GLenum
+ int32 first; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glDrawElements.
+struct DrawElements {
+ static const CommandId kCmdId = 306;
+
+ CommandHeader header;
+ uint32 mode; //!< GLenum
+ int32 count; //!< GLsizei
+ uint32 type; //!< GLenum
+ uint32 index_offset; //!< GLuint
+};
+
+//! Command that corresponds to glEnable.
+struct Enable {
+ static const CommandId kCmdId = 307;
+
+ CommandHeader header;
+ uint32 cap; //!< GLenum
+};
+
+//! Command that corresponds to glEnableVertexAttribArray.
+struct EnableVertexAttribArray {
+ static const CommandId kCmdId = 308;
+
+ CommandHeader header;
+ uint32 index; //!< GLuint
+};
+
+//! Command that corresponds to glFinish.
+struct Finish {
+ static const CommandId kCmdId = 309;
+
+ CommandHeader header;
+};
+
+//! Command that corresponds to glFlush.
+struct Flush {
+ static const CommandId kCmdId = 310;
+
+ CommandHeader header;
+};
+
+//! Command that corresponds to glFramebufferRenderbuffer.
+struct FramebufferRenderbuffer {
+ static const CommandId kCmdId = 311;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 attachment; //!< GLenum
+ uint32 renderbuffertarget; //!< GLenum
+ uint32 renderbuffer; //!< GLuint
+};
+
+//! Command that corresponds to glFramebufferTexture2D.
+struct FramebufferTexture2D {
+ static const CommandId kCmdId = 312;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 attachment; //!< GLenum
+ uint32 textarget; //!< GLenum
+ uint32 texture; //!< GLuint
+ int32 level; //!< GLint
+};
+
+//! Command that corresponds to glFrontFace.
+struct FrontFace {
+ static const CommandId kCmdId = 313;
+
+ CommandHeader header;
+ uint32 mode; //!< GLenum
+};
+
+//! Command that corresponds to glGenBuffers.
+struct GenBuffers {
+ static const CommandId kCmdId = 314;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 buffers_shm_id; //!< uint32
+ uint32 buffers_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glGenBuffers.
+struct GenBuffersImmediate {
+ static const CommandId kCmdId = 315;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glGenerateMipmap.
+struct GenerateMipmap {
+ static const CommandId kCmdId = 316;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+};
+
+//! Command that corresponds to glGenFramebuffers.
+struct GenFramebuffers {
+ static const CommandId kCmdId = 317;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 framebuffers_shm_id; //!< uint32
+ uint32 framebuffers_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glGenFramebuffers.
+struct GenFramebuffersImmediate {
+ static const CommandId kCmdId = 318;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glGenRenderbuffers.
+struct GenRenderbuffers {
+ static const CommandId kCmdId = 319;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 renderbuffers_shm_id; //!< uint32
+ uint32 renderbuffers_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glGenRenderbuffers.
+struct GenRenderbuffersImmediate {
+ static const CommandId kCmdId = 320;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glGenTextures.
+struct GenTextures {
+ static const CommandId kCmdId = 321;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 textures_shm_id; //!< uint32
+ uint32 textures_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glGenTextures.
+struct GenTexturesImmediate {
+ static const CommandId kCmdId = 322;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+};
+
+//! Command that corresponds to glGetActiveAttrib.
+struct GetActiveAttrib {
+ static const CommandId kCmdId = 323;
+
+ struct Result {
+ int32 success;
+ int32 size;
+ uint32 type;
+ };
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 index; //!< GLuint
+ uint32 name_bucket_id; //!< uint32
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetActiveUniform.
+struct GetActiveUniform {
+ static const CommandId kCmdId = 324;
+
+ struct Result {
+ int32 success;
+ int32 size;
+ uint32 type;
+ };
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 index; //!< GLuint
+ uint32 name_bucket_id; //!< uint32
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetAttachedShaders.
+struct GetAttachedShaders {
+ static const CommandId kCmdId = 325;
+
+ typedef SizedResult<GLuint> Result;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+ uint32 result_size; //!< uint32
+};
+
+//! Command that corresponds to glGetAttribLocation.
+struct GetAttribLocation {
+ static const CommandId kCmdId = 326;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_shm_id;
+ uint32 name_shm_offset;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+//! Immediate version of command that corresponds to glGetAttribLocation.
+struct GetAttribLocationImmediate {
+ static const CommandId kCmdId = 327;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 program;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+//! Bucket version of command that corresponds to glGetAttribLocation.
+struct GetAttribLocationBucket {
+ static const CommandId kCmdId = 434;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_bucket_id;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+};
+
+//! Command that corresponds to glGetBooleanv.
+struct GetBooleanv {
+ static const CommandId kCmdId = 328;
+
+ typedef SizedResult<GLboolean> Result;
+
+ CommandHeader header;
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetBufferParameteriv.
+struct GetBufferParameteriv {
+ static const CommandId kCmdId = 329;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetError.
+struct GetError {
+ static const CommandId kCmdId = 330;
+
+ typedef GLenum Result;
+
+ CommandHeader header;
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetFloatv.
+struct GetFloatv {
+ static const CommandId kCmdId = 331;
+
+ typedef SizedResult<GLfloat> Result;
+
+ CommandHeader header;
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetFramebufferAttachmentParameteriv.
+struct GetFramebufferAttachmentParameteriv {
+ static const CommandId kCmdId = 332;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 attachment; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetIntegerv.
+struct GetIntegerv {
+ static const CommandId kCmdId = 333;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetProgramiv.
+struct GetProgramiv {
+ static const CommandId kCmdId = 334;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetProgramInfoLog.
+struct GetProgramInfoLog {
+ static const CommandId kCmdId = 335;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 bucket_id; //!< uint32
+};
+
+//! Command that corresponds to glGetRenderbufferParameteriv.
+struct GetRenderbufferParameteriv {
+ static const CommandId kCmdId = 336;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetShaderiv.
+struct GetShaderiv {
+ static const CommandId kCmdId = 337;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetShaderInfoLog.
+struct GetShaderInfoLog {
+ static const CommandId kCmdId = 338;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 bucket_id; //!< uint32
+};
+
+//! Command that corresponds to glGetShaderPrecisionFormat.
+struct GetShaderPrecisionFormat {
+ static const CommandId kCmdId = 339;
+
+ struct Result {
+ int32 success;
+ int32 min_range;
+ int32 max_range;
+ int32 precision;
+ };
+
+ CommandHeader header;
+ uint32 shadertype; //!< GLenum
+ uint32 precisiontype; //!< GLenum
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetShaderSource.
+struct GetShaderSource {
+ static const CommandId kCmdId = 340;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 bucket_id; //!< uint32
+};
+
+//! Command that corresponds to glGetString.
+struct GetString {
+ static const CommandId kCmdId = 341;
+
+ CommandHeader header;
+ uint32 name; //!< GLenum
+ uint32 bucket_id; //!< uint32
+};
+
+//! Command that corresponds to glGetTexParameterfv.
+struct GetTexParameterfv {
+ static const CommandId kCmdId = 342;
+
+ typedef SizedResult<GLfloat> Result;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetTexParameteriv.
+struct GetTexParameteriv {
+ static const CommandId kCmdId = 343;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetUniformLocation.
+struct GetUniformLocation {
+ static const CommandId kCmdId = 346;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_shm_id;
+ uint32 name_shm_offset;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+//! Immediate version of command that corresponds to glGetUniformLocation.
+struct GetUniformLocationImmediate {
+ static const CommandId kCmdId = 347;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 program;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+ uint32 data_size;
+};
+
+//! Bucket version of command that corresponds to glGetUniformLocation.
+struct GetUniformLocationBucket {
+ static const CommandId kCmdId = 433;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 program;
+ uint32 name_bucket_id;
+ uint32 location_shm_id;
+ uint32 location_shm_offset;
+};
+
+
+//! Command that corresponds to glGetUniformfv.
+struct GetUniformfv {
+ static const CommandId kCmdId = 344;
+
+ typedef SizedResult<GLfloat> Result;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ int32 location; //!< GLint
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetUniformiv.
+struct GetUniformiv {
+ static const CommandId kCmdId = 345;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ int32 location; //!< GLint
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetVertexAttribfv.
+struct GetVertexAttribfv {
+ static const CommandId kCmdId = 348;
+
+ typedef SizedResult<GLfloat> Result;
+
+ CommandHeader header;
+ uint32 index; //!< GLuint
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetVertexAttribiv.
+struct GetVertexAttribiv {
+ static const CommandId kCmdId = 349;
+
+ typedef SizedResult<GLint> Result;
+
+ CommandHeader header;
+ uint32 index; //!< GLuint
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glGetVertexAttribPointerv.
+struct GetVertexAttribPointerv {
+ static const CommandId kCmdId = 350;
+
+ typedef SizedResult<GLuint> Result;
+
+ CommandHeader header;
+ uint32 index; //!< GLuint
+ uint32 pname; //!< GLenum
+ uint32 pointer_shm_id; //!< uint32
+ uint32 pointer_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glHint.
+struct Hint {
+ static const CommandId kCmdId = 351;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 mode; //!< GLenum
+};
+
+//! Command that corresponds to glIsBuffer.
+struct IsBuffer {
+ static const CommandId kCmdId = 352;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 buffer; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glIsEnabled.
+struct IsEnabled {
+ static const CommandId kCmdId = 353;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 cap; //!< GLenum
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glIsFramebuffer.
+struct IsFramebuffer {
+ static const CommandId kCmdId = 354;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 framebuffer; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glIsProgram.
+struct IsProgram {
+ static const CommandId kCmdId = 355;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glIsRenderbuffer.
+struct IsRenderbuffer {
+ static const CommandId kCmdId = 356;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 renderbuffer; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glIsShader.
+struct IsShader {
+ static const CommandId kCmdId = 357;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glIsTexture.
+struct IsTexture {
+ static const CommandId kCmdId = 358;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ uint32 texture; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glLineWidth.
+struct LineWidth {
+ static const CommandId kCmdId = 359;
+
+ CommandHeader header;
+ float width; //!< GLfloat
+};
+
+//! Command that corresponds to glLinkProgram.
+struct LinkProgram {
+ static const CommandId kCmdId = 360;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+};
+
+//! Command that corresponds to glPixelStorei.
+struct PixelStorei {
+ static const CommandId kCmdId = 361;
+
+ CommandHeader header;
+ uint32 pname; //!< GLenum
+ int32 param; //!< GLint
+};
+
+//! Command that corresponds to glPolygonOffset.
+struct PolygonOffset {
+ static const CommandId kCmdId = 362;
+
+ CommandHeader header;
+ float factor; //!< GLfloat
+ float units; //!< GLfloat
+};
+
+//! Command that corresponds to glReadPixels.
+//! ReadPixels has the result separated from the pixel buffer so that
+//! it is easier to specify the result going to some specific place
+//! that exactly fits the rectangle of pixels.
+struct ReadPixels {
+ static const CommandId kCmdId = 363;
+
+ typedef uint32 Result;
+
+ CommandHeader header;
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ uint32 format; //!< GLenum
+ uint32 type; //!< GLenum
+ uint32 pixels_shm_id; //!< uint32
+ uint32 pixels_shm_offset; //!< uint32
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that corresponds to glReleaseShaderCompiler.
+struct ReleaseShaderCompiler {
+ static const CommandId kCmdId = 437;
+
+ CommandHeader header;
+};
+
+//! Command that corresponds to glRenderbufferStorage.
+struct RenderbufferStorage {
+ static const CommandId kCmdId = 364;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 internalformat; //!< GLenum
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+};
+
+//! Command that corresponds to glSampleCoverage.
+struct SampleCoverage {
+ static const CommandId kCmdId = 365;
+
+ CommandHeader header;
+ float value; //!< GLclampf
+ uint32 invert; //!< GLboolean
+};
+
+//! Command that corresponds to glScissor.
+struct Scissor {
+ static const CommandId kCmdId = 366;
+
+ CommandHeader header;
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+};
+
+//! Command that corresponds to glShaderBinary.
+struct ShaderBinary {
+ static const CommandId kCmdId = 436;
+
+ CommandHeader header;
+ int32 n; //!< GLsizei
+ uint32 shaders_shm_id; //!< uint32
+ uint32 shaders_shm_offset; //!< uint32
+ uint32 binaryformat; //!< GLenum
+ uint32 binary_shm_id; //!< uint32
+ uint32 binary_shm_offset; //!< uint32
+ int32 length; //!< GLsizei
+};
+
+//! Command that corresponds to glShaderSource.
+struct ShaderSource {
+ static const CommandId kCmdId = 367;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 data_shm_id; //!< uint32
+ uint32 data_shm_offset; //!< uint32
+ uint32 data_size; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glShaderSource.
+struct ShaderSourceImmediate {
+ static const CommandId kCmdId = 368;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 data_size; //!< uint32
+};
+
+//! Bucket version of command that corresponds to glShaderSource.
+struct ShaderSourceBucket {
+ static const CommandId kCmdId = 435;
+
+ CommandHeader header;
+ uint32 shader; //!< GLuint
+ uint32 data_bucket_id; //!< uint32
+};
+
+//! Command that corresponds to glStencilFunc.
+struct StencilFunc {
+ static const CommandId kCmdId = 369;
+
+ CommandHeader header;
+ uint32 func; //!< GLenum
+ int32 ref; //!< GLint
+ uint32 mask; //!< GLuint
+};
+
+//! Command that corresponds to glStencilFuncSeparate.
+struct StencilFuncSeparate {
+ static const CommandId kCmdId = 370;
+
+ CommandHeader header;
+ uint32 face; //!< GLenum
+ uint32 func; //!< GLenum
+ int32 ref; //!< GLint
+ uint32 mask; //!< GLuint
+};
+
+//! Command that corresponds to glStencilMask.
+struct StencilMask {
+ static const CommandId kCmdId = 371;
+
+ CommandHeader header;
+ uint32 mask; //!< GLuint
+};
+
+//! Command that corresponds to glStencilMaskSeparate.
+struct StencilMaskSeparate {
+ static const CommandId kCmdId = 372;
+
+ CommandHeader header;
+ uint32 face; //!< GLenum
+ uint32 mask; //!< GLuint
+};
+
+//! Command that corresponds to glStencilOp.
+struct StencilOp {
+ static const CommandId kCmdId = 373;
+
+ CommandHeader header;
+ uint32 fail; //!< GLenum
+ uint32 zfail; //!< GLenum
+ uint32 zpass; //!< GLenum
+};
+
+//! Command that corresponds to glStencilOpSeparate.
+struct StencilOpSeparate {
+ static const CommandId kCmdId = 374;
+
+ CommandHeader header;
+ uint32 face; //!< GLenum
+ uint32 fail; //!< GLenum
+ uint32 zfail; //!< GLenum
+ uint32 zpass; //!< GLenum
+};
+
+//! Command that corresponds to glTexImage2D.
+struct TexImage2D {
+ static const CommandId kCmdId = 375;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 internalformat; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ int32 border; //!< GLint
+ uint32 format; //!< GLenum
+ uint32 type; //!< GLenum
+ uint32 pixels_shm_id; //!< uint32
+ uint32 pixels_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glTexImage2D.
+struct TexImage2DImmediate {
+ static const CommandId kCmdId = 376;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 internalformat; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ int32 border; //!< GLint
+ uint32 format; //!< GLenum
+ uint32 type; //!< GLenum
+};
+
+//! Command that corresponds to glTexParameterf.
+struct TexParameterf {
+ static const CommandId kCmdId = 377;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ float param; //!< GLfloat
+};
+
+//! Command that corresponds to glTexParameterfv.
+struct TexParameterfv {
+ static const CommandId kCmdId = 378;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glTexParameterfv.
+struct TexParameterfvImmediate {
+ static const CommandId kCmdId = 379;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+};
+
+//! Command that corresponds to glTexParameteri.
+struct TexParameteri {
+ static const CommandId kCmdId = 380;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ int32 param; //!< GLint
+};
+
+//! Command that corresponds to glTexParameteriv.
+struct TexParameteriv {
+ static const CommandId kCmdId = 381;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+ uint32 params_shm_id; //!< uint32
+ uint32 params_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glTexParameteriv.
+struct TexParameterivImmediate {
+ static const CommandId kCmdId = 382;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ uint32 pname; //!< GLenum
+};
+
+//! Command that corresponds to glTexSubImage2D.
+struct TexSubImage2D {
+ static const CommandId kCmdId = 383;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 xoffset; //!< GLint
+ int32 yoffset; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ uint32 format; //!< GLenum
+ uint32 type; //!< GLenum
+ uint32 pixels_shm_id; //!< uint32
+ uint32 pixels_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glTexSubImage2D.
+struct TexSubImage2DImmediate {
+ static const CommandId kCmdId = 384;
+
+ CommandHeader header;
+ uint32 target; //!< GLenum
+ int32 level; //!< GLint
+ int32 xoffset; //!< GLint
+ int32 yoffset; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+ uint32 format; //!< GLenum
+ uint32 type; //!< GLenum
+};
+
+//! Command that corresponds to glUniform1f.
+struct Uniform1f {
+ static const CommandId kCmdId = 385;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ float x; //!< GLfloat
+};
+
+//! Command that corresponds to glUniform1fv.
+struct Uniform1fv {
+ static const CommandId kCmdId = 386;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform1fv.
+struct Uniform1fvImmediate {
+ static const CommandId kCmdId = 387;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform1i.
+struct Uniform1i {
+ static const CommandId kCmdId = 388;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 x; //!< GLint
+};
+
+//! Command that corresponds to glUniform1iv.
+struct Uniform1iv {
+ static const CommandId kCmdId = 389;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform1iv.
+struct Uniform1ivImmediate {
+ static const CommandId kCmdId = 390;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform2f.
+struct Uniform2f {
+ static const CommandId kCmdId = 391;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ float x; //!< GLfloat
+ float y; //!< GLfloat
+};
+
+//! Command that corresponds to glUniform2fv.
+struct Uniform2fv {
+ static const CommandId kCmdId = 392;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform2fv.
+struct Uniform2fvImmediate {
+ static const CommandId kCmdId = 393;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform2i.
+struct Uniform2i {
+ static const CommandId kCmdId = 394;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+};
+
+//! Command that corresponds to glUniform2iv.
+struct Uniform2iv {
+ static const CommandId kCmdId = 395;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform2iv.
+struct Uniform2ivImmediate {
+ static const CommandId kCmdId = 396;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform3f.
+struct Uniform3f {
+ static const CommandId kCmdId = 397;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ float x; //!< GLfloat
+ float y; //!< GLfloat
+ float z; //!< GLfloat
+};
+
+//! Command that corresponds to glUniform3fv.
+struct Uniform3fv {
+ static const CommandId kCmdId = 398;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform3fv.
+struct Uniform3fvImmediate {
+ static const CommandId kCmdId = 399;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform3i.
+struct Uniform3i {
+ static const CommandId kCmdId = 400;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 z; //!< GLint
+};
+
+//! Command that corresponds to glUniform3iv.
+struct Uniform3iv {
+ static const CommandId kCmdId = 401;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform3iv.
+struct Uniform3ivImmediate {
+ static const CommandId kCmdId = 402;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform4f.
+struct Uniform4f {
+ static const CommandId kCmdId = 403;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ float x; //!< GLfloat
+ float y; //!< GLfloat
+ float z; //!< GLfloat
+ float w; //!< GLfloat
+};
+
+//! Command that corresponds to glUniform4fv.
+struct Uniform4fv {
+ static const CommandId kCmdId = 404;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform4fv.
+struct Uniform4fvImmediate {
+ static const CommandId kCmdId = 405;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniform4i.
+struct Uniform4i {
+ static const CommandId kCmdId = 406;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 z; //!< GLint
+ int32 w; //!< GLint
+};
+
+//! Command that corresponds to glUniform4iv.
+struct Uniform4iv {
+ static const CommandId kCmdId = 407;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 v_shm_id; //!< uint32
+ uint32 v_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniform4iv.
+struct Uniform4ivImmediate {
+ static const CommandId kCmdId = 408;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+};
+
+//! Command that corresponds to glUniformMatrix2fv.
+struct UniformMatrix2fv {
+ static const CommandId kCmdId = 409;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 transpose; //!< GLboolean
+ uint32 value_shm_id; //!< uint32
+ uint32 value_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniformMatrix2fv.
+struct UniformMatrix2fvImmediate {
+ static const CommandId kCmdId = 410;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 transpose; //!< GLboolean
+};
+
+//! Command that corresponds to glUniformMatrix3fv.
+struct UniformMatrix3fv {
+ static const CommandId kCmdId = 411;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 transpose; //!< GLboolean
+ uint32 value_shm_id; //!< uint32
+ uint32 value_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniformMatrix3fv.
+struct UniformMatrix3fvImmediate {
+ static const CommandId kCmdId = 412;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 transpose; //!< GLboolean
+};
+
+//! Command that corresponds to glUniformMatrix4fv.
+struct UniformMatrix4fv {
+ static const CommandId kCmdId = 413;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 transpose; //!< GLboolean
+ uint32 value_shm_id; //!< uint32
+ uint32 value_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glUniformMatrix4fv.
+struct UniformMatrix4fvImmediate {
+ static const CommandId kCmdId = 414;
+
+ CommandHeader header;
+ int32 location; //!< GLint
+ int32 count; //!< GLsizei
+ uint32 transpose; //!< GLboolean
+};
+
+//! Command that corresponds to glUseProgram.
+struct UseProgram {
+ static const CommandId kCmdId = 415;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+};
+
+//! Command that corresponds to glValidateProgram.
+struct ValidateProgram {
+ static const CommandId kCmdId = 416;
+
+ CommandHeader header;
+ uint32 program; //!< GLuint
+};
+
+//! Command that corresponds to glVertexAttrib1f.
+struct VertexAttrib1f {
+ static const CommandId kCmdId = 417;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ float x; //!< GLfloat
+};
+
+//! Command that corresponds to glVertexAttrib1fv.
+struct VertexAttrib1fv {
+ static const CommandId kCmdId = 418;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ uint32 values_shm_id; //!< uint32
+ uint32 values_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glVertexAttrib1fv.
+struct VertexAttrib1fvImmediate {
+ static const CommandId kCmdId = 419;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+};
+
+//! Command that corresponds to glVertexAttrib2f.
+struct VertexAttrib2f {
+ static const CommandId kCmdId = 420;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ float x; //!< GLfloat
+ float y; //!< GLfloat
+};
+
+//! Command that corresponds to glVertexAttrib2fv.
+struct VertexAttrib2fv {
+ static const CommandId kCmdId = 421;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ uint32 values_shm_id; //!< uint32
+ uint32 values_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glVertexAttrib2fv.
+struct VertexAttrib2fvImmediate {
+ static const CommandId kCmdId = 422;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+};
+
+//! Command that corresponds to glVertexAttrib3f.
+struct VertexAttrib3f {
+ static const CommandId kCmdId = 423;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ float x; //!< GLfloat
+ float y; //!< GLfloat
+ float z; //!< GLfloat
+};
+
+//! Command that corresponds to glVertexAttrib3fv.
+struct VertexAttrib3fv {
+ static const CommandId kCmdId = 424;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ uint32 values_shm_id; //!< uint32
+ uint32 values_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glVertexAttrib3fv.
+struct VertexAttrib3fvImmediate {
+ static const CommandId kCmdId = 425;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+};
+
+//! Command that corresponds to glVertexAttrib4f.
+struct VertexAttrib4f {
+ static const CommandId kCmdId = 426;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ float x; //!< GLfloat
+ float y; //!< GLfloat
+ float z; //!< GLfloat
+ float w; //!< GLfloat
+};
+
+//! Command that corresponds to glVertexAttrib4fv.
+struct VertexAttrib4fv {
+ static const CommandId kCmdId = 427;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ uint32 values_shm_id; //!< uint32
+ uint32 values_shm_offset; //!< uint32
+};
+
+//! Immediate version of command that corresponds to glVertexAttrib4fv.
+struct VertexAttrib4fvImmediate {
+ static const CommandId kCmdId = 428;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+};
+
+//! Command that corresponds to glVertexAttribPointer.
+struct VertexAttribPointer {
+ static const CommandId kCmdId = 429;
+
+ CommandHeader header;
+ uint32 indx; //!< GLuint
+ int32 size; //!< GLint
+ uint32 type; //!< GLenum
+ uint32 normalized; //!< GLboolean
+ int32 stride; //!< GLsizei
+ uint32 offset; //!< GLuint
+};
+
+//! Command that corresponds to glViewport.
+struct Viewport {
+ static const CommandId kCmdId = 430;
+
+ CommandHeader header;
+ int32 x; //!< GLint
+ int32 y; //!< GLint
+ int32 width; //!< GLsizei
+ int32 height; //!< GLsizei
+};
+
+//! Command that corresponds to SwapBuffers.
+struct SwapBuffers {
+ static const CommandId kCmdId = 431;
+
+ CommandHeader header;
+};
+
+//! Command that corresponds to GetMaxValueInBuffer.
+struct GetMaxValueInBuffer {
+ static const CommandId kCmdId = 436;
+
+ typedef GLuint Result;
+
+ CommandHeader header;
+ uint32 buffer_id; //!< GLuint
+ int32 count; //!< GLsizei
+ uint32 type; //!< GLenum
+ uint32 offset; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+//! Command that generates shared ids for contexts that share resources.
+struct GenSharedIds {
+ static const CommandId kCmdId = 439;
+
+ CommandHeader header;
+ uint32 namespace_id; //!< GLuint
+ uint32 id_offset; //!< GLuint
+ int32 n; //!< GLsizei
+ uint32 ids_shm_id; //!< uint32
+ uint32 ids_shm_offset; //!< uint32
+};
+
+//! Command that deletes shared ids.
+struct DeleteSharedIds {
+ static const CommandId kCmdId = 440;
+
+ CommandHeader header;
+ uint32 namespace_id; //!< GLuint
+ int32 n; //!< GLsizei
+ uint32 ids_shm_id; //!< uint32
+ uint32 ids_shm_offset; //!< uint32
+};
+
+//! Command that registers shared ids. It is an error to attempt
+//! to register an id that is already registered.
+struct RegisterSharedIds {
+ static const CommandId kCmdId = 441;
+
+ CommandHeader header;
+ uint32 namespace_id; //!< GLuint
+ int32 n; //!< GLsizei
+ uint32 ids_shm_id; //!< uint32
+ uint32 ids_shm_offset; //!< uint32
+};
+
+//! Command that enables features. The bucket should contain the feature string.
+struct CommandBufferEnable {
+ static const CommandId kCmdId = 442;
+
+ typedef GLint Result;
+
+ CommandHeader header;
+ uint32 bucket_id; //!< GLuint
+ uint32 result_shm_id; //!< uint32
+ uint32 result_shm_offset; //!< uint32
+};
+
+
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.cc
new file mode 100644
index 00000000000..074f6752dd8
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+#include "base/memory/shared_memory.h"
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+
+namespace gpu {
+
+namespace {
+
+void* GetAddressImpl(base::SharedMemory* shared_memory,
+ uint32 shm_size,
+ uint32 shm_data_offset,
+ uint32 shm_data_size) {
+ // Memory bounds have already been validated, so there
+ // are just DCHECKS here.
+ DCHECK(shared_memory);
+ DCHECK(shared_memory->memory());
+ DCHECK_LE(shm_data_offset + shm_data_size, shm_size);
+ return static_cast<int8*>(shared_memory->memory()) + shm_data_offset;
+}
+
+} // namespace
+
+AsyncPixelTransferUploadStats::AsyncPixelTransferUploadStats()
+ : texture_upload_count_(0) {}
+
+AsyncPixelTransferUploadStats::~AsyncPixelTransferUploadStats() {}
+
+void AsyncPixelTransferUploadStats::AddUpload(base::TimeDelta transfer_time) {
+ base::AutoLock scoped_lock(lock_);
+ texture_upload_count_++;
+ total_texture_upload_time_ += transfer_time;
+}
+
+int AsyncPixelTransferUploadStats::GetStats(
+ base::TimeDelta* total_texture_upload_time) {
+ base::AutoLock scoped_lock(lock_);
+ if (total_texture_upload_time)
+ *total_texture_upload_time = total_texture_upload_time_;
+ return texture_upload_count_;
+}
+
+AsyncPixelTransferDelegate::AsyncPixelTransferDelegate(){}
+
+AsyncPixelTransferDelegate::~AsyncPixelTransferDelegate(){}
+
+// static
+void* AsyncPixelTransferDelegate::GetAddress(
+ const AsyncMemoryParams& mem_params) {
+ return GetAddressImpl(mem_params.shared_memory,
+ mem_params.shm_size,
+ mem_params.shm_data_offset,
+ mem_params.shm_data_size);
+}
+
+// static
+void* AsyncPixelTransferDelegate::GetAddress(
+ ScopedSafeSharedMemory* safe_shared_memory,
+ const AsyncMemoryParams& mem_params) {
+ return GetAddressImpl(safe_shared_memory->shared_memory(),
+ mem_params.shm_size,
+ mem_params.shm_data_offset,
+ mem_params.shm_data_size);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.h
new file mode 100644
index 00000000000..dc0f2d7b62f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace base {
+class SharedMemory;
+}
+
+namespace gpu {
+
+class ScopedSafeSharedMemory;
+
+struct AsyncTexImage2DParams {
+ GLenum target;
+ GLint level;
+ GLenum internal_format;
+ GLsizei width;
+ GLsizei height;
+ GLint border;
+ GLenum format;
+ GLenum type;
+};
+
+struct AsyncTexSubImage2DParams {
+ GLenum target;
+ GLint level;
+ GLint xoffset;
+ GLint yoffset;
+ GLsizei width;
+ GLsizei height;
+ GLenum format;
+ GLenum type;
+};
+
+struct AsyncMemoryParams {
+ base::SharedMemory* shared_memory;
+ uint32 shm_size;
+ uint32 shm_data_offset;
+ uint32 shm_data_size;
+};
+
+class AsyncPixelTransferUploadStats
+ : public base::RefCountedThreadSafe<AsyncPixelTransferUploadStats> {
+ public:
+ AsyncPixelTransferUploadStats();
+
+ void AddUpload(base::TimeDelta transfer_time);
+ int GetStats(base::TimeDelta* total_texture_upload_time);
+
+ private:
+ friend class base::RefCountedThreadSafe<AsyncPixelTransferUploadStats>;
+
+ ~AsyncPixelTransferUploadStats();
+
+ int texture_upload_count_;
+ base::TimeDelta total_texture_upload_time_;
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferUploadStats);
+};
+
+class GPU_EXPORT AsyncPixelTransferDelegate {
+ public:
+ virtual ~AsyncPixelTransferDelegate();
+
+ // The callback occurs on the caller thread, once the texture is
+ // safe/ready to be used.
+ virtual void AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) = 0;
+
+ virtual void AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) = 0;
+
+ // Returns true if there is a transfer in progress.
+ virtual bool TransferIsInProgress() = 0;
+
+ // Block until the specified transfer completes.
+ virtual void WaitForTransferCompletion() = 0;
+
+ // Gets the address of the data from shared memory.
+ static void* GetAddress(const AsyncMemoryParams& mem_params);
+
+ // Sometimes the |safe_shared_memory| is duplicate to prevent use after free.
+ static void* GetAddress(ScopedSafeSharedMemory* safe_shared_memory,
+ const AsyncMemoryParams& mem_params);
+
+ protected:
+ AsyncPixelTransferDelegate();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegate);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_H_
+
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc
new file mode 100644
index 00000000000..8e2d75fd9e4
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h"
+
+namespace gpu {
+
+MockAsyncPixelTransferDelegate::MockAsyncPixelTransferDelegate() {
+}
+
+MockAsyncPixelTransferDelegate::~MockAsyncPixelTransferDelegate() {
+ Destroy();
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
new file mode 100644
index 00000000000..9d2873023ed
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_MOCK
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_MOCK
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+class MockAsyncPixelTransferDelegate : public AsyncPixelTransferDelegate {
+ public:
+ MockAsyncPixelTransferDelegate();
+ virtual ~MockAsyncPixelTransferDelegate();
+
+ // Called in ~MockAsyncPixelTransferDelegate.
+ MOCK_METHOD0(Destroy, void());
+
+ // Implement AsyncPixelTransferDelegate.
+ MOCK_METHOD3(AsyncTexImage2D,
+ void(const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback));
+ MOCK_METHOD2(AsyncTexSubImage2D,
+ void(const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params));
+ MOCK_METHOD0(TransferIsInProgress, bool());
+ MOCK_METHOD0(WaitForTransferCompletion, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAsyncPixelTransferDelegate);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_DELEGATE_MOCK
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager.cc
new file mode 100644
index 00000000000..3084dd61964
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager.cc
@@ -0,0 +1,76 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+
+AsyncPixelTransferCompletionObserver::AsyncPixelTransferCompletionObserver() {}
+
+AsyncPixelTransferCompletionObserver::~AsyncPixelTransferCompletionObserver() {}
+
+AsyncPixelTransferManager::AsyncPixelTransferManager() {}
+
+AsyncPixelTransferManager::~AsyncPixelTransferManager() {
+ if (manager_)
+ manager_->RemoveObserver(this);
+}
+
+void AsyncPixelTransferManager::Initialize(gles2::TextureManager* manager) {
+ manager_ = manager;
+ manager_->AddObserver(this);
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManager::CreatePixelTransferDelegate(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) {
+ DCHECK(!GetPixelTransferDelegate(ref));
+ AsyncPixelTransferDelegate* delegate =
+ CreatePixelTransferDelegateImpl(ref, define_params);
+ delegate_map_[ref] = make_linked_ptr(delegate);
+ return delegate;
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManager::GetPixelTransferDelegate(
+ gles2::TextureRef* ref) {
+ TextureToDelegateMap::iterator it = delegate_map_.find(ref);
+ if (it == delegate_map_.end()) {
+ return NULL;
+ } else {
+ return it->second.get();
+ }
+}
+
+void AsyncPixelTransferManager::ClearPixelTransferDelegateForTest(
+ gles2::TextureRef* ref) {
+ TextureToDelegateMap::iterator it = delegate_map_.find(ref);
+ if (it != delegate_map_.end())
+ delegate_map_.erase(it);
+}
+
+bool AsyncPixelTransferManager::AsyncTransferIsInProgress(
+ gles2::TextureRef* ref) {
+ AsyncPixelTransferDelegate* delegate = GetPixelTransferDelegate(ref);
+ return delegate && delegate->TransferIsInProgress();
+}
+
+void AsyncPixelTransferManager::OnTextureManagerDestroying(
+ gles2::TextureManager* manager) {
+ // TextureManager should outlive AsyncPixelTransferManager.
+ NOTREACHED();
+ manager_ = NULL;
+}
+
+void AsyncPixelTransferManager::OnTextureRefDestroying(
+ gles2::TextureRef* texture) {
+ TextureToDelegateMap::iterator it = delegate_map_.find(texture);
+ if (it != delegate_map_.end())
+ delegate_map_.erase(it);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager.h
new file mode 100644
index 00000000000..d0ea5da153c
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager.h
@@ -0,0 +1,119 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_H_
+
+#include <set>
+
+#include "base/basictypes.h"
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/gpu_export.h"
+
+#if defined(COMPILER_GCC)
+namespace BASE_HASH_NAMESPACE {
+template <>
+ struct hash<gpu::gles2::TextureRef*> {
+ size_t operator()(gpu::gles2::TextureRef* ptr) const {
+ return hash<size_t>()(reinterpret_cast<size_t>(ptr));
+ }
+};
+} // namespace BASE_HASH_NAMESPACE
+#endif // COMPILER
+
+namespace gfx {
+class GLContext;
+}
+
+namespace gpu {
+class AsyncPixelTransferDelegate;
+struct AsyncMemoryParams;
+struct AsyncTexImage2DParams;
+
+class AsyncPixelTransferCompletionObserver
+ : public base::RefCountedThreadSafe<AsyncPixelTransferCompletionObserver> {
+ public:
+ AsyncPixelTransferCompletionObserver();
+
+ virtual void DidComplete(const AsyncMemoryParams& mem_params) = 0;
+
+ protected:
+ virtual ~AsyncPixelTransferCompletionObserver();
+
+ private:
+ friend class base::RefCountedThreadSafe<AsyncPixelTransferCompletionObserver>;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserver);
+};
+
+class GPU_EXPORT AsyncPixelTransferManager
+ : public gles2::TextureManager::DestructionObserver {
+ public:
+ static AsyncPixelTransferManager* Create(gfx::GLContext* context);
+
+ virtual ~AsyncPixelTransferManager();
+
+ void Initialize(gles2::TextureManager* texture_manager);
+
+ virtual void BindCompletedAsyncTransfers() = 0;
+
+ // There's no guarantee that callback will run on the caller thread.
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) = 0;
+
+ virtual uint32 GetTextureUploadCount() = 0;
+ virtual base::TimeDelta GetTotalTextureUploadTime() = 0;
+
+ // ProcessMorePendingTransfers() will be called at a good time
+ // to process a small amount of pending transfer work while
+ // NeedsProcessMorePendingTransfers() returns true. Implementations
+ // that can't dispatch work to separate threads should use
+ // this to avoid blocking the caller thread inappropriately.
+ virtual void ProcessMorePendingTransfers() = 0;
+ virtual bool NeedsProcessMorePendingTransfers() = 0;
+
+ AsyncPixelTransferDelegate* CreatePixelTransferDelegate(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params);
+
+ AsyncPixelTransferDelegate* GetPixelTransferDelegate(
+ gles2::TextureRef* ref);
+
+ void ClearPixelTransferDelegateForTest(gles2::TextureRef* ref);
+
+ bool AsyncTransferIsInProgress(gles2::TextureRef* ref);
+
+ // gles2::TextureRef::DestructionObserver implementation:
+ virtual void OnTextureManagerDestroying(gles2::TextureManager* manager)
+ OVERRIDE;
+ virtual void OnTextureRefDestroying(gles2::TextureRef* texture) OVERRIDE;
+
+ protected:
+ AsyncPixelTransferManager();
+
+ private:
+ gles2::TextureManager* manager_;
+
+ typedef base::hash_map<gles2::TextureRef*,
+ linked_ptr<AsyncPixelTransferDelegate> >
+ TextureToDelegateMap;
+ TextureToDelegateMap delegate_map_;
+
+ // A factory method called by CreatePixelTransferDelegate that is overriden
+ // by each implementation.
+ virtual AsyncPixelTransferDelegate* CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) = 0;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManager);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_android.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_android.cc
new file mode 100644
index 00000000000..8de7d58a07a
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_android.cc
@@ -0,0 +1,66 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_egl.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_stub.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_sync.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+namespace {
+
+bool IsBroadcom() {
+ const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ if (vendor)
+ return std::string(vendor).find("Broadcom") != std::string::npos;
+ return false;
+}
+
+bool IsImagination() {
+ const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ if (vendor)
+ return std::string(vendor).find("Imagination") != std::string::npos;
+ return false;
+}
+
+}
+
+// We only used threaded uploads when we can:
+// - Create EGLImages out of OpenGL textures (EGL_KHR_gl_texture_2D_image)
+// - Bind EGLImages to OpenGL textures (GL_OES_EGL_image)
+// - Use fences (to test for upload completion).
+// - The heap size is large enough.
+// TODO(kaanb|epenner): Remove the IsImagination() check pending the
+// resolution of crbug.com/249147
+AsyncPixelTransferManager* AsyncPixelTransferManager::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferManager::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationEGLGLES2:
+ DCHECK(context);
+ if (context->HasExtension("EGL_KHR_fence_sync") &&
+ context->HasExtension("EGL_KHR_image") &&
+ context->HasExtension("EGL_KHR_image_base") &&
+ context->HasExtension("EGL_KHR_gl_texture_2D_image") &&
+ context->HasExtension("GL_OES_EGL_image") &&
+ !IsBroadcom() &&
+ !IsImagination()) {
+ return new AsyncPixelTransferManagerEGL;
+ }
+ LOG(INFO) << "Async pixel transfers not supported";
+ return new AsyncPixelTransferManagerIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferManagerStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
new file mode 100644
index 00000000000..64e1f32c76b
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
@@ -0,0 +1,769 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_egl.h"
+
+#include <list>
+#include <string>
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/scoped_binders.h"
+
+namespace gpu {
+
+namespace {
+
+bool CheckErrors(const char* file, int line) {
+ EGLint eglerror;
+ GLenum glerror;
+ bool success = true;
+ while ((eglerror = eglGetError()) != EGL_SUCCESS) {
+ LOG(ERROR) << "Async transfer EGL error at "
+ << file << ":" << line << " " << eglerror;
+ success = false;
+ }
+ while ((glerror = glGetError()) != GL_NO_ERROR) {
+ LOG(ERROR) << "Async transfer OpenGL error at "
+ << file << ":" << line << " " << glerror;
+ success = false;
+ }
+ return success;
+}
+#define CHECK_GL() CheckErrors(__FILE__, __LINE__)
+
+const char kAsyncTransferThreadName[] = "AsyncTransferThread";
+
+// Regular glTexImage2D call.
+void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
+ glTexImage2D(
+ GL_TEXTURE_2D, tex_params.level, tex_params.internal_format,
+ tex_params.width, tex_params.height,
+ tex_params.border, tex_params.format, tex_params.type, data);
+}
+
+// Regular glTexSubImage2D call.
+void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) {
+ glTexSubImage2D(
+ GL_TEXTURE_2D, tex_params.level,
+ tex_params.xoffset, tex_params.yoffset,
+ tex_params.width, tex_params.height,
+ tex_params.format, tex_params.type, data);
+}
+
+// Full glTexSubImage2D call, from glTexImage2D params.
+void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
+ glTexSubImage2D(
+ GL_TEXTURE_2D, tex_params.level,
+ 0, 0, tex_params.width, tex_params.height,
+ tex_params.format, tex_params.type, data);
+}
+
+void SetGlParametersForEglImageTexture() {
+ // These params are needed for EGLImage creation to succeed on several
+ // Android devices. I couldn't find this requirement in the EGLImage
+ // extension spec, but several devices fail without it.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+}
+
+void PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
+ TRACE_EVENT0("gpu", "PerformNotifyCompletion");
+ AsyncMemoryParams safe_mem_params = mem_params;
+ safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
+ observer->DidComplete(safe_mem_params);
+}
+
+class TransferThread : public base::Thread {
+ public:
+ TransferThread() : base::Thread(kAsyncTransferThreadName) {
+ Start();
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+ SetPriority(base::kThreadPriority_Background);
+#endif
+ }
+ virtual ~TransferThread() {
+ Stop();
+ }
+
+ virtual void Init() OVERRIDE {
+ gfx::GLShareGroup* share_group = NULL;
+ surface_ = new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1));
+ surface_->Initialize();
+ context_ = gfx::GLContext::CreateGLContext(
+ share_group, surface_.get(), gfx::PreferDiscreteGpu);
+ bool is_current = context_->MakeCurrent(surface_.get());
+ DCHECK(is_current);
+ }
+
+ virtual void CleanUp() OVERRIDE {
+ surface_ = NULL;
+ context_->ReleaseCurrent(surface_.get());
+ context_ = NULL;
+ }
+
+ SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return &safe_shared_memory_pool_;
+ }
+
+ private:
+ scoped_refptr<gfx::GLContext> context_;
+ scoped_refptr<gfx::GLSurface> surface_;
+
+ SafeSharedMemoryPool safe_shared_memory_pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransferThread);
+};
+
+base::LazyInstance<TransferThread>
+ g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
+
+base::MessageLoopProxy* transfer_message_loop_proxy() {
+ return g_transfer_thread.Pointer()->message_loop_proxy().get();
+}
+
+SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return g_transfer_thread.Pointer()->safe_shared_memory_pool();
+}
+
+// Class which holds async pixel transfers state (EGLImage).
+// The EGLImage is accessed by either thread, but everything
+// else accessed only on the main thread.
+class TransferStateInternal
+ : public base::RefCountedThreadSafe<TransferStateInternal> {
+ public:
+ TransferStateInternal(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params,
+ bool wait_for_uploads,
+ bool wait_for_creation,
+ bool use_image_preserved)
+ : texture_id_(texture_id),
+ thread_texture_id_(0),
+ transfer_completion_(true, true),
+ egl_image_(EGL_NO_IMAGE_KHR),
+ wait_for_uploads_(wait_for_uploads),
+ wait_for_creation_(wait_for_creation),
+ use_image_preserved_(use_image_preserved) {
+ define_params_ = define_params;
+ }
+
+ bool TransferIsInProgress() {
+ return !transfer_completion_.IsSignaled();
+ }
+
+ void BindTransfer() {
+ TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
+ "width", define_params_.width,
+ "height", define_params_.height);
+ DCHECK(texture_id_);
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
+ bind_callback_.Run();
+
+ DCHECK(CHECK_GL());
+ }
+
+ void CreateEglImage(GLuint texture_id) {
+ TRACE_EVENT0("gpu", "eglCreateImageKHR");
+ DCHECK(texture_id);
+ DCHECK_EQ(egl_image_, EGL_NO_IMAGE_KHR);
+
+ EGLDisplay egl_display = eglGetCurrentDisplay();
+ EGLContext egl_context = eglGetCurrentContext();
+ EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
+ EGLClientBuffer egl_buffer =
+ reinterpret_cast<EGLClientBuffer>(texture_id);
+
+ EGLint image_preserved = use_image_preserved_ ? EGL_TRUE : EGL_FALSE;
+ EGLint egl_attrib_list[] = {
+ EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip-level.
+ EGL_IMAGE_PRESERVED_KHR, image_preserved,
+ EGL_NONE
+ };
+ egl_image_ = eglCreateImageKHR(
+ egl_display,
+ egl_context,
+ egl_target,
+ egl_buffer,
+ egl_attrib_list);
+
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+ }
+
+ void CreateEglImageOnUploadThread() {
+ CreateEglImage(thread_texture_id_);
+ }
+
+ void CreateEglImageOnMainThreadIfNeeded() {
+ if (egl_image_ == EGL_NO_IMAGE_KHR) {
+ CreateEglImage(texture_id_);
+ if (wait_for_creation_) {
+ TRACE_EVENT0("gpu", "glFinish creation");
+ glFinish();
+ }
+ }
+ }
+
+ void WaitForLastUpload() {
+ // This glFinish is just a safe-guard for if uploads have some
+ // GPU action that needs to occur. We could use fences and try
+ // to do this less often. However, on older drivers fences are
+ // not always reliable (eg. Mali-400 just blocks forever).
+ if (wait_for_uploads_) {
+ TRACE_EVENT0("gpu", "glFinish");
+ glFinish();
+ }
+ }
+
+ void MarkAsTransferIsInProgress() {
+ transfer_completion_.Reset();
+ }
+
+ void MarkAsCompleted() {
+ transfer_completion_.Signal();
+ }
+
+ void WaitForTransferCompletion() {
+ TRACE_EVENT0("gpu", "WaitForTransferCompletion");
+ // TODO(backer): Deschedule the channel rather than blocking the main GPU
+ // thread (crbug.com/240265).
+ transfer_completion_.Wait();
+ }
+
+ void PerformAsyncTexImage2D(
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
+ TRACE_EVENT2("gpu",
+ "PerformAsyncTexImage",
+ "width",
+ tex_params.width,
+ "height",
+ tex_params.height);
+ DCHECK(!thread_texture_id_);
+ DCHECK_EQ(0, tex_params.level);
+ DCHECK_EQ(EGL_NO_IMAGE_KHR, egl_image_);
+
+ void* data =
+ AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
+
+ base::TimeTicks begin_time;
+ if (texture_upload_stats.get())
+ begin_time = base::TimeTicks::HighResNow();
+
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D no data");
+ glGenTextures(1, &thread_texture_id_);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
+
+ SetGlParametersForEglImageTexture();
+
+ // If we need to use image_preserved, we pass the data with
+ // the allocation. Otherwise we use a NULL allocation to
+ // try to avoid any costs associated with creating the EGLImage.
+ if (use_image_preserved_)
+ DoTexImage2D(tex_params, data);
+ else
+ DoTexImage2D(tex_params, NULL);
+ }
+
+ CreateEglImageOnUploadThread();
+
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D with data");
+
+ // If we didn't use image_preserved, we haven't uploaded
+ // the data yet, so we do this with a full texSubImage.
+ if (!use_image_preserved_)
+ DoFullTexSubImage2D(tex_params, data);
+ }
+
+ WaitForLastUpload();
+ MarkAsCompleted();
+
+ DCHECK(CHECK_GL());
+ if (texture_upload_stats.get()) {
+ texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
+ begin_time);
+ }
+ }
+
+ void PerformAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
+ TRACE_EVENT2("gpu",
+ "PerformAsyncTexSubImage2D",
+ "width",
+ tex_params.width,
+ "height",
+ tex_params.height);
+
+ DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
+ DCHECK_EQ(0, tex_params.level);
+
+ void* data =
+ AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
+
+ base::TimeTicks begin_time;
+ if (texture_upload_stats.get())
+ begin_time = base::TimeTicks::HighResNow();
+
+ if (!thread_texture_id_) {
+ TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES");
+ glGenTextures(1, &thread_texture_id_);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
+ } else {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
+ }
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ DoTexSubImage2D(tex_params, data);
+ }
+ WaitForLastUpload();
+ MarkAsCompleted();
+
+ DCHECK(CHECK_GL());
+ if (texture_upload_stats.get()) {
+ texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
+ begin_time);
+ }
+ }
+
+ protected:
+ friend class base::RefCountedThreadSafe<TransferStateInternal>;
+ friend class gpu::AsyncPixelTransferDelegateEGL;
+
+ static void DeleteTexture(GLuint id) {
+ glDeleteTextures(1, &id);
+ }
+
+ virtual ~TransferStateInternal() {
+ if (egl_image_ != EGL_NO_IMAGE_KHR) {
+ EGLDisplay display = eglGetCurrentDisplay();
+ eglDestroyImageKHR(display, egl_image_);
+ }
+ if (thread_texture_id_) {
+ transfer_message_loop_proxy()->PostTask(FROM_HERE,
+ base::Bind(&DeleteTexture, thread_texture_id_));
+ }
+ }
+
+ // The 'real' texture.
+ GLuint texture_id_;
+
+ // The EGLImage sibling on the upload thread.
+ GLuint thread_texture_id_;
+
+ // Definition params for texture that needs binding.
+ AsyncTexImage2DParams define_params_;
+
+ // Indicates that an async transfer is in progress.
+ base::WaitableEvent transfer_completion_;
+
+ // It would be nice if we could just create a new EGLImage for
+ // every upload, but I found that didn't work, so this stores
+ // one for the lifetime of the texture.
+ EGLImageKHR egl_image_;
+
+ // Callback to invoke when AsyncTexImage2D is complete
+ // and the client can safely use the texture. This occurs
+ // during BindCompletedAsyncTransfers().
+ base::Closure bind_callback_;
+
+ // Customize when we block on fences (these are work-arounds).
+ bool wait_for_uploads_;
+ bool wait_for_creation_;
+ bool use_image_preserved_;
+};
+
+} // namespace
+
+// Class which handles async pixel transfers using EGLImageKHR and another
+// upload thread
+class AsyncPixelTransferDelegateEGL
+ : public AsyncPixelTransferDelegate,
+ public base::SupportsWeakPtr<AsyncPixelTransferDelegateEGL> {
+ public:
+ AsyncPixelTransferDelegateEGL(
+ AsyncPixelTransferManagerEGL::SharedState* shared_state,
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params);
+ virtual ~AsyncPixelTransferDelegateEGL();
+
+ void BindTransfer() { state_->BindTransfer(); }
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual void AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual bool TransferIsInProgress() OVERRIDE;
+ virtual void WaitForTransferCompletion() OVERRIDE;
+
+ private:
+ // Returns true if a work-around was used.
+ bool WorkAroundAsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback);
+ bool WorkAroundAsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params);
+
+ // A raw pointer is safe because the SharedState is owned by the Manager,
+ // which owns this Delegate.
+ AsyncPixelTransferManagerEGL::SharedState* shared_state_;
+ scoped_refptr<TransferStateInternal> state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateEGL);
+};
+
+AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL(
+ AsyncPixelTransferManagerEGL::SharedState* shared_state,
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params)
+ : shared_state_(shared_state) {
+ // We can't wait on uploads on imagination (it can take 200ms+).
+ // In practice, they are complete when the CPU glTexSubImage2D completes.
+ bool wait_for_uploads = !shared_state_->is_imagination;
+
+ // Qualcomm runs into texture corruption problems if the same texture is
+ // uploaded to with both async and normal uploads. Synchronize after EGLImage
+ // creation on the main thread as a work-around.
+ bool wait_for_creation = shared_state_->is_qualcomm;
+
+ // Qualcomm has a race when using image_preserved=FALSE,
+ // which can result in black textures even after the first upload.
+ // Since using FALSE is mainly for performance (to avoid layout changes),
+ // but Qualcomm itself doesn't seem to get any performance benefit,
+ // we just using image_preservedd=TRUE on Qualcomm as a work-around.
+ bool use_image_preserved =
+ shared_state_->is_qualcomm || shared_state_->is_imagination;
+
+ state_ = new TransferStateInternal(texture_id,
+ define_params,
+ wait_for_uploads,
+ wait_for_creation,
+ use_image_preserved);
+}
+
+AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {}
+
+bool AsyncPixelTransferDelegateEGL::TransferIsInProgress() {
+ return state_->TransferIsInProgress();
+}
+
+void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion() {
+ if (state_->TransferIsInProgress()) {
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+ g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Display);
+#endif
+
+ state_->WaitForTransferCompletion();
+ DCHECK(!state_->TransferIsInProgress());
+
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+ g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Background);
+#endif
+ }
+}
+
+void AsyncPixelTransferDelegateEGL::AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ if (WorkAroundAsyncTexImage2D(tex_params, mem_params, bind_callback))
+ return;
+
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK(!state_->TransferIsInProgress());
+ DCHECK_EQ(state_->egl_image_, EGL_NO_IMAGE_KHR);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK_EQ(tex_params.level, 0);
+
+ // Mark the transfer in progress and save the late bind
+ // callback, so we can notify the client when it is bound.
+ shared_state_->pending_allocations.push_back(AsWeakPtr());
+ state_->bind_callback_ = bind_callback;
+
+ // Mark the transfer in progress.
+ state_->MarkAsTransferIsInProgress();
+
+ // Duplicate the shared memory so there is no way we can get
+ // a use-after-free of the raw pixels.
+ transfer_message_loop_proxy()->PostTask(FROM_HERE,
+ base::Bind(
+ &TransferStateInternal::PerformAsyncTexImage2D,
+ state_,
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ shared_state_->texture_upload_stats));
+
+ DCHECK(CHECK_GL());
+}
+
+void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+ if (WorkAroundAsyncTexSubImage2D(tex_params, mem_params))
+ return;
+ DCHECK(!state_->TransferIsInProgress());
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK_EQ(tex_params.level, 0);
+
+ // Mark the transfer in progress.
+ state_->MarkAsTransferIsInProgress();
+
+ // If this wasn't async allocated, we don't have an EGLImage yet.
+ // Create the EGLImage if it hasn't already been created.
+ state_->CreateEglImageOnMainThreadIfNeeded();
+
+ // Duplicate the shared memory so there are no way we can get
+ // a use-after-free of the raw pixels.
+ transfer_message_loop_proxy()->PostTask(FROM_HERE,
+ base::Bind(
+ &TransferStateInternal::PerformAsyncTexSubImage2D,
+ state_,
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ shared_state_->texture_upload_stats));
+
+ DCHECK(CHECK_GL());
+}
+
+namespace {
+bool IsPowerOfTwo (unsigned int x) {
+ return ((x != 0) && !(x & (x - 1)));
+}
+
+bool IsMultipleOfEight(unsigned int x) {
+ return (x & 7) == 0;
+}
+
+bool DimensionsSupportImgFastPath(int width, int height) {
+ // Multiple of eight, but not a power of two.
+ return IsMultipleOfEight(width) &&
+ IsMultipleOfEight(height) &&
+ !(IsPowerOfTwo(width) &&
+ IsPowerOfTwo(height));
+}
+} // namespace
+
+// It is very difficult to stream uploads on Imagination GPUs:
+// - glTexImage2D defers a swizzle/stall until draw-time
+// - glTexSubImage2D will sleep for 16ms on a good day, and 100ms
+// or longer if OpenGL is in heavy use by another thread.
+// The one combination that avoids these problems requires:
+// a.) Allocations/Uploads must occur on different threads/contexts.
+// b.) Texture size must be non-power-of-two.
+// When using a+b, uploads will be incorrect/corrupt unless:
+// c.) Texture size must be a multiple-of-eight.
+//
+// To achieve a.) we allocate synchronously on the main thread followed
+// by uploading on the upload thread. When b/c are not true we fall back
+// on purely synchronous allocation/upload on the main thread.
+
+bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ if (!shared_state_->is_imagination)
+ return false;
+
+ // On imagination we allocate synchronously all the time, even
+ // if the dimensions support fast uploads. This is for part a.)
+ // above, so allocations occur on a different thread/context as uploads.
+ void* data = GetAddress(mem_params);
+ SetGlParametersForEglImageTexture();
+
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D with data");
+ DoTexImage2D(tex_params, data);
+ }
+
+ // The allocation has already occured, so mark it as finished
+ // and ready for binding.
+ CHECK(!state_->TransferIsInProgress());
+
+ // If the dimensions support fast async uploads, create the
+ // EGLImage for future uploads. The late bind should not
+ // be needed since the EGLImage was created from the main thread
+ // texture, but this is required to prevent an imagination driver crash.
+ if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
+ state_->CreateEglImageOnMainThreadIfNeeded();
+ shared_state_->pending_allocations.push_back(AsWeakPtr());
+ state_->bind_callback_ = bind_callback;
+ }
+
+ DCHECK(CHECK_GL());
+ return true;
+}
+
+bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ if (!shared_state_->is_imagination)
+ return false;
+
+ // If the dimensions support fast async uploads, we can use the
+ // normal async upload path for uploads.
+ if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
+ return false;
+
+ // Fall back on a synchronous stub as we don't have a known fast path.
+ // Also, older ICS drivers crash when we do any glTexSubImage2D on the
+ // same thread. To work around this we do glTexImage2D instead. Since
+ // we didn't create an EGLImage for this texture (see above), this is
+ // okay, but it limits this API to full updates for now.
+ DCHECK(!state_->egl_image_);
+ DCHECK_EQ(tex_params.xoffset, 0);
+ DCHECK_EQ(tex_params.yoffset, 0);
+ DCHECK_EQ(state_->define_params_.width, tex_params.width);
+ DCHECK_EQ(state_->define_params_.height, tex_params.height);
+ DCHECK_EQ(state_->define_params_.level, tex_params.level);
+ DCHECK_EQ(state_->define_params_.format, tex_params.format);
+ DCHECK_EQ(state_->define_params_.type, tex_params.type);
+
+ void* data = GetAddress(mem_params);
+ base::TimeTicks begin_time;
+ if (shared_state_->texture_upload_stats.get())
+ begin_time = base::TimeTicks::HighResNow();
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ // Note we use define_params_ instead of tex_params.
+ // The DCHECKs above verify this is always the same.
+ DoTexImage2D(state_->define_params_, data);
+ }
+ if (shared_state_->texture_upload_stats.get()) {
+ shared_state_->texture_upload_stats
+ ->AddUpload(base::TimeTicks::HighResNow() - begin_time);
+ }
+
+ DCHECK(CHECK_GL());
+ return true;
+}
+
+AsyncPixelTransferManagerEGL::SharedState::SharedState()
+ // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
+ : texture_upload_stats(new AsyncPixelTransferUploadStats) {
+ std::string vendor;
+ vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
+ is_imagination = vendor.find("Imagination") != std::string::npos;
+ is_qualcomm = vendor.find("Qualcomm") != std::string::npos;
+}
+
+AsyncPixelTransferManagerEGL::SharedState::~SharedState() {}
+
+AsyncPixelTransferManagerEGL::AsyncPixelTransferManagerEGL() {}
+
+AsyncPixelTransferManagerEGL::~AsyncPixelTransferManagerEGL() {}
+
+void AsyncPixelTransferManagerEGL::BindCompletedAsyncTransfers() {
+ scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
+
+ while(!shared_state_.pending_allocations.empty()) {
+ if (!shared_state_.pending_allocations.front().get()) {
+ shared_state_.pending_allocations.pop_front();
+ continue;
+ }
+ AsyncPixelTransferDelegateEGL* delegate =
+ shared_state_.pending_allocations.front().get();
+ // Terminate early, as all transfers finish in order, currently.
+ if (delegate->TransferIsInProgress())
+ break;
+
+ if (!texture_binder)
+ texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
+
+ // If the transfer is finished, bind it to the texture
+ // and remove it from pending list.
+ delegate->BindTransfer();
+ shared_state_.pending_allocations.pop_front();
+ }
+}
+
+void AsyncPixelTransferManagerEGL::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) {
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ // Post a PerformNotifyCompletion task to the upload thread. This task
+ // will run after all async transfers are complete.
+ transfer_message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&PerformNotifyCompletion,
+ mem_params,
+ base::Owned(
+ new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ make_scoped_refptr(observer)));
+}
+
+uint32 AsyncPixelTransferManagerEGL::GetTextureUploadCount() {
+ return shared_state_.texture_upload_stats->GetStats(NULL);
+}
+
+base::TimeDelta AsyncPixelTransferManagerEGL::GetTotalTextureUploadTime() {
+ base::TimeDelta total_texture_upload_time;
+ shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time);
+ return total_texture_upload_time;
+}
+
+void AsyncPixelTransferManagerEGL::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferManagerEGL::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManagerEGL::CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferDelegateEGL(
+ &shared_state_, ref->service_id(), define_params);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.h
new file mode 100644
index 00000000000..4c273fe7f52
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_egl.h
@@ -0,0 +1,57 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_EGL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_EGL_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "base/memory/ref_counted.h"
+
+namespace gpu {
+class AsyncPixelTransferDelegateEGL;
+class AsyncPixelTransferUploadStats;
+
+class AsyncPixelTransferManagerEGL : public AsyncPixelTransferManager {
+ public:
+ AsyncPixelTransferManagerEGL();
+ virtual ~AsyncPixelTransferManagerEGL();
+
+ // AsyncPixelTransferManager implementation:
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ // State shared between Managers and Delegates.
+ struct SharedState {
+ SharedState();
+ ~SharedState();
+
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats;
+ bool is_imagination;
+ bool is_qualcomm;
+ typedef std::list<base::WeakPtr<AsyncPixelTransferDelegateEGL> >
+ TransferQueue;
+ TransferQueue pending_allocations;
+ };
+
+ private:
+ // AsyncPixelTransferManager implementation:
+ virtual AsyncPixelTransferDelegate* CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+
+ SharedState shared_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManagerEGL);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_EGL_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc
new file mode 100644
index 00000000000..88aff575b08
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.cc
@@ -0,0 +1,338 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/memory/weak_ptr.h"
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+#include "ui/gl/scoped_binders.h"
+
+namespace gpu {
+
+namespace {
+
+base::LazyInstance<SafeSharedMemoryPool> g_safe_shared_memory_pool =
+ LAZY_INSTANCE_INITIALIZER;
+
+SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return g_safe_shared_memory_pool.Pointer();
+}
+
+static uint64 g_next_pixel_transfer_state_id = 1;
+
+void PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
+ TRACE_EVENT0("gpu", "PerformNotifyCompletion");
+ AsyncMemoryParams safe_mem_params = mem_params;
+ safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
+ observer->DidComplete(safe_mem_params);
+}
+
+} // namespace
+
+// Class which handles async pixel transfers in a platform
+// independent way.
+class AsyncPixelTransferDelegateIdle
+ : public AsyncPixelTransferDelegate,
+ public base::SupportsWeakPtr<AsyncPixelTransferDelegateIdle> {
+ public:
+ AsyncPixelTransferDelegateIdle(
+ AsyncPixelTransferManagerIdle::SharedState* state,
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params);
+ virtual ~AsyncPixelTransferDelegateIdle();
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual void AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual bool TransferIsInProgress() OVERRIDE;
+ virtual void WaitForTransferCompletion() OVERRIDE;
+
+ private:
+ void PerformAsyncTexImage2D(
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ const base::Closure& bind_callback,
+ ScopedSafeSharedMemory* safe_shared_memory);
+ void PerformAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory);
+
+ uint64 id_;
+ GLuint texture_id_;
+ bool transfer_in_progress_;
+ AsyncTexImage2DParams define_params_;
+
+ // Safe to hold a raw pointer because SharedState is owned by the Manager
+ // which owns the Delegate.
+ AsyncPixelTransferManagerIdle::SharedState* shared_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateIdle);
+};
+
+AsyncPixelTransferDelegateIdle::AsyncPixelTransferDelegateIdle(
+ AsyncPixelTransferManagerIdle::SharedState* shared_state,
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params)
+ : id_(g_next_pixel_transfer_state_id++),
+ texture_id_(texture_id),
+ transfer_in_progress_(false),
+ define_params_(define_params),
+ shared_state_(shared_state) {}
+
+AsyncPixelTransferDelegateIdle::~AsyncPixelTransferDelegateIdle() {}
+
+void AsyncPixelTransferDelegateIdle::AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+
+ shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
+ id_,
+ base::Bind(
+ &AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D,
+ AsWeakPtr(),
+ tex_params,
+ mem_params,
+ bind_callback,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)))));
+
+ transfer_in_progress_ = true;
+}
+
+void AsyncPixelTransferDelegateIdle::AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+
+ shared_state_->tasks.push_back(AsyncPixelTransferManagerIdle::Task(
+ id_,
+ base::Bind(
+ &AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D,
+ AsWeakPtr(),
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)))));
+
+ transfer_in_progress_ = true;
+}
+
+bool AsyncPixelTransferDelegateIdle::TransferIsInProgress() {
+ return transfer_in_progress_;
+}
+
+void AsyncPixelTransferDelegateIdle::WaitForTransferCompletion() {
+ for (std::list<AsyncPixelTransferManagerIdle::Task>::iterator iter =
+ shared_state_->tasks.begin();
+ iter != shared_state_->tasks.end();
+ ++iter) {
+ if (iter->transfer_id != id_)
+ continue;
+
+ (*iter).task.Run();
+ shared_state_->tasks.erase(iter);
+ break;
+ }
+
+ shared_state_->ProcessNotificationTasks();
+}
+
+void AsyncPixelTransferDelegateIdle::PerformAsyncTexImage2D(
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ const base::Closure& bind_callback,
+ ScopedSafeSharedMemory* safe_shared_memory) {
+ TRACE_EVENT2("gpu", "PerformAsyncTexImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+
+ void* data = GetAddress(safe_shared_memory, mem_params);
+
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_);
+
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D");
+ glTexImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.internal_format,
+ tex_params.width,
+ tex_params.height,
+ tex_params.border,
+ tex_params.format,
+ tex_params.type,
+ data);
+ }
+
+ transfer_in_progress_ = false;
+ shared_state_->texture_upload_count++;
+ shared_state_->total_texture_upload_time +=
+ base::TimeTicks::HighResNow() - begin_time;
+
+ // The texture is already fully bound so just call it now.
+ bind_callback.Run();
+}
+
+void AsyncPixelTransferDelegateIdle::PerformAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory) {
+ TRACE_EVENT2("gpu", "PerformAsyncTexSubImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+
+ void* data = GetAddress(safe_shared_memory, mem_params);
+
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ gfx::ScopedTextureBinder texture_binder(tex_params.target, texture_id_);
+
+ // If it's a full texture update, use glTexImage2D as it's faster.
+ // TODO(epenner): Make this configurable (http://crbug.com/259924)
+ if (tex_params.xoffset == 0 &&
+ tex_params.yoffset == 0 &&
+ tex_params.target == define_params_.target &&
+ tex_params.level == define_params_.level &&
+ tex_params.width == define_params_.width &&
+ tex_params.height == define_params_.height) {
+ TRACE_EVENT0("gpu", "glTexImage2D");
+ glTexImage2D(
+ define_params_.target,
+ define_params_.level,
+ define_params_.internal_format,
+ define_params_.width,
+ define_params_.height,
+ define_params_.border,
+ tex_params.format,
+ tex_params.type,
+ data);
+ } else {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ glTexSubImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.xoffset,
+ tex_params.yoffset,
+ tex_params.width,
+ tex_params.height,
+ tex_params.format,
+ tex_params.type,
+ data);
+ }
+
+ transfer_in_progress_ = false;
+ shared_state_->texture_upload_count++;
+ shared_state_->total_texture_upload_time +=
+ base::TimeTicks::HighResNow() - begin_time;
+}
+
+AsyncPixelTransferManagerIdle::Task::Task(
+ uint64 transfer_id, const base::Closure& task)
+ : transfer_id(transfer_id),
+ task(task) {
+}
+
+AsyncPixelTransferManagerIdle::Task::~Task() {}
+
+AsyncPixelTransferManagerIdle::SharedState::SharedState()
+ : texture_upload_count(0) {}
+
+AsyncPixelTransferManagerIdle::SharedState::~SharedState() {}
+
+void AsyncPixelTransferManagerIdle::SharedState::ProcessNotificationTasks() {
+ while (!tasks.empty()) {
+ // Stop when we reach a pixel transfer task.
+ if (tasks.front().transfer_id)
+ return;
+
+ tasks.front().task.Run();
+ tasks.pop_front();
+ }
+}
+
+AsyncPixelTransferManagerIdle::AsyncPixelTransferManagerIdle()
+ : shared_state_() {
+}
+
+AsyncPixelTransferManagerIdle::~AsyncPixelTransferManagerIdle() {}
+
+void AsyncPixelTransferManagerIdle::BindCompletedAsyncTransfers() {
+ // Everything is already bound.
+}
+
+void AsyncPixelTransferManagerIdle::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) {
+ if (shared_state_.tasks.empty()) {
+ observer->DidComplete(mem_params);
+ return;
+ }
+
+ shared_state_.tasks.push_back(
+ Task(0, // 0 transfer_id for notification tasks.
+ base::Bind(
+ &PerformNotifyCompletion,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ make_scoped_refptr(observer))));
+}
+
+uint32 AsyncPixelTransferManagerIdle::GetTextureUploadCount() {
+ return shared_state_.texture_upload_count;
+}
+
+base::TimeDelta AsyncPixelTransferManagerIdle::GetTotalTextureUploadTime() {
+ return shared_state_.total_texture_upload_time;
+}
+
+void AsyncPixelTransferManagerIdle::ProcessMorePendingTransfers() {
+ if (shared_state_.tasks.empty())
+ return;
+
+ // First task should always be a pixel transfer task.
+ DCHECK(shared_state_.tasks.front().transfer_id);
+ shared_state_.tasks.front().task.Run();
+ shared_state_.tasks.pop_front();
+
+ shared_state_.ProcessNotificationTasks();
+}
+
+bool AsyncPixelTransferManagerIdle::NeedsProcessMorePendingTransfers() {
+ return !shared_state_.tasks.empty();
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManagerIdle::CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferDelegateIdle(&shared_state_,
+ ref->service_id(),
+ define_params);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.h
new file mode 100644
index 00000000000..e7f990e317a
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_idle.h
@@ -0,0 +1,63 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_IDLE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_IDLE_H_
+
+#include <list>
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+namespace gpu {
+
+class AsyncPixelTransferManagerIdle : public AsyncPixelTransferManager {
+ public:
+ AsyncPixelTransferManagerIdle();
+ virtual ~AsyncPixelTransferManagerIdle();
+
+ // AsyncPixelTransferManager implementation:
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ struct Task {
+ Task(uint64 transfer_id, const base::Closure& task);
+ ~Task();
+
+ // This is non-zero if pixel transfer task.
+ uint64 transfer_id;
+
+ base::Closure task;
+ };
+
+ // State shared between Managers and Delegates.
+ struct SharedState {
+ SharedState();
+ ~SharedState();
+ void ProcessNotificationTasks();
+
+ int texture_upload_count;
+ base::TimeDelta total_texture_upload_time;
+ std::list<Task> tasks;
+ };
+
+ private:
+ // AsyncPixelTransferManager implementation:
+ virtual AsyncPixelTransferDelegate* CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+
+ SharedState shared_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManagerIdle);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_IDLE_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_linux.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_linux.cc
new file mode 100644
index 00000000000..8d25f00a0e4
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_linux.cc
@@ -0,0 +1,40 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_stub.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+AsyncPixelTransferManager* AsyncPixelTransferManager::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferManager::Create");
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableShareGroupAsyncTextureUpload)) {
+ DCHECK(context);
+ return static_cast<AsyncPixelTransferManager*> (
+ new AsyncPixelTransferManagerShareGroup(context));
+ }
+
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationOSMesaGL:
+ case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationEGLGLES2:
+ return new AsyncPixelTransferManagerIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferManagerStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mac.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mac.cc
new file mode 100644
index 00000000000..8c19b57d2fb
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mac.cc
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+AsyncPixelTransferManager* AsyncPixelTransferManager::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferManager::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationOSMesaGL:
+ case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationAppleGL:
+ return new AsyncPixelTransferManagerIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferManagerStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.cc
new file mode 100644
index 00000000000..84e95e3d883
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.cc
@@ -0,0 +1,15 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_mock.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+MockAsyncPixelTransferManager::MockAsyncPixelTransferManager() {}
+
+MockAsyncPixelTransferManager::~MockAsyncPixelTransferManager() {}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.h
new file mode 100644
index 00000000000..adc2a6f939e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_mock.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_TEST_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_TEST_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+class MockAsyncPixelTransferManager : public AsyncPixelTransferManager {
+ public:
+ MockAsyncPixelTransferManager();
+ virtual ~MockAsyncPixelTransferManager();
+
+ // AsyncPixelTransferManager implementation:
+ MOCK_METHOD0(BindCompletedAsyncTransfers, void());
+ MOCK_METHOD2(AsyncNotifyCompletion,
+ void(const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer));
+ MOCK_METHOD0(GetTextureUploadCount, uint32());
+ MOCK_METHOD0(GetTotalTextureUploadTime, base::TimeDelta());
+ MOCK_METHOD0(ProcessMorePendingTransfers, void());
+ MOCK_METHOD0(NeedsProcessMorePendingTransfers, bool());
+ MOCK_METHOD2(
+ CreatePixelTransferDelegateImpl,
+ AsyncPixelTransferDelegate*(gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockAsyncPixelTransferManager);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_TEST_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
new file mode 100644
index 00000000000..f71e07e76ee
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.cc
@@ -0,0 +1,579 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h"
+
+#include <list>
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/synchronization/cancellation_flag.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_checker.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gpu_preference.h"
+#include "ui/gl/scoped_binders.h"
+
+namespace gpu {
+
+namespace {
+
+const char kAsyncTransferThreadName[] = "AsyncTransferThread";
+
+void PerformNotifyCompletion(
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
+ TRACE_EVENT0("gpu", "PerformNotifyCompletion");
+ AsyncMemoryParams safe_mem_params = mem_params;
+ safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
+ observer->DidComplete(safe_mem_params);
+}
+
+// TODO(backer): Factor out common thread scheduling logic from the EGL and
+// ShareGroup implementations. http://crbug.com/239889
+class TransferThread : public base::Thread {
+ public:
+ TransferThread()
+ : base::Thread(kAsyncTransferThreadName),
+ initialized_(false) {
+ Start();
+#if defined(OS_ANDROID) || defined(OS_LINUX)
+ SetPriority(base::kThreadPriority_Background);
+#endif
+ }
+
+ virtual ~TransferThread() {
+ // The only instance of this class was declared leaky.
+ NOTREACHED();
+ }
+
+ void InitializeOnMainThread(gfx::GLContext* parent_context) {
+ TRACE_EVENT0("gpu", "TransferThread::InitializeOnMainThread");
+ if (initialized_)
+ return;
+
+ base::WaitableEvent wait_for_init(true, false);
+ message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&TransferThread::InitializeOnTransferThread,
+ base::Unretained(this),
+ base::Unretained(parent_context),
+ &wait_for_init));
+ wait_for_init.Wait();
+ }
+
+ virtual void CleanUp() OVERRIDE {
+ surface_ = NULL;
+ context_ = NULL;
+ }
+
+ SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return &safe_shared_memory_pool_;
+ }
+
+ private:
+ bool initialized_;
+
+ scoped_refptr<gfx::GLSurface> surface_;
+ scoped_refptr<gfx::GLContext> context_;
+ SafeSharedMemoryPool safe_shared_memory_pool_;
+
+ void InitializeOnTransferThread(gfx::GLContext* parent_context,
+ base::WaitableEvent* caller_wait) {
+ TRACE_EVENT0("gpu", "InitializeOnTransferThread");
+
+ if (!parent_context) {
+ LOG(ERROR) << "No parent context provided.";
+ caller_wait->Signal();
+ return;
+ }
+
+ surface_ = gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1));
+ if (!surface_.get()) {
+ LOG(ERROR) << "Unable to create GLSurface";
+ caller_wait->Signal();
+ return;
+ }
+
+ // TODO(backer): This is coded for integrated GPUs. For discrete GPUs
+ // we would probably want to use a PBO texture upload for a true async
+ // upload (that would hopefully be optimized as a DMA transfer by the
+ // driver).
+ context_ = gfx::GLContext::CreateGLContext(parent_context->share_group(),
+ surface_.get(),
+ gfx::PreferIntegratedGpu);
+ if (!context_.get()) {
+ LOG(ERROR) << "Unable to create GLContext.";
+ caller_wait->Signal();
+ return;
+ }
+
+ context_->MakeCurrent(surface_.get());
+ initialized_ = true;
+ caller_wait->Signal();
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(TransferThread);
+};
+
+base::LazyInstance<TransferThread>::Leaky
+ g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
+
+base::MessageLoopProxy* transfer_message_loop_proxy() {
+ return g_transfer_thread.Pointer()->message_loop_proxy().get();
+}
+
+SafeSharedMemoryPool* safe_shared_memory_pool() {
+ return g_transfer_thread.Pointer()->safe_shared_memory_pool();
+}
+
+class PendingTask : public base::RefCountedThreadSafe<PendingTask> {
+ public:
+ explicit PendingTask(const base::Closure& task)
+ : task_(task), task_pending_(true, false) {}
+
+ bool TryRun() {
+ // This is meant to be called on the main thread where the texture
+ // is already bound.
+ DCHECK(checker_.CalledOnValidThread());
+ if (task_lock_.Try()) {
+ // Only run once.
+ if (!task_.is_null())
+ task_.Run();
+ task_.Reset();
+
+ task_lock_.Release();
+ task_pending_.Signal();
+ return true;
+ }
+ return false;
+ }
+
+ void BindAndRun(GLuint texture_id) {
+ // This is meant to be called on the upload thread where we don't have to
+ // restore the previous texture binding.
+ DCHECK(!checker_.CalledOnValidThread());
+ base::AutoLock locked(task_lock_);
+ if (!task_.is_null()) {
+ glBindTexture(GL_TEXTURE_2D, texture_id);
+ task_.Run();
+ task_.Reset();
+ glBindTexture(GL_TEXTURE_2D, 0);
+ // Flush for synchronization between threads.
+ glFlush();
+ task_pending_.Signal();
+ }
+ }
+
+ void Cancel() {
+ base::AutoLock locked(task_lock_);
+ task_.Reset();
+ task_pending_.Signal();
+ }
+
+ bool TaskIsInProgress() {
+ return !task_pending_.IsSignaled();
+ }
+
+ void WaitForTask() {
+ task_pending_.Wait();
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<PendingTask>;
+
+ virtual ~PendingTask() {}
+
+ base::ThreadChecker checker_;
+
+ base::Lock task_lock_;
+ base::Closure task_;
+ base::WaitableEvent task_pending_;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingTask);
+};
+
+// Class which holds async pixel transfers state.
+// The texture_id is accessed by either thread, but everything
+// else accessed only on the main thread.
+class TransferStateInternal
+ : public base::RefCountedThreadSafe<TransferStateInternal> {
+ public:
+ TransferStateInternal(GLuint texture_id,
+ const AsyncTexImage2DParams& define_params)
+ : texture_id_(texture_id), define_params_(define_params) {}
+
+ bool TransferIsInProgress() {
+ return pending_upload_task_.get() &&
+ pending_upload_task_->TaskIsInProgress();
+ }
+
+ void BindTransfer() {
+ TRACE_EVENT2("gpu", "BindAsyncTransfer",
+ "width", define_params_.width,
+ "height", define_params_.height);
+ DCHECK(texture_id_);
+
+ glBindTexture(GL_TEXTURE_2D, texture_id_);
+ bind_callback_.Run();
+ }
+
+ void WaitForTransferCompletion() {
+ TRACE_EVENT0("gpu", "WaitForTransferCompletion");
+ DCHECK(pending_upload_task_.get());
+ if (!pending_upload_task_->TryRun()) {
+ pending_upload_task_->WaitForTask();
+ }
+ pending_upload_task_ = NULL;
+ }
+
+ void CancelUpload() {
+ TRACE_EVENT0("gpu", "CancelUpload");
+ if (pending_upload_task_.get())
+ pending_upload_task_->Cancel();
+ pending_upload_task_ = NULL;
+ }
+
+ void ScheduleAsyncTexImage2D(
+ const AsyncTexImage2DParams tex_params,
+ const AsyncMemoryParams mem_params,
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats,
+ const base::Closure& bind_callback) {
+ pending_upload_task_ = new PendingTask(base::Bind(
+ &TransferStateInternal::PerformAsyncTexImage2D,
+ this,
+ tex_params,
+ mem_params,
+ // Duplicate the shared memory so there is no way we can get
+ // a use-after-free of the raw pixels.
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ texture_upload_stats));
+ transfer_message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &PendingTask::BindAndRun, pending_upload_task_, texture_id_));
+
+ // Save the late bind callback, so we can notify the client when it is
+ // bound.
+ bind_callback_ = bind_callback;
+ }
+
+ void ScheduleAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
+ pending_upload_task_ = new PendingTask(base::Bind(
+ &TransferStateInternal::PerformAsyncTexSubImage2D,
+ this,
+ tex_params,
+ mem_params,
+ base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ texture_upload_stats));
+ transfer_message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &PendingTask::BindAndRun, pending_upload_task_, texture_id_));
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<TransferStateInternal>;
+
+ virtual ~TransferStateInternal() {
+ }
+
+ void PerformAsyncTexImage2D(
+ AsyncTexImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
+ TRACE_EVENT2("gpu",
+ "PerformAsyncTexImage",
+ "width",
+ tex_params.width,
+ "height",
+ tex_params.height);
+ DCHECK_EQ(0, tex_params.level);
+
+ base::TimeTicks begin_time;
+ if (texture_upload_stats.get())
+ begin_time = base::TimeTicks::HighResNow();
+
+ void* data =
+ AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
+
+ {
+ TRACE_EVENT0("gpu", "glTexImage2D");
+ glTexImage2D(GL_TEXTURE_2D,
+ tex_params.level,
+ tex_params.internal_format,
+ tex_params.width,
+ tex_params.height,
+ tex_params.border,
+ tex_params.format,
+ tex_params.type,
+ data);
+ }
+
+ if (texture_upload_stats.get()) {
+ texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
+ begin_time);
+ }
+ }
+
+ void PerformAsyncTexSubImage2D(
+ AsyncTexSubImage2DParams tex_params,
+ AsyncMemoryParams mem_params,
+ ScopedSafeSharedMemory* safe_shared_memory,
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
+ TRACE_EVENT2("gpu",
+ "PerformAsyncTexSubImage2D",
+ "width",
+ tex_params.width,
+ "height",
+ tex_params.height);
+ DCHECK_EQ(0, tex_params.level);
+
+ base::TimeTicks begin_time;
+ if (texture_upload_stats.get())
+ begin_time = base::TimeTicks::HighResNow();
+
+ void* data =
+ AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
+
+ {
+ TRACE_EVENT0("gpu", "glTexSubImage2D");
+ glTexSubImage2D(GL_TEXTURE_2D,
+ tex_params.level,
+ tex_params.xoffset,
+ tex_params.yoffset,
+ tex_params.width,
+ tex_params.height,
+ tex_params.format,
+ tex_params.type,
+ data);
+ }
+
+ if (texture_upload_stats.get()) {
+ texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
+ begin_time);
+ }
+ }
+
+ scoped_refptr<PendingTask> pending_upload_task_;
+
+ GLuint texture_id_;
+
+ // Definition params for texture that needs binding.
+ AsyncTexImage2DParams define_params_;
+
+ // Callback to invoke when AsyncTexImage2D is complete
+ // and the client can safely use the texture. This occurs
+ // during BindCompletedAsyncTransfers().
+ base::Closure bind_callback_;
+};
+
+} // namespace
+
+class AsyncPixelTransferDelegateShareGroup
+ : public AsyncPixelTransferDelegate,
+ public base::SupportsWeakPtr<AsyncPixelTransferDelegateShareGroup> {
+ public:
+ AsyncPixelTransferDelegateShareGroup(
+ AsyncPixelTransferManagerShareGroup::SharedState* shared_state,
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params);
+ virtual ~AsyncPixelTransferDelegateShareGroup();
+
+ void BindTransfer() { state_->BindTransfer(); }
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual void AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual bool TransferIsInProgress() OVERRIDE;
+ virtual void WaitForTransferCompletion() OVERRIDE;
+
+ private:
+ // A raw pointer is safe because the SharedState is owned by the Manager,
+ // which owns this Delegate.
+ AsyncPixelTransferManagerShareGroup::SharedState* shared_state_;
+ scoped_refptr<TransferStateInternal> state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateShareGroup);
+};
+
+AsyncPixelTransferDelegateShareGroup::AsyncPixelTransferDelegateShareGroup(
+ AsyncPixelTransferManagerShareGroup::SharedState* shared_state,
+ GLuint texture_id,
+ const AsyncTexImage2DParams& define_params)
+ : shared_state_(shared_state),
+ state_(new TransferStateInternal(texture_id, define_params)) {}
+
+AsyncPixelTransferDelegateShareGroup::~AsyncPixelTransferDelegateShareGroup() {
+ TRACE_EVENT0("gpu", " ~AsyncPixelTransferDelegateShareGroup");
+ state_->CancelUpload();
+}
+
+bool AsyncPixelTransferDelegateShareGroup::TransferIsInProgress() {
+ return state_->TransferIsInProgress();
+}
+
+void AsyncPixelTransferDelegateShareGroup::WaitForTransferCompletion() {
+ if (state_->TransferIsInProgress()) {
+ state_->WaitForTransferCompletion();
+ DCHECK(!state_->TransferIsInProgress());
+ }
+
+ // Fast track the BindTransfer, if applicable.
+ for (AsyncPixelTransferManagerShareGroup::SharedState::TransferQueue::iterator
+ iter = shared_state_->pending_allocations.begin();
+ iter != shared_state_->pending_allocations.end();
+ ++iter) {
+ if (iter->get() != this)
+ continue;
+
+ shared_state_->pending_allocations.erase(iter);
+ BindTransfer();
+ break;
+ }
+}
+
+void AsyncPixelTransferDelegateShareGroup::AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK(!state_->TransferIsInProgress());
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK_EQ(tex_params.level, 0);
+
+ shared_state_->pending_allocations.push_back(AsWeakPtr());
+ state_->ScheduleAsyncTexImage2D(tex_params,
+ mem_params,
+ shared_state_->texture_upload_stats,
+ bind_callback);
+}
+
+void AsyncPixelTransferDelegateShareGroup::AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
+ "width", tex_params.width,
+ "height", tex_params.height);
+ DCHECK(!state_->TransferIsInProgress());
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
+ DCHECK_EQ(tex_params.level, 0);
+
+ state_->ScheduleAsyncTexSubImage2D(
+ tex_params, mem_params, shared_state_->texture_upload_stats);
+}
+
+AsyncPixelTransferManagerShareGroup::SharedState::SharedState()
+ // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
+ : texture_upload_stats(new AsyncPixelTransferUploadStats) {}
+
+AsyncPixelTransferManagerShareGroup::SharedState::~SharedState() {}
+
+AsyncPixelTransferManagerShareGroup::AsyncPixelTransferManagerShareGroup(
+ gfx::GLContext* context) {
+ g_transfer_thread.Pointer()->InitializeOnMainThread(context);
+}
+
+AsyncPixelTransferManagerShareGroup::~AsyncPixelTransferManagerShareGroup() {}
+
+void AsyncPixelTransferManagerShareGroup::BindCompletedAsyncTransfers() {
+ scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
+
+ while (!shared_state_.pending_allocations.empty()) {
+ if (!shared_state_.pending_allocations.front().get()) {
+ shared_state_.pending_allocations.pop_front();
+ continue;
+ }
+ AsyncPixelTransferDelegateShareGroup* delegate =
+ shared_state_.pending_allocations.front().get();
+ // Terminate early, as all transfers finish in order, currently.
+ if (delegate->TransferIsInProgress())
+ break;
+
+ if (!texture_binder)
+ texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
+
+ // Used to set tex info from the gles2 cmd decoder once upload has
+ // finished (it'll bind the texture and call a callback).
+ delegate->BindTransfer();
+
+ shared_state_.pending_allocations.pop_front();
+ }
+}
+
+void AsyncPixelTransferManagerShareGroup::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) {
+ DCHECK(mem_params.shared_memory);
+ DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
+ mem_params.shm_size);
+ // Post a PerformNotifyCompletion task to the upload thread. This task
+ // will run after all async transfers are complete.
+ transfer_message_loop_proxy()->PostTask(
+ FROM_HERE,
+ base::Bind(&PerformNotifyCompletion,
+ mem_params,
+ base::Owned(
+ new ScopedSafeSharedMemory(safe_shared_memory_pool(),
+ mem_params.shared_memory,
+ mem_params.shm_size)),
+ make_scoped_refptr(observer)));
+}
+
+uint32 AsyncPixelTransferManagerShareGroup::GetTextureUploadCount() {
+ return shared_state_.texture_upload_stats->GetStats(NULL);
+}
+
+base::TimeDelta
+AsyncPixelTransferManagerShareGroup::GetTotalTextureUploadTime() {
+ base::TimeDelta total_texture_upload_time;
+ shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time);
+ return total_texture_upload_time;
+}
+
+void AsyncPixelTransferManagerShareGroup::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferManagerShareGroup::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManagerShareGroup::CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferDelegateShareGroup(
+ &shared_state_, ref->service_id(), define_params);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h
new file mode 100644
index 00000000000..173b5322faf
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_share_group.h
@@ -0,0 +1,59 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_SHARE_GROUP_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_SHARE_GROUP_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "base/memory/ref_counted.h"
+
+namespace gfx {
+class GLContext;
+}
+
+namespace gpu {
+class AsyncPixelTransferDelegateShareGroup;
+class AsyncPixelTransferUploadStats;
+
+class AsyncPixelTransferManagerShareGroup : public AsyncPixelTransferManager {
+ public:
+ explicit AsyncPixelTransferManagerShareGroup(gfx::GLContext* context);
+ virtual ~AsyncPixelTransferManagerShareGroup();
+
+ // AsyncPixelTransferManager implementation:
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ // State shared between Managers and Delegates.
+ struct SharedState {
+ SharedState();
+ ~SharedState();
+
+ scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats;
+ typedef std::list<base::WeakPtr<AsyncPixelTransferDelegateShareGroup> >
+ TransferQueue;
+ TransferQueue pending_allocations;
+ };
+
+ private:
+ // AsyncPixelTransferManager implementation:
+ virtual AsyncPixelTransferDelegate* CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+
+ SharedState shared_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManagerShareGroup);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_SHARE_GROUP_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.cc
new file mode 100644
index 00000000000..ccd5d3d3e60
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.cc
@@ -0,0 +1,88 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_stub.h"
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+
+class AsyncPixelTransferDelegateStub : public AsyncPixelTransferDelegate {
+ public:
+ AsyncPixelTransferDelegateStub();
+ virtual ~AsyncPixelTransferDelegateStub();
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual void AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual bool TransferIsInProgress() OVERRIDE;
+ virtual void WaitForTransferCompletion() OVERRIDE;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateStub);
+};
+
+AsyncPixelTransferDelegateStub::AsyncPixelTransferDelegateStub() {}
+
+AsyncPixelTransferDelegateStub::~AsyncPixelTransferDelegateStub() {}
+
+void AsyncPixelTransferDelegateStub::AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ bind_callback.Run();
+}
+
+void AsyncPixelTransferDelegateStub::AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+}
+
+bool AsyncPixelTransferDelegateStub::TransferIsInProgress() {
+ return false;
+}
+
+void AsyncPixelTransferDelegateStub::WaitForTransferCompletion() {}
+
+AsyncPixelTransferManagerStub::AsyncPixelTransferManagerStub() {}
+
+AsyncPixelTransferManagerStub::~AsyncPixelTransferManagerStub() {}
+
+void AsyncPixelTransferManagerStub::BindCompletedAsyncTransfers() {
+}
+
+void AsyncPixelTransferManagerStub::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) {
+ observer->DidComplete(mem_params);
+}
+
+uint32 AsyncPixelTransferManagerStub::GetTextureUploadCount() {
+ return 0;
+}
+
+base::TimeDelta AsyncPixelTransferManagerStub::GetTotalTextureUploadTime() {
+ return base::TimeDelta();
+}
+
+void AsyncPixelTransferManagerStub::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferManagerStub::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManagerStub::CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferDelegateStub();
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.h
new file mode 100644
index 00000000000..0f4e4ba95cd
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_stub.h
@@ -0,0 +1,38 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_STUB_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_STUB_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+namespace gpu {
+
+class AsyncPixelTransferManagerStub : public AsyncPixelTransferManager {
+ public:
+ AsyncPixelTransferManagerStub();
+ virtual ~AsyncPixelTransferManagerStub();
+
+ // AsyncPixelTransferManager implementation:
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ private:
+ // AsyncPixelTransferManager implementation:
+ virtual AsyncPixelTransferDelegate* CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManagerStub);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_STUB_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.cc
new file mode 100644
index 00000000000..ffe55849358
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.cc
@@ -0,0 +1,138 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_sync.h"
+
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+
+namespace gpu {
+
+// Class which handles async pixel transfers synchronously.
+class AsyncPixelTransferDelegateSync : public AsyncPixelTransferDelegate {
+ public:
+ explicit AsyncPixelTransferDelegateSync(
+ AsyncPixelTransferManagerSync::SharedState* shared_state);
+ virtual ~AsyncPixelTransferDelegateSync();
+
+ // Implement AsyncPixelTransferDelegate:
+ virtual void AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) OVERRIDE;
+ virtual void AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) OVERRIDE;
+ virtual bool TransferIsInProgress() OVERRIDE;
+ virtual void WaitForTransferCompletion() OVERRIDE;
+
+ private:
+ // Safe to hold a raw pointer because SharedState is owned by the Manager
+ // which owns the Delegate.
+ AsyncPixelTransferManagerSync::SharedState* shared_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateSync);
+};
+
+AsyncPixelTransferDelegateSync::AsyncPixelTransferDelegateSync(
+ AsyncPixelTransferManagerSync::SharedState* shared_state)
+ : shared_state_(shared_state) {}
+
+AsyncPixelTransferDelegateSync::~AsyncPixelTransferDelegateSync() {}
+
+void AsyncPixelTransferDelegateSync::AsyncTexImage2D(
+ const AsyncTexImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params,
+ const base::Closure& bind_callback) {
+ // Save the define params to return later during deferred
+ // binding of the transfer texture.
+ void* data = GetAddress(mem_params);
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ glTexImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.internal_format,
+ tex_params.width,
+ tex_params.height,
+ tex_params.border,
+ tex_params.format,
+ tex_params.type,
+ data);
+ shared_state_->texture_upload_count++;
+ shared_state_->total_texture_upload_time +=
+ base::TimeTicks::HighResNow() - begin_time;
+ // The texture is already fully bound so just call it now.
+ bind_callback.Run();
+}
+
+void AsyncPixelTransferDelegateSync::AsyncTexSubImage2D(
+ const AsyncTexSubImage2DParams& tex_params,
+ const AsyncMemoryParams& mem_params) {
+ void* data = GetAddress(mem_params);
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ glTexSubImage2D(
+ tex_params.target,
+ tex_params.level,
+ tex_params.xoffset,
+ tex_params.yoffset,
+ tex_params.width,
+ tex_params.height,
+ tex_params.format,
+ tex_params.type,
+ data);
+ shared_state_->texture_upload_count++;
+ shared_state_->total_texture_upload_time +=
+ base::TimeTicks::HighResNow() - begin_time;
+}
+
+bool AsyncPixelTransferDelegateSync::TransferIsInProgress() {
+ // Already done.
+ return false;
+}
+
+void AsyncPixelTransferDelegateSync::WaitForTransferCompletion() {
+ // Already done.
+}
+
+AsyncPixelTransferManagerSync::SharedState::SharedState()
+ : texture_upload_count(0) {}
+
+AsyncPixelTransferManagerSync::SharedState::~SharedState() {}
+
+AsyncPixelTransferManagerSync::AsyncPixelTransferManagerSync() {}
+
+AsyncPixelTransferManagerSync::~AsyncPixelTransferManagerSync() {}
+
+void AsyncPixelTransferManagerSync::BindCompletedAsyncTransfers() {
+ // Everything is already bound.
+}
+
+void AsyncPixelTransferManagerSync::AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) {
+ observer->DidComplete(mem_params);
+}
+
+uint32 AsyncPixelTransferManagerSync::GetTextureUploadCount() {
+ return shared_state_.texture_upload_count;
+}
+
+base::TimeDelta AsyncPixelTransferManagerSync::GetTotalTextureUploadTime() {
+ return shared_state_.total_texture_upload_time;
+}
+
+void AsyncPixelTransferManagerSync::ProcessMorePendingTransfers() {
+}
+
+bool AsyncPixelTransferManagerSync::NeedsProcessMorePendingTransfers() {
+ return false;
+}
+
+AsyncPixelTransferDelegate*
+AsyncPixelTransferManagerSync::CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) {
+ return new AsyncPixelTransferDelegateSync(&shared_state_);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.h b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.h
new file mode 100644
index 00000000000..cb62062a860
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_sync.h
@@ -0,0 +1,49 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_SYNC_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_SYNC_H_
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+namespace gpu {
+
+class AsyncPixelTransferManagerSync : public AsyncPixelTransferManager {
+ public:
+ AsyncPixelTransferManagerSync();
+ virtual ~AsyncPixelTransferManagerSync();
+
+ // AsyncPixelTransferManager implementation:
+ virtual void BindCompletedAsyncTransfers() OVERRIDE;
+ virtual void AsyncNotifyCompletion(
+ const AsyncMemoryParams& mem_params,
+ AsyncPixelTransferCompletionObserver* observer) OVERRIDE;
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual void ProcessMorePendingTransfers() OVERRIDE;
+ virtual bool NeedsProcessMorePendingTransfers() OVERRIDE;
+
+ // State shared between Managers and Delegates.
+ struct SharedState {
+ SharedState();
+ ~SharedState();
+
+ int texture_upload_count;
+ base::TimeDelta total_texture_upload_time;
+ };
+
+ private:
+ // AsyncPixelTransferManager implementation:
+ virtual AsyncPixelTransferDelegate* CreatePixelTransferDelegateImpl(
+ gles2::TextureRef* ref,
+ const AsyncTexImage2DParams& define_params) OVERRIDE;
+
+ SharedState shared_state_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferManagerSync);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ASYNC_PIXEL_TRANSFER_MANAGER_SYNC_H_
diff --git a/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_win.cc b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_win.cc
new file mode 100644
index 00000000000..69558855d5f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/async_pixel_transfer_manager_win.cc
@@ -0,0 +1,30 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_idle.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_stub.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+
+AsyncPixelTransferManager* AsyncPixelTransferManager::Create(
+ gfx::GLContext* context) {
+ TRACE_EVENT0("gpu", "AsyncPixelTransferManager::Create");
+ switch (gfx::GetGLImplementation()) {
+ case gfx::kGLImplementationOSMesaGL:
+ case gfx::kGLImplementationDesktopGL:
+ case gfx::kGLImplementationEGLGLES2:
+ return new AsyncPixelTransferManagerIdle;
+ case gfx::kGLImplementationMockGL:
+ return new AsyncPixelTransferManagerStub;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/buffer_manager.cc b/chromium/gpu/command_buffer/service/buffer_manager.cc
new file mode 100644
index 00000000000..f9cec7ace9a
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/buffer_manager.cc
@@ -0,0 +1,407 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include <limits>
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/context_state.h"
+#include "gpu/command_buffer/service/error_state.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+namespace gles2 {
+
+BufferManager::BufferManager(
+ MemoryTracker* memory_tracker,
+ FeatureInfo* feature_info)
+ : memory_tracker_(
+ new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
+ feature_info_(feature_info),
+ allow_buffers_on_multiple_targets_(false),
+ buffer_count_(0),
+ have_context_(true),
+ use_client_side_arrays_for_stream_buffers_(
+ feature_info ? feature_info->workarounds(
+ ).use_client_side_arrays_for_stream_buffers : 0) {
+}
+
+BufferManager::~BufferManager() {
+ DCHECK(buffers_.empty());
+ CHECK_EQ(buffer_count_, 0u);
+}
+
+void BufferManager::Destroy(bool have_context) {
+ have_context_ = have_context;
+ buffers_.clear();
+ DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
+}
+
+void BufferManager::CreateBuffer(GLuint client_id, GLuint service_id) {
+ scoped_refptr<Buffer> buffer(new Buffer(this, service_id));
+ std::pair<BufferMap::iterator, bool> result =
+ buffers_.insert(std::make_pair(client_id, buffer));
+ DCHECK(result.second);
+}
+
+Buffer* BufferManager::GetBuffer(
+ GLuint client_id) {
+ BufferMap::iterator it = buffers_.find(client_id);
+ return it != buffers_.end() ? it->second.get() : NULL;
+}
+
+void BufferManager::RemoveBuffer(GLuint client_id) {
+ BufferMap::iterator it = buffers_.find(client_id);
+ if (it != buffers_.end()) {
+ Buffer* buffer = it->second.get();
+ buffer->MarkAsDeleted();
+ buffers_.erase(it);
+ }
+}
+
+void BufferManager::StartTracking(Buffer* /* buffer */) {
+ ++buffer_count_;
+}
+
+void BufferManager::StopTracking(Buffer* buffer) {
+ memory_tracker_->TrackMemFree(buffer->size());
+ --buffer_count_;
+}
+
+Buffer::Buffer(BufferManager* manager, GLuint service_id)
+ : manager_(manager),
+ deleted_(false),
+ service_id_(service_id),
+ target_(0),
+ size_(0),
+ usage_(GL_STATIC_DRAW),
+ shadowed_(false),
+ is_client_side_array_(false) {
+ manager_->StartTracking(this);
+}
+
+Buffer::~Buffer() {
+ if (manager_) {
+ if (manager_->have_context_) {
+ GLuint id = service_id();
+ glDeleteBuffersARB(1, &id);
+ }
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+void Buffer::SetInfo(
+ GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
+ bool is_client_side_array) {
+ usage_ = usage;
+ is_client_side_array_ = is_client_side_array;
+ ClearCache();
+ if (size != size_ || shadow != shadowed_) {
+ shadowed_ = shadow;
+ size_ = size;
+ if (shadowed_) {
+ shadow_.reset(new int8[size]);
+ } else {
+ shadow_.reset();
+ }
+ }
+ if (shadowed_) {
+ if (data) {
+ memcpy(shadow_.get(), data, size);
+ } else {
+ memset(shadow_.get(), 0, size);
+ }
+ }
+}
+
+bool Buffer::CheckRange(
+ GLintptr offset, GLsizeiptr size) const {
+ int32 end = 0;
+ return offset >= 0 && size >= 0 &&
+ offset <= std::numeric_limits<int32>::max() &&
+ size <= std::numeric_limits<int32>::max() &&
+ SafeAddInt32(offset, size, &end) && end <= size_;
+}
+
+bool Buffer::SetRange(
+ GLintptr offset, GLsizeiptr size, const GLvoid * data) {
+ if (!CheckRange(offset, size)) {
+ return false;
+ }
+ if (shadowed_) {
+ memcpy(shadow_.get() + offset, data, size);
+ ClearCache();
+ }
+ return true;
+}
+
+const void* Buffer::GetRange(
+ GLintptr offset, GLsizeiptr size) const {
+ if (!shadowed_) {
+ return NULL;
+ }
+ if (!CheckRange(offset, size)) {
+ return NULL;
+ }
+ return shadow_.get() + offset;
+}
+
+void Buffer::ClearCache() {
+ range_set_.clear();
+}
+
+template <typename T>
+GLuint GetMaxValue(const void* data, GLuint offset, GLsizei count) {
+ GLuint max_value = 0;
+ const T* element = reinterpret_cast<const T*>(
+ static_cast<const int8*>(data) + offset);
+ const T* end = element + count;
+ for (; element < end; ++element) {
+ if (*element > max_value) {
+ max_value = *element;
+ }
+ }
+ return max_value;
+}
+
+bool Buffer::GetMaxValueForRange(
+ GLuint offset, GLsizei count, GLenum type, GLuint* max_value) {
+ Range range(offset, count, type);
+ RangeToMaxValueMap::iterator it = range_set_.find(range);
+ if (it != range_set_.end()) {
+ *max_value = it->second;
+ return true;
+ }
+
+ uint32 size;
+ if (!SafeMultiplyUint32(
+ count, GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type), &size)) {
+ return false;
+ }
+
+ if (!SafeAddUint32(offset, size, &size)) {
+ return false;
+ }
+
+ if (size > static_cast<uint32>(size_)) {
+ return false;
+ }
+
+ if (!shadowed_) {
+ return false;
+ }
+
+ // Scan the range for the max value and store
+ GLuint max_v = 0;
+ switch (type) {
+ case GL_UNSIGNED_BYTE:
+ max_v = GetMaxValue<uint8>(shadow_.get(), offset, count);
+ break;
+ case GL_UNSIGNED_SHORT:
+ // Check we are not accessing an odd byte for a 2 byte value.
+ if ((offset & 1) != 0) {
+ return false;
+ }
+ max_v = GetMaxValue<uint16>(shadow_.get(), offset, count);
+ break;
+ case GL_UNSIGNED_INT:
+ // Check we are not accessing a non aligned address for a 4 byte value.
+ if ((offset & 3) != 0) {
+ return false;
+ }
+ max_v = GetMaxValue<uint32>(shadow_.get(), offset, count);
+ break;
+ default:
+ NOTREACHED(); // should never get here by validation.
+ break;
+ }
+ range_set_.insert(std::make_pair(range, max_v));
+ *max_value = max_v;
+ return true;
+}
+
+bool BufferManager::GetClientId(GLuint service_id, GLuint* client_id) const {
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (BufferMap::const_iterator it = buffers_.begin();
+ it != buffers_.end(); ++it) {
+ if (it->second->service_id() == service_id) {
+ *client_id = it->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BufferManager::IsUsageClientSideArray(GLenum usage) {
+ return usage == GL_STREAM_DRAW && use_client_side_arrays_for_stream_buffers_;
+}
+
+bool BufferManager::UseNonZeroSizeForClientSideArrayBuffer() {
+ return feature_info_.get() &&
+ feature_info_->workarounds()
+ .use_non_zero_size_for_client_side_stream_buffers;
+}
+
+void BufferManager::SetInfo(
+ Buffer* buffer, GLsizeiptr size, GLenum usage, const GLvoid* data) {
+ DCHECK(buffer);
+ memory_tracker_->TrackMemFree(buffer->size());
+ bool is_client_side_array = IsUsageClientSideArray(usage);
+ bool shadow = buffer->target() == GL_ELEMENT_ARRAY_BUFFER ||
+ allow_buffers_on_multiple_targets_ ||
+ is_client_side_array;
+ buffer->SetInfo(size, usage, shadow, data, is_client_side_array);
+ memory_tracker_->TrackMemAlloc(buffer->size());
+}
+
+void BufferManager::ValidateAndDoBufferData(
+ ContextState* context_state, GLenum target, GLsizeiptr size,
+ const GLvoid * data, GLenum usage) {
+ ErrorState* error_state = context_state->GetErrorState();
+ if (!feature_info_->validators()->buffer_target.IsValid(target)) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, "glBufferData", target, "target");
+ return;
+ }
+ if (!feature_info_->validators()->buffer_usage.IsValid(usage)) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, "glBufferData", usage, "usage");
+ return;
+ }
+ if (size < 0) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_VALUE, "glBufferData", "size < 0");
+ return;
+ }
+
+ Buffer* buffer = GetBufferInfoForTarget(context_state, target);
+ if (!buffer) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_VALUE, "glBufferData", "unknown buffer");
+ return;
+ }
+
+ if (!memory_tracker_->EnsureGPUMemoryAvailable(size)) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_OUT_OF_MEMORY, "glBufferData", "out of memory");
+ return;
+ }
+
+ DoBufferData(error_state, buffer, size, usage, data);
+}
+
+
+void BufferManager::DoBufferData(
+ ErrorState* error_state,
+ Buffer* buffer,
+ GLsizeiptr size,
+ GLenum usage,
+ const GLvoid* data) {
+ // Clear the buffer to 0 if no initial data was passed in.
+ scoped_ptr<int8[]> zero;
+ if (!data) {
+ zero.reset(new int8[size]);
+ memset(zero.get(), 0, size);
+ data = zero.get();
+ }
+
+ ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glBufferData");
+ if (IsUsageClientSideArray(usage)) {
+ GLsizei empty_size = UseNonZeroSizeForClientSideArrayBuffer() ? 1 : 0;
+ glBufferData(buffer->target(), empty_size, NULL, usage);
+ } else {
+ glBufferData(buffer->target(), size, data, usage);
+ }
+ GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glBufferData");
+ if (error == GL_NO_ERROR) {
+ SetInfo(buffer, size, usage, data);
+ } else {
+ SetInfo(buffer, 0, usage, NULL);
+ }
+}
+
+void BufferManager::ValidateAndDoBufferSubData(
+ ContextState* context_state, GLenum target, GLintptr offset, GLsizeiptr size,
+ const GLvoid * data) {
+ ErrorState* error_state = context_state->GetErrorState();
+ Buffer* buffer = GetBufferInfoForTarget(context_state, target);
+ if (!buffer) {
+ ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, "glBufferSubData",
+ "unknown buffer");
+ return;
+ }
+
+ DoBufferSubData(error_state, buffer, offset, size, data);
+}
+
+void BufferManager::DoBufferSubData(
+ ErrorState* error_state,
+ Buffer* buffer,
+ GLintptr offset,
+ GLsizeiptr size,
+ const GLvoid* data) {
+ if (!buffer->SetRange(offset, size, data)) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_VALUE, "glBufferSubData", "out of range");
+ return;
+ }
+
+ if (!buffer->IsClientSideArray()) {
+ glBufferSubData(buffer->target(), offset, size, data);
+ }
+}
+
+void BufferManager::ValidateAndDoGetBufferParameteriv(
+ ContextState* context_state, GLenum target, GLenum pname, GLint* params) {
+ Buffer* buffer = GetBufferInfoForTarget(context_state, target);
+ if (!buffer) {
+ ERRORSTATE_SET_GL_ERROR(
+ context_state->GetErrorState(), GL_INVALID_OPERATION,
+ "glGetBufferParameteriv", "no buffer bound for target");
+ return;
+ }
+ switch (pname) {
+ case GL_BUFFER_SIZE:
+ *params = buffer->size();
+ break;
+ case GL_BUFFER_USAGE:
+ *params = buffer->usage();
+ break;
+ default:
+ NOTREACHED();
+ }
+}
+
+bool BufferManager::SetTarget(Buffer* buffer, GLenum target) {
+ // Check that we are not trying to bind it to a different target.
+ if (buffer->target() != 0 && buffer->target() != target &&
+ !allow_buffers_on_multiple_targets_) {
+ return false;
+ }
+ if (buffer->target() == 0) {
+ buffer->set_target(target);
+ }
+ return true;
+}
+
+// Since one BufferManager can be shared by multiple decoders, ContextState is
+// passed in each time and not just passed in during initialization.
+Buffer* BufferManager::GetBufferInfoForTarget(
+ ContextState* state, GLenum target) {
+ DCHECK(target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER);
+ if (target == GL_ARRAY_BUFFER) {
+ return state->bound_array_buffer.get();
+ } else {
+ return state->vertex_attrib_manager->element_array_buffer();
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/buffer_manager.h b/chromium/gpu/command_buffer/service/buffer_manager.h
new file mode 100644
index 00000000000..8ddf334d42f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/buffer_manager.h
@@ -0,0 +1,286 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_BUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_BUFFER_MANAGER_H_
+
+#include <map>
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class BufferManager;
+struct ContextState;
+class ErrorState;
+class FeatureInfo;
+class TestHelper;
+
+// Info about Buffers currently in the system.
+class GPU_EXPORT Buffer : public base::RefCounted<Buffer> {
+ public:
+ Buffer(BufferManager* manager, GLuint service_id);
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ GLenum target() const {
+ return target_;
+ }
+
+ GLsizeiptr size() const {
+ return size_;
+ }
+
+ GLenum usage() const {
+ return usage_;
+ }
+
+ // Gets the maximum value in the buffer for the given range interpreted as
+ // the given type. Returns false if offset and count are out of range.
+ // offset is in bytes.
+ // count is in elements of type.
+ bool GetMaxValueForRange(GLuint offset, GLsizei count, GLenum type,
+ GLuint* max_value);
+
+ // Returns a pointer to shadowed data.
+ const void* GetRange(GLintptr offset, GLsizeiptr size) const;
+
+ bool IsDeleted() const {
+ return deleted_;
+ }
+
+ bool IsValid() const {
+ return target() && !IsDeleted();
+ }
+
+ bool IsClientSideArray() const {
+ return is_client_side_array_;
+ }
+
+ private:
+ friend class BufferManager;
+ friend class BufferManagerTestBase;
+ friend class base::RefCounted<Buffer>;
+
+ // Represents a range in a buffer.
+ class Range {
+ public:
+ Range(GLuint offset, GLsizei count, GLenum type)
+ : offset_(offset),
+ count_(count),
+ type_(type) {
+ }
+
+ // A less functor provided for std::map so it can find ranges.
+ struct Less {
+ bool operator() (const Range& lhs, const Range& rhs) const {
+ if (lhs.offset_ != rhs.offset_) {
+ return lhs.offset_ < rhs.offset_;
+ }
+ if (lhs.count_ != rhs.count_) {
+ return lhs.count_ < rhs.count_;
+ }
+ return lhs.type_ < rhs.type_;
+ }
+ };
+
+ private:
+ GLuint offset_;
+ GLsizei count_;
+ GLenum type_;
+ };
+
+ ~Buffer();
+
+ void set_target(GLenum target) {
+ DCHECK_EQ(target_, 0u); // you can only set this once.
+ target_ = target;
+ }
+
+ bool shadowed() const {
+ return shadowed_;
+ }
+
+ void MarkAsDeleted() {
+ deleted_ = true;
+ }
+
+ // Sets the size, usage and initial data of a buffer.
+ // If shadow is true then if data is NULL buffer will be initialized to 0.
+ void SetInfo(
+ GLsizeiptr size, GLenum usage, bool shadow, const GLvoid* data,
+ bool is_client_side_array);
+
+ // Sets a range of data for this buffer. Returns false if the offset or size
+ // is out of range.
+ bool SetRange(
+ GLintptr offset, GLsizeiptr size, const GLvoid * data);
+
+ // Clears any cache of index ranges.
+ void ClearCache();
+
+ // Check if an offset, size range is valid for the current buffer.
+ bool CheckRange(GLintptr offset, GLsizeiptr size) const;
+
+ // The manager that owns this Buffer.
+ BufferManager* manager_;
+
+ // True if deleted.
+ bool deleted_;
+
+ // Service side buffer id.
+ GLuint service_id_;
+
+ // The type of buffer. 0 = unset, GL_BUFFER_ARRAY = vertex data,
+ // GL_ELEMENT_BUFFER_ARRAY = index data.
+ // Once set a buffer can not be used for something else.
+ GLenum target_;
+
+ // Size of buffer.
+ GLsizeiptr size_;
+
+ // Usage of buffer.
+ GLenum usage_;
+
+ // Whether or not the data is shadowed.
+ bool shadowed_;
+
+ // Whether or not this Buffer is not uploaded to the GPU but just
+ // sitting in local memory.
+ bool is_client_side_array_;
+
+ // A copy of the data in the buffer. This data is only kept if the target
+ // is backed_ = true.
+ scoped_ptr<int8[]> shadow_;
+
+ // A map of ranges to the highest value in that range of a certain type.
+ typedef std::map<Range, GLuint, Range::Less> RangeToMaxValueMap;
+ RangeToMaxValueMap range_set_;
+};
+
+// This class keeps track of the buffers and their sizes so we can do
+// bounds checking.
+//
+// NOTE: To support shared resources an instance of this class will need to be
+// shared by multiple GLES2Decoders.
+class GPU_EXPORT BufferManager {
+ public:
+ BufferManager(MemoryTracker* memory_tracker, FeatureInfo* feature_info);
+ ~BufferManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a Buffer for the given buffer.
+ void CreateBuffer(GLuint client_id, GLuint service_id);
+
+ // Gets the buffer info for the given buffer.
+ Buffer* GetBuffer(GLuint client_id);
+
+ // Removes a buffer info for the given buffer.
+ void RemoveBuffer(GLuint client_id);
+
+ // Gets a client id for a given service id.
+ bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
+ // Validates a glBufferSubData, and then calls DoBufferData if validation was
+ // successful.
+ void ValidateAndDoBufferSubData(
+ ContextState* context_state, GLenum target, GLintptr offset,
+ GLsizeiptr size, const GLvoid * data);
+
+ // Validates a glBufferData, and then calls DoBufferData if validation was
+ // successful.
+ void ValidateAndDoBufferData(
+ ContextState* context_state, GLenum target, GLsizeiptr size,
+ const GLvoid * data, GLenum usage);
+
+ // Validates a glGetBufferParameteriv, and then calls GetBufferParameteriv if
+ // validation was successful.
+ void ValidateAndDoGetBufferParameteriv(
+ ContextState* context_state, GLenum target, GLenum pname, GLint* params);
+
+ // Sets the target of a buffer. Returns false if the target can not be set.
+ bool SetTarget(Buffer* buffer, GLenum target);
+
+ void set_allow_buffers_on_multiple_targets(bool allow) {
+ allow_buffers_on_multiple_targets_ = allow;
+ }
+
+ size_t mem_represented() const {
+ return memory_tracker_->GetMemRepresented();
+ }
+
+ // Tells for a given usage if this would be a client side array.
+ bool IsUsageClientSideArray(GLenum usage);
+
+ // Tells whether a buffer that is emulated using client-side arrays should be
+ // set to a non-zero size.
+ bool UseNonZeroSizeForClientSideArrayBuffer();
+
+ private:
+ friend class Buffer;
+ friend class TestHelper; // Needs access to DoBufferData.
+ friend class BufferManagerTestBase; // Needs access to DoBufferSubData.
+ void StartTracking(Buffer* buffer);
+ void StopTracking(Buffer* buffer);
+
+ Buffer* GetBufferInfoForTarget(ContextState* state, GLenum target);
+
+ // Does a glBufferSubData and updates the approriate accounting.
+ // Assumes the values have already been validated.
+ void DoBufferSubData(
+ ErrorState* error_state,
+ Buffer* buffer,
+ GLintptr offset,
+ GLsizeiptr size,
+ const GLvoid* data);
+
+ // Does a glBufferData and updates the approprate accounting. Currently
+ // Assumes the values have already been validated.
+ void DoBufferData(
+ ErrorState* error_state,
+ Buffer* buffer,
+ GLsizeiptr size,
+ GLenum usage,
+ const GLvoid* data);
+
+ // Sets the size, usage and initial data of a buffer.
+ // If data is NULL buffer will be initialized to 0 if shadowed.
+ void SetInfo(
+ Buffer* buffer, GLsizeiptr size, GLenum usage, const GLvoid* data);
+
+ scoped_ptr<MemoryTypeTracker> memory_tracker_;
+ scoped_refptr<FeatureInfo> feature_info_;
+
+ // Info for each buffer in the system.
+ typedef base::hash_map<GLuint, scoped_refptr<Buffer> > BufferMap;
+ BufferMap buffers_;
+
+ // Whether or not buffers can be bound to multiple targets.
+ bool allow_buffers_on_multiple_targets_;
+
+ // Counts the number of Buffer allocated with 'this' as its manager.
+ // Allows to check no Buffer will outlive this.
+ unsigned int buffer_count_;
+
+ bool have_context_;
+ bool use_client_side_arrays_for_stream_buffers_;
+
+ DISALLOW_COPY_AND_ASSIGN(BufferManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_BUFFER_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/buffer_manager_unittest.cc b/chromium/gpu/command_buffer/service/buffer_manager_unittest.cc
new file mode 100644
index 00000000000..f6fb8386d03
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/buffer_manager_unittest.cc
@@ -0,0 +1,426 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/error_state_mock.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::_;
+using ::testing::Return;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+class BufferManagerTestBase : public testing::Test {
+ protected:
+ void SetUpBase(
+ MemoryTracker* memory_tracker,
+ FeatureInfo* feature_info,
+ const char* extensions) {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ if (feature_info) {
+ TestHelper::SetupFeatureInfoInitExpectations(gl_.get(), extensions);
+ feature_info->Initialize(NULL);
+ }
+ error_state_.reset(new MockErrorState());
+ manager_.reset(new BufferManager(memory_tracker, feature_info));
+ }
+
+ virtual void TearDown() {
+ manager_->Destroy(false);
+ manager_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ error_state_.reset();
+ gl_.reset();
+ }
+
+ GLenum GetTarget(const Buffer* buffer) const {
+ return buffer->target();
+ }
+
+ void DoBufferData(
+ Buffer* buffer, GLsizeiptr size, GLenum usage, const GLvoid* data,
+ GLenum error) {
+ TestHelper::DoBufferData(
+ gl_.get(), error_state_.get(), manager_.get(),
+ buffer, size, usage, data, error);
+ }
+
+ bool DoBufferSubData(
+ Buffer* buffer, GLintptr offset, GLsizeiptr size,
+ const GLvoid* data) {
+ bool success = true;
+ if (!buffer->CheckRange(offset, size)) {
+ EXPECT_CALL(*error_state_, SetGLError(_, _, GL_INVALID_VALUE, _, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ success = false;
+ } else if (!buffer->IsClientSideArray()) {
+ EXPECT_CALL(*gl_, BufferSubData(
+ buffer->target(), offset, size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ manager_->DoBufferSubData(
+ error_state_.get(), buffer, offset, size, data);
+ return success;
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_ptr<BufferManager> manager_;
+ scoped_ptr<MockErrorState> error_state_;
+};
+
+class BufferManagerTest : public BufferManagerTestBase {
+ protected:
+ virtual void SetUp() {
+ SetUpBase(NULL, NULL, "");
+ }
+};
+
+class BufferManagerMemoryTrackerTest : public BufferManagerTestBase {
+ protected:
+ virtual void SetUp() {
+ mock_memory_tracker_ = new StrictMock<MockMemoryTracker>();
+ SetUpBase(mock_memory_tracker_.get(), NULL, "");
+ }
+
+ scoped_refptr<MockMemoryTracker> mock_memory_tracker_;
+};
+
+class BufferManagerClientSideArraysTest : public BufferManagerTestBase {
+ protected:
+ virtual void SetUp() {
+ feature_info_ = new FeatureInfo();
+ feature_info_->workarounds_.use_client_side_arrays_for_stream_buffers =
+ true;
+ SetUpBase(NULL, feature_info_.get(), "");
+ }
+
+ scoped_refptr<FeatureInfo> feature_info_;
+};
+
+#define EXPECT_MEMORY_ALLOCATION_CHANGE(old_size, new_size, pool) \
+ EXPECT_CALL(*mock_memory_tracker_.get(), \
+ TrackMemoryAllocatedChange(old_size, new_size, pool)) \
+ .Times(1).RetiresOnSaturation()
+
+TEST_F(BufferManagerTest, Basic) {
+ const GLuint kClientBuffer1Id = 1;
+ const GLuint kServiceBuffer1Id = 11;
+ const GLsizeiptr kBuffer1Size = 123;
+ const GLuint kClientBuffer2Id = 2;
+ // Check we can create buffer.
+ manager_->CreateBuffer(kClientBuffer1Id, kServiceBuffer1Id);
+ // Check buffer got created.
+ Buffer* buffer1 = manager_->GetBuffer(kClientBuffer1Id);
+ ASSERT_TRUE(buffer1 != NULL);
+ EXPECT_EQ(0u, GetTarget(buffer1));
+ EXPECT_EQ(0, buffer1->size());
+ EXPECT_EQ(static_cast<GLenum>(GL_STATIC_DRAW), buffer1->usage());
+ EXPECT_FALSE(buffer1->IsDeleted());
+ EXPECT_FALSE(buffer1->IsClientSideArray());
+ EXPECT_EQ(kServiceBuffer1Id, buffer1->service_id());
+ GLuint client_id = 0;
+ EXPECT_TRUE(manager_->GetClientId(buffer1->service_id(), &client_id));
+ EXPECT_EQ(kClientBuffer1Id, client_id);
+ manager_->SetTarget(buffer1, GL_ELEMENT_ARRAY_BUFFER);
+ EXPECT_EQ(static_cast<GLenum>(GL_ELEMENT_ARRAY_BUFFER), GetTarget(buffer1));
+ // Check we and set its size.
+ DoBufferData(buffer1, kBuffer1Size, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_EQ(kBuffer1Size, buffer1->size());
+ EXPECT_EQ(static_cast<GLenum>(GL_DYNAMIC_DRAW), buffer1->usage());
+ // Check we get nothing for a non-existent buffer.
+ EXPECT_TRUE(manager_->GetBuffer(kClientBuffer2Id) == NULL);
+ // Check trying to a remove non-existent buffers does not crash.
+ manager_->RemoveBuffer(kClientBuffer2Id);
+ // Check that it gets deleted when the last reference is released.
+ EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kServiceBuffer1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ // Check we can't get the buffer after we remove it.
+ manager_->RemoveBuffer(kClientBuffer1Id);
+ EXPECT_TRUE(manager_->GetBuffer(kClientBuffer1Id) == NULL);
+}
+
+TEST_F(BufferManagerMemoryTrackerTest, Basic) {
+ const GLuint kClientBuffer1Id = 1;
+ const GLuint kServiceBuffer1Id = 11;
+ const GLsizeiptr kBuffer1Size1 = 123;
+ const GLsizeiptr kBuffer1Size2 = 456;
+ // Check we can create buffer.
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kManaged);
+ manager_->CreateBuffer(kClientBuffer1Id, kServiceBuffer1Id);
+ // Check buffer got created.
+ Buffer* buffer1 = manager_->GetBuffer(kClientBuffer1Id);
+ ASSERT_TRUE(buffer1 != NULL);
+ manager_->SetTarget(buffer1, GL_ELEMENT_ARRAY_BUFFER);
+ // Check we and set its size.
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size1, MemoryTracker::kManaged);
+ DoBufferData(buffer1, kBuffer1Size1, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size1, 0, MemoryTracker::kManaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, kBuffer1Size2, MemoryTracker::kManaged);
+ DoBufferData(buffer1, kBuffer1Size2, GL_DYNAMIC_DRAW, NULL, GL_NO_ERROR);
+ // On delete it will get freed.
+ EXPECT_MEMORY_ALLOCATION_CHANGE(kBuffer1Size2, 0, MemoryTracker::kManaged);
+}
+
+TEST_F(BufferManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create buffer.
+ manager_->CreateBuffer(kClient1Id, kService1Id);
+ // Check buffer got created.
+ Buffer* buffer1 = manager_->GetBuffer(kClient1Id);
+ ASSERT_TRUE(buffer1 != NULL);
+ EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_->Destroy(true);
+ // Check the resources were released.
+ buffer1 = manager_->GetBuffer(kClient1Id);
+ ASSERT_TRUE(buffer1 == NULL);
+}
+
+TEST_F(BufferManagerTest, DoBufferSubData) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
+ EXPECT_TRUE(DoBufferSubData(buffer, sizeof(data), 0, data));
+ EXPECT_FALSE(DoBufferSubData(buffer, sizeof(data), 1, data));
+ EXPECT_FALSE(DoBufferSubData(buffer, 0, sizeof(data) + 1, data));
+ EXPECT_FALSE(DoBufferSubData(buffer, -1, sizeof(data), data));
+ EXPECT_FALSE(DoBufferSubData(buffer, 0, -1, data));
+ DoBufferData(buffer, 1, GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ const int size = 0x20000;
+ scoped_ptr<uint8[]> temp(new uint8[size]);
+ EXPECT_FALSE(DoBufferSubData(buffer, 0 - size, size, temp.get()));
+ EXPECT_FALSE(DoBufferSubData(buffer, 1, size / 2, temp.get()));
+}
+
+TEST_F(BufferManagerTest, GetRange) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ const char* buf =
+ static_cast<const char*>(buffer->GetRange(0, sizeof(data)));
+ ASSERT_TRUE(buf != NULL);
+ const char* buf1 =
+ static_cast<const char*>(buffer->GetRange(1, sizeof(data) - 1));
+ EXPECT_EQ(buf + 1, buf1);
+ EXPECT_TRUE(buffer->GetRange(sizeof(data), 1) == NULL);
+ EXPECT_TRUE(buffer->GetRange(0, sizeof(data) + 1) == NULL);
+ EXPECT_TRUE(buffer->GetRange(-1, sizeof(data)) == NULL);
+ EXPECT_TRUE(buffer->GetRange(-0, -1) == NULL);
+ const int size = 0x20000;
+ DoBufferData(buffer, size / 2, GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(buffer->GetRange(0 - size, size) == NULL);
+ EXPECT_TRUE(buffer->GetRange(1, size / 2) == NULL);
+}
+
+TEST_F(BufferManagerTest, GetMaxValueForRangeUint8) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint8 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint8 new_data[] = {100, 120, 110};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
+ GLuint max_value;
+ // Check entire range succeeds.
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(10u, max_value);
+ // Check sub range succeeds.
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 4, 3, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(6u, max_value);
+ // Check changing sub range succeeds.
+ EXPECT_TRUE(DoBufferSubData(buffer, 4, sizeof(new_data), new_data));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 4, 3, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(120u, max_value);
+ max_value = 0;
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_EQ(120u, max_value);
+ // Check out of range fails.
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 0, 11, GL_UNSIGNED_BYTE, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 10, 1, GL_UNSIGNED_BYTE, &max_value));
+}
+
+TEST_F(BufferManagerTest, GetMaxValueForRangeUint16) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint16 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint16 new_data[] = {100, 120, 110};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
+ GLuint max_value;
+ // Check entire range succeeds.
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(10u, max_value);
+ // Check odd offset fails for GL_UNSIGNED_SHORT.
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 1, 10, GL_UNSIGNED_SHORT, &max_value));
+ // Check sub range succeeds.
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 8, 3, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(6u, max_value);
+ // Check changing sub range succeeds.
+ EXPECT_TRUE(DoBufferSubData(buffer, 8, sizeof(new_data), new_data));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 8, 3, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(120u, max_value);
+ max_value = 0;
+ EXPECT_TRUE(buffer->GetMaxValueForRange(
+ 0, 10, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_EQ(120u, max_value);
+ // Check out of range fails.
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 0, 11, GL_UNSIGNED_SHORT, &max_value));
+ EXPECT_FALSE(buffer->GetMaxValueForRange(
+ 20, 1, GL_UNSIGNED_SHORT, &max_value));
+}
+
+TEST_F(BufferManagerTest, GetMaxValueForRangeUint32) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint32 new_data[] = {100, 120, 110};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ EXPECT_TRUE(DoBufferSubData(buffer, 0, sizeof(data), data));
+ GLuint max_value;
+ // Check entire range succeeds.
+ EXPECT_TRUE(
+ buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(10u, max_value);
+ // Check non aligned offsets fails for GL_UNSIGNED_INT.
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(1, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(2, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(3, 10, GL_UNSIGNED_INT, &max_value));
+ // Check sub range succeeds.
+ EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(6u, max_value);
+ // Check changing sub range succeeds.
+ EXPECT_TRUE(DoBufferSubData(buffer, 16, sizeof(new_data), new_data));
+ EXPECT_TRUE(buffer->GetMaxValueForRange(16, 3, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(120u, max_value);
+ max_value = 0;
+ EXPECT_TRUE(buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(120u, max_value);
+ // Check out of range fails.
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(0, 11, GL_UNSIGNED_INT, &max_value));
+ EXPECT_FALSE(
+ buffer->GetMaxValueForRange(40, 1, GL_UNSIGNED_INT, &max_value));
+}
+
+TEST_F(BufferManagerTest, UseDeletedBuffer) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ scoped_refptr<Buffer> buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer.get() != NULL);
+ manager_->SetTarget(buffer.get(), GL_ARRAY_BUFFER);
+ // Remove buffer
+ manager_->RemoveBuffer(kClientBufferId);
+ // Use it after removing
+ DoBufferData(buffer.get(), sizeof(data), GL_STATIC_DRAW, NULL, GL_NO_ERROR);
+ // Check that it gets deleted when the last reference is released.
+ EXPECT_CALL(*gl_, DeleteBuffersARB(1, ::testing::Pointee(kServiceBufferId)))
+ .Times(1)
+ .RetiresOnSaturation();
+ buffer = NULL;
+}
+
+// Test buffers get shadowed when they are supposed to be.
+TEST_F(BufferManagerClientSideArraysTest, StreamBuffersAreShadowed) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ static const uint32 data[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ARRAY_BUFFER);
+ DoBufferData(buffer, sizeof(data), GL_STREAM_DRAW, data, GL_NO_ERROR);
+ EXPECT_TRUE(buffer->IsClientSideArray());
+ EXPECT_EQ(0, memcmp(data, buffer->GetRange(0, sizeof(data)), sizeof(data)));
+ DoBufferData(buffer, sizeof(data), GL_DYNAMIC_DRAW, data, GL_NO_ERROR);
+ EXPECT_FALSE(buffer->IsClientSideArray());
+}
+
+TEST_F(BufferManagerTest, MaxValueCacheClearedCorrectly) {
+ const GLuint kClientBufferId = 1;
+ const GLuint kServiceBufferId = 11;
+ const uint32 data1[] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
+ const uint32 data2[] = {11, 12, 13, 14, 15, 16, 17, 18, 19, 20};
+ const uint32 data3[] = {30, 29, 28};
+ manager_->CreateBuffer(kClientBufferId, kServiceBufferId);
+ Buffer* buffer = manager_->GetBuffer(kClientBufferId);
+ ASSERT_TRUE(buffer != NULL);
+ manager_->SetTarget(buffer, GL_ELEMENT_ARRAY_BUFFER);
+ GLuint max_value;
+ // Load the buffer with some initial data, and then get the maximum value for
+ // a range, which has the side effect of caching it.
+ DoBufferData(buffer, sizeof(data1), GL_STATIC_DRAW, data1, GL_NO_ERROR);
+ EXPECT_TRUE(
+ buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(10u, max_value);
+ // Check that any cached values are invalidated if the buffer is reloaded
+ // with the same amount of data (but different content)
+ ASSERT_EQ(sizeof(data2), sizeof(data1));
+ DoBufferData(buffer, sizeof(data2), GL_STATIC_DRAW, data2, GL_NO_ERROR);
+ EXPECT_TRUE(
+ buffer->GetMaxValueForRange(0, 10, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(20u, max_value);
+ // Check that any cached values are invalidated if the buffer is reloaded
+ // with entirely different content.
+ ASSERT_NE(sizeof(data3), sizeof(data1));
+ DoBufferData(buffer, sizeof(data3), GL_STATIC_DRAW, data3, GL_NO_ERROR);
+ EXPECT_TRUE(
+ buffer->GetMaxValueForRange(0, 3, GL_UNSIGNED_INT, &max_value));
+ EXPECT_EQ(30u, max_value);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/cmd_buffer_engine.h b/chromium/gpu/command_buffer/service/cmd_buffer_engine.h
new file mode 100644
index 00000000000..6aefe82e35e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/cmd_buffer_engine.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file defines the CommandBufferEngine class, providing the main loop for
+// the service, exposing the RPC API, managing the command parser.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CMD_BUFFER_ENGINE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CMD_BUFFER_ENGINE_H_
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/common/buffer.h"
+
+namespace gpu {
+
+class CommandBufferEngine {
+ public:
+ CommandBufferEngine() {
+ }
+
+ virtual ~CommandBufferEngine() {
+ }
+
+ // Gets the base address and size of a registered shared memory buffer.
+ // Parameters:
+ // shm_id: the identifier for the shared memory buffer.
+ virtual Buffer GetSharedMemoryBuffer(int32 shm_id) = 0;
+
+ // Sets the token value.
+ virtual void set_token(int32 token) = 0;
+
+ // Sets the shared memory buffer used for commands.
+ virtual bool SetGetBuffer(int32 transfer_buffer_id) = 0;
+
+ // Sets the "get" pointer. Return false if offset is out of range.
+ virtual bool SetGetOffset(int32 offset) = 0;
+
+ // Gets the "get" pointer.
+ virtual int32 GetGetOffset() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferEngine);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CMD_BUFFER_ENGINE_H_
diff --git a/chromium/gpu/command_buffer/service/cmd_parser.cc b/chromium/gpu/command_buffer/service/cmd_parser.cc
new file mode 100644
index 00000000000..0ca1e616a86
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/cmd_parser.cc
@@ -0,0 +1,107 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the implementation of the command parser.
+
+#include "gpu/command_buffer/service/cmd_parser.h"
+
+#include "base/logging.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+
+namespace gpu {
+
+CommandParser::CommandParser(AsyncAPIInterface* handler)
+ : get_(0),
+ put_(0),
+ buffer_(NULL),
+ entry_count_(0),
+ handler_(handler),
+ trace_gl_commands_(false) {
+ trace_gl_commands_ =
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceGL);
+}
+
+void CommandParser::SetBuffer(
+ void* shm_address,
+ size_t shm_size,
+ ptrdiff_t offset,
+ size_t size) {
+ // check proper alignments.
+ DCHECK_EQ(0, (reinterpret_cast<intptr_t>(shm_address)) % 4);
+ DCHECK_EQ(0, offset % 4);
+ DCHECK_EQ(0u, size % 4);
+ // check that the command buffer fits into the memory buffer.
+ DCHECK_GE(shm_size, offset + size);
+ get_ = 0;
+ put_ = 0;
+ char* buffer_begin = static_cast<char*>(shm_address) + offset;
+ buffer_ = reinterpret_cast<CommandBufferEntry*>(buffer_begin);
+ entry_count_ = size / 4;
+}
+
+// Process one command, reading the header from the command buffer, and
+// forwarding the command index and the arguments to the handler.
+// Note that:
+// - validation needs to happen on a copy of the data (to avoid race
+// conditions). This function only validates the header, leaving the arguments
+// validation to the handler, so it can pass a reference to them.
+// - get_ is modified *after* the command has been executed.
+error::Error CommandParser::ProcessCommand() {
+ CommandBufferOffset get = get_;
+ if (get == put_)
+ return error::kNoError;
+
+ CommandHeader header = buffer_[get].value_header;
+ if (header.size == 0) {
+ DVLOG(1) << "Error: zero sized command in command buffer";
+ return error::kInvalidSize;
+ }
+
+ if (static_cast<int>(header.size) + get > entry_count_) {
+ DVLOG(1) << "Error: get offset out of bounds";
+ return error::kOutOfBounds;
+ }
+
+ if (trace_gl_commands_)
+ TRACE_EVENT_BEGIN0("cb_command", handler_->GetCommandName(header.command));
+
+ error::Error result = handler_->DoCommand(
+ header.command, header.size - 1, buffer_ + get);
+
+ // TODO(gman): If you want to log errors this is the best place to catch them.
+ // It seems like we need an official way to turn on a debug mode and
+ // get these errors.
+ if (error::IsError(result)) {
+ ReportError(header.command, result);
+ }
+
+ // If get was not set somewhere else advance it.
+ if (get == get_ && result != error::kDeferCommandUntilLater)
+ get_ = (get + header.size) % entry_count_;
+
+ if (trace_gl_commands_)
+ TRACE_EVENT_END0("cb_command", handler_->GetCommandName(header.command));
+ return result;
+}
+
+void CommandParser::ReportError(unsigned int command_id,
+ error::Error result) {
+ DVLOG(1) << "Error: " << result << " for Command "
+ << handler_->GetCommandName(command_id);
+}
+
+// Processes all the commands, while the buffer is not empty. Stop if an error
+// is encountered.
+error::Error CommandParser::ProcessAllCommands() {
+ while (!IsEmpty()) {
+ error::Error error = ProcessCommand();
+ if (error)
+ return error;
+ }
+ return error::kNoError;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/cmd_parser.h b/chromium/gpu/command_buffer/service/cmd_parser.h
new file mode 100644
index 00000000000..c808c4e7e66
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/cmd_parser.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the command parser class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CMD_PARSER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CMD_PARSER_H_
+
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class AsyncAPIInterface;
+
+// Command parser class. This class parses commands from a shared memory
+// buffer, to implement some asynchronous RPC mechanism.
+class GPU_EXPORT CommandParser {
+ public:
+ explicit CommandParser(AsyncAPIInterface* handler);
+
+ // Sets the buffer to read commands from.
+ void SetBuffer(
+ void* shm_address,
+ size_t shm_size,
+ ptrdiff_t offset,
+ size_t size);
+
+ // Gets the "get" pointer. The get pointer is an index into the command
+ // buffer considered as an array of CommandBufferEntry.
+ CommandBufferOffset get() const { return get_; }
+
+ // Sets the "get" pointer. The get pointer is an index into the command buffer
+ // considered as an array of CommandBufferEntry.
+ bool set_get(CommandBufferOffset get) {
+ if (get >= 0 && get < entry_count_) {
+ get_ = get;
+ return true;
+ }
+ return false;
+ }
+
+ // Sets the "put" pointer. The put pointer is an index into the command
+ // buffer considered as an array of CommandBufferEntry.
+ void set_put(CommandBufferOffset put) { put_ = put; }
+
+ // Gets the "put" pointer. The put pointer is an index into the command
+ // buffer considered as an array of CommandBufferEntry.
+ CommandBufferOffset put() const { return put_; }
+
+ // Checks whether there are commands to process.
+ bool IsEmpty() const { return put_ == get_; }
+
+ // Processes one command, updating the get pointer. This will return an error
+ // if there are no commands in the buffer.
+ error::Error ProcessCommand();
+
+ // Processes all commands until get == put.
+ error::Error ProcessAllCommands();
+
+ // Reports an error.
+ void ReportError(unsigned int command_id, error::Error result);
+
+ private:
+ CommandBufferOffset get_;
+ CommandBufferOffset put_;
+ CommandBufferEntry* buffer_;
+ int32 entry_count_;
+ AsyncAPIInterface* handler_;
+ bool trace_gl_commands_;
+};
+
+// This class defines the interface for an asynchronous API handler, that
+// is responsible for de-multiplexing commands and their arguments.
+class AsyncAPIInterface {
+ public:
+ AsyncAPIInterface() {}
+ virtual ~AsyncAPIInterface() {}
+
+ // Executes a command.
+ // Parameters:
+ // command: the command index.
+ // arg_count: the number of CommandBufferEntry arguments.
+ // cmd_data: the command data.
+ // Returns:
+ // error::kNoError if no error was found, one of
+ // error::Error otherwise.
+ virtual error::Error DoCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) = 0;
+
+ // Returns a name for a command. Useful for logging / debuging.
+ virtual const char* GetCommandName(unsigned int command_id) const = 0;
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CMD_PARSER_H_
diff --git a/chromium/gpu/command_buffer/service/cmd_parser_test.cc b/chromium/gpu/command_buffer/service/cmd_parser_test.cc
new file mode 100644
index 00000000000..232ebe7dd09
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/cmd_parser_test.cc
@@ -0,0 +1,319 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Tests for the command parser.
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+using testing::Return;
+using testing::Mock;
+using testing::Truly;
+using testing::Sequence;
+using testing::_;
+
+// Test fixture for CommandParser test - Creates a mock AsyncAPIInterface, and
+// a fixed size memory buffer. Also provides a simple API to create a
+// CommandParser.
+class CommandParserTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ api_mock_.reset(new AsyncAPIMock);
+ buffer_entry_count_ = 20;
+ buffer_.reset(new CommandBufferEntry[buffer_entry_count_]);
+ }
+ virtual void TearDown() {}
+
+ // Adds a DoCommand expectation in the mock.
+ void AddDoCommandExpect(error::Error _return,
+ unsigned int command,
+ unsigned int arg_count,
+ CommandBufferEntry *args) {
+ EXPECT_CALL(*api_mock(), DoCommand(command, arg_count,
+ Truly(AsyncAPIMock::IsArgs(arg_count, args))))
+ .InSequence(sequence_)
+ .WillOnce(Return(_return));
+ }
+
+ // Creates a parser, with a buffer of the specified size (in entries).
+ CommandParser *MakeParser(unsigned int entry_count) {
+ size_t shm_size = buffer_entry_count_ *
+ sizeof(CommandBufferEntry); // NOLINT
+ size_t command_buffer_size = entry_count *
+ sizeof(CommandBufferEntry); // NOLINT
+ DCHECK_LE(command_buffer_size, shm_size);
+ CommandParser* parser = new CommandParser(api_mock());
+
+ parser->SetBuffer(buffer(), shm_size, 0, command_buffer_size);
+ return parser;
+ }
+
+ unsigned int buffer_entry_count() { return 20; }
+ AsyncAPIMock *api_mock() { return api_mock_.get(); }
+ CommandBufferEntry *buffer() { return buffer_.get(); }
+ private:
+ unsigned int buffer_entry_count_;
+ scoped_ptr<AsyncAPIMock> api_mock_;
+ scoped_ptr<CommandBufferEntry[]> buffer_;
+ Sequence sequence_;
+};
+
+// Tests initialization conditions.
+TEST_F(CommandParserTest, TestInit) {
+ scoped_ptr<CommandParser> parser(MakeParser(10));
+ EXPECT_EQ(0, parser->get());
+ EXPECT_EQ(0, parser->put());
+ EXPECT_TRUE(parser->IsEmpty());
+}
+
+// Tests simple commands.
+TEST_F(CommandParserTest, TestSimple) {
+ scoped_ptr<CommandParser> parser(MakeParser(10));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add a single command, no args
+ header.size = 1;
+ header.command = 123;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ AddDoCommandExpect(error::kNoError, 123, 0, NULL);
+ EXPECT_EQ(error::kNoError, parser->ProcessCommand());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add a single command, 2 args
+ header.size = 3;
+ header.command = 456;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 2134;
+ buffer()[put++].value_float = 1.f;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ CommandBufferEntry param_array[2];
+ param_array[0].value_int32 = 2134;
+ param_array[1].value_float = 1.f;
+ AddDoCommandExpect(error::kNoError, 456, 2, param_array);
+ EXPECT_EQ(error::kNoError, parser->ProcessCommand());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+// Tests having multiple commands in the buffer.
+TEST_F(CommandParserTest, TestMultipleCommands) {
+ scoped_ptr<CommandParser> parser(MakeParser(10));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add 2 commands, test with single ProcessCommand()
+ header.size = 2;
+ header.command = 789;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 5151;
+
+ CommandBufferOffset put_cmd2 = put;
+ header.size = 2;
+ header.command = 876;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 3434;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ CommandBufferEntry param_array[2];
+ param_array[0].value_int32 = 5151;
+ AddDoCommandExpect(error::kNoError, 789, 1, param_array);
+ param_array[1].value_int32 = 3434;
+ AddDoCommandExpect(error::kNoError, 876, 1,
+ param_array+1);
+
+ EXPECT_EQ(error::kNoError, parser->ProcessCommand());
+ EXPECT_EQ(put_cmd2, parser->get());
+ EXPECT_EQ(error::kNoError, parser->ProcessCommand());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add 2 commands again, test with ProcessAllCommands()
+ header.size = 2;
+ header.command = 123;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 5656;
+
+ header.size = 2;
+ header.command = 321;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 7878;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+
+ param_array[0].value_int32 = 5656;
+ AddDoCommandExpect(error::kNoError, 123, 1, param_array);
+ param_array[1].value_int32 = 7878;
+ AddDoCommandExpect(error::kNoError, 321, 1,
+ param_array+1);
+
+ EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+// Tests that the parser will wrap correctly at the end of the buffer.
+TEST_F(CommandParserTest, TestWrap) {
+ scoped_ptr<CommandParser> parser(MakeParser(5));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add 3 commands with no args (1 word each)
+ for (unsigned int i = 0; i < 3; ++i) {
+ header.size = 1;
+ header.command = i;
+ buffer()[put++].value_header = header;
+ AddDoCommandExpect(error::kNoError, i, 0, NULL);
+ }
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add 1 command with 1 arg (2 words). That should put us at the end of the
+ // buffer.
+ header.size = 2;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 5;
+ CommandBufferEntry param;
+ param.value_int32 = 5;
+ AddDoCommandExpect(error::kNoError, 3, 1, &param);
+
+ DCHECK_EQ(5, put);
+ put = 0;
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ // add 1 command with 1 arg (2 words).
+ header.size = 2;
+ header.command = 4;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 6;
+ param.value_int32 = 6;
+ AddDoCommandExpect(error::kNoError, 4, 1, &param);
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+// Tests error conditions.
+TEST_F(CommandParserTest, TestError) {
+ const unsigned int kNumEntries = 5;
+ scoped_ptr<CommandParser> parser(MakeParser(kNumEntries));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ EXPECT_FALSE(parser->set_get(-1));
+ EXPECT_FALSE(parser->set_get(kNumEntries));
+
+ // Generate a command with size 0.
+ header.size = 0;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(error::kInvalidSize,
+ parser->ProcessAllCommands());
+ // check that no DoCommand call was made.
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ parser.reset(MakeParser(5));
+ put = parser->put();
+
+ // Generate a command with size 6, extends beyond the end of the buffer.
+ header.size = 6;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ EXPECT_EQ(error::kOutOfBounds,
+ parser->ProcessAllCommands());
+ // check that no DoCommand call was made.
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ parser.reset(MakeParser(5));
+ put = parser->put();
+
+ // Generates 2 commands.
+ header.size = 1;
+ header.command = 3;
+ buffer()[put++].value_header = header;
+ CommandBufferOffset put_post_fail = put;
+ header.size = 1;
+ header.command = 4;
+ buffer()[put++].value_header = header;
+
+ parser->set_put(put);
+ EXPECT_EQ(put, parser->put());
+ // have the first command fail to parse.
+ AddDoCommandExpect(error::kUnknownCommand, 3, 0, NULL);
+ EXPECT_EQ(error::kUnknownCommand,
+ parser->ProcessAllCommands());
+ // check that only one command was executed, and that get reflects that
+ // correctly.
+ EXPECT_EQ(put_post_fail, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+ // make the second one succeed, and check that the parser recovered fine.
+ AddDoCommandExpect(error::kNoError, 4, 0, NULL);
+ EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
+ EXPECT_EQ(put, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+}
+
+TEST_F(CommandParserTest, SetBuffer) {
+ scoped_ptr<CommandParser> parser(MakeParser(3));
+ CommandBufferOffset put = parser->put();
+ CommandHeader header;
+
+ // add a single command, no args
+ header.size = 2;
+ header.command = 123;
+ buffer()[put++].value_header = header;
+ buffer()[put++].value_int32 = 456;
+
+ CommandBufferEntry param_array[1];
+ param_array[0].value_int32 = 456;
+
+ parser->set_put(put);
+ AddDoCommandExpect(error::kNoError, 123, 1, param_array);
+ EXPECT_EQ(error::kNoError, parser->ProcessAllCommands());
+ // We should have advanced 2 entries
+ EXPECT_EQ(2, parser->get());
+ Mock::VerifyAndClearExpectations(api_mock());
+
+ scoped_ptr<CommandBufferEntry[]> buffer2(new CommandBufferEntry[2]);
+ parser->SetBuffer(
+ buffer2.get(), sizeof(CommandBufferEntry) * 2, 0,
+ sizeof(CommandBufferEntry) * 2);
+ // The put and get should have reset to 0.
+ EXPECT_EQ(0, parser->get());
+ EXPECT_EQ(0, parser->put());
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/command_buffer_service.cc b/chromium/gpu/command_buffer/service/command_buffer_service.cc
new file mode 100644
index 00000000000..1cd68f53ea4
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/command_buffer_service.cc
@@ -0,0 +1,210 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/command_buffer_service.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/debug/trace_event.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/common/command_buffer_shared.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+
+using ::base::SharedMemory;
+
+namespace gpu {
+
+CommandBufferService::CommandBufferService(
+ TransferBufferManagerInterface* transfer_buffer_manager)
+ : ring_buffer_id_(-1),
+ shared_state_(NULL),
+ num_entries_(0),
+ get_offset_(0),
+ put_offset_(0),
+ transfer_buffer_manager_(transfer_buffer_manager),
+ token_(0),
+ generation_(0),
+ error_(error::kNoError),
+ context_lost_reason_(error::kUnknown) {
+}
+
+CommandBufferService::~CommandBufferService() {
+}
+
+bool CommandBufferService::Initialize() {
+ return true;
+}
+
+CommandBufferService::State CommandBufferService::GetState() {
+ State state;
+ state.num_entries = num_entries_;
+ state.get_offset = get_offset_;
+ state.put_offset = put_offset_;
+ state.token = token_;
+ state.error = error_;
+ state.context_lost_reason = context_lost_reason_;
+ state.generation = ++generation_;
+
+ return state;
+}
+
+CommandBufferService::State CommandBufferService::GetLastState() {
+ return GetState();
+}
+
+int32 CommandBufferService::GetLastToken() {
+ return GetState().token;
+}
+
+void CommandBufferService::UpdateState() {
+ if (shared_state_) {
+ CommandBufferService::State state = GetState();
+ shared_state_->Write(state);
+ }
+}
+
+CommandBufferService::State CommandBufferService::FlushSync(
+ int32 put_offset, int32 last_known_get) {
+ if (put_offset < 0 || put_offset > num_entries_) {
+ error_ = gpu::error::kOutOfBounds;
+ return GetState();
+ }
+
+ put_offset_ = put_offset;
+
+ if (!put_offset_change_callback_.is_null())
+ put_offset_change_callback_.Run();
+
+ return GetState();
+}
+
+void CommandBufferService::Flush(int32 put_offset) {
+ if (put_offset < 0 || put_offset > num_entries_) {
+ error_ = gpu::error::kOutOfBounds;
+ return;
+ }
+
+ put_offset_ = put_offset;
+
+ if (!put_offset_change_callback_.is_null())
+ put_offset_change_callback_.Run();
+}
+
+void CommandBufferService::SetGetBuffer(int32 transfer_buffer_id) {
+ DCHECK_EQ(-1, ring_buffer_id_);
+ DCHECK_EQ(put_offset_, get_offset_); // Only if it's empty.
+ ring_buffer_ = GetTransferBuffer(transfer_buffer_id);
+ DCHECK(ring_buffer_.ptr);
+ ring_buffer_id_ = transfer_buffer_id;
+ num_entries_ = ring_buffer_.size / sizeof(CommandBufferEntry);
+ put_offset_ = 0;
+ SetGetOffset(0);
+ if (!get_buffer_change_callback_.is_null()) {
+ get_buffer_change_callback_.Run(ring_buffer_id_);
+ }
+
+ UpdateState();
+}
+
+bool CommandBufferService::SetSharedStateBuffer(
+ scoped_ptr<base::SharedMemory> shared_state_shm) {
+ shared_state_shm_.reset(shared_state_shm.release());
+ if (!shared_state_shm_->Map(sizeof(*shared_state_)))
+ return false;
+
+ shared_state_ =
+ static_cast<CommandBufferSharedState*>(shared_state_shm_->memory());
+
+ UpdateState();
+ return true;
+}
+
+void CommandBufferService::SetGetOffset(int32 get_offset) {
+ DCHECK(get_offset >= 0 && get_offset < num_entries_);
+ get_offset_ = get_offset;
+}
+
+Buffer CommandBufferService::CreateTransferBuffer(size_t size,
+ int32* id) {
+ *id = -1;
+
+ SharedMemory buffer;
+ if (!buffer.CreateAnonymous(size))
+ return Buffer();
+
+ static int32 next_id = 1;
+ *id = next_id++;
+
+ if (!RegisterTransferBuffer(*id, &buffer, size)) {
+ *id = -1;
+ return Buffer();
+ }
+
+ return GetTransferBuffer(*id);
+}
+
+void CommandBufferService::DestroyTransferBuffer(int32 id) {
+ transfer_buffer_manager_->DestroyTransferBuffer(id);
+ if (id == ring_buffer_id_) {
+ ring_buffer_id_ = -1;
+ ring_buffer_ = Buffer();
+ num_entries_ = 0;
+ get_offset_ = 0;
+ put_offset_ = 0;
+ }
+}
+
+Buffer CommandBufferService::GetTransferBuffer(int32 id) {
+ return transfer_buffer_manager_->GetTransferBuffer(id);
+}
+
+bool CommandBufferService::RegisterTransferBuffer(
+ int32 id,
+ base::SharedMemory* shared_memory,
+ size_t size) {
+ return transfer_buffer_manager_->RegisterTransferBuffer(id,
+ shared_memory,
+ size);
+}
+
+void CommandBufferService::SetToken(int32 token) {
+ token_ = token;
+ UpdateState();
+}
+
+void CommandBufferService::SetParseError(error::Error error) {
+ if (error_ == error::kNoError) {
+ error_ = error;
+ if (!parse_error_callback_.is_null())
+ parse_error_callback_.Run();
+ }
+}
+
+void CommandBufferService::SetContextLostReason(
+ error::ContextLostReason reason) {
+ context_lost_reason_ = reason;
+}
+
+void CommandBufferService::SetPutOffsetChangeCallback(
+ const base::Closure& callback) {
+ put_offset_change_callback_ = callback;
+}
+
+void CommandBufferService::SetGetBufferChangeCallback(
+ const GetBufferChangedCallback& callback) {
+ get_buffer_change_callback_ = callback;
+}
+
+void CommandBufferService::SetParseErrorCallback(
+ const base::Closure& callback) {
+ parse_error_callback_ = callback;
+}
+
+uint32 CommandBufferService::InsertSyncPoint() {
+ NOTREACHED();
+ return 0;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/command_buffer_service.h b/chromium/gpu/command_buffer/service/command_buffer_service.h
new file mode 100644
index 00000000000..232bdc0a56b
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/command_buffer_service.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_COMMAND_BUFFER_SERVICE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_COMMAND_BUFFER_SERVICE_H_
+
+#include "base/callback.h"
+#include "base/memory/shared_memory.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/command_buffer_shared.h"
+
+namespace gpu {
+
+class TransferBufferManagerInterface;
+
+// An object that implements a shared memory command buffer and a synchronous
+// API to manage the put and get pointers.
+class GPU_EXPORT CommandBufferService : public CommandBuffer {
+ public:
+ typedef base::Callback<bool(int32)> GetBufferChangedCallback;
+ explicit CommandBufferService(
+ TransferBufferManagerInterface* transfer_buffer_manager);
+ virtual ~CommandBufferService();
+
+ // CommandBuffer implementation:
+ virtual bool Initialize() OVERRIDE;
+ virtual State GetState() OVERRIDE;
+ virtual State GetLastState() OVERRIDE;
+ virtual int32 GetLastToken() OVERRIDE;
+ virtual void Flush(int32 put_offset) OVERRIDE;
+ virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE;
+ virtual void SetGetBuffer(int32 transfer_buffer_id) OVERRIDE;
+ virtual void SetGetOffset(int32 get_offset) OVERRIDE;
+ virtual Buffer CreateTransferBuffer(size_t size, int32* id) OVERRIDE;
+ virtual void DestroyTransferBuffer(int32 id) OVERRIDE;
+ virtual Buffer GetTransferBuffer(int32 id) OVERRIDE;
+ virtual void SetToken(int32 token) OVERRIDE;
+ virtual void SetParseError(error::Error error) OVERRIDE;
+ virtual void SetContextLostReason(error::ContextLostReason) OVERRIDE;
+ virtual uint32 InsertSyncPoint() OVERRIDE;
+
+ // Sets a callback that is called whenever the put offset is changed. When
+ // called with sync==true, the callback must not return until some progress
+ // has been made (unless the command buffer is empty), i.e. the get offset
+ // must have changed. It need not process the entire command buffer though.
+ // This allows concurrency between the writer and the reader while giving the
+ // writer a means of waiting for the reader to make some progress before
+ // attempting to write more to the command buffer. Takes ownership of
+ // callback.
+ virtual void SetPutOffsetChangeCallback(const base::Closure& callback);
+ // Sets a callback that is called whenever the get buffer is changed.
+ virtual void SetGetBufferChangeCallback(
+ const GetBufferChangedCallback& callback);
+ virtual void SetParseErrorCallback(const base::Closure& callback);
+
+ // Setup the shared memory that shared state should be copied into.
+ bool SetSharedStateBuffer(scoped_ptr<base::SharedMemory> shared_state_shm);
+
+ // Copy the current state into the shared state transfer buffer.
+ void UpdateState();
+
+ // Register an existing shared memory object and get an ID that can be used
+ // to identify it in the command buffer. Callee dups the handle until
+ // DestroyTransferBuffer is called.
+ bool RegisterTransferBuffer(int32 id,
+ base::SharedMemory* shared_memory,
+ size_t size);
+
+ private:
+ int32 ring_buffer_id_;
+ Buffer ring_buffer_;
+ scoped_ptr<base::SharedMemory> shared_state_shm_;
+ CommandBufferSharedState* shared_state_;
+ int32 num_entries_;
+ int32 get_offset_;
+ int32 put_offset_;
+ base::Closure put_offset_change_callback_;
+ GetBufferChangedCallback get_buffer_change_callback_;
+ base::Closure parse_error_callback_;
+ TransferBufferManagerInterface* transfer_buffer_manager_;
+ int32 token_;
+ uint32 generation_;
+ error::Error error_;
+ error::ContextLostReason context_lost_reason_;
+
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferService);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_COMMAND_BUFFER_SERVICE_H_
diff --git a/chromium/gpu/command_buffer/service/command_buffer_service_unittest.cc b/chromium/gpu/command_buffer/service/command_buffer_service_unittest.cc
new file mode 100644
index 00000000000..bf4d619f819
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/command_buffer_service_unittest.cc
@@ -0,0 +1,156 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/threading/thread.h"
+#include "gpu/command_buffer/common/cmd_buffer_common.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::SharedMemory;
+using testing::_;
+using testing::DoAll;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu {
+
+class CommandBufferServiceTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ EXPECT_TRUE(manager->Initialize());
+ }
+ command_buffer_.reset(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ EXPECT_TRUE(command_buffer_->Initialize());
+ }
+
+ int32 GetGetOffset() {
+ return command_buffer_->GetState().get_offset;
+ }
+
+ int32 GetPutOffset() {
+ return command_buffer_->GetState().put_offset;
+ }
+
+ int32 GetToken() {
+ return command_buffer_->GetState().token;
+ }
+
+ int32 GetError() {
+ return command_buffer_->GetState().error;
+ }
+
+ bool Initialize(size_t size) {
+ int32 id;
+ command_buffer_->CreateTransferBuffer(size, &id);
+ EXPECT_GT(id, 0);
+ command_buffer_->SetGetBuffer(id);
+ return true;
+ }
+
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<CommandBufferService> command_buffer_;
+};
+
+TEST_F(CommandBufferServiceTest, InitializesCommandBuffer) {
+ EXPECT_TRUE(Initialize(1024));
+ CommandBuffer::State state = command_buffer_->GetState();
+ EXPECT_EQ(0, state.get_offset);
+ EXPECT_EQ(0, state.put_offset);
+ EXPECT_EQ(0, state.token);
+ EXPECT_EQ(error::kNoError, state.error);
+}
+
+namespace {
+
+class CallbackTest {
+ public:
+ virtual void PutOffsetChanged() = 0;
+ virtual bool GetBufferChanged(int32 id) = 0;
+};
+
+class MockCallbackTest : public CallbackTest {
+ public:
+ MOCK_METHOD0(PutOffsetChanged, void());
+ MOCK_METHOD1(GetBufferChanged, bool(int32));
+};
+
+} // anonymous namespace
+
+TEST_F(CommandBufferServiceTest, CanSyncGetAndPutOffset) {
+ Initialize(1024);
+
+ scoped_ptr<StrictMock<MockCallbackTest> > change_callback(
+ new StrictMock<MockCallbackTest>);
+ command_buffer_->SetPutOffsetChangeCallback(
+ base::Bind(
+ &CallbackTest::PutOffsetChanged,
+ base::Unretained(change_callback.get())));
+
+ EXPECT_CALL(*change_callback, PutOffsetChanged());
+ command_buffer_->Flush(2);
+ EXPECT_EQ(0, GetGetOffset());
+ EXPECT_EQ(2, GetPutOffset());
+
+ EXPECT_CALL(*change_callback, PutOffsetChanged());
+ command_buffer_->Flush(4);
+ EXPECT_EQ(0, GetGetOffset());
+ EXPECT_EQ(4, GetPutOffset());
+
+ command_buffer_->SetGetOffset(2);
+ EXPECT_EQ(2, GetGetOffset());
+ EXPECT_CALL(*change_callback, PutOffsetChanged());
+ command_buffer_->Flush(6);
+
+ command_buffer_->Flush(-1);
+ EXPECT_NE(error::kNoError, GetError());
+ command_buffer_->Flush(1024);
+ EXPECT_NE(error::kNoError, GetError());
+}
+
+TEST_F(CommandBufferServiceTest, SetGetBuffer) {
+ int32 ring_buffer_id;
+ command_buffer_->CreateTransferBuffer(1024, &ring_buffer_id);
+ EXPECT_GT(ring_buffer_id, 0);
+
+ scoped_ptr<StrictMock<MockCallbackTest> > change_callback(
+ new StrictMock<MockCallbackTest>);
+ command_buffer_->SetGetBufferChangeCallback(
+ base::Bind(
+ &CallbackTest::GetBufferChanged,
+ base::Unretained(change_callback.get())));
+
+ EXPECT_CALL(*change_callback, GetBufferChanged(ring_buffer_id))
+ .WillOnce(Return(true));
+
+ command_buffer_->SetGetBuffer(ring_buffer_id);
+ EXPECT_EQ(0, GetGetOffset());
+}
+
+TEST_F(CommandBufferServiceTest, DefaultTokenIsZero) {
+ EXPECT_EQ(0, GetToken());
+}
+
+TEST_F(CommandBufferServiceTest, CanSetToken) {
+ command_buffer_->SetToken(7);
+ EXPECT_EQ(7, GetToken());
+}
+
+TEST_F(CommandBufferServiceTest, DefaultParseErrorIsNoError) {
+ EXPECT_EQ(0, GetError());
+}
+
+TEST_F(CommandBufferServiceTest, CanSetParseError) {
+ command_buffer_->SetParseError(error::kInvalidSize);
+ EXPECT_EQ(1, GetError());
+}
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/common_decoder.cc b/chromium/gpu/command_buffer/service/common_decoder.cc
new file mode 100644
index 00000000000..72f30a30bfc
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/common_decoder.cc
@@ -0,0 +1,292 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+
+namespace gpu {
+
+CommonDecoder::Bucket::Bucket() : size_(0) {}
+
+CommonDecoder::Bucket::~Bucket() {}
+
+void* CommonDecoder::Bucket::GetData(size_t offset, size_t size) const {
+ if (OffsetSizeValid(offset, size)) {
+ return data_.get() + offset;
+ }
+ return NULL;
+}
+
+void CommonDecoder::Bucket::SetSize(size_t size) {
+ if (size != size_) {
+ data_.reset(size ? new int8[size] : NULL);
+ size_ = size;
+ memset(data_.get(), 0, size);
+ }
+}
+
+bool CommonDecoder::Bucket::SetData(
+ const void* src, size_t offset, size_t size) {
+ if (OffsetSizeValid(offset, size)) {
+ memcpy(data_.get() + offset, src, size);
+ return true;
+ }
+ return false;
+}
+
+void CommonDecoder::Bucket::SetFromString(const char* str) {
+ // Strings are passed NULL terminated to distinguish between empty string
+ // and no string.
+ if (!str) {
+ SetSize(0);
+ } else {
+ size_t size = strlen(str) + 1;
+ SetSize(size);
+ SetData(str, 0, size);
+ }
+}
+
+bool CommonDecoder::Bucket::GetAsString(std::string* str) {
+ DCHECK(str);
+ if (size_ == 0) {
+ return false;
+ }
+ str->assign(GetDataAs<const char*>(0, size_ - 1), size_ - 1);
+ return true;
+}
+
+CommonDecoder::CommonDecoder() : engine_(NULL) {}
+
+CommonDecoder::~CommonDecoder() {}
+
+void* CommonDecoder::GetAddressAndCheckSize(unsigned int shm_id,
+ unsigned int offset,
+ unsigned int size) {
+ CHECK(engine_);
+ Buffer buffer = engine_->GetSharedMemoryBuffer(shm_id);
+ if (!buffer.ptr)
+ return NULL;
+ unsigned int end = offset + size;
+ if (end > buffer.size || end < offset) {
+ return NULL;
+ }
+ return static_cast<int8*>(buffer.ptr) + offset;
+}
+
+Buffer CommonDecoder::GetSharedMemoryBuffer(unsigned int shm_id) {
+ return engine_->GetSharedMemoryBuffer(shm_id);
+}
+
+const char* CommonDecoder::GetCommonCommandName(
+ cmd::CommandId command_id) const {
+ return cmd::GetCommandName(command_id);
+}
+
+CommonDecoder::Bucket* CommonDecoder::GetBucket(uint32 bucket_id) const {
+ BucketMap::const_iterator iter(buckets_.find(bucket_id));
+ return iter != buckets_.end() ? &(*iter->second) : NULL;
+}
+
+CommonDecoder::Bucket* CommonDecoder::CreateBucket(uint32 bucket_id) {
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ bucket = new Bucket();
+ buckets_[bucket_id] = linked_ptr<Bucket>(bucket);
+ }
+ return bucket;
+}
+
+namespace {
+
+// Returns the address of the first byte after a struct.
+template <typename T>
+const void* AddressAfterStruct(const T& pod) {
+ return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
+}
+
+// Returns the address of the frst byte after the struct.
+template <typename RETURN_TYPE, typename COMMAND_TYPE>
+RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod) {
+ return static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod)));
+}
+
+// A struct to hold info about each command.
+struct CommandInfo {
+ int arg_flags; // How to handle the arguments for this command
+ int arg_count; // How many arguments are expected for this command.
+};
+
+// A table of CommandInfo for all the commands.
+const CommandInfo g_command_info[] = {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) { \
+ cmd::name::kArgFlags, \
+ sizeof(cmd::name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+};
+
+} // anonymous namespace.
+
+// Decode command with its arguments, and call the corresponding method.
+// Note: args is a pointer to the command buffer. As such, it could be changed
+// by a (malicious) client at any time, so if validation has to happen, it
+// should operate on a copy of them.
+error::Error CommonDecoder::DoCommonCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) {
+ if (command < arraysize(g_command_info)) {
+ const CommandInfo& info = g_command_info[command];
+ unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
+ if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
+ (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
+ uint32 immediate_data_size =
+ (arg_count - info_arg_count) * sizeof(CommandBufferEntry); // NOLINT
+ switch (command) {
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
+ case cmd::name::kCmdId: \
+ return Handle ## name( \
+ immediate_data_size, \
+ *static_cast<const cmd::name*>(cmd_data)); \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+ }
+ } else {
+ return error::kInvalidArguments;
+ }
+ }
+ return error::kUnknownCommand;
+}
+
+error::Error CommonDecoder::HandleNoop(
+ uint32 immediate_data_size,
+ const cmd::Noop& args) {
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetToken(
+ uint32 immediate_data_size,
+ const cmd::SetToken& args) {
+ engine_->set_token(args.token);
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetBucketSize(
+ uint32 immediate_data_size,
+ const cmd::SetBucketSize& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32 size = args.size;
+
+ Bucket* bucket = CreateBucket(bucket_id);
+ bucket->SetSize(size);
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetBucketData(
+ uint32 immediate_data_size,
+ const cmd::SetBucketData& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32 offset = args.offset;
+ uint32 size = args.size;
+ const void* data = GetSharedMemoryAs<const void*>(
+ args.shared_memory_id, args.shared_memory_offset, size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ if (!bucket->SetData(data, offset, size)) {
+ return error::kInvalidArguments;
+ }
+
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleSetBucketDataImmediate(
+ uint32 immediate_data_size,
+ const cmd::SetBucketDataImmediate& args) {
+ const void* data = GetImmediateDataAs<const void*>(args);
+ uint32 bucket_id = args.bucket_id;
+ uint32 offset = args.offset;
+ uint32 size = args.size;
+ if (size > immediate_data_size) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ if (!bucket->SetData(data, offset, size)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleGetBucketStart(
+ uint32 immediate_data_size,
+ const cmd::GetBucketStart& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32* result = GetSharedMemoryAs<uint32*>(
+ args.result_memory_id, args.result_memory_offset, sizeof(*result));
+ int32 data_memory_id = args.data_memory_id;
+ uint32 data_memory_offset = args.data_memory_offset;
+ uint32 data_memory_size = args.data_memory_size;
+ uint8* data = NULL;
+ if (data_memory_size != 0 || data_memory_id != 0 || data_memory_offset != 0) {
+ data = GetSharedMemoryAs<uint8*>(
+ args.data_memory_id, args.data_memory_offset, args.data_memory_size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ }
+ if (!result) {
+ return error::kInvalidArguments;
+ }
+ // Check that the client initialized the result.
+ if (*result != 0) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ uint32 bucket_size = bucket->size();
+ *result = bucket_size;
+ if (data) {
+ uint32 size = std::min(data_memory_size, bucket_size);
+ memcpy(data, bucket->GetData(0, size), size);
+ }
+ return error::kNoError;
+}
+
+error::Error CommonDecoder::HandleGetBucketData(
+ uint32 immediate_data_size,
+ const cmd::GetBucketData& args) {
+ uint32 bucket_id = args.bucket_id;
+ uint32 offset = args.offset;
+ uint32 size = args.size;
+ void* data = GetSharedMemoryAs<void*>(
+ args.shared_memory_id, args.shared_memory_offset, size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ const void* src = bucket->GetData(offset, size);
+ if (!src) {
+ return error::kInvalidArguments;
+ }
+ memcpy(data, src, size);
+ return error::kNoError;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/common_decoder.h b/chromium/gpu/command_buffer/service/common_decoder.h
new file mode 100644
index 00000000000..03002c8b06f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/common_decoder.h
@@ -0,0 +1,175 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_COMMON_DECODER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_COMMON_DECODER_H_
+
+#include <map>
+#include <stack>
+#include <string>
+#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/common/buffer.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class CommandBufferEngine;
+
+// This class is a helper base class for implementing the common parts of the
+// o3d/gl2 command buffer decoder.
+class GPU_EXPORT CommonDecoder : NON_EXPORTED_BASE(public AsyncAPIInterface) {
+ public:
+ typedef error::Error Error;
+
+ static const unsigned int kMaxStackDepth = 32;
+
+ // A bucket is a buffer to help collect memory across a command buffer. When
+ // creating a command buffer implementation of an existing API, sometimes that
+ // API has functions that take a pointer to data. A good example is OpenGL's
+ // glBufferData. Because the data is separated between client and service,
+ // there are 2 ways to get this data across. 1 is to put all the data in
+ // shared memory. The problem with this is the data can be arbitarily large
+ // and the host OS may not support that much shared memory. Another solution
+ // is to shuffle memory across a little bit at a time, collecting it on the
+ // service side and when it is all there then call glBufferData. Buckets
+ // implement this second solution. Using the common commands, SetBucketSize,
+ // SetBucketData, SetBucketDataImmediate the client can fill a bucket. It can
+ // then call a command that uses that bucket (like BufferDataBucket in the
+ // GLES2 command buffer implementation).
+ //
+ // If you are designing an API from scratch you can avoid this need for
+ // Buckets by making your API always take an offset and a size
+ // similar to glBufferSubData.
+ //
+ // Buckets also help pass strings to/from the service. To return a string of
+ // arbitary size, the service puts the string in a bucket. The client can
+ // then query the size of a bucket and request sections of the bucket to
+ // be passed across shared memory.
+ class GPU_EXPORT Bucket {
+ public:
+ Bucket();
+ ~Bucket();
+
+ size_t size() const {
+ return size_;
+ }
+
+ // Gets a pointer to a section the bucket. Returns NULL if offset or size is
+ // out of range.
+ void* GetData(size_t offset, size_t size) const;
+
+ template <typename T>
+ T GetDataAs(size_t offset, size_t size) const {
+ return reinterpret_cast<T>(GetData(offset, size));
+ }
+
+ // Sets the size of the bucket.
+ void SetSize(size_t size);
+
+ // Sets a part of the bucket.
+ // Returns false if offset or size is out of range.
+ bool SetData(const void* src, size_t offset, size_t size);
+
+ // Sets the bucket data from a string. Strings are passed NULL terminated to
+ // distinguish between empty string and no string.
+ void SetFromString(const char* str);
+
+ // Gets the bucket data as a string. Strings are passed NULL terminated to
+ // distrinquish between empty string and no string. Returns False if there
+ // is no string.
+ bool GetAsString(std::string* str);
+
+ private:
+ bool OffsetSizeValid(size_t offset, size_t size) const {
+ size_t temp = offset + size;
+ return temp <= size_ && temp >= offset;
+ }
+
+ size_t size_;
+ ::scoped_ptr<int8[]> data_;
+
+ DISALLOW_COPY_AND_ASSIGN(Bucket);
+ };
+
+ CommonDecoder();
+ virtual ~CommonDecoder();
+
+ // Sets the engine, to get shared memory buffers from, and to set the token
+ // to.
+ void set_engine(CommandBufferEngine* engine) {
+ engine_ = engine;
+ }
+ CommandBufferEngine* engine() const { return engine_; }
+
+ // Creates a bucket. If the bucket already exists returns that bucket.
+ Bucket* CreateBucket(uint32 bucket_id);
+
+ // Gets a bucket. Returns NULL if the bucket does not exist.
+ Bucket* GetBucket(uint32 bucket_id) const;
+
+ // Gets the address of shared memory data, given a shared memory ID and an
+ // offset. Also checks that the size is consistent with the shared memory
+ // size.
+ // Parameters:
+ // shm_id: the id of the shared memory buffer.
+ // offset: the offset of the data in the shared memory buffer.
+ // size: the size of the data.
+ // Returns:
+ // NULL if shm_id isn't a valid shared memory buffer ID or if the size
+ // check fails. Return a pointer to the data otherwise.
+ void* GetAddressAndCheckSize(unsigned int shm_id,
+ unsigned int offset,
+ unsigned int size);
+
+ // Typed version of GetAddressAndCheckSize.
+ template <typename T>
+ T GetSharedMemoryAs(unsigned int shm_id, unsigned int offset,
+ unsigned int size) {
+ return static_cast<T>(GetAddressAndCheckSize(shm_id, offset, size));
+ }
+
+ // Get the actual shared memory buffer.
+ Buffer GetSharedMemoryBuffer(unsigned int shm_id);
+
+ protected:
+ // Executes a common command.
+ // Parameters:
+ // command: the command index.
+ // arg_count: the number of CommandBufferEntry arguments.
+ // cmd_data: the command data.
+ // Returns:
+ // error::kNoError if no error was found, one of
+ // error::Error otherwise.
+ error::Error DoCommonCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data);
+
+ // Gets an name for a common command.
+ const char* GetCommonCommandName(cmd::CommandId command_id) const;
+
+ private:
+ // Generate a member function prototype for each command in an automated and
+ // typesafe way.
+ #define COMMON_COMMAND_BUFFER_CMD_OP(name) \
+ error::Error Handle##name( \
+ uint32 immediate_data_size, \
+ const cmd::name& args); \
+
+ COMMON_COMMAND_BUFFER_CMDS(COMMON_COMMAND_BUFFER_CMD_OP)
+
+ #undef COMMON_COMMAND_BUFFER_CMD_OP
+
+ CommandBufferEngine* engine_;
+
+ typedef std::map<uint32, linked_ptr<Bucket> > BucketMap;
+ BucketMap buckets_;
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_COMMON_DECODER_H_
+
diff --git a/chromium/gpu/command_buffer/service/common_decoder_unittest.cc b/chromium/gpu/command_buffer/service/common_decoder_unittest.cc
new file mode 100644
index 00000000000..d90e34bf93b
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/common_decoder_unittest.cc
@@ -0,0 +1,512 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+TEST(CommonDecoderBucket, Basic) {
+ CommonDecoder::Bucket bucket;
+ EXPECT_EQ(0u, bucket.size());
+ EXPECT_TRUE(NULL == bucket.GetData(0, 0));
+}
+
+TEST(CommonDecoderBucket, Size) {
+ CommonDecoder::Bucket bucket;
+ bucket.SetSize(24);
+ EXPECT_EQ(24u, bucket.size());
+ bucket.SetSize(12);
+ EXPECT_EQ(12u, bucket.size());
+}
+
+TEST(CommonDecoderBucket, GetData) {
+ CommonDecoder::Bucket bucket;
+
+ bucket.SetSize(24);
+ EXPECT_TRUE(NULL != bucket.GetData(0, 0));
+ EXPECT_TRUE(NULL != bucket.GetData(24, 0));
+ EXPECT_TRUE(NULL == bucket.GetData(25, 0));
+ EXPECT_TRUE(NULL != bucket.GetData(0, 24));
+ EXPECT_TRUE(NULL == bucket.GetData(0, 25));
+ bucket.SetSize(23);
+ EXPECT_TRUE(NULL == bucket.GetData(0, 24));
+}
+
+TEST(CommonDecoderBucket, SetData) {
+ CommonDecoder::Bucket bucket;
+ static const char data[] = "testing";
+
+ bucket.SetSize(10);
+ EXPECT_TRUE(bucket.SetData(data, 0, sizeof(data)));
+ EXPECT_EQ(0, memcmp(data, bucket.GetData(0, sizeof(data)), sizeof(data)));
+ EXPECT_TRUE(bucket.SetData(data, 2, sizeof(data)));
+ EXPECT_EQ(0, memcmp(data, bucket.GetData(2, sizeof(data)), sizeof(data)));
+ EXPECT_FALSE(bucket.SetData(data, 0, sizeof(data) * 2));
+ EXPECT_FALSE(bucket.SetData(data, 5, sizeof(data)));
+}
+
+class TestCommonDecoder : public CommonDecoder {
+ public:
+ // Overridden from AsyncAPIInterface
+ virtual const char* GetCommandName(unsigned int command_id) const OVERRIDE {
+ return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
+ }
+
+ // Overridden from AsyncAPIInterface
+ virtual error::Error DoCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) OVERRIDE {
+ return DoCommonCommand(command, arg_count, cmd_data);
+ }
+
+ CommonDecoder::Bucket* GetBucket(uint32 id) const {
+ return CommonDecoder::GetBucket(id);
+ }
+};
+
+class MockCommandBufferEngine : public CommandBufferEngine {
+ public:
+ static const int32 kStartValidShmId = 1;
+ static const int32 kValidShmId = 2;
+ static const int32 kInvalidShmId = 3;
+ static const size_t kBufferSize = 1024;
+ static const int32 kValidOffset = kBufferSize / 2;
+ static const int32 kInvalidOffset = kBufferSize;
+
+ MockCommandBufferEngine()
+ : CommandBufferEngine(),
+ token_(),
+ get_offset_(0) {
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
+ Buffer buffer;
+ if (IsValidSharedMemoryId(shm_id)) {
+ buffer.ptr = buffer_;
+ buffer.size = kBufferSize;
+ }
+ return buffer;
+ }
+
+ template <typename T>
+ T GetSharedMemoryAs(uint32 offset) {
+ DCHECK_LT(offset, kBufferSize);
+ return reinterpret_cast<T>(&buffer_[offset]);
+ }
+
+ int32 GetSharedMemoryOffset(const void* memory) {
+ ptrdiff_t offset = reinterpret_cast<const int8*>(memory) - &buffer_[0];
+ DCHECK_GE(offset, 0);
+ DCHECK_LT(static_cast<size_t>(offset), kBufferSize);
+ return static_cast<int32>(offset);
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual void set_token(int32 token) OVERRIDE {
+ token_ = token;
+ }
+
+ int32 token() const {
+ return token_;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual bool SetGetBuffer(int32 transfer_buffer_id) OVERRIDE {
+ NOTREACHED();
+ return false;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual bool SetGetOffset(int32 offset) OVERRIDE {
+ if (static_cast<size_t>(offset) < kBufferSize) {
+ get_offset_ = offset;
+ return true;
+ }
+ return false;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual int32 GetGetOffset() OVERRIDE {
+ return get_offset_;
+ }
+
+ private:
+ bool IsValidSharedMemoryId(int32 shm_id) {
+ return shm_id == kValidShmId || shm_id == kStartValidShmId;
+ }
+
+ int8 buffer_[kBufferSize];
+ int32 token_;
+ int32 get_offset_;
+};
+
+const int32 MockCommandBufferEngine::kStartValidShmId;
+const int32 MockCommandBufferEngine::kValidShmId;
+const int32 MockCommandBufferEngine::kInvalidShmId;
+const size_t MockCommandBufferEngine::kBufferSize;
+const int32 MockCommandBufferEngine::kValidOffset;
+const int32 MockCommandBufferEngine::kInvalidOffset;
+
+class CommonDecoderTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ decoder_.set_engine(&engine_);
+ }
+
+ virtual void TearDown() {
+ }
+
+ template <typename T>
+ error::Error ExecuteCmd(const T& cmd) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ return decoder_.DoCommand(cmd.kCmdId,
+ ComputeNumEntries(sizeof(cmd)) - 1,
+ &cmd);
+ }
+
+ template <typename T>
+ error::Error ExecuteImmediateCmd(const T& cmd, size_t data_size) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ return decoder_.DoCommand(cmd.kCmdId,
+ ComputeNumEntries(sizeof(cmd) + data_size) - 1,
+ &cmd);
+ }
+
+ MockCommandBufferEngine engine_;
+ TestCommonDecoder decoder_;
+};
+
+TEST_F(CommonDecoderTest, Initialize) {
+ EXPECT_EQ(0, engine_.GetGetOffset());
+}
+
+TEST_F(CommonDecoderTest, DoCommonCommandInvalidCommand) {
+ EXPECT_EQ(error::kUnknownCommand, decoder_.DoCommand(999999, 0, NULL));
+}
+
+TEST_F(CommonDecoderTest, HandleNoop) {
+ cmd::Noop cmd;
+ const uint32 kSkipCount = 5;
+ cmd.Init(kSkipCount);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(
+ cmd, kSkipCount * kCommandBufferEntrySize));
+ const uint32 kSkipCount2 = 1;
+ cmd.Init(kSkipCount2);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(
+ cmd, kSkipCount2 * kCommandBufferEntrySize));
+}
+
+TEST_F(CommonDecoderTest, SetToken) {
+ cmd::SetToken cmd;
+ const int32 kTokenId = 123;
+ EXPECT_EQ(0, engine_.token());
+ cmd.Init(kTokenId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kTokenId, engine_.token());
+}
+
+TEST_F(CommonDecoderTest, SetBucketSize) {
+ cmd::SetBucketSize cmd;
+ const uint32 kBucketId = 123;
+ const uint32 kBucketLength1 = 1234;
+ const uint32 kBucketLength2 = 78;
+ // Check the bucket does not exist.
+ EXPECT_TRUE(NULL == decoder_.GetBucket(kBucketId));
+ // Check we can create one.
+ cmd.Init(kBucketId, kBucketLength1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ CommonDecoder::Bucket* bucket;
+ bucket = decoder_.GetBucket(kBucketId);
+ EXPECT_TRUE(NULL != bucket);
+ EXPECT_EQ(kBucketLength1, bucket->size());
+ // Check we can change it.
+ cmd.Init(kBucketId, kBucketLength2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ bucket = decoder_.GetBucket(kBucketId);
+ EXPECT_TRUE(NULL != bucket);
+ EXPECT_EQ(kBucketLength2, bucket->size());
+ // Check we can delete it.
+ cmd.Init(kBucketId, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ bucket = decoder_.GetBucket(kBucketId);
+ EXPECT_EQ(0u, bucket->size());
+}
+
+TEST_F(CommonDecoderTest, SetBucketData) {
+ cmd::SetBucketSize size_cmd;
+ cmd::SetBucketData cmd;
+
+ static const char kData[] = "1234567890123456789";
+
+ const uint32 kBucketId = 123;
+ const uint32 kInvalidBucketId = 124;
+
+ size_cmd.Init(kBucketId, sizeof(kData));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
+ CommonDecoder::Bucket* bucket = decoder_.GetBucket(kBucketId);
+ // Check the data is not there.
+ EXPECT_NE(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
+
+ // Check we can set it.
+ const uint32 kSomeOffsetInSharedMemory = 50;
+ void* memory = engine_.GetSharedMemoryAs<void*>(kSomeOffsetInSharedMemory);
+ memcpy(memory, kData, sizeof(kData));
+ cmd.Init(kBucketId, 0, sizeof(kData),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
+
+ // Check we can set it partially.
+ static const char kData2[] = "ABCEDFG";
+ const uint32 kSomeOffsetInBucket = 5;
+ memcpy(memory, kData2, sizeof(kData2));
+ cmd.Init(kBucketId, kSomeOffsetInBucket, sizeof(kData2),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, memcmp(bucket->GetData(kSomeOffsetInBucket, sizeof(kData2)),
+ kData2, sizeof(kData2)));
+ const char* bucket_data = bucket->GetDataAs<const char*>(0, sizeof(kData));
+ // Check that nothing was affected outside of updated area.
+ EXPECT_EQ(kData[kSomeOffsetInBucket - 1],
+ bucket_data[kSomeOffsetInBucket - 1]);
+ EXPECT_EQ(kData[kSomeOffsetInBucket + sizeof(kData2)],
+ bucket_data[kSomeOffsetInBucket + sizeof(kData2)]);
+
+ // Check that it fails if the bucket_id is invalid
+ cmd.Init(kInvalidBucketId, kSomeOffsetInBucket, sizeof(kData2),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the offset is out of range.
+ cmd.Init(kBucketId, bucket->size(), 1,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the size is out of range.
+ cmd.Init(kBucketId, 0, bucket->size() + 1,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(CommonDecoderTest, SetBucketDataImmediate) {
+ cmd::SetBucketSize size_cmd;
+ int8 buffer[1024];
+ cmd::SetBucketDataImmediate& cmd =
+ *reinterpret_cast<cmd::SetBucketDataImmediate*>(&buffer);
+
+ static const char kData[] = "1234567890123456789";
+
+ const uint32 kBucketId = 123;
+ const uint32 kInvalidBucketId = 124;
+
+ size_cmd.Init(kBucketId, sizeof(kData));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
+ CommonDecoder::Bucket* bucket = decoder_.GetBucket(kBucketId);
+ // Check the data is not there.
+ EXPECT_NE(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
+
+ // Check we can set it.
+ void* memory = &buffer[0] + sizeof(cmd);
+ memcpy(memory, kData, sizeof(kData));
+ cmd.Init(kBucketId, 0, sizeof(kData));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(kData)));
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, sizeof(kData)), kData, sizeof(kData)));
+
+ // Check we can set it partially.
+ static const char kData2[] = "ABCEDFG";
+ const uint32 kSomeOffsetInBucket = 5;
+ memcpy(memory, kData2, sizeof(kData2));
+ cmd.Init(kBucketId, kSomeOffsetInBucket, sizeof(kData2));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(kData2)));
+ EXPECT_EQ(0, memcmp(bucket->GetData(kSomeOffsetInBucket, sizeof(kData2)),
+ kData2, sizeof(kData2)));
+ const char* bucket_data = bucket->GetDataAs<const char*>(0, sizeof(kData));
+ // Check that nothing was affected outside of updated area.
+ EXPECT_EQ(kData[kSomeOffsetInBucket - 1],
+ bucket_data[kSomeOffsetInBucket - 1]);
+ EXPECT_EQ(kData[kSomeOffsetInBucket + sizeof(kData2)],
+ bucket_data[kSomeOffsetInBucket + sizeof(kData2)]);
+
+ // Check that it fails if the bucket_id is invalid
+ cmd.Init(kInvalidBucketId, kSomeOffsetInBucket, sizeof(kData2));
+ EXPECT_NE(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(kData2)));
+
+ // Check that it fails if the offset is out of range.
+ cmd.Init(kBucketId, bucket->size(), 1);
+ EXPECT_NE(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(kData2)));
+
+ // Check that it fails if the size is out of range.
+ cmd.Init(kBucketId, 0, bucket->size() + 1);
+ EXPECT_NE(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(kData2)));
+}
+
+TEST_F(CommonDecoderTest, GetBucketStart) {
+ cmd::SetBucketSize size_cmd;
+ cmd::SetBucketData set_cmd;
+ cmd::GetBucketStart cmd;
+
+ static const char kData[] = "1234567890123456789";
+ static const char zero[sizeof(kData)] = { 0, };
+
+ const uint32 kBucketSize = sizeof(kData);
+ const uint32 kBucketId = 123;
+ const uint32 kInvalidBucketId = 124;
+
+ // Put data in the bucket.
+ size_cmd.Init(kBucketId, sizeof(kData));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
+ const uint32 kSomeOffsetInSharedMemory = 50;
+ uint8* start = engine_.GetSharedMemoryAs<uint8*>(kSomeOffsetInSharedMemory);
+ memcpy(start, kData, sizeof(kData));
+ set_cmd.Init(kBucketId, 0, sizeof(kData),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(set_cmd));
+
+ // Check that the size is correct with no data buffer.
+ uint32* memory =
+ engine_.GetSharedMemoryAs<uint32*>(kSomeOffsetInSharedMemory);
+ *memory = 0x0;
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ 0, 0, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kBucketSize, *memory);
+
+ // Check that the data is copied with data buffer.
+ const uint32 kDataOffsetInSharedMemory = 54;
+ uint8* data = engine_.GetSharedMemoryAs<uint8*>(kDataOffsetInSharedMemory);
+ *memory = 0x0;
+ memset(data, 0, sizeof(kData));
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ kBucketSize, MockCommandBufferEngine::kValidShmId,
+ kDataOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kBucketSize, *memory);
+ EXPECT_EQ(0, memcmp(data, kData, kBucketSize));
+
+ // Check that we can get a piece.
+ *memory = 0x0;
+ memset(data, 0, sizeof(kData));
+ const uint32 kPieceSize = kBucketSize / 2;
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ kPieceSize, MockCommandBufferEngine::kValidShmId,
+ kDataOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kBucketSize, *memory);
+ EXPECT_EQ(0, memcmp(data, kData, kPieceSize));
+ EXPECT_EQ(0, memcmp(data + kPieceSize, zero, sizeof(kData) - kPieceSize));
+
+ // Check that it fails if the result_id is invalid
+ cmd.Init(kInvalidBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ 0, 0, 0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the data_id is invalid
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ 1, MockCommandBufferEngine::kInvalidShmId, 0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the data_size is invalid
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ 1, 0, 0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ MockCommandBufferEngine::kBufferSize + 1,
+ MockCommandBufferEngine::kValidShmId, 0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the data_offset is invalid
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ 0, 0, 1);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ MockCommandBufferEngine::kBufferSize,
+ MockCommandBufferEngine::kValidShmId, 1);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the result size is not set to zero
+ *memory = 0x1;
+ cmd.Init(kBucketId,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory,
+ 0, 0, 0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(CommonDecoderTest, GetBucketData) {
+ cmd::SetBucketSize size_cmd;
+ cmd::SetBucketData set_cmd;
+ cmd::GetBucketData cmd;
+
+ static const char kData[] = "1234567890123456789";
+ static const char zero[sizeof(kData)] = { 0, };
+
+ const uint32 kBucketId = 123;
+ const uint32 kInvalidBucketId = 124;
+
+ size_cmd.Init(kBucketId, sizeof(kData));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(size_cmd));
+ const uint32 kSomeOffsetInSharedMemory = 50;
+ uint8* memory = engine_.GetSharedMemoryAs<uint8*>(kSomeOffsetInSharedMemory);
+ memcpy(memory, kData, sizeof(kData));
+ set_cmd.Init(kBucketId, 0, sizeof(kData),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(set_cmd));
+
+ // Check we can get the whole thing.
+ memset(memory, 0, sizeof(kData));
+ cmd.Init(kBucketId, 0, sizeof(kData),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, memcmp(memory, kData, sizeof(kData)));
+
+ // Check we can get a piece.
+ const uint32 kSomeOffsetInBucket = 5;
+ const uint32 kLengthOfPiece = 6;
+ const uint8 kSentinel = 0xff;
+ memset(memory, 0, sizeof(kData));
+ memory[-1] = kSentinel;
+ cmd.Init(kBucketId, kSomeOffsetInBucket, kLengthOfPiece,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, memcmp(memory, kData + kSomeOffsetInBucket, kLengthOfPiece));
+ EXPECT_EQ(0, memcmp(memory + kLengthOfPiece, zero,
+ sizeof(kData) - kLengthOfPiece));
+ EXPECT_EQ(kSentinel, memory[-1]);
+
+ // Check that it fails if the bucket_id is invalid
+ cmd.Init(kInvalidBucketId, kSomeOffsetInBucket, sizeof(kData),
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the offset is invalid
+ cmd.Init(kBucketId, sizeof(kData) + 1, 1,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Check that it fails if the size is invalid
+ cmd.Init(kBucketId, 0, sizeof(kData) + 1,
+ MockCommandBufferEngine::kValidShmId, kSomeOffsetInSharedMemory);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/context_group.cc b/chromium/gpu/command_buffer/service/context_group.cc
new file mode 100644
index 00000000000..0cf991a7f45
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_group.cc
@@ -0,0 +1,387 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/context_group.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/command_line.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+namespace gles2 {
+
+ContextGroup::ContextGroup(
+ MailboxManager* mailbox_manager,
+ ImageManager* image_manager,
+ MemoryTracker* memory_tracker,
+ StreamTextureManager* stream_texture_manager,
+ bool bind_generates_resource)
+ : mailbox_manager_(mailbox_manager ? mailbox_manager : new MailboxManager),
+ image_manager_(image_manager ? image_manager : new ImageManager),
+ memory_tracker_(memory_tracker),
+ stream_texture_manager_(stream_texture_manager),
+ enforce_gl_minimums_(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnforceGLMinimums)),
+ bind_generates_resource_(bind_generates_resource),
+ max_vertex_attribs_(0u),
+ max_texture_units_(0u),
+ max_texture_image_units_(0u),
+ max_vertex_texture_image_units_(0u),
+ max_fragment_uniform_vectors_(0u),
+ max_varying_vectors_(0u),
+ max_vertex_uniform_vectors_(0u),
+ max_color_attachments_(1u),
+ max_draw_buffers_(1u),
+ program_cache_(NULL),
+ feature_info_(new FeatureInfo()),
+ draw_buffer_(GL_BACK) {
+ {
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ manager->Initialize();
+ }
+
+ id_namespaces_[id_namespaces::kBuffers].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kFramebuffers].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kProgramsAndShaders].reset(
+ new NonReusedIdAllocator);
+ id_namespaces_[id_namespaces::kRenderbuffers].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kTextures].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kQueries].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kVertexArrays].reset(new IdAllocator);
+ id_namespaces_[id_namespaces::kImages].reset(new IdAllocator);
+}
+
+static void GetIntegerv(GLenum pname, uint32* var) {
+ GLint value = 0;
+ glGetIntegerv(pname, &value);
+ *var = value;
+}
+
+bool ContextGroup::Initialize(
+ GLES2Decoder* decoder,
+ const DisallowedFeatures& disallowed_features,
+ const char* allowed_features) {
+ // If we've already initialized the group just add the context.
+ if (HaveContexts()) {
+ decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
+ return true;
+ }
+
+ if (!feature_info_->Initialize(disallowed_features, allowed_features)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because FeatureInfo "
+ << "initialization failed.";
+ return false;
+ }
+
+ const GLint kMinRenderbufferSize = 512; // GL says 1 pixel!
+ GLint max_renderbuffer_size = 0;
+ if (!QueryGLFeature(
+ GL_MAX_RENDERBUFFER_SIZE, kMinRenderbufferSize,
+ &max_renderbuffer_size)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because maximum "
+ << "renderbuffer size too small.";
+ return false;
+ }
+ GLint max_samples = 0;
+ if (feature_info_->feature_flags().chromium_framebuffer_multisample ||
+ feature_info_->feature_flags().multisampled_render_to_texture) {
+ if (feature_info_->feature_flags(
+ ).use_img_for_multisampled_render_to_texture) {
+ glGetIntegerv(GL_MAX_SAMPLES_IMG, &max_samples);
+ } else {
+ glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
+ }
+ }
+
+ if (feature_info_->feature_flags().ext_draw_buffers) {
+ GetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments_);
+ if (max_color_attachments_ < 1)
+ max_color_attachments_ = 1;
+ GetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buffers_);
+ if (max_draw_buffers_ < 1)
+ max_draw_buffers_ = 1;
+ draw_buffer_ = GL_BACK;
+ }
+
+ buffer_manager_.reset(
+ new BufferManager(memory_tracker_.get(), feature_info_.get()));
+ framebuffer_manager_.reset(
+ new FramebufferManager(max_draw_buffers_, max_color_attachments_));
+ renderbuffer_manager_.reset(new RenderbufferManager(
+ memory_tracker_.get(), max_renderbuffer_size, max_samples));
+ shader_manager_.reset(new ShaderManager());
+ program_manager_.reset(new ProgramManager(program_cache_));
+
+ // Lookup GL things we need to know.
+ const GLint kGLES2RequiredMinimumVertexAttribs = 8u;
+ if (!QueryGLFeatureU(
+ GL_MAX_VERTEX_ATTRIBS, kGLES2RequiredMinimumVertexAttribs,
+ &max_vertex_attribs_)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because too few "
+ << "vertex attributes supported.";
+ return false;
+ }
+
+ const GLuint kGLES2RequiredMinimumTextureUnits = 8u;
+ if (!QueryGLFeatureU(
+ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, kGLES2RequiredMinimumTextureUnits,
+ &max_texture_units_)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because too few "
+ << "texture units supported.";
+ return false;
+ }
+
+ GLint max_texture_size = 0;
+ GLint max_cube_map_texture_size = 0;
+ const GLint kMinTextureSize = 2048; // GL actually says 64!?!?
+ const GLint kMinCubeMapSize = 256; // GL actually says 16!?!?
+ if (!QueryGLFeature(
+ GL_MAX_TEXTURE_SIZE, kMinTextureSize, &max_texture_size) ||
+ !QueryGLFeature(
+ GL_MAX_CUBE_MAP_TEXTURE_SIZE, kMinCubeMapSize,
+ &max_cube_map_texture_size)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because maximum texture size"
+ << "is too small.";
+ return false;
+ }
+
+ if (feature_info_->workarounds().max_texture_size) {
+ max_texture_size = std::min(
+ max_texture_size, feature_info_->workarounds().max_texture_size);
+ }
+ if (feature_info_->workarounds().max_cube_map_texture_size) {
+ max_cube_map_texture_size = std::min(
+ max_cube_map_texture_size,
+ feature_info_->workarounds().max_cube_map_texture_size);
+ }
+
+ texture_manager_.reset(new TextureManager(memory_tracker_.get(),
+ feature_info_.get(),
+ max_texture_size,
+ max_cube_map_texture_size));
+ texture_manager_->set_framebuffer_manager(framebuffer_manager_.get());
+ texture_manager_->set_stream_texture_manager(stream_texture_manager_);
+
+ const GLint kMinTextureImageUnits = 8;
+ const GLint kMinVertexTextureImageUnits = 0;
+ if (!QueryGLFeatureU(
+ GL_MAX_TEXTURE_IMAGE_UNITS, kMinTextureImageUnits,
+ &max_texture_image_units_) ||
+ !QueryGLFeatureU(
+ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, kMinVertexTextureImageUnits,
+ &max_vertex_texture_image_units_)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because too few "
+ << "texture units.";
+ return false;
+ }
+
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+ &max_fragment_uniform_vectors_);
+ GetIntegerv(GL_MAX_VARYING_VECTORS, &max_varying_vectors_);
+ GetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &max_vertex_uniform_vectors_);
+ } else {
+ GetIntegerv(
+ GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &max_fragment_uniform_vectors_);
+ max_fragment_uniform_vectors_ /= 4;
+ GetIntegerv(GL_MAX_VARYING_FLOATS, &max_varying_vectors_);
+ max_varying_vectors_ /= 4;
+ GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &max_vertex_uniform_vectors_);
+ max_vertex_uniform_vectors_ /= 4;
+ }
+
+ const GLint kMinFragmentUniformVectors = 16;
+ const GLint kMinVaryingVectors = 8;
+ const GLint kMinVertexUniformVectors = 128;
+ if (!CheckGLFeatureU(
+ kMinFragmentUniformVectors, &max_fragment_uniform_vectors_) ||
+ !CheckGLFeatureU(kMinVaryingVectors, &max_varying_vectors_) ||
+ !CheckGLFeatureU(
+ kMinVertexUniformVectors, &max_vertex_uniform_vectors_)) {
+ LOG(ERROR) << "ContextGroup::Initialize failed because too few "
+ << "uniforms or varyings supported.";
+ return false;
+ }
+
+ // TODO(gman): Use workarounds similar to max_texture_size above to implement.
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationOSMesaGL) {
+ // Some shaders in Skia needed more than the min.
+ max_fragment_uniform_vectors_ =
+ std::min(static_cast<uint32>(kMinFragmentUniformVectors * 2),
+ max_fragment_uniform_vectors_);
+ max_varying_vectors_ =
+ std::min(static_cast<uint32>(kMinVaryingVectors * 2),
+ max_varying_vectors_);
+ max_vertex_uniform_vectors_ =
+ std::min(static_cast<uint32>(kMinVertexUniformVectors * 2),
+ max_vertex_uniform_vectors_);
+ }
+
+ if (!texture_manager_->Initialize()) {
+ LOG(ERROR) << "Context::Group::Initialize failed because texture manager "
+ << "failed to initialize.";
+ return false;
+ }
+
+ decoders_.push_back(base::AsWeakPtr<GLES2Decoder>(decoder));
+ return true;
+}
+
+namespace {
+
+bool IsNull(const base::WeakPtr<gles2::GLES2Decoder>& decoder) {
+ return !decoder.get();
+}
+
+template <typename T>
+class WeakPtrEquals {
+ public:
+ explicit WeakPtrEquals(T* t) : t_(t) {}
+
+ bool operator()(const base::WeakPtr<T>& t) {
+ return t.get() == t_;
+ }
+
+ private:
+ T* const t_;
+};
+
+} // namespace anonymous
+
+bool ContextGroup::HaveContexts() {
+ decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(), IsNull),
+ decoders_.end());
+ return !decoders_.empty();
+}
+
+void ContextGroup::Destroy(GLES2Decoder* decoder, bool have_context) {
+ decoders_.erase(std::remove_if(decoders_.begin(), decoders_.end(),
+ WeakPtrEquals<gles2::GLES2Decoder>(decoder)),
+ decoders_.end());
+ // If we still have contexts do nothing.
+ if (HaveContexts()) {
+ return;
+ }
+
+ if (buffer_manager_ != NULL) {
+ buffer_manager_->Destroy(have_context);
+ buffer_manager_.reset();
+ }
+
+ if (framebuffer_manager_ != NULL) {
+ framebuffer_manager_->Destroy(have_context);
+ if (texture_manager_)
+ texture_manager_->set_framebuffer_manager(NULL);
+ framebuffer_manager_.reset();
+ }
+
+ if (renderbuffer_manager_ != NULL) {
+ renderbuffer_manager_->Destroy(have_context);
+ renderbuffer_manager_.reset();
+ }
+
+ if (texture_manager_ != NULL) {
+ texture_manager_->Destroy(have_context);
+ texture_manager_.reset();
+ }
+
+ if (program_manager_ != NULL) {
+ program_manager_->Destroy(have_context);
+ program_manager_.reset();
+ }
+
+ if (shader_manager_ != NULL) {
+ shader_manager_->Destroy(have_context);
+ shader_manager_.reset();
+ }
+
+ memory_tracker_ = NULL;
+ stream_texture_manager_ = NULL;
+}
+
+IdAllocatorInterface* ContextGroup::GetIdAllocator(unsigned namespace_id) {
+ if (namespace_id >= arraysize(id_namespaces_))
+ return NULL;
+
+ return id_namespaces_[namespace_id].get();
+}
+
+uint32 ContextGroup::GetMemRepresented() const {
+ uint32 total = 0;
+ if (buffer_manager_.get())
+ total += buffer_manager_->mem_represented();
+ if (renderbuffer_manager_.get())
+ total += renderbuffer_manager_->mem_represented();
+ if (texture_manager_.get())
+ total += texture_manager_->mem_represented();
+ return total;
+}
+
+void ContextGroup::LoseContexts(GLenum reset_status) {
+ for (size_t ii = 0; ii < decoders_.size(); ++ii) {
+ if (decoders_[ii].get()) {
+ decoders_[ii]->LoseContext(reset_status);
+ }
+ }
+}
+
+ContextGroup::~ContextGroup() {
+ CHECK(!HaveContexts());
+}
+
+bool ContextGroup::CheckGLFeature(GLint min_required, GLint* v) {
+ GLint value = *v;
+ if (enforce_gl_minimums_) {
+ value = std::min(min_required, value);
+ }
+ *v = value;
+ return value >= min_required;
+}
+
+bool ContextGroup::CheckGLFeatureU(GLint min_required, uint32* v) {
+ GLint value = *v;
+ if (enforce_gl_minimums_) {
+ value = std::min(min_required, value);
+ }
+ *v = value;
+ return value >= min_required;
+}
+
+bool ContextGroup::QueryGLFeature(
+ GLenum pname, GLint min_required, GLint* v) {
+ GLint value = 0;
+ glGetIntegerv(pname, &value);
+ *v = value;
+ return CheckGLFeature(min_required, v);
+}
+
+bool ContextGroup::QueryGLFeatureU(
+ GLenum pname, GLint min_required, uint32* v) {
+ uint32 value = 0;
+ GetIntegerv(pname, &value);
+ bool result = CheckGLFeatureU(min_required, &value);
+ *v = value;
+ return result;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/context_group.h b/chromium/gpu/command_buffer/service/context_group.h
new file mode 100644
index 00000000000..13d031a707e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_group.h
@@ -0,0 +1,235 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CONTEXT_GROUP_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CONTEXT_GROUP_H_
+
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_validation.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class IdAllocatorInterface;
+class StreamTextureManager;
+class TransferBufferManagerInterface;
+
+namespace gles2 {
+
+class ProgramCache;
+class BufferManager;
+class GLES2Decoder;
+class FramebufferManager;
+class ImageManager;
+class MailboxManager;
+class RenderbufferManager;
+class ProgramManager;
+class ShaderManager;
+class TextureManager;
+class MemoryTracker;
+struct DisallowedFeatures;
+
+// A Context Group helps manage multiple GLES2Decoders that share
+// resources.
+class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> {
+ public:
+ ContextGroup(
+ MailboxManager* mailbox_manager,
+ ImageManager* image_manager,
+ MemoryTracker* memory_tracker,
+ StreamTextureManager* stream_texture_manager,
+ bool bind_generates_resource);
+
+ // This should only be called by GLES2Decoder. This must be paired with a
+ // call to destroy if it succeeds.
+ bool Initialize(
+ GLES2Decoder* decoder,
+ const DisallowedFeatures& disallowed_features,
+ const char* allowed_features);
+
+ // Destroys all the resources when called for the last context in the group.
+ // It should only be called by GLES2Decoder.
+ void Destroy(GLES2Decoder* decoder, bool have_context);
+
+ MailboxManager* mailbox_manager() const {
+ return mailbox_manager_.get();
+ }
+
+ ImageManager* image_manager() const {
+ return image_manager_.get();
+ }
+
+ MemoryTracker* memory_tracker() const {
+ return memory_tracker_.get();
+ }
+
+ StreamTextureManager* stream_texture_manager() const {
+ return stream_texture_manager_;
+ }
+
+ bool bind_generates_resource() {
+ return bind_generates_resource_;
+ }
+
+ uint32 max_vertex_attribs() const {
+ return max_vertex_attribs_;
+ }
+
+ uint32 max_texture_units() const {
+ return max_texture_units_;
+ }
+
+ uint32 max_texture_image_units() const {
+ return max_texture_image_units_;
+ }
+
+ uint32 max_vertex_texture_image_units() const {
+ return max_vertex_texture_image_units_;
+ }
+
+ uint32 max_fragment_uniform_vectors() const {
+ return max_fragment_uniform_vectors_;
+ }
+
+ uint32 max_varying_vectors() const {
+ return max_varying_vectors_;
+ }
+
+ uint32 max_vertex_uniform_vectors() const {
+ return max_vertex_uniform_vectors_;
+ }
+
+ uint32 max_color_attachments() const {
+ return max_color_attachments_;
+ }
+
+ uint32 max_draw_buffers() const {
+ return max_draw_buffers_;
+ }
+
+ FeatureInfo* feature_info() {
+ return feature_info_.get();
+ }
+
+ BufferManager* buffer_manager() const {
+ return buffer_manager_.get();
+ }
+
+ FramebufferManager* framebuffer_manager() const {
+ return framebuffer_manager_.get();
+ }
+
+ RenderbufferManager* renderbuffer_manager() const {
+ return renderbuffer_manager_.get();
+ }
+
+ TextureManager* texture_manager() const {
+ return texture_manager_.get();
+ }
+
+ ProgramManager* program_manager() const {
+ return program_manager_.get();
+ }
+
+ bool has_program_cache() const {
+ return program_cache_ != NULL;
+ }
+
+ void set_program_cache(ProgramCache* program_cache) {
+ program_cache_ = program_cache;
+ }
+
+ ShaderManager* shader_manager() const {
+ return shader_manager_.get();
+ }
+
+ TransferBufferManagerInterface* transfer_buffer_manager() const {
+ return transfer_buffer_manager_.get();
+ }
+
+ IdAllocatorInterface* GetIdAllocator(unsigned namespace_id);
+
+ uint32 GetMemRepresented() const;
+
+ // Loses all the context associated with this group.
+ void LoseContexts(GLenum reset_status);
+
+ // EXT_draw_buffer related states for backbuffer.
+ GLenum draw_buffer() const {
+ return draw_buffer_;
+ }
+ void set_draw_buffer(GLenum buf) {
+ draw_buffer_ = buf;
+ }
+
+ private:
+ friend class base::RefCounted<ContextGroup>;
+ ~ContextGroup();
+
+ bool CheckGLFeature(GLint min_required, GLint* v);
+ bool CheckGLFeatureU(GLint min_required, uint32* v);
+ bool QueryGLFeature(GLenum pname, GLint min_required, GLint* v);
+ bool QueryGLFeatureU(GLenum pname, GLint min_required, uint32* v);
+ bool HaveContexts();
+
+ scoped_refptr<MailboxManager> mailbox_manager_;
+ scoped_refptr<ImageManager> image_manager_;
+ scoped_refptr<MemoryTracker> memory_tracker_;
+ StreamTextureManager* stream_texture_manager_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+
+ bool enforce_gl_minimums_;
+ bool bind_generates_resource_;
+
+ uint32 max_vertex_attribs_;
+ uint32 max_texture_units_;
+ uint32 max_texture_image_units_;
+ uint32 max_vertex_texture_image_units_;
+ uint32 max_fragment_uniform_vectors_;
+ uint32 max_varying_vectors_;
+ uint32 max_vertex_uniform_vectors_;
+ uint32 max_color_attachments_;
+ uint32 max_draw_buffers_;
+
+ ProgramCache* program_cache_;
+
+ scoped_ptr<BufferManager> buffer_manager_;
+
+ scoped_ptr<FramebufferManager> framebuffer_manager_;
+
+ scoped_ptr<RenderbufferManager> renderbuffer_manager_;
+
+ scoped_ptr<TextureManager> texture_manager_;
+
+ scoped_ptr<ProgramManager> program_manager_;
+
+ scoped_ptr<ShaderManager> shader_manager_;
+
+ linked_ptr<IdAllocatorInterface>
+ id_namespaces_[id_namespaces::kNumIdNamespaces];
+
+ scoped_refptr<FeatureInfo> feature_info_;
+
+ std::vector<base::WeakPtr<gles2::GLES2Decoder> > decoders_;
+
+ GLenum draw_buffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(ContextGroup);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CONTEXT_GROUP_H_
+
+
diff --git a/chromium/gpu/command_buffer/service/context_group_unittest.cc b/chromium/gpu/command_buffer/service/context_group_unittest.cc
new file mode 100644
index 00000000000..c80f6190a8e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_group_unittest.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/context_group.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::HasSubstr;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Not;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+class ContextGroupTest : public testing::Test {
+ public:
+ ContextGroupTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ decoder_.reset(new MockGLES2Decoder());
+ group_ = scoped_refptr<ContextGroup>(
+ new ContextGroup(NULL, NULL, NULL, NULL, true));
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_ptr<MockGLES2Decoder> decoder_;
+ scoped_refptr<ContextGroup> group_;
+};
+
+TEST_F(ContextGroupTest, Basic) {
+ // Test it starts off uninitialized.
+ EXPECT_EQ(0u, group_->max_vertex_attribs());
+ EXPECT_EQ(0u, group_->max_texture_units());
+ EXPECT_EQ(0u, group_->max_texture_image_units());
+ EXPECT_EQ(0u, group_->max_vertex_texture_image_units());
+ EXPECT_EQ(0u, group_->max_fragment_uniform_vectors());
+ EXPECT_EQ(0u, group_->max_varying_vectors());
+ EXPECT_EQ(0u, group_->max_vertex_uniform_vectors());
+ EXPECT_TRUE(group_->buffer_manager() == NULL);
+ EXPECT_TRUE(group_->framebuffer_manager() == NULL);
+ EXPECT_TRUE(group_->renderbuffer_manager() == NULL);
+ EXPECT_TRUE(group_->texture_manager() == NULL);
+ EXPECT_TRUE(group_->program_manager() == NULL);
+ EXPECT_TRUE(group_->shader_manager() == NULL);
+}
+
+TEST_F(ContextGroupTest, InitializeNoExtensions) {
+ TestHelper::SetupContextGroupInitExpectations(gl_.get(),
+ DisallowedFeatures(), "");
+ group_->Initialize(decoder_.get(), DisallowedFeatures(), "");
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kNumVertexAttribs),
+ group_->max_vertex_attribs());
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kNumTextureUnits),
+ group_->max_texture_units());
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kMaxTextureImageUnits),
+ group_->max_texture_image_units());
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kMaxVertexTextureImageUnits),
+ group_->max_vertex_texture_image_units());
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kMaxFragmentUniformVectors),
+ group_->max_fragment_uniform_vectors());
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kMaxVaryingVectors),
+ group_->max_varying_vectors());
+ EXPECT_EQ(static_cast<uint32>(TestHelper::kMaxVertexUniformVectors),
+ group_->max_vertex_uniform_vectors());
+ EXPECT_TRUE(group_->buffer_manager() != NULL);
+ EXPECT_TRUE(group_->framebuffer_manager() != NULL);
+ EXPECT_TRUE(group_->renderbuffer_manager() != NULL);
+ EXPECT_TRUE(group_->texture_manager() != NULL);
+ EXPECT_TRUE(group_->program_manager() != NULL);
+ EXPECT_TRUE(group_->shader_manager() != NULL);
+
+ group_->Destroy(decoder_.get(), false);
+ EXPECT_TRUE(group_->buffer_manager() == NULL);
+ EXPECT_TRUE(group_->framebuffer_manager() == NULL);
+ EXPECT_TRUE(group_->renderbuffer_manager() == NULL);
+ EXPECT_TRUE(group_->texture_manager() == NULL);
+ EXPECT_TRUE(group_->program_manager() == NULL);
+ EXPECT_TRUE(group_->shader_manager() == NULL);
+}
+
+TEST_F(ContextGroupTest, MultipleContexts) {
+ scoped_ptr<MockGLES2Decoder> decoder2_(new MockGLES2Decoder());
+ TestHelper::SetupContextGroupInitExpectations(gl_.get(),
+ DisallowedFeatures(), "");
+ group_->Initialize(decoder_.get(), DisallowedFeatures(), "");
+ group_->Initialize(decoder2_.get(), DisallowedFeatures(), "");
+
+ EXPECT_TRUE(group_->buffer_manager() != NULL);
+ EXPECT_TRUE(group_->framebuffer_manager() != NULL);
+ EXPECT_TRUE(group_->renderbuffer_manager() != NULL);
+ EXPECT_TRUE(group_->texture_manager() != NULL);
+ EXPECT_TRUE(group_->program_manager() != NULL);
+ EXPECT_TRUE(group_->shader_manager() != NULL);
+
+ group_->Destroy(decoder_.get(), false);
+
+ EXPECT_TRUE(group_->buffer_manager() != NULL);
+ EXPECT_TRUE(group_->framebuffer_manager() != NULL);
+ EXPECT_TRUE(group_->renderbuffer_manager() != NULL);
+ EXPECT_TRUE(group_->texture_manager() != NULL);
+ EXPECT_TRUE(group_->program_manager() != NULL);
+ EXPECT_TRUE(group_->shader_manager() != NULL);
+
+ group_->Destroy(decoder2_.get(), false);
+
+ EXPECT_TRUE(group_->buffer_manager() == NULL);
+ EXPECT_TRUE(group_->framebuffer_manager() == NULL);
+ EXPECT_TRUE(group_->renderbuffer_manager() == NULL);
+ EXPECT_TRUE(group_->texture_manager() == NULL);
+ EXPECT_TRUE(group_->program_manager() == NULL);
+ EXPECT_TRUE(group_->shader_manager() == NULL);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/context_state.cc b/chromium/gpu/command_buffer/service/context_state.cc
new file mode 100644
index 00000000000..e8912cfe162
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_state.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/context_state.h"
+
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/error_state.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+void EnableDisable(GLenum pname, bool enable) {
+ if (enable) {
+ glEnable(pname);
+ } else {
+ glDisable(pname);
+ }
+}
+
+} // anonymous namespace.
+
+TextureUnit::TextureUnit()
+ : bind_target(GL_TEXTURE_2D) {
+}
+
+TextureUnit::~TextureUnit() {
+}
+
+ContextState::ContextState(FeatureInfo* feature_info, Logger* logger)
+ : active_texture_unit(0),
+ pack_reverse_row_order(false),
+ fbo_binding_for_scissor_workaround_dirty_(false),
+ feature_info_(feature_info),
+ error_state_(ErrorState::Create(logger)) {
+ Initialize();
+}
+
+ContextState::~ContextState() {
+}
+
+void ContextState::RestoreTextureUnitBindings(GLuint unit) const {
+ DCHECK_LT(unit, texture_units.size());
+ const TextureUnit& texture_unit = texture_units[unit];
+ glActiveTexture(GL_TEXTURE0 + unit);
+ GLuint service_id = texture_unit.bound_texture_2d.get()
+ ? texture_unit.bound_texture_2d->service_id()
+ : 0;
+ glBindTexture(GL_TEXTURE_2D, service_id);
+ service_id = texture_unit.bound_texture_cube_map.get()
+ ? texture_unit.bound_texture_cube_map->service_id()
+ : 0;
+ glBindTexture(GL_TEXTURE_CUBE_MAP, service_id);
+
+ if (feature_info_->feature_flags().oes_egl_image_external) {
+ service_id = texture_unit.bound_texture_external_oes.get()
+ ? texture_unit.bound_texture_external_oes->service_id()
+ : 0;
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id);
+ }
+
+ if (feature_info_->feature_flags().arb_texture_rectangle) {
+ service_id = texture_unit.bound_texture_rectangle_arb.get()
+ ? texture_unit.bound_texture_rectangle_arb->service_id()
+ : 0;
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, service_id);
+ }
+}
+
+void ContextState::RestoreBufferBindings() const {
+ if (vertex_attrib_manager.get()) {
+ Buffer* element_array_buffer =
+ vertex_attrib_manager->element_array_buffer();
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
+ element_array_buffer ? element_array_buffer->service_id() : 0);
+ }
+ glBindBuffer(GL_ARRAY_BUFFER,
+ bound_array_buffer.get() ? bound_array_buffer->service_id() : 0);
+}
+
+void ContextState::RestoreRenderbufferBindings() const {
+ // Restore Bindings
+ glBindRenderbufferEXT(
+ GL_RENDERBUFFER,
+ bound_renderbuffer.get() ? bound_renderbuffer->service_id() : 0);
+}
+
+void ContextState::RestoreProgramBindings() const {
+ glUseProgram(current_program.get() ? current_program->service_id() : 0);
+}
+
+void ContextState::RestoreActiveTexture() const {
+ glActiveTexture(GL_TEXTURE0 + active_texture_unit);
+}
+
+void ContextState::RestoreAllTextureUnitBindings() const {
+ // Restore Texture state.
+ for (size_t ii = 0; ii < texture_units.size(); ++ii) {
+ RestoreTextureUnitBindings(ii);
+ }
+ RestoreActiveTexture();
+}
+
+void ContextState::RestoreAttribute(GLuint attrib_index) const {
+ const VertexAttrib* attrib =
+ vertex_attrib_manager->GetVertexAttrib(attrib_index);
+ const void* ptr = reinterpret_cast<const void*>(attrib->offset());
+ Buffer* buffer = attrib->buffer();
+ glBindBuffer(GL_ARRAY_BUFFER, buffer ? buffer->service_id() : 0);
+ glVertexAttribPointer(
+ attrib_index, attrib->size(), attrib->type(), attrib->normalized(),
+ attrib->gl_stride(), ptr);
+ if (attrib->divisor())
+ glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
+ // Never touch vertex attribute 0's state (in particular, never
+ // disable it) when running on desktop GL because it will never be
+ // re-enabled.
+ if (attrib_index != 0 ||
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ if (attrib->enabled()) {
+ glEnableVertexAttribArray(attrib_index);
+ } else {
+ glDisableVertexAttribArray(attrib_index);
+ }
+ }
+ glVertexAttrib4fv(attrib_index, attrib_values[attrib_index].v);
+}
+
+void ContextState::RestoreGlobalState() const {
+ InitCapabilities();
+ InitState();
+}
+
+void ContextState::RestoreState() const {
+ RestoreAllTextureUnitBindings();
+
+ // Restore Attrib State
+ // TODO: This if should not be needed. RestoreState is getting called
+ // before GLES2Decoder::Initialize which is a bug.
+ if (vertex_attrib_manager.get()) {
+ // TODO(gman): Move this restoration to VertexAttribManager.
+ for (size_t attrib = 0; attrib < vertex_attrib_manager->num_attribs();
+ ++attrib) {
+ RestoreAttribute(attrib);
+ }
+ }
+
+ RestoreBufferBindings();
+ RestoreRenderbufferBindings();
+ RestoreProgramBindings();
+ RestoreGlobalState();
+}
+
+ErrorState* ContextState::GetErrorState() {
+ return error_state_.get();
+}
+
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/service/context_state_impl_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/context_state.h b/chromium/gpu/command_buffer/service/context_state.h
new file mode 100644
index 00000000000..4e5b2da6f05
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_state.h
@@ -0,0 +1,170 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the ContextState class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_H_
+
+#include <vector>
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+#include "gpu/command_buffer/service/vertex_array_manager.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class Buffer;
+class ErrorState;
+class FeatureInfo;
+class Framebuffer;
+class Program;
+class Renderbuffer;
+
+// State associated with each texture unit.
+struct GPU_EXPORT TextureUnit {
+ TextureUnit();
+ ~TextureUnit();
+
+ // The last target that was bound to this texture unit.
+ GLenum bind_target;
+
+ // texture currently bound to this unit's GL_TEXTURE_2D with glBindTexture
+ scoped_refptr<TextureRef> bound_texture_2d;
+
+ // texture currently bound to this unit's GL_TEXTURE_CUBE_MAP with
+ // glBindTexture
+ scoped_refptr<TextureRef> bound_texture_cube_map;
+
+ // texture currently bound to this unit's GL_TEXTURE_EXTERNAL_OES with
+ // glBindTexture
+ scoped_refptr<TextureRef> bound_texture_external_oes;
+
+ // texture currently bound to this unit's GL_TEXTURE_RECTANGLE_ARB with
+ // glBindTexture
+ scoped_refptr<TextureRef> bound_texture_rectangle_arb;
+
+ scoped_refptr<TextureRef> GetInfoForSamplerType(
+ GLenum type) {
+ DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE ||
+ type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB);
+ switch (type) {
+ case GL_SAMPLER_2D:
+ return bound_texture_2d;
+ case GL_SAMPLER_CUBE:
+ return bound_texture_cube_map;
+ case GL_SAMPLER_EXTERNAL_OES:
+ return bound_texture_external_oes;
+ case GL_SAMPLER_2D_RECT_ARB:
+ return bound_texture_rectangle_arb;
+ }
+
+ NOTREACHED();
+ return NULL;
+ }
+
+ void Unbind(TextureRef* texture) {
+ if (bound_texture_2d.get() == texture) {
+ bound_texture_2d = NULL;
+ }
+ if (bound_texture_cube_map.get() == texture) {
+ bound_texture_cube_map = NULL;
+ }
+ if (bound_texture_external_oes.get() == texture) {
+ bound_texture_external_oes = NULL;
+ }
+ }
+};
+
+struct Vec4 {
+ Vec4() {
+ v[0] = 0.0f;
+ v[1] = 0.0f;
+ v[2] = 0.0f;
+ v[3] = 1.0f;
+ }
+ float v[4];
+};
+
+struct GPU_EXPORT ContextState {
+ ContextState(FeatureInfo* feature_info, Logger* logger);
+ ~ContextState();
+
+ void Initialize();
+
+ void RestoreState() const;
+ void InitCapabilities() const;
+ void InitState() const;
+
+ void RestoreActiveTexture() const;
+ void RestoreAllTextureUnitBindings() const;
+ void RestoreAttribute(GLuint index) const;
+ void RestoreBufferBindings() const;
+ void RestoreGlobalState() const;
+ void RestoreProgramBindings() const;
+ void RestoreRenderbufferBindings() const;
+ void RestoreTextureUnitBindings(GLuint unit) const;
+
+ // Helper for getting cached state.
+ bool GetStateAsGLint(
+ GLenum pname, GLint* params, GLsizei* num_written) const;
+ bool GetStateAsGLfloat(
+ GLenum pname, GLfloat* params, GLsizei* num_written) const;
+ bool GetEnabled(GLenum cap) const;
+
+ ErrorState* GetErrorState();
+
+ #include "gpu/command_buffer/service/context_state_autogen.h"
+
+ EnableFlags enable_flags;
+
+ // Current active texture by 0 - n index.
+ // In other words, if we call glActiveTexture(GL_TEXTURE2) this value would
+ // be 2.
+ GLuint active_texture_unit;
+
+ // The currently bound array buffer. If this is 0 it is illegal to call
+ // glVertexAttribPointer.
+ scoped_refptr<Buffer> bound_array_buffer;
+
+ // Which textures are bound to texture units through glActiveTexture.
+ std::vector<TextureUnit> texture_units;
+
+ // The values for each attrib.
+ std::vector<Vec4> attrib_values;
+
+ // Class that manages vertex attribs.
+ scoped_refptr<VertexAttribManager> vertex_attrib_manager;
+
+ // The program in use by glUseProgram
+ scoped_refptr<Program> current_program;
+
+ // The currently bound framebuffers
+ scoped_refptr<Framebuffer> bound_read_framebuffer;
+ scoped_refptr<Framebuffer> bound_draw_framebuffer;
+
+ // The currently bound renderbuffer
+ scoped_refptr<Renderbuffer> bound_renderbuffer;
+
+ scoped_refptr<QueryManager::Query> current_query;
+
+ bool pack_reverse_row_order;
+
+ mutable bool fbo_binding_for_scissor_workaround_dirty_;
+ FeatureInfo* feature_info_;
+
+ private:
+ scoped_ptr<ErrorState> error_state_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_H_
+
diff --git a/chromium/gpu/command_buffer/service/context_state_autogen.h b/chromium/gpu/command_buffer/service/context_state_autogen.h
new file mode 100644
index 00000000000..a76aabccac7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_state_autogen.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by context_state.h
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_AUTOGEN_H_
+
+struct EnableFlags {
+ EnableFlags();
+ bool blend;
+ bool cull_face;
+ bool depth_test;
+ bool dither;
+ bool polygon_offset_fill;
+ bool sample_alpha_to_coverage;
+ bool sample_coverage;
+ bool scissor_test;
+ bool stencil_test;
+};
+
+GLfloat blend_color_red;
+GLfloat blend_color_green;
+GLfloat blend_color_blue;
+GLfloat blend_color_alpha;
+GLenum blend_equation_rgb;
+GLenum blend_equation_alpha;
+GLenum blend_source_rgb;
+GLenum blend_dest_rgb;
+GLenum blend_source_alpha;
+GLenum blend_dest_alpha;
+GLfloat color_clear_red;
+GLfloat color_clear_green;
+GLfloat color_clear_blue;
+GLfloat color_clear_alpha;
+GLclampf depth_clear;
+GLint stencil_clear;
+GLboolean color_mask_red;
+GLboolean color_mask_green;
+GLboolean color_mask_blue;
+GLboolean color_mask_alpha;
+GLenum cull_mode;
+GLenum depth_func;
+GLboolean depth_mask;
+GLclampf z_near;
+GLclampf z_far;
+GLenum front_face;
+GLenum hint_generate_mipmap;
+GLenum hint_fragment_shader_derivative;
+GLfloat line_width;
+GLint pack_alignment;
+GLint unpack_alignment;
+GLfloat polygon_offset_factor;
+GLfloat polygon_offset_units;
+GLclampf sample_coverage_value;
+GLboolean sample_coverage_invert;
+GLint scissor_x;
+GLint scissor_y;
+GLsizei scissor_width;
+GLsizei scissor_height;
+GLenum stencil_front_func;
+GLint stencil_front_ref;
+GLuint stencil_front_mask;
+GLenum stencil_back_func;
+GLint stencil_back_ref;
+GLuint stencil_back_mask;
+GLuint stencil_front_writemask;
+GLuint stencil_back_writemask;
+GLenum stencil_front_fail_op;
+GLenum stencil_front_z_fail_op;
+GLenum stencil_front_z_pass_op;
+GLenum stencil_back_fail_op;
+GLenum stencil_back_z_fail_op;
+GLenum stencil_back_z_pass_op;
+GLint viewport_x;
+GLint viewport_y;
+GLsizei viewport_width;
+GLsizei viewport_height;
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/context_state_impl_autogen.h b/chromium/gpu/command_buffer/service/context_state_impl_autogen.h
new file mode 100644
index 00000000000..65bc1181508
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/context_state_impl_autogen.h
@@ -0,0 +1,814 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by context_state.cc
+#ifndef GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_IMPL_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_IMPL_AUTOGEN_H_
+
+ContextState::EnableFlags::EnableFlags()
+ : blend(false),
+ cull_face(false),
+ depth_test(false),
+ dither(true),
+ polygon_offset_fill(false),
+ sample_alpha_to_coverage(false),
+ sample_coverage(false),
+ scissor_test(false),
+ stencil_test(false) {
+}
+
+void ContextState::Initialize() {
+ blend_color_red = 0.0f;
+ blend_color_green = 0.0f;
+ blend_color_blue = 0.0f;
+ blend_color_alpha = 0.0f;
+ blend_equation_rgb = GL_FUNC_ADD;
+ blend_equation_alpha = GL_FUNC_ADD;
+ blend_source_rgb = GL_ONE;
+ blend_dest_rgb = GL_ZERO;
+ blend_source_alpha = GL_ONE;
+ blend_dest_alpha = GL_ZERO;
+ color_clear_red = 0.0f;
+ color_clear_green = 0.0f;
+ color_clear_blue = 0.0f;
+ color_clear_alpha = 0.0f;
+ depth_clear = 1.0f;
+ stencil_clear = 0;
+ color_mask_red = true;
+ color_mask_green = true;
+ color_mask_blue = true;
+ color_mask_alpha = true;
+ cull_mode = GL_BACK;
+ depth_func = GL_LESS;
+ depth_mask = true;
+ z_near = 0.0f;
+ z_far = 1.0f;
+ front_face = GL_CCW;
+ hint_generate_mipmap = GL_DONT_CARE;
+ hint_fragment_shader_derivative = GL_DONT_CARE;
+ line_width = 1.0f;
+ pack_alignment = 4;
+ unpack_alignment = 4;
+ polygon_offset_factor = 0.0f;
+ polygon_offset_units = 0.0f;
+ sample_coverage_value = 1.0f;
+ sample_coverage_invert = false;
+ scissor_x = 0;
+ scissor_y = 0;
+ scissor_width = 1;
+ scissor_height = 1;
+ stencil_front_func = GL_ALWAYS;
+ stencil_front_ref = 0;
+ stencil_front_mask = 0xFFFFFFFFU;
+ stencil_back_func = GL_ALWAYS;
+ stencil_back_ref = 0;
+ stencil_back_mask = 0xFFFFFFFFU;
+ stencil_front_writemask = 0xFFFFFFFFU;
+ stencil_back_writemask = 0xFFFFFFFFU;
+ stencil_front_fail_op = GL_KEEP;
+ stencil_front_z_fail_op = GL_KEEP;
+ stencil_front_z_pass_op = GL_KEEP;
+ stencil_back_fail_op = GL_KEEP;
+ stencil_back_z_fail_op = GL_KEEP;
+ stencil_back_z_pass_op = GL_KEEP;
+ viewport_x = 0;
+ viewport_y = 0;
+ viewport_width = 1;
+ viewport_height = 1;
+}
+
+void ContextState::InitCapabilities() const {
+ EnableDisable(GL_BLEND, enable_flags.blend);
+ EnableDisable(GL_CULL_FACE, enable_flags.cull_face);
+ EnableDisable(GL_DEPTH_TEST, enable_flags.depth_test);
+ EnableDisable(GL_DITHER, enable_flags.dither);
+ EnableDisable(GL_POLYGON_OFFSET_FILL, enable_flags.polygon_offset_fill);
+ EnableDisable(
+ GL_SAMPLE_ALPHA_TO_COVERAGE, enable_flags.sample_alpha_to_coverage);
+ EnableDisable(GL_SAMPLE_COVERAGE, enable_flags.sample_coverage);
+ EnableDisable(GL_SCISSOR_TEST, enable_flags.scissor_test);
+ EnableDisable(GL_STENCIL_TEST, enable_flags.stencil_test);
+}
+
+void ContextState::InitState() const {
+ glBlendColor(
+ blend_color_red, blend_color_green, blend_color_blue, blend_color_alpha);
+ glBlendEquationSeparate(blend_equation_rgb, blend_equation_alpha);
+ glBlendFuncSeparate(
+ blend_source_rgb, blend_dest_rgb, blend_source_alpha, blend_dest_alpha);
+ glClearColor(
+ color_clear_red, color_clear_green, color_clear_blue, color_clear_alpha);
+ glClearDepth(depth_clear);
+ glClearStencil(stencil_clear);
+ glColorMask(
+ color_mask_red, color_mask_green, color_mask_blue, color_mask_alpha);
+ glCullFace(cull_mode);
+ glDepthFunc(depth_func);
+ glDepthMask(depth_mask);
+ glDepthRange(z_near, z_far);
+ glFrontFace(front_face);
+ glHint(GL_GENERATE_MIPMAP_HINT, hint_generate_mipmap);
+ if (feature_info_->feature_flags().oes_standard_derivatives)
+ glHint(
+ GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES, hint_fragment_shader_derivative);
+ glLineWidth(line_width);
+ glPixelStorei(GL_PACK_ALIGNMENT, pack_alignment);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
+ glPolygonOffset(polygon_offset_factor, polygon_offset_units);
+ glSampleCoverage(sample_coverage_value, sample_coverage_invert);
+ glScissor(scissor_x, scissor_y, scissor_width, scissor_height);
+ glStencilFuncSeparate(
+ GL_FRONT, stencil_front_func, stencil_front_ref, stencil_front_mask);
+ glStencilFuncSeparate(
+ GL_BACK, stencil_back_func, stencil_back_ref, stencil_back_mask);
+ glStencilMaskSeparate(GL_FRONT, stencil_front_writemask);
+ glStencilMaskSeparate(GL_BACK, stencil_back_writemask);
+ glStencilOpSeparate(
+ GL_FRONT, stencil_front_fail_op, stencil_front_z_fail_op,
+ stencil_front_z_pass_op);
+ glStencilOpSeparate(
+ GL_BACK, stencil_back_fail_op, stencil_back_z_fail_op,
+ stencil_back_z_pass_op);
+ glViewport(viewport_x, viewport_y, viewport_width, viewport_height);
+}
+bool ContextState::GetEnabled(GLenum cap) const {
+ switch (cap) {
+ case GL_BLEND:
+ return enable_flags.blend;
+ case GL_CULL_FACE:
+ return enable_flags.cull_face;
+ case GL_DEPTH_TEST:
+ return enable_flags.depth_test;
+ case GL_DITHER:
+ return enable_flags.dither;
+ case GL_POLYGON_OFFSET_FILL:
+ return enable_flags.polygon_offset_fill;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ return enable_flags.sample_alpha_to_coverage;
+ case GL_SAMPLE_COVERAGE:
+ return enable_flags.sample_coverage;
+ case GL_SCISSOR_TEST:
+ return enable_flags.scissor_test;
+ case GL_STENCIL_TEST:
+ return enable_flags.stencil_test;
+ default:
+ GPU_NOTREACHED();
+ return false;
+ }
+}
+
+bool ContextState::GetStateAsGLint(
+ GLenum pname, GLint* params, GLsizei* num_written) const {
+ switch (pname) {
+ case GL_BLEND_COLOR:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_color_red);
+ params[1] = static_cast<GLint>(blend_color_green);
+ params[2] = static_cast<GLint>(blend_color_blue);
+ params[3] = static_cast<GLint>(blend_color_alpha);
+ }
+ return true;
+ case GL_BLEND_EQUATION_RGB:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_equation_rgb);
+ }
+ return true;
+ case GL_BLEND_EQUATION_ALPHA:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_equation_alpha);
+ }
+ return true;
+ case GL_BLEND_SRC_RGB:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_source_rgb);
+ }
+ return true;
+ case GL_BLEND_DST_RGB:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_dest_rgb);
+ }
+ return true;
+ case GL_BLEND_SRC_ALPHA:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_source_alpha);
+ }
+ return true;
+ case GL_BLEND_DST_ALPHA:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(blend_dest_alpha);
+ }
+ return true;
+ case GL_COLOR_CLEAR_VALUE:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLint>(color_clear_red);
+ params[1] = static_cast<GLint>(color_clear_green);
+ params[2] = static_cast<GLint>(color_clear_blue);
+ params[3] = static_cast<GLint>(color_clear_alpha);
+ }
+ return true;
+ case GL_DEPTH_CLEAR_VALUE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(depth_clear);
+ }
+ return true;
+ case GL_STENCIL_CLEAR_VALUE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_clear);
+ }
+ return true;
+ case GL_COLOR_WRITEMASK:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLint>(color_mask_red);
+ params[1] = static_cast<GLint>(color_mask_green);
+ params[2] = static_cast<GLint>(color_mask_blue);
+ params[3] = static_cast<GLint>(color_mask_alpha);
+ }
+ return true;
+ case GL_CULL_FACE_MODE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(cull_mode);
+ }
+ return true;
+ case GL_DEPTH_FUNC:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(depth_func);
+ }
+ return true;
+ case GL_DEPTH_WRITEMASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(depth_mask);
+ }
+ return true;
+ case GL_DEPTH_RANGE:
+ *num_written = 2;
+ if (params) {
+ params[0] = static_cast<GLint>(z_near);
+ params[1] = static_cast<GLint>(z_far);
+ }
+ return true;
+ case GL_FRONT_FACE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(front_face);
+ }
+ return true;
+ case GL_GENERATE_MIPMAP_HINT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(hint_generate_mipmap);
+ }
+ return true;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(hint_fragment_shader_derivative);
+ }
+ return true;
+ case GL_LINE_WIDTH:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(line_width);
+ }
+ return true;
+ case GL_PACK_ALIGNMENT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(pack_alignment);
+ }
+ return true;
+ case GL_UNPACK_ALIGNMENT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(unpack_alignment);
+ }
+ return true;
+ case GL_POLYGON_OFFSET_FACTOR:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(polygon_offset_factor);
+ }
+ return true;
+ case GL_POLYGON_OFFSET_UNITS:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(polygon_offset_units);
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE_VALUE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(sample_coverage_value);
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE_INVERT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(sample_coverage_invert);
+ }
+ return true;
+ case GL_SCISSOR_BOX:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLint>(scissor_x);
+ params[1] = static_cast<GLint>(scissor_y);
+ params[2] = static_cast<GLint>(scissor_width);
+ params[3] = static_cast<GLint>(scissor_height);
+ }
+ return true;
+ case GL_STENCIL_FUNC:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_func);
+ }
+ return true;
+ case GL_STENCIL_REF:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_ref);
+ }
+ return true;
+ case GL_STENCIL_VALUE_MASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_mask);
+ }
+ return true;
+ case GL_STENCIL_BACK_FUNC:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_func);
+ }
+ return true;
+ case GL_STENCIL_BACK_REF:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_ref);
+ }
+ return true;
+ case GL_STENCIL_BACK_VALUE_MASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_mask);
+ }
+ return true;
+ case GL_STENCIL_WRITEMASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_writemask);
+ }
+ return true;
+ case GL_STENCIL_BACK_WRITEMASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_writemask);
+ }
+ return true;
+ case GL_STENCIL_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_fail_op);
+ }
+ return true;
+ case GL_STENCIL_PASS_DEPTH_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_z_fail_op);
+ }
+ return true;
+ case GL_STENCIL_PASS_DEPTH_PASS:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_front_z_pass_op);
+ }
+ return true;
+ case GL_STENCIL_BACK_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_fail_op);
+ }
+ return true;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_z_fail_op);
+ }
+ return true;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(stencil_back_z_pass_op);
+ }
+ return true;
+ case GL_VIEWPORT:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLint>(viewport_x);
+ params[1] = static_cast<GLint>(viewport_y);
+ params[2] = static_cast<GLint>(viewport_width);
+ params[3] = static_cast<GLint>(viewport_height);
+ }
+ return true;
+ case GL_BLEND:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.blend);
+ }
+ return true;
+ case GL_CULL_FACE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.cull_face);
+ }
+ return true;
+ case GL_DEPTH_TEST:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.depth_test);
+ }
+ return true;
+ case GL_DITHER:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.dither);
+ }
+ return true;
+ case GL_POLYGON_OFFSET_FILL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.polygon_offset_fill);
+ }
+ return true;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.sample_alpha_to_coverage);
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.sample_coverage);
+ }
+ return true;
+ case GL_SCISSOR_TEST:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.scissor_test);
+ }
+ return true;
+ case GL_STENCIL_TEST:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.stencil_test);
+ }
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool ContextState::GetStateAsGLfloat(
+ GLenum pname, GLfloat* params, GLsizei* num_written) const {
+ switch (pname) {
+ case GL_BLEND_COLOR:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_color_red);
+ params[1] = static_cast<GLfloat>(blend_color_green);
+ params[2] = static_cast<GLfloat>(blend_color_blue);
+ params[3] = static_cast<GLfloat>(blend_color_alpha);
+ }
+ return true;
+ case GL_BLEND_EQUATION_RGB:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_equation_rgb);
+ }
+ return true;
+ case GL_BLEND_EQUATION_ALPHA:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_equation_alpha);
+ }
+ return true;
+ case GL_BLEND_SRC_RGB:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_source_rgb);
+ }
+ return true;
+ case GL_BLEND_DST_RGB:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_dest_rgb);
+ }
+ return true;
+ case GL_BLEND_SRC_ALPHA:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_source_alpha);
+ }
+ return true;
+ case GL_BLEND_DST_ALPHA:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(blend_dest_alpha);
+ }
+ return true;
+ case GL_COLOR_CLEAR_VALUE:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLfloat>(color_clear_red);
+ params[1] = static_cast<GLfloat>(color_clear_green);
+ params[2] = static_cast<GLfloat>(color_clear_blue);
+ params[3] = static_cast<GLfloat>(color_clear_alpha);
+ }
+ return true;
+ case GL_DEPTH_CLEAR_VALUE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(depth_clear);
+ }
+ return true;
+ case GL_STENCIL_CLEAR_VALUE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_clear);
+ }
+ return true;
+ case GL_COLOR_WRITEMASK:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLfloat>(color_mask_red);
+ params[1] = static_cast<GLfloat>(color_mask_green);
+ params[2] = static_cast<GLfloat>(color_mask_blue);
+ params[3] = static_cast<GLfloat>(color_mask_alpha);
+ }
+ return true;
+ case GL_CULL_FACE_MODE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(cull_mode);
+ }
+ return true;
+ case GL_DEPTH_FUNC:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(depth_func);
+ }
+ return true;
+ case GL_DEPTH_WRITEMASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(depth_mask);
+ }
+ return true;
+ case GL_DEPTH_RANGE:
+ *num_written = 2;
+ if (params) {
+ params[0] = static_cast<GLfloat>(z_near);
+ params[1] = static_cast<GLfloat>(z_far);
+ }
+ return true;
+ case GL_FRONT_FACE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(front_face);
+ }
+ return true;
+ case GL_GENERATE_MIPMAP_HINT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(hint_generate_mipmap);
+ }
+ return true;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(hint_fragment_shader_derivative);
+ }
+ return true;
+ case GL_LINE_WIDTH:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(line_width);
+ }
+ return true;
+ case GL_PACK_ALIGNMENT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(pack_alignment);
+ }
+ return true;
+ case GL_UNPACK_ALIGNMENT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(unpack_alignment);
+ }
+ return true;
+ case GL_POLYGON_OFFSET_FACTOR:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(polygon_offset_factor);
+ }
+ return true;
+ case GL_POLYGON_OFFSET_UNITS:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(polygon_offset_units);
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE_VALUE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(sample_coverage_value);
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE_INVERT:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(sample_coverage_invert);
+ }
+ return true;
+ case GL_SCISSOR_BOX:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLfloat>(scissor_x);
+ params[1] = static_cast<GLfloat>(scissor_y);
+ params[2] = static_cast<GLfloat>(scissor_width);
+ params[3] = static_cast<GLfloat>(scissor_height);
+ }
+ return true;
+ case GL_STENCIL_FUNC:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_func);
+ }
+ return true;
+ case GL_STENCIL_REF:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_ref);
+ }
+ return true;
+ case GL_STENCIL_VALUE_MASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_mask);
+ }
+ return true;
+ case GL_STENCIL_BACK_FUNC:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_func);
+ }
+ return true;
+ case GL_STENCIL_BACK_REF:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_ref);
+ }
+ return true;
+ case GL_STENCIL_BACK_VALUE_MASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_mask);
+ }
+ return true;
+ case GL_STENCIL_WRITEMASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_writemask);
+ }
+ return true;
+ case GL_STENCIL_BACK_WRITEMASK:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_writemask);
+ }
+ return true;
+ case GL_STENCIL_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_fail_op);
+ }
+ return true;
+ case GL_STENCIL_PASS_DEPTH_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_z_fail_op);
+ }
+ return true;
+ case GL_STENCIL_PASS_DEPTH_PASS:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_front_z_pass_op);
+ }
+ return true;
+ case GL_STENCIL_BACK_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_fail_op);
+ }
+ return true;
+ case GL_STENCIL_BACK_PASS_DEPTH_FAIL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_z_fail_op);
+ }
+ return true;
+ case GL_STENCIL_BACK_PASS_DEPTH_PASS:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(stencil_back_z_pass_op);
+ }
+ return true;
+ case GL_VIEWPORT:
+ *num_written = 4;
+ if (params) {
+ params[0] = static_cast<GLfloat>(viewport_x);
+ params[1] = static_cast<GLfloat>(viewport_y);
+ params[2] = static_cast<GLfloat>(viewport_width);
+ params[3] = static_cast<GLfloat>(viewport_height);
+ }
+ return true;
+ case GL_BLEND:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.blend);
+ }
+ return true;
+ case GL_CULL_FACE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.cull_face);
+ }
+ return true;
+ case GL_DEPTH_TEST:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.depth_test);
+ }
+ return true;
+ case GL_DITHER:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.dither);
+ }
+ return true;
+ case GL_POLYGON_OFFSET_FILL:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.polygon_offset_fill);
+ }
+ return true;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ *num_written = 1;
+ if (params) {
+ params[0] =
+ static_cast<GLfloat>(enable_flags.sample_alpha_to_coverage);
+ }
+ return true;
+ case GL_SAMPLE_COVERAGE:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.sample_coverage);
+ }
+ return true;
+ case GL_SCISSOR_TEST:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.scissor_test);
+ }
+ return true;
+ case GL_STENCIL_TEST:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.stencil_test);
+ }
+ return true;
+ default:
+ return false;
+ }
+}
+#endif // GPU_COMMAND_BUFFER_SERVICE_CONTEXT_STATE_IMPL_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/disk_cache_proto.proto b/chromium/gpu/command_buffer/service/disk_cache_proto.proto
new file mode 100644
index 00000000000..c165443e9fd
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/disk_cache_proto.proto
@@ -0,0 +1,23 @@
+option optimize_for = LITE_RUNTIME;
+
+message ShaderInfoProto {
+ optional int32 type = 1;
+ optional int32 size = 2;
+ optional string name = 3;
+ optional string key = 4;
+}
+
+message ShaderProto {
+ optional bytes sha = 1;
+ repeated ShaderInfoProto attribs = 2;
+ repeated ShaderInfoProto uniforms = 3;
+}
+
+message GpuProgramProto {
+ optional bytes sha = 1;
+ optional int32 format = 2;
+ optional bytes program = 3;
+
+ optional ShaderProto vertex_shader = 4;
+ optional ShaderProto fragment_shader = 5;
+}
diff --git a/chromium/gpu/command_buffer/service/error_state.cc b/chromium/gpu/command_buffer/service/error_state.cc
new file mode 100644
index 00000000000..524ea4f79ec
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/error_state.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/error_state.h"
+
+#include <string>
+
+#include "base/strings/stringprintf.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/logger.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ErrorStateImpl : public ErrorState {
+ public:
+ explicit ErrorStateImpl(Logger* logger);
+ virtual ~ErrorStateImpl();
+
+ virtual uint32 GetGLError() OVERRIDE;
+
+ virtual void SetGLError(
+ const char* filename,
+ int line,
+ unsigned int error,
+ const char* function_name,
+ const char* msg) OVERRIDE;
+ virtual void SetGLErrorInvalidEnum(
+ const char* filename,
+ int line,
+ const char* function_name,
+ unsigned int value,
+ const char* label) OVERRIDE;
+ virtual void SetGLErrorInvalidParam(
+ const char* filename,
+ int line,
+ unsigned int error,
+ const char* function_name,
+ unsigned int pname,
+ int param) OVERRIDE;
+
+ virtual unsigned int PeekGLError(
+ const char* filename, int line, const char* function_name) OVERRIDE;
+
+ virtual void CopyRealGLErrorsToWrapper(
+ const char* filename, int line, const char* function_name) OVERRIDE;
+
+ virtual void ClearRealGLErrors(
+ const char* filename, int line, const char* function_name) OVERRIDE;
+
+ private:
+ // The last error message set.
+ std::string last_error_;
+ // Current GL error bits.
+ uint32 error_bits_;
+
+ Logger* logger_;
+
+ DISALLOW_COPY_AND_ASSIGN(ErrorStateImpl);
+};
+
+ErrorState::ErrorState() {}
+
+ErrorState::~ErrorState() {}
+
+ErrorState* ErrorState::Create(Logger* logger) {
+ return new ErrorStateImpl(logger);
+}
+
+ErrorStateImpl::ErrorStateImpl(Logger* logger)
+ : error_bits_(0),
+ logger_(logger) {}
+
+ErrorStateImpl::~ErrorStateImpl() {}
+
+uint32 ErrorStateImpl::GetGLError() {
+ // Check the GL error first, then our wrapped error.
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR && error_bits_ != 0) {
+ for (uint32 mask = 1; mask != 0; mask = mask << 1) {
+ if ((error_bits_ & mask) != 0) {
+ error = GLES2Util::GLErrorBitToGLError(mask);
+ break;
+ }
+ }
+ }
+
+ if (error != GL_NO_ERROR) {
+ // There was an error, clear the corresponding wrapped error.
+ error_bits_ &= ~GLES2Util::GLErrorToErrorBit(error);
+ }
+ return error;
+}
+
+unsigned int ErrorStateImpl::PeekGLError(
+ const char* filename, int line, const char* function_name) {
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ SetGLError(filename, line, error, function_name, "");
+ }
+ return error;
+}
+
+void ErrorStateImpl::SetGLError(
+ const char* filename,
+ int line,
+ unsigned int error,
+ const char* function_name,
+ const char* msg) {
+ if (msg) {
+ last_error_ = msg;
+ logger_->LogMessage(
+ filename, line,
+ std::string("GL ERROR :") +
+ GLES2Util::GetStringEnum(error) + " : " +
+ function_name + ": " + msg);
+ }
+ error_bits_ |= GLES2Util::GLErrorToErrorBit(error);
+}
+
+void ErrorStateImpl::SetGLErrorInvalidEnum(
+ const char* filename,
+ int line,
+ const char* function_name,
+ unsigned int value,
+ const char* label) {
+ SetGLError(filename, line, GL_INVALID_ENUM, function_name,
+ (std::string(label) + " was " +
+ GLES2Util::GetStringEnum(value)).c_str());
+}
+
+void ErrorStateImpl::SetGLErrorInvalidParam(
+ const char* filename,
+ int line,
+ unsigned int error,
+ const char* function_name,
+ unsigned int pname, int param) {
+ if (error == GL_INVALID_ENUM) {
+ SetGLError(
+ filename, line, GL_INVALID_ENUM, function_name,
+ (std::string("trying to set ") +
+ GLES2Util::GetStringEnum(pname) + " to " +
+ GLES2Util::GetStringEnum(param)).c_str());
+ } else {
+ SetGLError(
+ filename, line, error, function_name,
+ (std::string("trying to set ") +
+ GLES2Util::GetStringEnum(pname) + " to " +
+ base::StringPrintf("%d", param)).c_str());
+ }
+}
+
+void ErrorStateImpl::CopyRealGLErrorsToWrapper(
+ const char* filename, int line, const char* function_name) {
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ SetGLError(filename, line, error, function_name,
+ "<- error from previous GL command");
+ }
+}
+
+void ErrorStateImpl::ClearRealGLErrors(
+ const char* filename, int line, const char* function_name) {
+ // Clears and logs all current gl errors.
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ if (error != GL_OUT_OF_MEMORY) {
+ // GL_OUT_OF_MEMORY can legally happen on lost device.
+ logger_->LogMessage(
+ filename, line,
+ std::string("GL ERROR :") +
+ GLES2Util::GetStringEnum(error) + " : " +
+ function_name + ": was unhandled");
+ NOTREACHED() << "GL error " << error << " was unhandled.";
+ }
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/error_state.h b/chromium/gpu/command_buffer/service/error_state.h
new file mode 100644
index 00000000000..507b7383670
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/error_state.h
@@ -0,0 +1,107 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the ErrorState class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ERROR_STATE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ERROR_STATE_H_
+
+#include "base/compiler_specific.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class Logger;
+
+// Use these macro to synthesize GL errors instead of calling the error_state
+// functions directly as they will propogate the __FILE__ and __LINE__.
+
+// Use to synthesize a GL error on the error_state.
+#define ERRORSTATE_SET_GL_ERROR(error_state, error, function_name, msg) \
+ error_state->SetGLError(__FILE__, __LINE__, error, function_name, msg)
+
+// Use to synthesize an INVALID_ENUM GL error on the error_state. Will attempt
+// to expand the enum to a string.
+#define ERRORSTATE_SET_GL_ERROR_INVALID_ENUM( \
+ error_state, function_name, value, label) \
+ error_state->SetGLErrorInvalidEnum( \
+ __FILE__, __LINE__, function_name, value, label)
+
+// Use to synthesize a GL error on the error_state for an invalid enum based
+// parameter. Will attempt to expand the parameter to a string.
+#define ERRORSTATE_SET_GL_ERROR_INVALID_PARAM( \
+ error_state, error, function_name, pname, param) \
+ error_state->SetGLErrorInvalidParam( \
+ __FILE__, __LINE__, error, function_name, pname, param)
+
+// Use to move all pending error to the wrapper so on your next GL call
+// you can see if that call generates an error.
+#define ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, function_name) \
+ error_state->CopyRealGLErrorsToWrapper(__FILE__, __LINE__, function_name)
+// Use to look at the real GL error and still pass it on to the user.
+#define ERRORSTATE_PEEK_GL_ERROR(error_state, function_name) \
+ error_state->PeekGLError(__FILE__, __LINE__, function_name)
+// Use to clear all current GL errors. FAILS if there are any.
+#define ERRORSTATE_CLEAR_REAL_GL_ERRORS(error_state, function_name) \
+ error_state->ClearRealGLErrors(__FILE__, __LINE__, function_name)
+
+
+class GPU_EXPORT ErrorState {
+ public:
+ virtual ~ErrorState();
+
+ static ErrorState* Create(Logger* logger);
+
+ virtual uint32 GetGLError() = 0;
+
+ virtual void SetGLError(
+ const char* filename,
+ int line,
+ unsigned int error,
+ const char* function_name,
+ const char* msg) = 0;
+ virtual void SetGLErrorInvalidEnum(
+ const char* filename,
+ int line,
+ const char* function_name,
+ unsigned int value,
+ const char* label) = 0;
+ virtual void SetGLErrorInvalidParam(
+ const char* filename,
+ int line,
+ unsigned int error,
+ const char* function_name,
+ unsigned int pname,
+ int param) = 0;
+
+ // Gets the GLError and stores it in our wrapper. Effectively
+ // this lets us peek at the error without losing it.
+ virtual unsigned int PeekGLError(
+ const char* filename, int line, const char* function_name) = 0;
+
+ // Copies the real GL errors to the wrapper. This is so we can
+ // make sure there are no native GL errors before calling some GL function
+ // so that on return we know any error generated was for that specific
+ // command.
+ virtual void CopyRealGLErrorsToWrapper(
+ const char* filename, int line, const char* function_name) = 0;
+
+ // Clear all real GL errors. This is to prevent the client from seeing any
+ // errors caused by GL calls that it was not responsible for issuing.
+ virtual void ClearRealGLErrors(
+ const char* filename, int line, const char* function_name) = 0;
+
+ protected:
+ ErrorState();
+
+ DISALLOW_COPY_AND_ASSIGN(ErrorState);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ERROR_STATE_H_
+
diff --git a/chromium/gpu/command_buffer/service/error_state_mock.cc b/chromium/gpu/command_buffer/service/error_state_mock.cc
new file mode 100644
index 00000000000..f3925d74352
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/error_state_mock.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/error_state_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+MockErrorState::MockErrorState()
+ : ErrorState() {}
+
+MockErrorState::~MockErrorState() {}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/error_state_mock.h b/chromium/gpu/command_buffer/service/error_state_mock.h
new file mode 100644
index 00000000000..00bed9a4712
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/error_state_mock.h
@@ -0,0 +1,48 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the mock ErrorState class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ERROR_STATE_MOCK_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ERROR_STATE_MOCK_H_
+
+#include "gpu/command_buffer/service/error_state.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class MockErrorState : public ErrorState {
+ public:
+ MockErrorState();
+ virtual ~MockErrorState();
+
+ MOCK_METHOD0(GetGLError, uint32());
+ MOCK_METHOD5(SetGLError, void(
+ const char* filename, int line,
+ unsigned error, const char* function_name, const char* msg));
+ MOCK_METHOD5(SetGLErrorInvalidEnum, void(
+ const char* filename, int line,
+ const char* function_name, unsigned value, const char* label));
+ MOCK_METHOD6(SetGLErrorInvalidParam, void(
+ const char* filename,
+ int line,
+ unsigned error,
+ const char* function_name,
+ unsigned pname,
+ int param));
+ MOCK_METHOD3(PeekGLError, unsigned(
+ const char* file, int line, const char* filename));
+ MOCK_METHOD3(CopyRealGLErrorsToWrapper, void(
+ const char* file, int line, const char* filename));
+ MOCK_METHOD3(ClearRealGLErrors, void(
+ const char* file, int line, const char* filename));
+
+ DISALLOW_COPY_AND_ASSIGN(MockErrorState);
+};
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ERROR_STATE_MOCK_H_
+
diff --git a/chromium/gpu/command_buffer/service/feature_info.cc b/chromium/gpu/command_buffer/service/feature_info.cc
new file mode 100644
index 00000000000..b0fb12073b2
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/feature_info.cc
@@ -0,0 +1,683 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/feature_info.h"
+
+#include <set>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "ui/gl/gl_implementation.h"
+
+#if defined(OS_MACOSX)
+#include "ui/gl/io_surface_support_mac.h"
+#endif
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+struct FormatInfo {
+ GLenum format;
+ const GLenum* types;
+ size_t count;
+};
+
+class StringSet {
+ public:
+ StringSet() {}
+
+ StringSet(const char* s) {
+ Init(s);
+ }
+
+ StringSet(const std::string& str) {
+ Init(str);
+ }
+
+ void Init(const char* s) {
+ std::string str(s ? s : "");
+ Init(str);
+ }
+
+ void Init(const std::string& str) {
+ std::vector<std::string> tokens;
+ Tokenize(str, " ", &tokens);
+ string_set_.insert(tokens.begin(), tokens.end());
+ }
+
+ bool Contains(const char* s) {
+ return string_set_.find(s) != string_set_.end();
+ }
+
+ bool Contains(const std::string& s) {
+ return string_set_.find(s) != string_set_.end();
+ }
+
+ private:
+ std::set<std::string> string_set_;
+};
+
+// Process a string of wordaround type IDs (seperated by ',') and set up
+// the corresponding Workaround flags.
+void StringToWorkarounds(
+ const std::string& types, FeatureInfo::Workarounds* workarounds) {
+ DCHECK(workarounds);
+ std::vector<std::string> pieces;
+ base::SplitString(types, ',', &pieces);
+ for (size_t i = 0; i < pieces.size(); ++i) {
+ int number = 0;
+ bool succeed = base::StringToInt(pieces[i], &number);
+ DCHECK(succeed);
+ switch (number) {
+#define GPU_OP(type, name) \
+ case gpu::type: \
+ workarounds->name = true; \
+ break;
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+ default:
+ NOTIMPLEMENTED();
+ }
+ }
+ if (workarounds->max_texture_size_limit_4096)
+ workarounds->max_texture_size = 4096;
+ if (workarounds->max_cube_map_texture_size_limit_4096)
+ workarounds->max_cube_map_texture_size = 4096;
+ if (workarounds->max_cube_map_texture_size_limit_1024)
+ workarounds->max_cube_map_texture_size = 1024;
+ if (workarounds->max_cube_map_texture_size_limit_512)
+ workarounds->max_cube_map_texture_size = 512;
+}
+
+} // anonymous namespace.
+
+FeatureInfo::FeatureFlags::FeatureFlags()
+ : chromium_framebuffer_multisample(false),
+ multisampled_render_to_texture(false),
+ use_img_for_multisampled_render_to_texture(false),
+ oes_standard_derivatives(false),
+ oes_egl_image_external(false),
+ npot_ok(false),
+ enable_texture_float_linear(false),
+ enable_texture_half_float_linear(false),
+ chromium_stream_texture(false),
+ angle_translated_shader_source(false),
+ angle_pack_reverse_row_order(false),
+ arb_texture_rectangle(false),
+ angle_instanced_arrays(false),
+ occlusion_query_boolean(false),
+ use_arb_occlusion_query2_for_occlusion_query_boolean(false),
+ use_arb_occlusion_query_for_occlusion_query_boolean(false),
+ native_vertex_array_object(false),
+ enable_shader_name_hashing(false),
+ enable_samplers(false),
+ ext_draw_buffers(false),
+ ext_frag_depth(false),
+ use_async_readpixels(false) {
+}
+
+FeatureInfo::Workarounds::Workarounds() :
+#define GPU_OP(type, name) name(false),
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+ max_texture_size(0),
+ max_cube_map_texture_size(0) {
+}
+
+FeatureInfo::FeatureInfo() {
+ static const GLenum kAlphaTypes[] = {
+ GL_UNSIGNED_BYTE,
+ };
+ static const GLenum kRGBTypes[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_5_6_5,
+ };
+ static const GLenum kRGBATypes[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_4_4_4_4,
+ GL_UNSIGNED_SHORT_5_5_5_1,
+ };
+ static const GLenum kLuminanceTypes[] = {
+ GL_UNSIGNED_BYTE,
+ };
+ static const GLenum kLuminanceAlphaTypes[] = {
+ GL_UNSIGNED_BYTE,
+ };
+ static const FormatInfo kFormatTypes[] = {
+ { GL_ALPHA, kAlphaTypes, arraysize(kAlphaTypes), },
+ { GL_RGB, kRGBTypes, arraysize(kRGBTypes), },
+ { GL_RGBA, kRGBATypes, arraysize(kRGBATypes), },
+ { GL_LUMINANCE, kLuminanceTypes, arraysize(kLuminanceTypes), },
+ { GL_LUMINANCE_ALPHA, kLuminanceAlphaTypes,
+ arraysize(kLuminanceAlphaTypes), } ,
+ };
+ for (size_t ii = 0; ii < arraysize(kFormatTypes); ++ii) {
+ const FormatInfo& info = kFormatTypes[ii];
+ ValueValidator<GLenum>& validator = texture_format_validators_[info.format];
+ for (size_t jj = 0; jj < info.count; ++jj) {
+ validator.AddValue(info.types[jj]);
+ }
+ }
+}
+
+bool FeatureInfo::Initialize(const char* allowed_features) {
+ disallowed_features_ = DisallowedFeatures();
+ AddFeatures(*CommandLine::ForCurrentProcess());
+ return true;
+}
+
+bool FeatureInfo::Initialize(const DisallowedFeatures& disallowed_features,
+ const char* allowed_features) {
+ disallowed_features_ = disallowed_features;
+ AddFeatures(*CommandLine::ForCurrentProcess());
+ return true;
+}
+
+void FeatureInfo::AddFeatures(const CommandLine& command_line) {
+ // Figure out what extensions to turn on.
+ StringSet extensions(
+ reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)));
+
+ if (command_line.HasSwitch(switches::kGpuDriverBugWorkarounds)) {
+ std::string types = command_line.GetSwitchValueASCII(
+ switches::kGpuDriverBugWorkarounds);
+ StringToWorkarounds(types, &workarounds_);
+ }
+
+ feature_flags_.enable_shader_name_hashing =
+ !command_line.HasSwitch(switches::kDisableShaderNameHashing);
+
+ bool npot_ok = false;
+
+ AddExtensionString("GL_ANGLE_translated_shader_source");
+ AddExtensionString("GL_CHROMIUM_async_pixel_transfers");
+ AddExtensionString("GL_CHROMIUM_bind_uniform_location");
+ AddExtensionString("GL_CHROMIUM_command_buffer_query");
+ AddExtensionString("GL_CHROMIUM_command_buffer_latency_query");
+ AddExtensionString("GL_CHROMIUM_copy_texture");
+ AddExtensionString("GL_CHROMIUM_discard_backbuffer");
+ AddExtensionString("GL_CHROMIUM_get_error_query");
+ AddExtensionString("GL_CHROMIUM_lose_context");
+ AddExtensionString("GL_CHROMIUM_pixel_transfer_buffer_object");
+ AddExtensionString("GL_CHROMIUM_rate_limit_offscreen_context");
+ AddExtensionString("GL_CHROMIUM_resize");
+ AddExtensionString("GL_CHROMIUM_resource_safe");
+ AddExtensionString("GL_CHROMIUM_set_visibility");
+ AddExtensionString("GL_CHROMIUM_strict_attribs");
+ AddExtensionString("GL_CHROMIUM_stream_texture");
+ AddExtensionString("GL_CHROMIUM_texture_mailbox");
+ AddExtensionString("GL_EXT_debug_marker");
+
+ if (workarounds_.enable_chromium_fast_npot_mo8_textures)
+ AddExtensionString("GL_CHROMIUM_fast_NPOT_MO8_textures");
+
+ feature_flags_.chromium_stream_texture = true;
+
+ // OES_vertex_array_object is emulated if not present natively,
+ // so the extension string is always exposed.
+ AddExtensionString("GL_OES_vertex_array_object");
+
+ if (!disallowed_features_.gpu_memory_manager)
+ AddExtensionString("GL_CHROMIUM_gpu_memory_manager");
+
+ if (extensions.Contains("GL_ANGLE_translated_shader_source")) {
+ feature_flags_.angle_translated_shader_source = true;
+ }
+
+ // Check if we should allow GL_EXT_texture_compression_dxt1 and
+ // GL_EXT_texture_compression_s3tc.
+ bool enable_dxt1 = false;
+ bool enable_dxt3 = false;
+ bool enable_dxt5 = false;
+ bool have_s3tc = extensions.Contains("GL_EXT_texture_compression_s3tc");
+ bool have_dxt3 =
+ have_s3tc || extensions.Contains("GL_ANGLE_texture_compression_dxt3");
+ bool have_dxt5 =
+ have_s3tc || extensions.Contains("GL_ANGLE_texture_compression_dxt5");
+
+ if (extensions.Contains("GL_EXT_texture_compression_dxt1") || have_s3tc) {
+ enable_dxt1 = true;
+ }
+ if (have_dxt3) {
+ enable_dxt3 = true;
+ }
+ if (have_dxt5) {
+ enable_dxt5 = true;
+ }
+
+ if (enable_dxt1) {
+ AddExtensionString("GL_EXT_texture_compression_dxt1");
+ validators_.compressed_texture_format.AddValue(
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
+ validators_.compressed_texture_format.AddValue(
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT);
+ }
+
+ if (enable_dxt3) {
+ // The difference between GL_EXT_texture_compression_s3tc and
+ // GL_CHROMIUM_texture_compression_dxt3 is that the former
+ // requires on the fly compression. The latter does not.
+ AddExtensionString("GL_CHROMIUM_texture_compression_dxt3");
+ validators_.compressed_texture_format.AddValue(
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
+ }
+
+ if (enable_dxt5) {
+ // The difference between GL_EXT_texture_compression_s3tc and
+ // GL_CHROMIUM_texture_compression_dxt5 is that the former
+ // requires on the fly compression. The latter does not.
+ AddExtensionString("GL_CHROMIUM_texture_compression_dxt5");
+ validators_.compressed_texture_format.AddValue(
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
+ }
+
+ // Check if we should enable GL_EXT_texture_filter_anisotropic.
+ if (extensions.Contains("GL_EXT_texture_filter_anisotropic")) {
+ AddExtensionString("GL_EXT_texture_filter_anisotropic");
+ validators_.texture_parameter.AddValue(
+ GL_TEXTURE_MAX_ANISOTROPY_EXT);
+ validators_.g_l_state.AddValue(
+ GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT);
+ }
+
+ // Check if we should support GL_OES_packed_depth_stencil and/or
+ // GL_GOOGLE_depth_texture / GL_CHROMIUM_depth_texture.
+ //
+ // NOTE: GL_OES_depth_texture requires support for depth cubemaps.
+ // GL_ARB_depth_texture requires other features that
+ // GL_OES_packed_depth_stencil does not provide.
+ //
+ // Therefore we made up GL_GOOGLE_depth_texture / GL_CHROMIUM_depth_texture.
+ //
+ // GL_GOOGLE_depth_texture is legacy. As we exposed it into NaCl we can't
+ // get rid of it.
+ //
+ bool enable_depth_texture = false;
+ if (!workarounds_.disable_depth_texture &&
+ (extensions.Contains("GL_ARB_depth_texture") ||
+ extensions.Contains("GL_OES_depth_texture") ||
+ extensions.Contains("GL_ANGLE_depth_texture"))) {
+ enable_depth_texture = true;
+ }
+
+ if (enable_depth_texture) {
+ AddExtensionString("GL_CHROMIUM_depth_texture");
+ AddExtensionString("GL_GOOGLE_depth_texture");
+ texture_format_validators_[GL_DEPTH_COMPONENT].AddValue(GL_UNSIGNED_SHORT);
+ texture_format_validators_[GL_DEPTH_COMPONENT].AddValue(GL_UNSIGNED_INT);
+ validators_.texture_internal_format.AddValue(GL_DEPTH_COMPONENT);
+ validators_.texture_format.AddValue(GL_DEPTH_COMPONENT);
+ validators_.pixel_type.AddValue(GL_UNSIGNED_SHORT);
+ validators_.pixel_type.AddValue(GL_UNSIGNED_INT);
+ }
+
+ if (extensions.Contains("GL_EXT_packed_depth_stencil") ||
+ extensions.Contains("GL_OES_packed_depth_stencil")) {
+ AddExtensionString("GL_OES_packed_depth_stencil");
+ if (enable_depth_texture) {
+ texture_format_validators_[GL_DEPTH_STENCIL].AddValue(
+ GL_UNSIGNED_INT_24_8);
+ validators_.texture_internal_format.AddValue(GL_DEPTH_STENCIL);
+ validators_.texture_format.AddValue(GL_DEPTH_STENCIL);
+ validators_.pixel_type.AddValue(GL_UNSIGNED_INT_24_8);
+ }
+ validators_.render_buffer_format.AddValue(GL_DEPTH24_STENCIL8);
+ }
+
+ if (extensions.Contains("GL_OES_vertex_array_object") ||
+ extensions.Contains("GL_ARB_vertex_array_object") ||
+ extensions.Contains("GL_APPLE_vertex_array_object")) {
+ feature_flags_.native_vertex_array_object = true;
+ }
+
+ // If we're using client_side_arrays we have to emulate
+ // vertex array objects since vertex array objects do not work
+ // with client side arrays.
+ if (workarounds_.use_client_side_arrays_for_stream_buffers) {
+ feature_flags_.native_vertex_array_object = false;
+ }
+
+ if (extensions.Contains("GL_OES_element_index_uint") ||
+ gfx::HasDesktopGLFeatures()) {
+ AddExtensionString("GL_OES_element_index_uint");
+ validators_.index_type.AddValue(GL_UNSIGNED_INT);
+ }
+
+ bool enable_texture_format_bgra8888 = false;
+ bool enable_read_format_bgra = false;
+ // Check if we should allow GL_EXT_texture_format_BGRA8888
+ if (extensions.Contains("GL_EXT_texture_format_BGRA8888") ||
+ extensions.Contains("GL_APPLE_texture_format_BGRA8888") ||
+ extensions.Contains("GL_EXT_bgra")) {
+ enable_texture_format_bgra8888 = true;
+ }
+
+ if (extensions.Contains("GL_EXT_bgra")) {
+ enable_texture_format_bgra8888 = true;
+ enable_read_format_bgra = true;
+ }
+
+ if (extensions.Contains("GL_EXT_read_format_bgra") ||
+ extensions.Contains("GL_EXT_bgra")) {
+ enable_read_format_bgra = true;
+ }
+
+ if (enable_texture_format_bgra8888) {
+ AddExtensionString("GL_EXT_texture_format_BGRA8888");
+ texture_format_validators_[GL_BGRA_EXT].AddValue(GL_UNSIGNED_BYTE);
+ validators_.texture_internal_format.AddValue(GL_BGRA_EXT);
+ validators_.texture_format.AddValue(GL_BGRA_EXT);
+ }
+
+ if (enable_read_format_bgra) {
+ AddExtensionString("GL_EXT_read_format_bgra");
+ validators_.read_pixel_format.AddValue(GL_BGRA_EXT);
+ }
+
+ if (extensions.Contains("GL_OES_rgb8_rgba8") || gfx::HasDesktopGLFeatures()) {
+ AddExtensionString("GL_OES_rgb8_rgba8");
+ validators_.render_buffer_format.AddValue(GL_RGB8_OES);
+ validators_.render_buffer_format.AddValue(GL_RGBA8_OES);
+ }
+
+ // Check if we should allow GL_OES_texture_npot
+ if (extensions.Contains("GL_ARB_texture_non_power_of_two") ||
+ extensions.Contains("GL_OES_texture_npot")) {
+ AddExtensionString("GL_OES_texture_npot");
+ npot_ok = true;
+ }
+
+ // Check if we should allow GL_OES_texture_float, GL_OES_texture_half_float,
+ // GL_OES_texture_float_linear, GL_OES_texture_half_float_linear
+ bool enable_texture_float = false;
+ bool enable_texture_float_linear = false;
+ bool enable_texture_half_float = false;
+ bool enable_texture_half_float_linear = false;
+
+ bool have_arb_texture_float = extensions.Contains("GL_ARB_texture_float");
+
+ if (have_arb_texture_float) {
+ enable_texture_float = true;
+ enable_texture_float_linear = true;
+ enable_texture_half_float = true;
+ enable_texture_half_float_linear = true;
+ } else {
+ if (extensions.Contains("GL_OES_texture_float") || have_arb_texture_float) {
+ enable_texture_float = true;
+ if (extensions.Contains("GL_OES_texture_float_linear") ||
+ have_arb_texture_float) {
+ enable_texture_float_linear = true;
+ }
+ }
+ if (extensions.Contains("GL_OES_texture_half_float") ||
+ have_arb_texture_float) {
+ enable_texture_half_float = true;
+ if (extensions.Contains("GL_OES_texture_half_float_linear") ||
+ have_arb_texture_float) {
+ enable_texture_half_float_linear = true;
+ }
+ }
+ }
+
+ if (enable_texture_float) {
+ texture_format_validators_[GL_ALPHA].AddValue(GL_FLOAT);
+ texture_format_validators_[GL_RGB].AddValue(GL_FLOAT);
+ texture_format_validators_[GL_RGBA].AddValue(GL_FLOAT);
+ texture_format_validators_[GL_LUMINANCE].AddValue(GL_FLOAT);
+ texture_format_validators_[GL_LUMINANCE_ALPHA].AddValue(GL_FLOAT);
+ validators_.pixel_type.AddValue(GL_FLOAT);
+ validators_.read_pixel_type.AddValue(GL_FLOAT);
+ AddExtensionString("GL_OES_texture_float");
+ if (enable_texture_float_linear) {
+ AddExtensionString("GL_OES_texture_float_linear");
+ }
+ }
+
+ if (enable_texture_half_float) {
+ texture_format_validators_[GL_ALPHA].AddValue(GL_HALF_FLOAT_OES);
+ texture_format_validators_[GL_RGB].AddValue(GL_HALF_FLOAT_OES);
+ texture_format_validators_[GL_RGBA].AddValue(GL_HALF_FLOAT_OES);
+ texture_format_validators_[GL_LUMINANCE].AddValue(GL_HALF_FLOAT_OES);
+ texture_format_validators_[GL_LUMINANCE_ALPHA].AddValue(GL_HALF_FLOAT_OES);
+ validators_.pixel_type.AddValue(GL_HALF_FLOAT_OES);
+ validators_.read_pixel_type.AddValue(GL_HALF_FLOAT_OES);
+ AddExtensionString("GL_OES_texture_half_float");
+ if (enable_texture_half_float_linear) {
+ AddExtensionString("GL_OES_texture_half_float_linear");
+ }
+ }
+
+ // Check for multisample support
+ if (!disallowed_features_.multisampling) {
+ bool ext_has_multisample =
+ extensions.Contains("GL_EXT_framebuffer_multisample");
+ if (!workarounds_.disable_angle_framebuffer_multisample) {
+ ext_has_multisample |=
+ extensions.Contains("GL_ANGLE_framebuffer_multisample");
+ }
+ if (ext_has_multisample) {
+ feature_flags_.chromium_framebuffer_multisample = true;
+ validators_.frame_buffer_target.AddValue(GL_READ_FRAMEBUFFER_EXT);
+ validators_.frame_buffer_target.AddValue(GL_DRAW_FRAMEBUFFER_EXT);
+ validators_.g_l_state.AddValue(GL_READ_FRAMEBUFFER_BINDING_EXT);
+ validators_.g_l_state.AddValue(GL_MAX_SAMPLES_EXT);
+ validators_.render_buffer_parameter.AddValue(GL_RENDERBUFFER_SAMPLES_EXT);
+ AddExtensionString("GL_CHROMIUM_framebuffer_multisample");
+ } else {
+ if (extensions.Contains("GL_EXT_multisampled_render_to_texture")) {
+ feature_flags_.multisampled_render_to_texture = true;
+ } else if (extensions.Contains("GL_IMG_multisampled_render_to_texture")) {
+ feature_flags_.multisampled_render_to_texture = true;
+ feature_flags_.use_img_for_multisampled_render_to_texture = true;
+ }
+ if (feature_flags_.multisampled_render_to_texture) {
+ validators_.render_buffer_parameter.AddValue(
+ GL_RENDERBUFFER_SAMPLES_EXT);
+ validators_.g_l_state.AddValue(GL_MAX_SAMPLES_EXT);
+ validators_.frame_buffer_parameter.AddValue(
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT);
+ AddExtensionString("GL_EXT_multisampled_render_to_texture");
+ }
+ }
+ }
+
+ if (extensions.Contains("GL_OES_depth24") || gfx::HasDesktopGLFeatures()) {
+ AddExtensionString("GL_OES_depth24");
+ validators_.render_buffer_format.AddValue(GL_DEPTH_COMPONENT24);
+ }
+
+ if (!workarounds_.disable_oes_standard_derivatives &&
+ (extensions.Contains("GL_OES_standard_derivatives") ||
+ gfx::HasDesktopGLFeatures())) {
+ AddExtensionString("GL_OES_standard_derivatives");
+ feature_flags_.oes_standard_derivatives = true;
+ validators_.hint_target.AddValue(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
+ validators_.g_l_state.AddValue(GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES);
+ }
+
+ if (extensions.Contains("GL_OES_EGL_image_external")) {
+ AddExtensionString("GL_OES_EGL_image_external");
+ feature_flags_.oes_egl_image_external = true;
+ validators_.texture_bind_target.AddValue(GL_TEXTURE_EXTERNAL_OES);
+ validators_.get_tex_param_target.AddValue(GL_TEXTURE_EXTERNAL_OES);
+ validators_.texture_parameter.AddValue(GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES);
+ validators_.g_l_state.AddValue(GL_TEXTURE_BINDING_EXTERNAL_OES);
+ }
+
+ if (extensions.Contains("GL_OES_compressed_ETC1_RGB8_texture")) {
+ AddExtensionString("GL_OES_compressed_ETC1_RGB8_texture");
+ validators_.compressed_texture_format.AddValue(GL_ETC1_RGB8_OES);
+ }
+
+ // Ideally we would only expose this extension on Mac OS X, to
+ // support GL_CHROMIUM_iosurface and the compositor. We don't want
+ // applications to start using it; they should use ordinary non-
+ // power-of-two textures. However, for unit testing purposes we
+ // expose it on all supported platforms.
+ if (extensions.Contains("GL_ARB_texture_rectangle")) {
+ AddExtensionString("GL_ARB_texture_rectangle");
+ feature_flags_.arb_texture_rectangle = true;
+ validators_.texture_bind_target.AddValue(GL_TEXTURE_RECTANGLE_ARB);
+ // For the moment we don't add this enum to the texture_target
+ // validator. This implies that the only way to get image data into a
+ // rectangular texture is via glTexImageIOSurface2DCHROMIUM, which is
+ // just fine since again we don't want applications depending on this
+ // extension.
+ validators_.get_tex_param_target.AddValue(GL_TEXTURE_RECTANGLE_ARB);
+ validators_.g_l_state.AddValue(GL_TEXTURE_BINDING_RECTANGLE_ARB);
+ }
+
+#if defined(OS_MACOSX)
+ if (IOSurfaceSupport::Initialize()) {
+ AddExtensionString("GL_CHROMIUM_iosurface");
+ }
+#endif
+
+ // TODO(gman): Add support for these extensions.
+ // GL_OES_depth32
+
+ feature_flags_.enable_texture_float_linear |= enable_texture_float_linear;
+ feature_flags_.enable_texture_half_float_linear |=
+ enable_texture_half_float_linear;
+ feature_flags_.npot_ok |= npot_ok;
+
+ if (extensions.Contains("GL_ANGLE_pack_reverse_row_order")) {
+ AddExtensionString("GL_ANGLE_pack_reverse_row_order");
+ feature_flags_.angle_pack_reverse_row_order = true;
+ validators_.pixel_store.AddValue(GL_PACK_REVERSE_ROW_ORDER_ANGLE);
+ validators_.g_l_state.AddValue(GL_PACK_REVERSE_ROW_ORDER_ANGLE);
+ }
+
+ if (extensions.Contains("GL_ANGLE_texture_usage")) {
+ AddExtensionString("GL_ANGLE_texture_usage");
+ validators_.texture_parameter.AddValue(GL_TEXTURE_USAGE_ANGLE);
+ }
+
+ if (extensions.Contains("GL_EXT_texture_storage")) {
+ AddExtensionString("GL_EXT_texture_storage");
+ validators_.texture_parameter.AddValue(GL_TEXTURE_IMMUTABLE_FORMAT_EXT);
+ if (enable_texture_format_bgra8888)
+ validators_.texture_internal_format_storage.AddValue(GL_BGRA8_EXT);
+ if (enable_texture_float) {
+ validators_.texture_internal_format_storage.AddValue(GL_RGBA32F_EXT);
+ validators_.texture_internal_format_storage.AddValue(GL_RGB32F_EXT);
+ validators_.texture_internal_format_storage.AddValue(GL_ALPHA32F_EXT);
+ validators_.texture_internal_format_storage.AddValue(
+ GL_LUMINANCE32F_EXT);
+ validators_.texture_internal_format_storage.AddValue(
+ GL_LUMINANCE_ALPHA32F_EXT);
+ }
+ if (enable_texture_half_float) {
+ validators_.texture_internal_format_storage.AddValue(GL_RGBA16F_EXT);
+ validators_.texture_internal_format_storage.AddValue(GL_RGB16F_EXT);
+ validators_.texture_internal_format_storage.AddValue(GL_ALPHA16F_EXT);
+ validators_.texture_internal_format_storage.AddValue(
+ GL_LUMINANCE16F_EXT);
+ validators_.texture_internal_format_storage.AddValue(
+ GL_LUMINANCE_ALPHA16F_EXT);
+ }
+ }
+
+ bool have_ext_occlusion_query_boolean =
+ extensions.Contains("GL_EXT_occlusion_query_boolean");
+ bool have_arb_occlusion_query2 =
+ extensions.Contains("GL_ARB_occlusion_query2");
+ bool have_arb_occlusion_query =
+ extensions.Contains("GL_ARB_occlusion_query");
+
+ if (!workarounds_.disable_ext_occlusion_query &&
+ (have_ext_occlusion_query_boolean ||
+ have_arb_occlusion_query2 ||
+ have_arb_occlusion_query)) {
+ AddExtensionString("GL_EXT_occlusion_query_boolean");
+ feature_flags_.occlusion_query_boolean = true;
+ feature_flags_.use_arb_occlusion_query2_for_occlusion_query_boolean =
+ !have_ext_occlusion_query_boolean && have_arb_occlusion_query2;
+ feature_flags_.use_arb_occlusion_query_for_occlusion_query_boolean =
+ !have_ext_occlusion_query_boolean && have_arb_occlusion_query &&
+ !have_arb_occlusion_query2;
+ }
+
+ if (extensions.Contains("GL_ANGLE_instanced_arrays") ||
+ (extensions.Contains("GL_ARB_instanced_arrays") &&
+ extensions.Contains("GL_ARB_draw_instanced"))) {
+ AddExtensionString("GL_ANGLE_instanced_arrays");
+ feature_flags_.angle_instanced_arrays = true;
+ validators_.vertex_attribute.AddValue(GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
+ }
+
+ if (!workarounds_.disable_ext_draw_buffers &&
+ (extensions.Contains("GL_ARB_draw_buffers") ||
+ extensions.Contains("GL_EXT_draw_buffers"))) {
+ AddExtensionString("GL_EXT_draw_buffers");
+ feature_flags_.ext_draw_buffers = true;
+
+ GLint max_color_attachments = 0;
+ glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &max_color_attachments);
+ for (GLenum i = GL_COLOR_ATTACHMENT1_EXT;
+ i < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + max_color_attachments);
+ ++i) {
+ validators_.attachment.AddValue(i);
+ }
+
+ validators_.g_l_state.AddValue(GL_MAX_COLOR_ATTACHMENTS_EXT);
+ validators_.g_l_state.AddValue(GL_MAX_DRAW_BUFFERS_ARB);
+ GLint max_draw_buffers = 0;
+ glGetIntegerv(GL_MAX_DRAW_BUFFERS_ARB, &max_draw_buffers);
+ for (GLenum i = GL_DRAW_BUFFER0_ARB;
+ i < static_cast<GLenum>(GL_DRAW_BUFFER0_ARB + max_draw_buffers);
+ ++i) {
+ validators_.g_l_state.AddValue(i);
+ }
+ }
+
+ if (extensions.Contains("GL_EXT_frag_depth") || gfx::HasDesktopGLFeatures()) {
+ AddExtensionString("GL_EXT_frag_depth");
+ feature_flags_.ext_frag_depth = true;
+ }
+
+ bool ui_gl_fence_works =
+ extensions.Contains("GL_NV_fence") ||
+ extensions.Contains("GL_ARB_sync");
+
+ if (ui_gl_fence_works &&
+ extensions.Contains("GL_ARB_pixel_buffer_object") &&
+ !workarounds_.disable_async_readpixels) {
+ feature_flags_.use_async_readpixels = true;
+ }
+
+ if (!disallowed_features_.swap_buffer_complete_callback)
+ AddExtensionString("GL_CHROMIUM_swapbuffers_complete_callback");
+
+ bool is_es3 = false;
+ const char* str = reinterpret_cast<const char*>(glGetString(GL_VERSION));
+ if (str) {
+ std::string lstr(StringToLowerASCII(std::string(str)));
+ is_es3 = (lstr.substr(0, 12) == "opengl es 3.");
+ }
+
+ if (is_es3 || extensions.Contains("GL_ARB_sampler_objects")) {
+ feature_flags_.enable_samplers = true;
+ // TODO(dsinclair): Add AddExtensionString("GL_CHROMIUM_sampler_objects")
+ // when available.
+ }
+}
+
+void FeatureInfo::AddExtensionString(const std::string& str) {
+ if (extensions_.find(str) == std::string::npos) {
+ extensions_ += (extensions_.empty() ? "" : " ") + str;
+ }
+}
+
+FeatureInfo::~FeatureInfo() {
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/feature_info.h b/chromium/gpu/command_buffer/service/feature_info.h
new file mode 100644
index 00000000000..a9ccf64c009
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/feature_info.h
@@ -0,0 +1,128 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_FEATURE_INFO_H_
+#define GPU_COMMAND_BUFFER_SERVICE_FEATURE_INFO_H_
+
+#include <set>
+#include <string>
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/sys_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gles2_cmd_validation.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "gpu/gpu_export.h"
+
+class CommandLine;
+
+namespace gpu {
+namespace gles2 {
+
+// FeatureInfo records the features that are available for a ContextGroup.
+class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> {
+ public:
+ struct FeatureFlags {
+ FeatureFlags();
+
+ bool chromium_framebuffer_multisample;
+ bool multisampled_render_to_texture;
+ // Use the IMG GLenum values and functions rather than EXT.
+ bool use_img_for_multisampled_render_to_texture;
+ bool oes_standard_derivatives;
+ bool oes_egl_image_external;
+ bool npot_ok;
+ bool enable_texture_float_linear;
+ bool enable_texture_half_float_linear;
+ bool chromium_stream_texture;
+ bool angle_translated_shader_source;
+ bool angle_pack_reverse_row_order;
+ bool arb_texture_rectangle;
+ bool angle_instanced_arrays;
+ bool occlusion_query_boolean;
+ bool use_arb_occlusion_query2_for_occlusion_query_boolean;
+ bool use_arb_occlusion_query_for_occlusion_query_boolean;
+ bool native_vertex_array_object;
+ bool enable_shader_name_hashing;
+ bool enable_samplers;
+ bool ext_draw_buffers;
+ bool ext_frag_depth;
+ bool use_async_readpixels;
+ };
+
+ struct Workarounds {
+ Workarounds();
+
+#define GPU_OP(type, name) bool name;
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+
+ // Note: 0 here means use driver limit.
+ GLint max_texture_size;
+ GLint max_cube_map_texture_size;
+ };
+
+ FeatureInfo();
+
+ // If allowed features = NULL or "*", all features are allowed. Otherwise
+ // only features that match the strings in allowed_features are allowed.
+ bool Initialize(const char* allowed_features);
+ bool Initialize(const DisallowedFeatures& disallowed_features,
+ const char* allowed_features);
+
+ // Turns on certain features if they can be turned on.
+ void AddFeatures(const CommandLine& command_line);
+
+ const Validators* validators() const {
+ return &validators_;
+ }
+
+ const ValueValidator<GLenum>& GetTextureFormatValidator(GLenum format) {
+ return texture_format_validators_[format];
+ }
+
+ const std::string& extensions() const {
+ return extensions_;
+ }
+
+ const FeatureFlags& feature_flags() const {
+ return feature_flags_;
+ }
+
+ const Workarounds& workarounds() const {
+ return workarounds_;
+ }
+
+ private:
+ friend class base::RefCounted<FeatureInfo>;
+ friend class BufferManagerClientSideArraysTest;
+ friend class GLES2DecoderTestBase;
+
+ typedef base::hash_map<GLenum, ValueValidator<GLenum> > ValidatorMap;
+ ValidatorMap texture_format_validators_;
+
+ ~FeatureInfo();
+
+ void AddExtensionString(const std::string& str);
+
+ Validators validators_;
+
+ DisallowedFeatures disallowed_features_;
+
+ // The extensions string returned by glGetString(GL_EXTENSIONS);
+ std::string extensions_;
+
+ // Flags for some features
+ FeatureFlags feature_flags_;
+
+ // Flags for Workarounds.
+ Workarounds workarounds_;
+
+ DISALLOW_COPY_AND_ASSIGN(FeatureInfo);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_FEATURE_INFO_H_
diff --git a/chromium/gpu/command_buffer/service/feature_info_unittest.cc b/chromium/gpu/command_buffer/service/feature_info_unittest.cc
new file mode 100644
index 00000000000..0dc1685e08d
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/feature_info_unittest.cc
@@ -0,0 +1,908 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/feature_info.h"
+
+#include "base/command_line.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::HasSubstr;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Not;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+class FeatureInfoTest : public testing::Test {
+ public:
+ FeatureInfoTest() {
+ }
+
+ void SetupInitExpectations(const char* extensions) {
+ SetupInitExpectationsWithGLVersion(extensions, "");
+ }
+
+ void SetupInitExpectationsWithGLVersion(
+ const char* extensions, const char* version) {
+ TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(
+ gl_.get(), extensions, version);
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ info_ = new FeatureInfo();
+ }
+
+ virtual void TearDown() {
+ info_ = NULL;
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_refptr<FeatureInfo> info_;
+};
+
+namespace {
+
+struct FormatInfo {
+ GLenum format;
+ const GLenum* types;
+ size_t count;
+};
+
+} // anonymous namespace.
+
+TEST_F(FeatureInfoTest, Basic) {
+ // Test it starts off uninitialized.
+ EXPECT_FALSE(info_->feature_flags().chromium_framebuffer_multisample);
+ EXPECT_FALSE(info_->feature_flags().multisampled_render_to_texture);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_img_for_multisampled_render_to_texture);
+ EXPECT_FALSE(info_->feature_flags().oes_standard_derivatives);
+ EXPECT_FALSE(info_->feature_flags().npot_ok);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_half_float_linear);
+ EXPECT_FALSE(info_->feature_flags().oes_egl_image_external);
+ EXPECT_FALSE(info_->feature_flags().chromium_stream_texture);
+ EXPECT_FALSE(info_->feature_flags().angle_translated_shader_source);
+ EXPECT_FALSE(info_->feature_flags().angle_pack_reverse_row_order);
+ EXPECT_FALSE(info_->feature_flags().arb_texture_rectangle);
+ EXPECT_FALSE(info_->feature_flags().angle_instanced_arrays);
+ EXPECT_FALSE(info_->feature_flags().occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_arb_occlusion_query2_for_occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_arb_occlusion_query_for_occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags().native_vertex_array_object);
+
+#define GPU_OP(type, name) EXPECT_FALSE(info_->workarounds().name);
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+ EXPECT_EQ(0, info_->workarounds().max_texture_size);
+ EXPECT_EQ(0, info_->workarounds().max_cube_map_texture_size);
+
+ // Test good types.
+ {
+ static const GLenum kAlphaTypes[] = {
+ GL_UNSIGNED_BYTE,
+ };
+ static const GLenum kRGBTypes[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_5_6_5,
+ };
+ static const GLenum kRGBATypes[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_4_4_4_4,
+ GL_UNSIGNED_SHORT_5_5_5_1,
+ };
+ static const GLenum kLuminanceTypes[] = {
+ GL_UNSIGNED_BYTE,
+ };
+ static const GLenum kLuminanceAlphaTypes[] = {
+ GL_UNSIGNED_BYTE,
+ };
+ static const FormatInfo kFormatTypes[] = {
+ { GL_ALPHA, kAlphaTypes, arraysize(kAlphaTypes), },
+ { GL_RGB, kRGBTypes, arraysize(kRGBTypes), },
+ { GL_RGBA, kRGBATypes, arraysize(kRGBATypes), },
+ { GL_LUMINANCE, kLuminanceTypes, arraysize(kLuminanceTypes), },
+ { GL_LUMINANCE_ALPHA, kLuminanceAlphaTypes,
+ arraysize(kLuminanceAlphaTypes), } ,
+ };
+ for (size_t ii = 0; ii < arraysize(kFormatTypes); ++ii) {
+ const FormatInfo& info = kFormatTypes[ii];
+ const ValueValidator<GLenum>& validator =
+ info_->GetTextureFormatValidator(info.format);
+ for (size_t jj = 0; jj < info.count; ++jj) {
+ EXPECT_TRUE(validator.IsValid(info.types[jj]));
+ }
+ }
+ }
+
+ // Test some bad types
+ {
+ static const GLenum kAlphaTypes[] = {
+ GL_UNSIGNED_SHORT_5_5_5_1,
+ GL_FLOAT,
+ };
+ static const GLenum kRGBTypes[] = {
+ GL_UNSIGNED_SHORT_4_4_4_4,
+ GL_FLOAT,
+ };
+ static const GLenum kRGBATypes[] = {
+ GL_UNSIGNED_SHORT_5_6_5,
+ GL_FLOAT,
+ };
+ static const GLenum kLuminanceTypes[] = {
+ GL_UNSIGNED_SHORT_4_4_4_4,
+ GL_FLOAT,
+ };
+ static const GLenum kLuminanceAlphaTypes[] = {
+ GL_UNSIGNED_SHORT_5_5_5_1,
+ GL_FLOAT,
+ };
+ static const GLenum kBGRATypes[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_5_6_5,
+ GL_FLOAT,
+ };
+ static const GLenum kDepthTypes[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT,
+ GL_UNSIGNED_INT,
+ GL_FLOAT,
+ };
+ static const FormatInfo kFormatTypes[] = {
+ { GL_ALPHA, kAlphaTypes, arraysize(kAlphaTypes), },
+ { GL_RGB, kRGBTypes, arraysize(kRGBTypes), },
+ { GL_RGBA, kRGBATypes, arraysize(kRGBATypes), },
+ { GL_LUMINANCE, kLuminanceTypes, arraysize(kLuminanceTypes), },
+ { GL_LUMINANCE_ALPHA, kLuminanceAlphaTypes,
+ arraysize(kLuminanceAlphaTypes), } ,
+ { GL_BGRA_EXT, kBGRATypes, arraysize(kBGRATypes), },
+ { GL_DEPTH_COMPONENT, kDepthTypes, arraysize(kDepthTypes), },
+ };
+ for (size_t ii = 0; ii < arraysize(kFormatTypes); ++ii) {
+ const FormatInfo& info = kFormatTypes[ii];
+ const ValueValidator<GLenum>& validator =
+ info_->GetTextureFormatValidator(info.format);
+ for (size_t jj = 0; jj < info.count; ++jj) {
+ EXPECT_FALSE(validator.IsValid(info.types[jj]));
+ }
+ }
+ }
+}
+
+TEST_F(FeatureInfoTest, InitializeNoExtensions) {
+ SetupInitExpectations("");
+ info_->Initialize(NULL);
+ // Check default extensions are there
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_CHROMIUM_resource_safe"));
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_CHROMIUM_strict_attribs"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_ANGLE_translated_shader_source"));
+
+ // Check a couple of random extensions that should not be there.
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_npot")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_EXT_texture_compression_dxt1")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_CHROMIUM_texture_compression_dxt3")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_CHROMIUM_texture_compression_dxt5")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_ANGLE_texture_usage")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_EXT_texture_storage")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_compressed_ETC1_RGB8_texture")));
+ EXPECT_FALSE(info_->feature_flags().npot_ok);
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT));
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT));
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT));
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT));
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_ETC1_RGB8_OES));
+ EXPECT_FALSE(info_->validators()->read_pixel_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_FALSE(info_->validators()->texture_parameter.IsValid(
+ GL_TEXTURE_MAX_ANISOTROPY_EXT));
+ EXPECT_FALSE(info_->validators()->g_l_state.IsValid(
+ GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT));
+ EXPECT_FALSE(info_->validators()->frame_buffer_target.IsValid(
+ GL_READ_FRAMEBUFFER_EXT));
+ EXPECT_FALSE(info_->validators()->frame_buffer_target.IsValid(
+ GL_DRAW_FRAMEBUFFER_EXT));
+ EXPECT_FALSE(info_->validators()->g_l_state.IsValid(
+ GL_READ_FRAMEBUFFER_BINDING_EXT));
+ EXPECT_FALSE(info_->validators()->render_buffer_parameter.IsValid(
+ GL_MAX_SAMPLES_EXT));
+ EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_SHORT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_INT));
+ EXPECT_FALSE(info_->validators()->render_buffer_format.IsValid(
+ GL_DEPTH24_STENCIL8));
+ EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_STENCIL));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(
+ GL_DEPTH_STENCIL));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(
+ GL_UNSIGNED_INT_24_8));
+ EXPECT_FALSE(info_->validators()->render_buffer_format.IsValid(
+ GL_DEPTH_COMPONENT24));
+ EXPECT_FALSE(info_->validators()->texture_parameter.IsValid(
+ GL_TEXTURE_USAGE_ANGLE));
+ EXPECT_FALSE(info_->validators()->texture_internal_format_storage.IsValid(
+ GL_DEPTH_COMPONENT16));
+ EXPECT_FALSE(info_->validators()->texture_internal_format_storage.IsValid(
+ GL_DEPTH_COMPONENT32_OES));
+ EXPECT_FALSE(info_->validators()->texture_internal_format_storage.IsValid(
+ GL_DEPTH24_STENCIL8_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeNPOTExtensionGLES) {
+ SetupInitExpectations("GL_OES_texture_npot");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_npot"));
+ EXPECT_TRUE(info_->feature_flags().npot_ok);
+}
+
+TEST_F(FeatureInfoTest, InitializeNPOTExtensionGL) {
+ SetupInitExpectations("GL_ARB_texture_non_power_of_two");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_npot"));
+ EXPECT_TRUE(info_->feature_flags().npot_ok);
+}
+
+TEST_F(FeatureInfoTest, InitializeDXTExtensionGLES2) {
+ SetupInitExpectations("GL_EXT_texture_compression_dxt1");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_texture_compression_dxt1"));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT));
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT));
+ EXPECT_FALSE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeDXTExtensionGL) {
+ SetupInitExpectations("GL_EXT_texture_compression_s3tc");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_texture_compression_dxt1"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_texture_compression_dxt3"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_texture_compression_dxt5"));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_texture_format_BGRA8888GLES2) {
+ SetupInitExpectations("GL_EXT_texture_format_BGRA8888");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_texture_format_BGRA8888"));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_BGRA_EXT).IsValid(
+ GL_UNSIGNED_BYTE));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_texture_format_BGRA8888GL) {
+ SetupInitExpectations("GL_EXT_bgra");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_texture_format_BGRA8888"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_read_format_bgra"));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->validators()->read_pixel_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_BGRA_EXT).IsValid(
+ GL_UNSIGNED_BYTE));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_texture_format_BGRA8888Apple) {
+ SetupInitExpectations("GL_APPLE_texture_format_BGRA8888");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_texture_format_BGRA8888"));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_BGRA_EXT).IsValid(
+ GL_UNSIGNED_BYTE));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_read_format_bgra) {
+ SetupInitExpectations("GL_EXT_read_format_bgra");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_read_format_bgra"));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+ GL_BGRA_EXT));
+ EXPECT_TRUE(info_->validators()->read_pixel_format.IsValid(
+ GL_BGRA_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_texture_floatGLES2) {
+ SetupInitExpectations("GL_OES_texture_float");
+ info_->Initialize(NULL);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_half_float_linear);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_float"));
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_half_float")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_float_linear")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_half_float_linear")));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_FLOAT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_texture_float_linearGLES2) {
+ SetupInitExpectations("GL_OES_texture_float GL_OES_texture_float_linear");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags().enable_texture_float_linear);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_half_float_linear);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_float"));
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_half_float")));
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_float_linear"));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_half_float_linear")));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_FLOAT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_texture_half_floatGLES2) {
+ SetupInitExpectations("GL_OES_texture_half_float");
+ info_->Initialize(NULL);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_half_float_linear);
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_float")));
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_half_float"));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_float_linear")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_half_float_linear")));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_FLOAT));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_texture_half_float_linearGLES2) {
+ SetupInitExpectations(
+ "GL_OES_texture_half_float GL_OES_texture_half_float_linear");
+ info_->Initialize(NULL);
+ EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear);
+ EXPECT_TRUE(info_->feature_flags().enable_texture_half_float_linear);
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_float")));
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_texture_half_float"));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_float_linear")));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_texture_half_float_linear"));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_FLOAT));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_HALF_FLOAT_OES));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_HALF_FLOAT_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_HALF_FLOAT_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_framebuffer_multisample) {
+ SetupInitExpectations("GL_EXT_framebuffer_multisample");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags().chromium_framebuffer_multisample);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_framebuffer_multisample"));
+ EXPECT_TRUE(info_->validators()->frame_buffer_target.IsValid(
+ GL_READ_FRAMEBUFFER_EXT));
+ EXPECT_TRUE(info_->validators()->frame_buffer_target.IsValid(
+ GL_DRAW_FRAMEBUFFER_EXT));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_READ_FRAMEBUFFER_BINDING_EXT));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_MAX_SAMPLES_EXT));
+ EXPECT_TRUE(info_->validators()->render_buffer_parameter.IsValid(
+ GL_RENDERBUFFER_SAMPLES_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_multisampled_render_to_texture) {
+ SetupInitExpectations("GL_EXT_multisampled_render_to_texture");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags(
+ ).multisampled_render_to_texture);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_img_for_multisampled_render_to_texture);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_multisampled_render_to_texture"));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_MAX_SAMPLES_EXT));
+ EXPECT_TRUE(info_->validators()->render_buffer_parameter.IsValid(
+ GL_RENDERBUFFER_SAMPLES_EXT));
+ EXPECT_TRUE(info_->validators()->frame_buffer_parameter.IsValid(
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeIMG_multisampled_render_to_texture) {
+ SetupInitExpectations("GL_IMG_multisampled_render_to_texture");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags(
+ ).use_img_for_multisampled_render_to_texture);
+ EXPECT_TRUE(info_->feature_flags(
+ ).use_img_for_multisampled_render_to_texture);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_multisampled_render_to_texture"));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_MAX_SAMPLES_EXT));
+ EXPECT_TRUE(info_->validators()->render_buffer_parameter.IsValid(
+ GL_RENDERBUFFER_SAMPLES_EXT));
+ EXPECT_TRUE(info_->validators()->frame_buffer_parameter.IsValid(
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_texture_filter_anisotropic) {
+ SetupInitExpectations("GL_EXT_texture_filter_anisotropic");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_texture_filter_anisotropic"));
+ EXPECT_TRUE(info_->validators()->texture_parameter.IsValid(
+ GL_TEXTURE_MAX_ANISOTROPY_EXT));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_ARB_depth_texture) {
+ SetupInitExpectations("GL_ARB_depth_texture");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_GOOGLE_depth_texture"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_depth_texture"));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_COMPONENT));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_DEPTH_STENCIL));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_INT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_INT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_DEPTH_STENCIL).IsValid(
+ GL_UNSIGNED_INT_24_8));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_ARB_depth_texture) {
+ SetupInitExpectations("GL_OES_depth_texture");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_GOOGLE_depth_texture"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_depth_texture"));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_COMPONENT));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_DEPTH_STENCIL));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_INT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_INT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_DEPTH_STENCIL).IsValid(
+ GL_UNSIGNED_INT_24_8));
+}
+
+TEST_F(FeatureInfoTest, InitializeANGLE_depth_texture) {
+ SetupInitExpectations("GL_ANGLE_depth_texture");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_GOOGLE_depth_texture"));
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_depth_texture"));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_ANGLE_depth_texture")));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_COMPONENT));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_DEPTH_STENCIL));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_INT));
+ EXPECT_FALSE(info_->validators()->texture_internal_format_storage.IsValid(
+ GL_DEPTH_COMPONENT16));
+ EXPECT_FALSE(info_->validators()->texture_internal_format_storage.IsValid(
+ GL_DEPTH_COMPONENT32_OES));
+ EXPECT_FALSE(info_->validators()->texture_internal_format_storage.IsValid(
+ GL_DEPTH24_STENCIL8_OES));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_INT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_DEPTH_STENCIL).IsValid(
+ GL_UNSIGNED_INT_24_8));
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_packed_depth_stencil) {
+ SetupInitExpectations("GL_EXT_packed_depth_stencil");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_packed_depth_stencil"));
+ EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+ GL_DEPTH24_STENCIL8));
+ EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_SHORT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_INT));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_packed_depth_stencil) {
+ SetupInitExpectations("GL_OES_packed_depth_stencil");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_packed_depth_stencil"));
+ EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+ GL_DEPTH24_STENCIL8));
+ EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->texture_format.IsValid(GL_DEPTH_COMPONENT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_SHORT));
+ EXPECT_FALSE(info_->validators()->pixel_type.IsValid(GL_UNSIGNED_INT));
+}
+
+TEST_F(FeatureInfoTest,
+ InitializeOES_packed_depth_stencil_and_GL_ARB_depth_texture) {
+ SetupInitExpectations("GL_OES_packed_depth_stencil GL_ARB_depth_texture");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_packed_depth_stencil"));
+ EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+ GL_DEPTH24_STENCIL8));
+ EXPECT_TRUE(info_->validators()->texture_internal_format.IsValid(
+ GL_DEPTH_STENCIL));
+ EXPECT_TRUE(info_->validators()->texture_format.IsValid(
+ GL_DEPTH_STENCIL));
+ EXPECT_TRUE(info_->validators()->pixel_type.IsValid(
+ GL_UNSIGNED_INT_24_8));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_SHORT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_COMPONENT).IsValid(
+ GL_UNSIGNED_INT));
+ EXPECT_TRUE(info_->GetTextureFormatValidator(GL_DEPTH_STENCIL).IsValid(
+ GL_UNSIGNED_INT_24_8));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_depth24) {
+ SetupInitExpectations("GL_OES_depth24");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_depth24"));
+ EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+ GL_DEPTH_COMPONENT24));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_standard_derivatives) {
+ SetupInitExpectations("GL_OES_standard_derivatives");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_OES_standard_derivatives"));
+ EXPECT_TRUE(info_->feature_flags().oes_standard_derivatives);
+ EXPECT_TRUE(info_->validators()->hint_target.IsValid(
+ GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_rgb8_rgba8) {
+ SetupInitExpectations("GL_OES_rgb8_rgba8");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_rgb8_rgba8"));
+ EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+ GL_RGB8_OES));
+ EXPECT_TRUE(info_->validators()->render_buffer_format.IsValid(
+ GL_RGBA8_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_EGL_image_external) {
+ SetupInitExpectations("GL_OES_EGL_image_external");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_EGL_image_external"));
+ EXPECT_TRUE(info_->feature_flags().oes_egl_image_external);
+ EXPECT_TRUE(info_->validators()->texture_bind_target.IsValid(
+ GL_TEXTURE_EXTERNAL_OES));
+ EXPECT_TRUE(info_->validators()->get_tex_param_target.IsValid(
+ GL_TEXTURE_EXTERNAL_OES));
+ EXPECT_TRUE(info_->validators()->texture_parameter.IsValid(
+ GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES));
+ EXPECT_TRUE(info_->validators()->g_l_state.IsValid(
+ GL_TEXTURE_BINDING_EXTERNAL_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_compressed_ETC1_RGB8_texture) {
+ SetupInitExpectations("GL_OES_compressed_ETC1_RGB8_texture");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_compressed_ETC1_RGB8_texture"));
+ EXPECT_TRUE(info_->validators()->compressed_texture_format.IsValid(
+ GL_ETC1_RGB8_OES));
+ EXPECT_FALSE(info_->validators()->texture_internal_format.IsValid(
+ GL_ETC1_RGB8_OES));
+}
+
+TEST_F(FeatureInfoTest, InitializeCHROMIUM_stream_texture) {
+ SetupInitExpectations("GL_CHROMIUM_stream_texture");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_CHROMIUM_stream_texture"));
+ EXPECT_TRUE(info_->feature_flags().chromium_stream_texture);
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_occlusion_query_boolean) {
+ SetupInitExpectations("GL_EXT_occlusion_query_boolean");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_occlusion_query_boolean"));
+ EXPECT_TRUE(info_->feature_flags().occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_arb_occlusion_query2_for_occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_arb_occlusion_query_for_occlusion_query_boolean);
+}
+
+TEST_F(FeatureInfoTest, InitializeARB_occlusion_query) {
+ SetupInitExpectations("GL_ARB_occlusion_query");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_occlusion_query_boolean"));
+ EXPECT_TRUE(info_->feature_flags().occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_arb_occlusion_query2_for_occlusion_query_boolean);
+ EXPECT_TRUE(info_->feature_flags(
+ ).use_arb_occlusion_query_for_occlusion_query_boolean);
+}
+
+TEST_F(FeatureInfoTest, InitializeARB_occlusion_query2) {
+ SetupInitExpectations("GL_ARB_occlusion_query2 GL_ARB_occlusion_query2");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_EXT_occlusion_query_boolean"));
+ EXPECT_TRUE(info_->feature_flags().occlusion_query_boolean);
+ EXPECT_TRUE(info_->feature_flags(
+ ).use_arb_occlusion_query2_for_occlusion_query_boolean);
+ EXPECT_FALSE(info_->feature_flags(
+ ).use_arb_occlusion_query_for_occlusion_query_boolean);
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_vertex_array_object) {
+ SetupInitExpectations("GL_OES_vertex_array_object");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_vertex_array_object"));
+ EXPECT_TRUE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeARB_vertex_array_object) {
+ SetupInitExpectations("GL_ARB_vertex_array_object");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_vertex_array_object"));
+ EXPECT_TRUE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeAPPLE_vertex_array_object) {
+ SetupInitExpectations("GL_APPLE_vertex_array_object");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_vertex_array_object"));
+ EXPECT_TRUE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeNo_vertex_array_object) {
+ SetupInitExpectations("");
+ info_->Initialize(NULL);
+ // Even if the native extensions are not available the implementation
+ // may still emulate the GL_OES_vertex_array_object functionality. In this
+ // scenario native_vertex_array_object must be false.
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_vertex_array_object"));
+ EXPECT_FALSE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeOES_element_index_uint) {
+ SetupInitExpectations("GL_OES_element_index_uint");
+ info_->Initialize(NULL);
+ EXPECT_THAT(info_->extensions(),
+ HasSubstr("GL_OES_element_index_uint"));
+ EXPECT_TRUE(info_->validators()->index_type.IsValid(GL_UNSIGNED_INT));
+}
+
+TEST_F(FeatureInfoTest, InitializeVAOsWithClientSideArrays) {
+ SetupInitExpectations("GL_OES_vertex_array_object");
+ CommandLine command_line(0, NULL);
+ command_line.AppendSwitchASCII(
+ switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS));
+ info_->AddFeatures(command_line);
+ EXPECT_TRUE(info_->workarounds().use_client_side_arrays_for_stream_buffers);
+ EXPECT_FALSE(info_->feature_flags().native_vertex_array_object);
+}
+
+TEST_F(FeatureInfoTest, InitializeEXT_frag_depth) {
+ SetupInitExpectations("GL_EXT_frag_depth");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags().ext_frag_depth);
+ EXPECT_THAT(info_->extensions(), HasSubstr("GL_EXT_frag_depth"));
+}
+
+TEST_F(FeatureInfoTest, InitializeSamplersWithARBSamplerObjects) {
+ SetupInitExpectationsWithGLVersion("GL_ARB_sampler_objects", "OpenGL 3.0");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags().enable_samplers);
+}
+
+TEST_F(FeatureInfoTest, InitializeSamplersWithES3) {
+ SetupInitExpectationsWithGLVersion("", "OpenGL ES 3.0");
+ info_->Initialize(NULL);
+ EXPECT_TRUE(info_->feature_flags().enable_samplers);
+}
+
+TEST_F(FeatureInfoTest, InitializeWithoutSamplers) {
+ SetupInitExpectationsWithGLVersion("", "OpenGL GL 3.0");
+ info_->Initialize(NULL);
+ EXPECT_FALSE(info_->feature_flags().enable_samplers);
+}
+
+TEST_F(FeatureInfoTest, ParseDriverBugWorkaroundsSingle) {
+ SetupInitExpectations("");
+ CommandLine command_line(0, NULL);
+ command_line.AppendSwitchASCII(
+ switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::EXIT_ON_CONTEXT_LOST));
+ EXPECT_FALSE(info_->workarounds().exit_on_context_lost);
+ info_->AddFeatures(command_line);
+ EXPECT_TRUE(info_->workarounds().exit_on_context_lost);
+}
+
+TEST_F(FeatureInfoTest, ParseDriverBugWorkaroundsMultiple) {
+ SetupInitExpectations("");
+ CommandLine command_line(0, NULL);
+ command_line.AppendSwitchASCII(
+ switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::EXIT_ON_CONTEXT_LOST) + "," +
+ base::IntToString(gpu::MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_1024) + "," +
+ base::IntToString(gpu::MAX_TEXTURE_SIZE_LIMIT_4096));
+ EXPECT_FALSE(info_->workarounds().exit_on_context_lost);
+ EXPECT_EQ(0, info_->workarounds().max_cube_map_texture_size);
+ EXPECT_EQ(0, info_->workarounds().max_texture_size);
+ info_->AddFeatures(command_line);
+ EXPECT_TRUE(info_->workarounds().exit_on_context_lost);
+ EXPECT_EQ(1024, info_->workarounds().max_cube_map_texture_size);
+ EXPECT_EQ(4096, info_->workarounds().max_texture_size);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/framebuffer_manager.cc b/chromium/gpu/command_buffer/service/framebuffer_manager.cc
new file mode 100644
index 00000000000..b4c6b090f0f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/framebuffer_manager.cc
@@ -0,0 +1,618 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+namespace gles2 {
+
+Framebuffer::FramebufferComboCompleteMap*
+ Framebuffer::framebuffer_combo_complete_map_;
+
+// Framebuffer completeness is not cacheable on OS X because of dynamic
+// graphics switching.
+// http://crbug.com/180876
+#if defined(OS_MACOSX)
+bool Framebuffer::allow_framebuffer_combo_complete_map_ = false;
+#else
+bool Framebuffer::allow_framebuffer_combo_complete_map_ = true;
+#endif
+
+void Framebuffer::ClearFramebufferCompleteComboMap() {
+ if (framebuffer_combo_complete_map_) {
+ framebuffer_combo_complete_map_->clear();
+ }
+}
+
+class RenderbufferAttachment
+ : public Framebuffer::Attachment {
+ public:
+ explicit RenderbufferAttachment(
+ Renderbuffer* renderbuffer)
+ : renderbuffer_(renderbuffer) {
+ }
+
+ virtual GLsizei width() const OVERRIDE {
+ return renderbuffer_->width();
+ }
+
+ virtual GLsizei height() const OVERRIDE {
+ return renderbuffer_->height();
+ }
+
+ virtual GLenum internal_format() const OVERRIDE {
+ return renderbuffer_->internal_format();
+ }
+
+ virtual GLsizei samples() const OVERRIDE {
+ return renderbuffer_->samples();
+ }
+
+ virtual GLuint object_name() const OVERRIDE {
+ return renderbuffer_->client_id();
+ }
+
+ virtual bool cleared() const OVERRIDE {
+ return renderbuffer_->cleared();
+ }
+
+ virtual void SetCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* /* texture_manager */,
+ bool cleared) OVERRIDE {
+ renderbuffer_manager->SetCleared(renderbuffer_.get(), cleared);
+ }
+
+ virtual bool IsTexture(
+ TextureRef* /* texture */) const OVERRIDE {
+ return false;
+ }
+
+ virtual bool IsRenderbuffer(
+ Renderbuffer* renderbuffer) const OVERRIDE {
+ return renderbuffer_.get() == renderbuffer;
+ }
+
+ virtual bool CanRenderTo() const OVERRIDE {
+ return true;
+ }
+
+ virtual void DetachFromFramebuffer() const OVERRIDE {
+ // Nothing to do for renderbuffers.
+ }
+
+ virtual bool ValidForAttachmentType(
+ GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
+ uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
+ attachment_type, max_color_attachments);
+ uint32 have = GLES2Util::GetChannelsForFormat(internal_format());
+ return (need & have) != 0;
+ }
+
+ Renderbuffer* renderbuffer() const {
+ return renderbuffer_.get();
+ }
+
+ virtual void AddToSignature(
+ TextureManager* texture_manager, std::string* signature) const OVERRIDE {
+ DCHECK(signature);
+ renderbuffer_->AddToSignature(signature);
+ }
+
+ protected:
+ virtual ~RenderbufferAttachment() { }
+
+ private:
+ scoped_refptr<Renderbuffer> renderbuffer_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferAttachment);
+};
+
+class TextureAttachment
+ : public Framebuffer::Attachment {
+ public:
+ TextureAttachment(
+ TextureRef* texture_ref, GLenum target, GLint level, GLsizei samples)
+ : texture_ref_(texture_ref),
+ target_(target),
+ level_(level),
+ samples_(samples) {
+ }
+
+ virtual GLsizei width() const OVERRIDE {
+ GLsizei temp_width = 0;
+ GLsizei temp_height = 0;
+ texture_ref_->texture()->GetLevelSize(
+ target_, level_, &temp_width, &temp_height);
+ return temp_width;
+ }
+
+ virtual GLsizei height() const OVERRIDE {
+ GLsizei temp_width = 0;
+ GLsizei temp_height = 0;
+ texture_ref_->texture()->GetLevelSize(
+ target_, level_, &temp_width, &temp_height);
+ return temp_height;
+ }
+
+ virtual GLenum internal_format() const OVERRIDE {
+ GLenum temp_type = 0;
+ GLenum temp_internal_format = 0;
+ texture_ref_->texture()->GetLevelType(
+ target_, level_, &temp_type, &temp_internal_format);
+ return temp_internal_format;
+ }
+
+ virtual GLsizei samples() const OVERRIDE {
+ return samples_;
+ }
+
+ virtual GLuint object_name() const OVERRIDE {
+ return texture_ref_->client_id();
+ }
+
+ virtual bool cleared() const OVERRIDE {
+ return texture_ref_->texture()->IsLevelCleared(target_, level_);
+ }
+
+ virtual void SetCleared(
+ RenderbufferManager* /* renderbuffer_manager */,
+ TextureManager* texture_manager,
+ bool cleared) OVERRIDE {
+ texture_manager->SetLevelCleared(
+ texture_ref_.get(), target_, level_, cleared);
+ }
+
+ virtual bool IsTexture(TextureRef* texture) const OVERRIDE {
+ return texture == texture_ref_.get();
+ }
+
+ virtual bool IsRenderbuffer(
+ Renderbuffer* /* renderbuffer */)
+ const OVERRIDE {
+ return false;
+ }
+
+ TextureRef* texture() const {
+ return texture_ref_.get();
+ }
+
+ virtual bool CanRenderTo() const OVERRIDE {
+ return texture_ref_->texture()->CanRenderTo();
+ }
+
+ virtual void DetachFromFramebuffer() const OVERRIDE {
+ texture_ref_->texture()->DetachFromFramebuffer();
+ }
+
+ virtual bool ValidForAttachmentType(
+ GLenum attachment_type, uint32 max_color_attachments) OVERRIDE {
+ GLenum type = 0;
+ GLenum internal_format = 0;
+ if (!texture_ref_->texture()->GetLevelType(
+ target_, level_, &type, &internal_format)) {
+ return false;
+ }
+ uint32 need = GLES2Util::GetChannelsNeededForAttachmentType(
+ attachment_type, max_color_attachments);
+ uint32 have = GLES2Util::GetChannelsForFormat(internal_format);
+
+ // Workaround for NVIDIA drivers that incorrectly expose these formats as
+ // renderable:
+ if (internal_format == GL_LUMINANCE || internal_format == GL_ALPHA ||
+ internal_format == GL_LUMINANCE_ALPHA) {
+ return false;
+ }
+ return (need & have) != 0;
+ }
+
+ virtual void AddToSignature(
+ TextureManager* texture_manager, std::string* signature) const OVERRIDE {
+ DCHECK(signature);
+ texture_manager->AddToSignature(
+ texture_ref_.get(), target_, level_, signature);
+ }
+
+ protected:
+ virtual ~TextureAttachment() {}
+
+ private:
+ scoped_refptr<TextureRef> texture_ref_;
+ GLenum target_;
+ GLint level_;
+ GLsizei samples_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureAttachment);
+};
+
+FramebufferManager::FramebufferManager(
+ uint32 max_draw_buffers, uint32 max_color_attachments)
+ : framebuffer_state_change_count_(1),
+ framebuffer_count_(0),
+ have_context_(true),
+ max_draw_buffers_(max_draw_buffers),
+ max_color_attachments_(max_color_attachments) {
+ DCHECK_GT(max_draw_buffers_, 0u);
+ DCHECK_GT(max_color_attachments_, 0u);
+}
+
+FramebufferManager::~FramebufferManager() {
+ DCHECK(framebuffers_.empty());
+ // If this triggers, that means something is keeping a reference to a
+ // Framebuffer belonging to this.
+ CHECK_EQ(framebuffer_count_, 0u);
+}
+
+void Framebuffer::MarkAsDeleted() {
+ deleted_ = true;
+ while (!attachments_.empty()) {
+ Attachment* attachment = attachments_.begin()->second.get();
+ attachment->DetachFromFramebuffer();
+ attachments_.erase(attachments_.begin());
+ }
+}
+
+void FramebufferManager::Destroy(bool have_context) {
+ have_context_ = have_context;
+ framebuffers_.clear();
+}
+
+void FramebufferManager::StartTracking(
+ Framebuffer* /* framebuffer */) {
+ ++framebuffer_count_;
+}
+
+void FramebufferManager::StopTracking(
+ Framebuffer* /* framebuffer */) {
+ --framebuffer_count_;
+}
+
+void FramebufferManager::CreateFramebuffer(
+ GLuint client_id, GLuint service_id) {
+ std::pair<FramebufferMap::iterator, bool> result =
+ framebuffers_.insert(
+ std::make_pair(
+ client_id,
+ scoped_refptr<Framebuffer>(
+ new Framebuffer(this, service_id))));
+ DCHECK(result.second);
+}
+
+Framebuffer::Framebuffer(
+ FramebufferManager* manager, GLuint service_id)
+ : manager_(manager),
+ deleted_(false),
+ service_id_(service_id),
+ has_been_bound_(false),
+ framebuffer_complete_state_count_id_(0) {
+ manager->StartTracking(this);
+ DCHECK_GT(manager->max_draw_buffers_, 0u);
+ draw_buffers_.reset(new GLenum[manager->max_draw_buffers_]);
+ draw_buffers_[0] = GL_COLOR_ATTACHMENT0;
+ for (uint32 i = 1; i < manager->max_draw_buffers_; ++i)
+ draw_buffers_[i] = GL_NONE;
+}
+
+Framebuffer::~Framebuffer() {
+ if (manager_) {
+ if (manager_->have_context_) {
+ GLuint id = service_id();
+ glDeleteFramebuffersEXT(1, &id);
+ }
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+bool Framebuffer::HasUnclearedAttachment(
+ GLenum attachment) const {
+ AttachmentMap::const_iterator it =
+ attachments_.find(attachment);
+ if (it != attachments_.end()) {
+ const Attachment* attachment = it->second.get();
+ return !attachment->cleared();
+ }
+ return false;
+}
+
+void Framebuffer::MarkAttachmentAsCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager,
+ GLenum attachment,
+ bool cleared) {
+ AttachmentMap::iterator it = attachments_.find(attachment);
+ if (it != attachments_.end()) {
+ Attachment* a = it->second.get();
+ if (a->cleared() != cleared) {
+ a->SetCleared(renderbuffer_manager,
+ texture_manager,
+ cleared);
+ }
+ }
+}
+
+void Framebuffer::MarkAttachmentsAsCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager,
+ bool cleared) {
+ for (AttachmentMap::iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ Attachment* attachment = it->second.get();
+ if (attachment->cleared() != cleared) {
+ attachment->SetCleared(renderbuffer_manager, texture_manager, cleared);
+ }
+ }
+}
+
+bool Framebuffer::HasDepthAttachment() const {
+ return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
+ attachments_.find(GL_DEPTH_ATTACHMENT) != attachments_.end();
+}
+
+bool Framebuffer::HasStencilAttachment() const {
+ return attachments_.find(GL_DEPTH_STENCIL_ATTACHMENT) != attachments_.end() ||
+ attachments_.find(GL_STENCIL_ATTACHMENT) != attachments_.end();
+}
+
+GLenum Framebuffer::GetColorAttachmentFormat() const {
+ AttachmentMap::const_iterator it = attachments_.find(GL_COLOR_ATTACHMENT0);
+ if (it == attachments_.end()) {
+ return 0;
+ }
+ const Attachment* attachment = it->second.get();
+ return attachment->internal_format();
+}
+
+GLenum Framebuffer::IsPossiblyComplete() const {
+ if (attachments_.empty()) {
+ return GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ }
+
+ GLsizei width = -1;
+ GLsizei height = -1;
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ GLenum attachment_type = it->first;
+ Attachment* attachment = it->second.get();
+ if (!attachment->ValidForAttachmentType(attachment_type,
+ manager_->max_color_attachments_)) {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ if (width < 0) {
+ width = attachment->width();
+ height = attachment->height();
+ if (width == 0 || height == 0) {
+ return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ }
+ } else {
+ if (attachment->width() != width || attachment->height() != height) {
+ return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT;
+ }
+ }
+
+ if (!attachment->CanRenderTo()) {
+ return GL_FRAMEBUFFER_UNSUPPORTED;
+ }
+ }
+
+ // This does not mean the framebuffer is actually complete. It just means our
+ // checks passed.
+ return GL_FRAMEBUFFER_COMPLETE;
+}
+
+GLenum Framebuffer::GetStatus(
+ TextureManager* texture_manager, GLenum target) const {
+ // Check if we have this combo already.
+ std::string signature;
+ if (allow_framebuffer_combo_complete_map_) {
+ signature = base::StringPrintf("|FBO|target=%04x", target);
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ Attachment* attachment = it->second.get();
+ signature +=
+ base::StringPrintf("|Attachment|attachmentpoint=%04x", it->first);
+ attachment->AddToSignature(texture_manager, &signature);
+ }
+
+ if (!framebuffer_combo_complete_map_) {
+ framebuffer_combo_complete_map_ = new FramebufferComboCompleteMap();
+ }
+
+ FramebufferComboCompleteMap::const_iterator it =
+ framebuffer_combo_complete_map_->find(signature);
+ if (it != framebuffer_combo_complete_map_->end()) {
+ return GL_FRAMEBUFFER_COMPLETE;
+ }
+ }
+
+ GLenum result = glCheckFramebufferStatusEXT(target);
+
+ // Insert the new result into the combo map.
+ if (allow_framebuffer_combo_complete_map_ &&
+ result == GL_FRAMEBUFFER_COMPLETE) {
+ framebuffer_combo_complete_map_->insert(std::make_pair(signature, true));
+ }
+
+ return result;
+}
+
+bool Framebuffer::IsCleared() const {
+ // are all the attachments cleaared?
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ Attachment* attachment = it->second.get();
+ if (!attachment->cleared()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+GLenum Framebuffer::GetDrawBuffer(GLenum draw_buffer) const {
+ GLsizei index = static_cast<GLsizei>(
+ draw_buffer - GL_DRAW_BUFFER0_ARB);
+ CHECK(index >= 0 &&
+ index < static_cast<GLsizei>(manager_->max_draw_buffers_));
+ return draw_buffers_[index];
+}
+
+void Framebuffer::SetDrawBuffers(GLsizei n, const GLenum* bufs) {
+ DCHECK(n <= static_cast<GLsizei>(manager_->max_draw_buffers_));
+ for (GLsizei i = 0; i < n; ++i)
+ draw_buffers_[i] = bufs[i];
+}
+
+bool Framebuffer::HasAlphaMRT() const {
+ for (uint32 i = 0; i < manager_->max_draw_buffers_; ++i) {
+ if (draw_buffers_[i] != GL_NONE) {
+ const Attachment* attachment = GetAttachment(draw_buffers_[i]);
+ if (!attachment)
+ continue;
+ if ((GLES2Util::GetChannelsForFormat(
+ attachment->internal_format()) & 0x0008) != 0)
+ return true;
+ }
+ }
+ return false;
+}
+
+void Framebuffer::UnbindRenderbuffer(
+ GLenum target, Renderbuffer* renderbuffer) {
+ bool done;
+ do {
+ done = true;
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ Attachment* attachment = it->second.get();
+ if (attachment->IsRenderbuffer(renderbuffer)) {
+ // TODO(gman): manually detach renderbuffer.
+ // glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
+ AttachRenderbuffer(it->first, NULL);
+ done = false;
+ break;
+ }
+ }
+ } while (!done);
+}
+
+void Framebuffer::UnbindTexture(
+ GLenum target, TextureRef* texture_ref) {
+ bool done;
+ do {
+ done = true;
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ Attachment* attachment = it->second.get();
+ if (attachment->IsTexture(texture_ref)) {
+ // TODO(gman): manually detach texture.
+ // glFramebufferTexture2DEXT(target, it->first, GL_TEXTURE_2D, 0, 0);
+ AttachTexture(it->first, NULL, GL_TEXTURE_2D, 0, 0);
+ done = false;
+ break;
+ }
+ }
+ } while (!done);
+}
+
+Framebuffer* FramebufferManager::GetFramebuffer(
+ GLuint client_id) {
+ FramebufferMap::iterator it = framebuffers_.find(client_id);
+ return it != framebuffers_.end() ? it->second.get() : NULL;
+}
+
+void FramebufferManager::RemoveFramebuffer(GLuint client_id) {
+ FramebufferMap::iterator it = framebuffers_.find(client_id);
+ if (it != framebuffers_.end()) {
+ it->second->MarkAsDeleted();
+ framebuffers_.erase(it);
+ }
+}
+
+void Framebuffer::AttachRenderbuffer(
+ GLenum attachment, Renderbuffer* renderbuffer) {
+ const Attachment* a = GetAttachment(attachment);
+ if (a)
+ a->DetachFromFramebuffer();
+ if (renderbuffer) {
+ attachments_[attachment] = scoped_refptr<Attachment>(
+ new RenderbufferAttachment(renderbuffer));
+ } else {
+ attachments_.erase(attachment);
+ }
+ framebuffer_complete_state_count_id_ = 0;
+}
+
+void Framebuffer::AttachTexture(
+ GLenum attachment, TextureRef* texture_ref, GLenum target,
+ GLint level, GLsizei samples) {
+ const Attachment* a = GetAttachment(attachment);
+ if (a)
+ a->DetachFromFramebuffer();
+ if (texture_ref) {
+ attachments_[attachment] = scoped_refptr<Attachment>(
+ new TextureAttachment(texture_ref, target, level, samples));
+ texture_ref->texture()->AttachToFramebuffer();
+ } else {
+ attachments_.erase(attachment);
+ }
+ framebuffer_complete_state_count_id_ = 0;
+}
+
+const Framebuffer::Attachment*
+ Framebuffer::GetAttachment(
+ GLenum attachment) const {
+ AttachmentMap::const_iterator it = attachments_.find(attachment);
+ if (it != attachments_.end()) {
+ return it->second.get();
+ }
+ return NULL;
+}
+
+bool FramebufferManager::GetClientId(
+ GLuint service_id, GLuint* client_id) const {
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (FramebufferMap::const_iterator it = framebuffers_.begin();
+ it != framebuffers_.end(); ++it) {
+ if (it->second->service_id() == service_id) {
+ *client_id = it->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+void FramebufferManager::MarkAttachmentsAsCleared(
+ Framebuffer* framebuffer,
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager) {
+ DCHECK(framebuffer);
+ framebuffer->MarkAttachmentsAsCleared(renderbuffer_manager,
+ texture_manager,
+ true);
+ MarkAsComplete(framebuffer);
+}
+
+void FramebufferManager::MarkAsComplete(
+ Framebuffer* framebuffer) {
+ DCHECK(framebuffer);
+ framebuffer->MarkAsComplete(framebuffer_state_change_count_);
+}
+
+bool FramebufferManager::IsComplete(
+ Framebuffer* framebuffer) {
+ DCHECK(framebuffer);
+ return framebuffer->framebuffer_complete_state_count_id() ==
+ framebuffer_state_change_count_;
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/framebuffer_manager.h b/chromium/gpu/command_buffer/service/framebuffer_manager.h
new file mode 100644
index 00000000000..aa1111813e1
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/framebuffer_manager.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_FRAMEBUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_FRAMEBUFFER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class FramebufferManager;
+class Renderbuffer;
+class RenderbufferManager;
+class Texture;
+class TextureRef;
+class TextureManager;
+
+// Info about a particular Framebuffer.
+class GPU_EXPORT Framebuffer : public base::RefCounted<Framebuffer> {
+ public:
+ class Attachment : public base::RefCounted<Attachment> {
+ public:
+ virtual GLsizei width() const = 0;
+ virtual GLsizei height() const = 0;
+ virtual GLenum internal_format() const = 0;
+ virtual GLsizei samples() const = 0;
+ virtual GLuint object_name() const = 0;
+ virtual bool cleared() const = 0;
+ virtual void SetCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager,
+ bool cleared) = 0;
+ virtual bool IsTexture(TextureRef* texture) const = 0;
+ virtual bool IsRenderbuffer(
+ Renderbuffer* renderbuffer) const = 0;
+ virtual bool CanRenderTo() const = 0;
+ virtual void DetachFromFramebuffer() const = 0;
+ virtual bool ValidForAttachmentType(
+ GLenum attachment_type, uint32 max_color_attachments) = 0;
+ virtual void AddToSignature(
+ TextureManager* texture_manager, std::string* signature) const = 0;
+
+ protected:
+ friend class base::RefCounted<Attachment>;
+ virtual ~Attachment() {}
+ };
+
+ Framebuffer(FramebufferManager* manager, GLuint service_id);
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ bool HasUnclearedAttachment(GLenum attachment) const;
+
+ void MarkAttachmentAsCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager,
+ GLenum attachment,
+ bool cleared);
+
+ // Attaches a renderbuffer to a particlar attachment.
+ // Pass null to detach.
+ void AttachRenderbuffer(
+ GLenum attachment, Renderbuffer* renderbuffer);
+
+ // Attaches a texture to a particlar attachment. Pass null to detach.
+ void AttachTexture(
+ GLenum attachment, TextureRef* texture_ref, GLenum target,
+ GLint level, GLsizei samples);
+
+ // Unbinds the given renderbuffer if it is bound.
+ void UnbindRenderbuffer(
+ GLenum target, Renderbuffer* renderbuffer);
+
+ // Unbinds the given texture if it is bound.
+ void UnbindTexture(
+ GLenum target, TextureRef* texture_ref);
+
+ const Attachment* GetAttachment(GLenum attachment) const;
+
+ bool IsDeleted() const {
+ return deleted_;
+ }
+
+ void MarkAsValid() {
+ has_been_bound_ = true;
+ }
+
+ bool IsValid() const {
+ return has_been_bound_ && !IsDeleted();
+ }
+
+ bool HasDepthAttachment() const;
+ bool HasStencilAttachment() const;
+ GLenum GetColorAttachmentFormat() const;
+
+ // Verify all the rules in OpenGL ES 2.0.25 4.4.5 are followed.
+ // Returns GL_FRAMEBUFFER_COMPLETE if there are no reasons we know we can't
+ // use this combination of attachments. Otherwise returns the value
+ // that glCheckFramebufferStatus should return for this set of attachments.
+ // Note that receiving GL_FRAMEBUFFER_COMPLETE from this function does
+ // not mean the real OpenGL will consider it framebuffer complete. It just
+ // means it passed our tests.
+ GLenum IsPossiblyComplete() const;
+
+ // Implements optimized glGetFramebufferStatus.
+ GLenum GetStatus(TextureManager* texture_manager, GLenum target) const;
+
+ // Check all attachments are cleared
+ bool IsCleared() const;
+
+ GLenum GetDrawBuffer(GLenum draw_buffer) const;
+
+ void SetDrawBuffers(GLsizei n, const GLenum* bufs);
+
+ // Return true if any draw buffers has an alpha channel.
+ bool HasAlphaMRT() const;
+
+ static void ClearFramebufferCompleteComboMap();
+
+ static bool AllowFramebufferComboCompleteMapForTesting() {
+ return allow_framebuffer_combo_complete_map_;
+ }
+
+ private:
+ friend class FramebufferManager;
+ friend class base::RefCounted<Framebuffer>;
+
+ ~Framebuffer();
+
+ void MarkAsDeleted();
+
+ void MarkAttachmentsAsCleared(
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager,
+ bool cleared);
+
+ void MarkAsComplete(unsigned state_id) {
+ framebuffer_complete_state_count_id_ = state_id;
+ }
+
+ unsigned framebuffer_complete_state_count_id() const {
+ return framebuffer_complete_state_count_id_;
+ }
+
+ // The managers that owns this.
+ FramebufferManager* manager_;
+
+ bool deleted_;
+
+ // Service side framebuffer id.
+ GLuint service_id_;
+
+ // Whether this framebuffer has ever been bound.
+ bool has_been_bound_;
+
+ // state count when this framebuffer was last checked for completeness.
+ unsigned framebuffer_complete_state_count_id_;
+
+ // A map of attachments.
+ typedef base::hash_map<GLenum, scoped_refptr<Attachment> > AttachmentMap;
+ AttachmentMap attachments_;
+
+ // A map of successful frame buffer combos. If it's in the map
+ // it should be FRAMEBUFFER_COMPLETE.
+ typedef base::hash_map<std::string, bool> FramebufferComboCompleteMap;
+ static FramebufferComboCompleteMap* framebuffer_combo_complete_map_;
+ static bool allow_framebuffer_combo_complete_map_;
+
+ scoped_ptr<GLenum[]> draw_buffers_;
+
+ DISALLOW_COPY_AND_ASSIGN(Framebuffer);
+};
+
+struct DecoderFramebufferState {
+ DecoderFramebufferState():
+ clear_state_dirty(true) {}
+
+ // State saved for clearing so we can clear render buffers and then
+ // restore to these values.
+ bool clear_state_dirty;
+};
+
+// This class keeps track of the frambebuffers and their attached renderbuffers
+// so we can correctly clear them.
+class GPU_EXPORT FramebufferManager {
+ public:
+ FramebufferManager(uint32 max_draw_buffers, uint32 max_color_attachments);
+ ~FramebufferManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a Framebuffer for the given framebuffer.
+ void CreateFramebuffer(GLuint client_id, GLuint service_id);
+
+ // Gets the framebuffer info for the given framebuffer.
+ Framebuffer* GetFramebuffer(GLuint client_id);
+
+ // Removes a framebuffer info for the given framebuffer.
+ void RemoveFramebuffer(GLuint client_id);
+
+ // Gets a client id for a given service id.
+ bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
+ void MarkAttachmentsAsCleared(
+ Framebuffer* framebuffer,
+ RenderbufferManager* renderbuffer_manager,
+ TextureManager* texture_manager);
+
+ void MarkAsComplete(Framebuffer* framebuffer);
+
+ bool IsComplete(Framebuffer* framebuffer);
+
+ void IncFramebufferStateChangeCount() {
+ // make sure this is never 0.
+ framebuffer_state_change_count_ =
+ (framebuffer_state_change_count_ + 1) | 0x80000000U;
+ }
+
+ private:
+ friend class Framebuffer;
+
+ void StartTracking(Framebuffer* framebuffer);
+ void StopTracking(Framebuffer* framebuffer);
+
+ // Info for each framebuffer in the system.
+ typedef base::hash_map<GLuint, scoped_refptr<Framebuffer> >
+ FramebufferMap;
+ FramebufferMap framebuffers_;
+
+ // Incremented anytime anything changes that might effect framebuffer
+ // state.
+ unsigned framebuffer_state_change_count_;
+
+ // Counts the number of Framebuffer allocated with 'this' as its manager.
+ // Allows to check no Framebuffer will outlive this.
+ unsigned int framebuffer_count_;
+
+ bool have_context_;
+
+ uint32 max_draw_buffers_;
+ uint32 max_color_attachments_;
+
+ DISALLOW_COPY_AND_ASSIGN(FramebufferManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_FRAMEBUFFER_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/framebuffer_manager_unittest.cc b/chromium/gpu/command_buffer/service/framebuffer_manager_unittest.cc
new file mode 100644
index 00000000000..a2c8aebcc46
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/framebuffer_manager_unittest.cc
@@ -0,0 +1,829 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/error_state_mock.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::Return;
+
+namespace gpu {
+namespace gles2 {
+
+class FramebufferManagerTest : public testing::Test {
+ static const GLint kMaxTextureSize = 64;
+ static const GLint kMaxCubemapSize = 64;
+ static const GLint kMaxRenderbufferSize = 64;
+ static const GLint kMaxSamples = 4;
+
+ public:
+ FramebufferManagerTest()
+ : manager_(1, 1),
+ texture_manager_(
+ NULL, new FeatureInfo(), kMaxTextureSize, kMaxCubemapSize),
+ renderbuffer_manager_(NULL, kMaxRenderbufferSize, kMaxSamples) {
+
+ }
+ virtual ~FramebufferManagerTest() {
+ manager_.Destroy(false);
+ texture_manager_.Destroy(false);
+ renderbuffer_manager_.Destroy(false);
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ FramebufferManager manager_;
+ TextureManager texture_manager_;
+ RenderbufferManager renderbuffer_manager_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLint FramebufferManagerTest::kMaxTextureSize;
+const GLint FramebufferManagerTest::kMaxCubemapSize;
+const GLint FramebufferManagerTest::kMaxRenderbufferSize;
+#endif
+
+TEST_F(FramebufferManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+ // Check we can create framebuffer.
+ manager_.CreateFramebuffer(kClient1Id, kService1Id);
+ // Check framebuffer got created.
+ Framebuffer* framebuffer1 = manager_.GetFramebuffer(kClient1Id);
+ ASSERT_TRUE(framebuffer1 != NULL);
+ EXPECT_FALSE(framebuffer1->IsDeleted());
+ EXPECT_EQ(kService1Id, framebuffer1->service_id());
+ GLuint client_id = 0;
+ EXPECT_TRUE(manager_.GetClientId(framebuffer1->service_id(), &client_id));
+ EXPECT_EQ(kClient1Id, client_id);
+ // Check we get nothing for a non-existent framebuffer.
+ EXPECT_TRUE(manager_.GetFramebuffer(kClient2Id) == NULL);
+ // Check trying to a remove non-existent framebuffers does not crash.
+ manager_.RemoveFramebuffer(kClient2Id);
+ // Check framebuffer gets deleted when last reference is released.
+ EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ // Check we can't get the framebuffer after we remove it.
+ manager_.RemoveFramebuffer(kClient1Id);
+ EXPECT_TRUE(manager_.GetFramebuffer(kClient1Id) == NULL);
+}
+
+TEST_F(FramebufferManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create framebuffer.
+ manager_.CreateFramebuffer(kClient1Id, kService1Id);
+ // Check framebuffer got created.
+ Framebuffer* framebuffer1 = manager_.GetFramebuffer(kClient1Id);
+ ASSERT_TRUE(framebuffer1 != NULL);
+ EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_.Destroy(true);
+ // Check the resources were released.
+ framebuffer1 = manager_.GetFramebuffer(kClient1Id);
+ ASSERT_TRUE(framebuffer1 == NULL);
+}
+
+class FramebufferInfoTest : public testing::Test {
+ public:
+ static const GLuint kClient1Id = 1;
+ static const GLuint kService1Id = 11;
+
+ static const GLint kMaxTextureSize = 64;
+ static const GLint kMaxCubemapSize = 64;
+ static const GLint kMaxRenderbufferSize = 64;
+ static const GLint kMaxSamples = 4;
+
+ FramebufferInfoTest()
+ : manager_(1, 1),
+ texture_manager_(
+ NULL, new FeatureInfo(), kMaxTextureSize, kMaxCubemapSize),
+ renderbuffer_manager_(NULL, kMaxRenderbufferSize, kMaxSamples) {
+ }
+ virtual ~FramebufferInfoTest() {
+ manager_.Destroy(false);
+ texture_manager_.Destroy(false);
+ renderbuffer_manager_.Destroy(false);
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ manager_.CreateFramebuffer(kClient1Id, kService1Id);
+ error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
+ framebuffer_ = manager_.GetFramebuffer(kClient1Id);
+ ASSERT_TRUE(framebuffer_ != NULL);
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ FramebufferManager manager_;
+ Framebuffer* framebuffer_;
+ TextureManager texture_manager_;
+ RenderbufferManager renderbuffer_manager_;
+ scoped_ptr<MockErrorState> error_state_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLuint FramebufferInfoTest::kClient1Id;
+const GLuint FramebufferInfoTest::kService1Id;
+const GLint FramebufferInfoTest::kMaxTextureSize;
+const GLint FramebufferInfoTest::kMaxCubemapSize;
+const GLint FramebufferInfoTest::kMaxRenderbufferSize;
+#endif
+
+TEST_F(FramebufferInfoTest, Basic) {
+ EXPECT_EQ(kService1Id, framebuffer_->service_id());
+ EXPECT_FALSE(framebuffer_->IsDeleted());
+ EXPECT_TRUE(NULL == framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_TRUE(NULL == framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_TRUE(NULL == framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_TRUE(
+ NULL == framebuffer_->GetAttachment(GL_DEPTH_STENCIL_ATTACHMENT));
+ EXPECT_FALSE(framebuffer_->HasDepthAttachment());
+ EXPECT_FALSE(framebuffer_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(0), framebuffer_->GetColorAttachmentFormat());
+ EXPECT_FALSE(manager_.IsComplete(framebuffer_));
+}
+
+TEST_F(FramebufferInfoTest, AttachRenderbuffer) {
+ const GLuint kRenderbufferClient1Id = 33;
+ const GLuint kRenderbufferService1Id = 333;
+ const GLuint kRenderbufferClient2Id = 34;
+ const GLuint kRenderbufferService2Id = 334;
+ const GLuint kRenderbufferClient3Id = 35;
+ const GLuint kRenderbufferService3Id = 335;
+ const GLuint kRenderbufferClient4Id = 36;
+ const GLuint kRenderbufferService4Id = 336;
+ const GLsizei kWidth1 = 16;
+ const GLsizei kHeight1 = 32;
+ const GLenum kFormat1 = GL_RGBA4;
+ const GLenum kBadFormat1 = GL_DEPTH_COMPONENT16;
+ const GLsizei kSamples1 = 0;
+ const GLsizei kWidth2 = 16;
+ const GLsizei kHeight2 = 32;
+ const GLenum kFormat2 = GL_DEPTH_COMPONENT16;
+ const GLsizei kSamples2 = 0;
+ const GLsizei kWidth3 = 16;
+ const GLsizei kHeight3 = 32;
+ const GLenum kFormat3 = GL_STENCIL_INDEX8;
+ const GLsizei kSamples3 = 0;
+ const GLsizei kWidth4 = 16;
+ const GLsizei kHeight4 = 32;
+ const GLenum kFormat4 = GL_STENCIL_INDEX8;
+ const GLsizei kSamples4 = 0;
+
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_FALSE(
+ framebuffer_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT));
+
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient1Id, kRenderbufferService1Id);
+ Renderbuffer* renderbuffer1 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+
+ // check adding one attachment
+ framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1);
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA4),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_FALSE(framebuffer_->HasDepthAttachment());
+ EXPECT_FALSE(framebuffer_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+
+ // Try a format that's not good for COLOR_ATTACHMENT0.
+ renderbuffer_manager_.SetInfo(
+ renderbuffer1, kSamples1, kBadFormat1, kWidth1, kHeight1);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+
+ // Try a good format.
+ renderbuffer_manager_.SetInfo(
+ renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1);
+ EXPECT_EQ(static_cast<GLenum>(kFormat1),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_FALSE(framebuffer_->HasDepthAttachment());
+ EXPECT_FALSE(framebuffer_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_FALSE(framebuffer_->IsCleared());
+
+ // check adding another
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient2Id, kRenderbufferService2Id);
+ Renderbuffer* renderbuffer2 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient2Id);
+ ASSERT_TRUE(renderbuffer2 != NULL);
+ framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer2);
+ EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(kFormat1),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_TRUE(framebuffer_->HasDepthAttachment());
+ EXPECT_FALSE(framebuffer_->HasStencilAttachment());
+ // The attachment has a size of 0,0 so depending on the order of the map
+ // of attachments it could either get INCOMPLETE_ATTACHMENT because it's 0,0
+ // or INCOMPLETE_DIMENSIONS because it's not the same size as the other
+ // attachment.
+ GLenum status = framebuffer_->IsPossiblyComplete();
+ EXPECT_TRUE(
+ status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ||
+ status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT);
+ EXPECT_FALSE(framebuffer_->IsCleared());
+
+ renderbuffer_manager_.SetInfo(
+ renderbuffer2, kSamples2, kFormat2, kWidth2, kHeight2);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_FALSE(framebuffer_->IsCleared());
+ EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+
+ // check marking them as cleared.
+ manager_.MarkAttachmentsAsCleared(
+ framebuffer_, &renderbuffer_manager_, &texture_manager_);
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+
+ // Check adding one that is already cleared.
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient3Id, kRenderbufferService3Id);
+ Renderbuffer* renderbuffer3 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient3Id);
+ ASSERT_TRUE(renderbuffer3 != NULL);
+ renderbuffer_manager_.SetInfo(
+ renderbuffer3, kSamples3, kFormat3, kWidth3, kHeight3);
+ renderbuffer_manager_.SetCleared(renderbuffer3, true);
+
+ framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer3);
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(kFormat1),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_TRUE(framebuffer_->HasDepthAttachment());
+ EXPECT_TRUE(framebuffer_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+
+ // Check marking the renderbuffer as unclared.
+ renderbuffer_manager_.SetInfo(
+ renderbuffer1, kSamples1, kFormat1, kWidth1, kHeight1);
+ EXPECT_EQ(static_cast<GLenum>(kFormat1),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_TRUE(framebuffer_->HasDepthAttachment());
+ EXPECT_TRUE(framebuffer_->HasStencilAttachment());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_FALSE(framebuffer_->IsCleared());
+
+ const Framebuffer::Attachment* attachment =
+ framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
+ ASSERT_TRUE(attachment != NULL);
+ EXPECT_EQ(kWidth1, attachment->width());
+ EXPECT_EQ(kHeight1, attachment->height());
+ EXPECT_EQ(kSamples1, attachment->samples());
+ EXPECT_EQ(kFormat1, attachment->internal_format());
+ EXPECT_FALSE(attachment->cleared());
+
+ EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+
+ // Clear it.
+ manager_.MarkAttachmentsAsCleared(
+ framebuffer_, &renderbuffer_manager_, &texture_manager_);
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_TRUE(framebuffer_->IsCleared());
+
+ // Check replacing an attachment
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient4Id, kRenderbufferService4Id);
+ Renderbuffer* renderbuffer4 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient4Id);
+ ASSERT_TRUE(renderbuffer4 != NULL);
+ renderbuffer_manager_.SetInfo(
+ renderbuffer4, kSamples4, kFormat4, kWidth4, kHeight4);
+
+ framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, renderbuffer4);
+ EXPECT_TRUE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_FALSE(framebuffer_->IsCleared());
+
+ attachment = framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT);
+ ASSERT_TRUE(attachment != NULL);
+ EXPECT_EQ(kWidth4, attachment->width());
+ EXPECT_EQ(kHeight4, attachment->height());
+ EXPECT_EQ(kSamples4, attachment->samples());
+ EXPECT_EQ(kFormat4, attachment->internal_format());
+ EXPECT_FALSE(attachment->cleared());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+
+ // Check changing an attachment.
+ renderbuffer_manager_.SetInfo(
+ renderbuffer4, kSamples4, kFormat4, kWidth4 + 1, kHeight4);
+
+ attachment = framebuffer_->GetAttachment(GL_STENCIL_ATTACHMENT);
+ ASSERT_TRUE(attachment != NULL);
+ EXPECT_EQ(kWidth4 + 1, attachment->width());
+ EXPECT_EQ(kHeight4, attachment->height());
+ EXPECT_EQ(kSamples4, attachment->samples());
+ EXPECT_EQ(kFormat4, attachment->internal_format());
+ EXPECT_FALSE(attachment->cleared());
+ EXPECT_FALSE(framebuffer_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT),
+ framebuffer_->IsPossiblyComplete());
+
+ // Check removing it.
+ framebuffer_->AttachRenderbuffer(GL_STENCIL_ATTACHMENT, NULL);
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(kFormat1),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_TRUE(framebuffer_->HasDepthAttachment());
+ EXPECT_FALSE(framebuffer_->HasStencilAttachment());
+
+ EXPECT_TRUE(framebuffer_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+
+ // Remove depth, Set color to 0 size.
+ framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, NULL);
+ renderbuffer_manager_.SetInfo(renderbuffer1, kSamples1, kFormat1, 0, 0);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+
+ // Remove color.
+ framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, NULL);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+}
+
+TEST_F(FramebufferInfoTest, AttachTexture) {
+ const GLuint kTextureClient1Id = 33;
+ const GLuint kTextureService1Id = 333;
+ const GLuint kTextureClient2Id = 34;
+ const GLuint kTextureService2Id = 334;
+ const GLint kDepth = 1;
+ const GLint kBorder = 0;
+ const GLenum kType = GL_UNSIGNED_BYTE;
+ const GLsizei kWidth1 = 16;
+ const GLsizei kHeight1 = 32;
+ const GLint kLevel1 = 0;
+ const GLenum kFormat1 = GL_RGBA;
+ const GLenum kBadFormat1 = GL_DEPTH_COMPONENT16;
+ const GLenum kTarget1 = GL_TEXTURE_2D;
+ const GLsizei kSamples1 = 0;
+ const GLsizei kWidth2 = 16;
+ const GLsizei kHeight2 = 32;
+ const GLint kLevel2 = 0;
+ const GLenum kFormat2 = GL_RGB;
+ const GLenum kTarget2 = GL_TEXTURE_2D;
+ const GLsizei kSamples2 = 0;
+ const GLsizei kWidth3 = 75;
+ const GLsizei kHeight3 = 123;
+ const GLint kLevel3 = 0;
+ const GLenum kFormat3 = GL_RGB565;
+ const GLsizei kSamples3 = 0;
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT));
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT));
+ EXPECT_FALSE(
+ framebuffer_->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT));
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+
+ texture_manager_.CreateTexture(kTextureClient1Id, kTextureService1Id);
+ scoped_refptr<TextureRef> texture1(
+ texture_manager_.GetTexture(kTextureClient1Id));
+ ASSERT_TRUE(texture1.get() != NULL);
+
+ // check adding one attachment
+ framebuffer_->AttachTexture(
+ GL_COLOR_ATTACHMENT0, texture1.get(), kTarget1, kLevel1, kSamples1);
+ EXPECT_FALSE(framebuffer_->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0));
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(0), framebuffer_->GetColorAttachmentFormat());
+
+ // Try format that doesn't work with COLOR_ATTACHMENT0
+ texture_manager_.SetTarget(texture1.get(), GL_TEXTURE_2D);
+ texture_manager_.SetLevelInfo(texture1.get(),
+ GL_TEXTURE_2D,
+ kLevel1,
+ kBadFormat1,
+ kWidth1,
+ kHeight1,
+ kDepth,
+ kBorder,
+ kBadFormat1,
+ kType,
+ true);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+
+ // Try a good format.
+ texture_manager_.SetLevelInfo(texture1.get(),
+ GL_TEXTURE_2D,
+ kLevel1,
+ kFormat1,
+ kWidth1,
+ kHeight1,
+ kDepth,
+ kBorder,
+ kFormat1,
+ kType,
+ false);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_FALSE(framebuffer_->IsCleared());
+ texture_manager_.SetLevelInfo(texture1.get(),
+ GL_TEXTURE_2D,
+ kLevel1,
+ kFormat1,
+ kWidth1,
+ kHeight1,
+ kDepth,
+ kBorder,
+ kFormat1,
+ kType,
+ true);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+ EXPECT_EQ(static_cast<GLenum>(kFormat1),
+ framebuffer_->GetColorAttachmentFormat());
+
+ const Framebuffer::Attachment* attachment =
+ framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
+ ASSERT_TRUE(attachment != NULL);
+ EXPECT_EQ(kWidth1, attachment->width());
+ EXPECT_EQ(kHeight1, attachment->height());
+ EXPECT_EQ(kSamples1, attachment->samples());
+ EXPECT_EQ(kFormat1, attachment->internal_format());
+ EXPECT_TRUE(attachment->cleared());
+
+ // Check replacing an attachment
+ texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id);
+ scoped_refptr<TextureRef> texture2(
+ texture_manager_.GetTexture(kTextureClient2Id));
+ ASSERT_TRUE(texture2.get() != NULL);
+ texture_manager_.SetTarget(texture2.get(), GL_TEXTURE_2D);
+ texture_manager_.SetLevelInfo(texture2.get(),
+ GL_TEXTURE_2D,
+ kLevel2,
+ kFormat2,
+ kWidth2,
+ kHeight2,
+ kDepth,
+ kBorder,
+ kFormat2,
+ kType,
+ true);
+
+ framebuffer_->AttachTexture(
+ GL_COLOR_ATTACHMENT0, texture2.get(), kTarget2, kLevel2, kSamples2);
+ EXPECT_EQ(static_cast<GLenum>(kFormat2),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+
+ attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
+ ASSERT_TRUE(attachment != NULL);
+ EXPECT_EQ(kWidth2, attachment->width());
+ EXPECT_EQ(kHeight2, attachment->height());
+ EXPECT_EQ(kSamples2, attachment->samples());
+ EXPECT_EQ(kFormat2, attachment->internal_format());
+ EXPECT_TRUE(attachment->cleared());
+
+ // Check changing attachment
+ texture_manager_.SetLevelInfo(texture2.get(),
+ GL_TEXTURE_2D,
+ kLevel3,
+ kFormat3,
+ kWidth3,
+ kHeight3,
+ kDepth,
+ kBorder,
+ kFormat3,
+ kType,
+ false);
+ attachment = framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0);
+ ASSERT_TRUE(attachment != NULL);
+ EXPECT_EQ(kWidth3, attachment->width());
+ EXPECT_EQ(kHeight3, attachment->height());
+ EXPECT_EQ(kSamples3, attachment->samples());
+ EXPECT_EQ(kFormat3, attachment->internal_format());
+ EXPECT_FALSE(attachment->cleared());
+ EXPECT_EQ(static_cast<GLenum>(kFormat3),
+ framebuffer_->GetColorAttachmentFormat());
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_FALSE(framebuffer_->IsCleared());
+
+ // Set to size 0
+ texture_manager_.SetLevelInfo(texture2.get(),
+ GL_TEXTURE_2D,
+ kLevel3,
+ kFormat3,
+ 0,
+ 0,
+ kDepth,
+ kBorder,
+ kFormat3,
+ kType,
+ false);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+
+ // Check removing it.
+ framebuffer_->AttachTexture(GL_COLOR_ATTACHMENT0, NULL, 0, 0, 0);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL);
+ EXPECT_EQ(static_cast<GLenum>(0), framebuffer_->GetColorAttachmentFormat());
+
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT),
+ framebuffer_->IsPossiblyComplete());
+ EXPECT_TRUE(framebuffer_->IsCleared());
+}
+
+TEST_F(FramebufferInfoTest, UnbindRenderbuffer) {
+ const GLuint kRenderbufferClient1Id = 33;
+ const GLuint kRenderbufferService1Id = 333;
+ const GLuint kRenderbufferClient2Id = 34;
+ const GLuint kRenderbufferService2Id = 334;
+
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient1Id, kRenderbufferService1Id);
+ Renderbuffer* renderbuffer1 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient2Id, kRenderbufferService2Id);
+ Renderbuffer* renderbuffer2 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient2Id);
+ ASSERT_TRUE(renderbuffer2 != NULL);
+
+ // Attach to 2 attachment points.
+ framebuffer_->AttachRenderbuffer(GL_COLOR_ATTACHMENT0, renderbuffer1);
+ framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1);
+ // Check they were attached.
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL);
+ // Unbind unattached renderbuffer.
+ framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer2);
+ // Should be no-op.
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL);
+ // Unbind renderbuffer.
+ framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1);
+ // Check they were detached
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) == NULL);
+}
+
+TEST_F(FramebufferInfoTest, UnbindTexture) {
+ const GLuint kTextureClient1Id = 33;
+ const GLuint kTextureService1Id = 333;
+ const GLuint kTextureClient2Id = 34;
+ const GLuint kTextureService2Id = 334;
+ const GLenum kTarget1 = GL_TEXTURE_2D;
+ const GLint kLevel1 = 0;
+ const GLint kSamples1 = 0;
+
+ texture_manager_.CreateTexture(kTextureClient1Id, kTextureService1Id);
+ scoped_refptr<TextureRef> texture1(
+ texture_manager_.GetTexture(kTextureClient1Id));
+ ASSERT_TRUE(texture1.get() != NULL);
+ texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id);
+ scoped_refptr<TextureRef> texture2(
+ texture_manager_.GetTexture(kTextureClient2Id));
+ ASSERT_TRUE(texture2.get() != NULL);
+
+ // Attach to 2 attachment points.
+ framebuffer_->AttachTexture(
+ GL_COLOR_ATTACHMENT0, texture1.get(), kTarget1, kLevel1, kSamples1);
+ framebuffer_->AttachTexture(
+ GL_DEPTH_ATTACHMENT, texture1.get(), kTarget1, kLevel1, kSamples1);
+ // Check they were attached.
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL);
+ // Unbind unattached texture.
+ framebuffer_->UnbindTexture(kTarget1, texture2.get());
+ // Should be no-op.
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) != NULL);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) != NULL);
+ // Unbind texture.
+ framebuffer_->UnbindTexture(kTarget1, texture1.get());
+ // Check they were detached
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_COLOR_ATTACHMENT0) == NULL);
+ EXPECT_TRUE(framebuffer_->GetAttachment(GL_DEPTH_ATTACHMENT) == NULL);
+}
+
+TEST_F(FramebufferInfoTest, IsCompleteMarkAsComplete) {
+ const GLuint kRenderbufferClient1Id = 33;
+ const GLuint kRenderbufferService1Id = 333;
+ const GLuint kTextureClient2Id = 34;
+ const GLuint kTextureService2Id = 334;
+ const GLenum kTarget1 = GL_TEXTURE_2D;
+ const GLint kLevel1 = 0;
+ const GLint kSamples1 = 0;
+
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient1Id, kRenderbufferService1Id);
+ Renderbuffer* renderbuffer1 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+ texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id);
+ scoped_refptr<TextureRef> texture2(
+ texture_manager_.GetTexture(kTextureClient2Id));
+ ASSERT_TRUE(texture2.get() != NULL);
+
+ // Check MarkAsComlete marks as complete.
+ manager_.MarkAsComplete(framebuffer_);
+ EXPECT_TRUE(manager_.IsComplete(framebuffer_));
+
+ // Check at attaching marks as not complete.
+ framebuffer_->AttachTexture(
+ GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1);
+ EXPECT_FALSE(manager_.IsComplete(framebuffer_));
+ manager_.MarkAsComplete(framebuffer_);
+ EXPECT_TRUE(manager_.IsComplete(framebuffer_));
+ framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1);
+ EXPECT_FALSE(manager_.IsComplete(framebuffer_));
+
+ // Check MarkAttachmentsAsCleared marks as complete.
+ manager_.MarkAttachmentsAsCleared(
+ framebuffer_, &renderbuffer_manager_, &texture_manager_);
+ EXPECT_TRUE(manager_.IsComplete(framebuffer_));
+
+ // Check Unbind marks as not complete.
+ framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1);
+ EXPECT_FALSE(manager_.IsComplete(framebuffer_));
+ manager_.MarkAsComplete(framebuffer_);
+ EXPECT_TRUE(manager_.IsComplete(framebuffer_));
+ framebuffer_->UnbindTexture(kTarget1, texture2.get());
+ EXPECT_FALSE(manager_.IsComplete(framebuffer_));
+}
+
+TEST_F(FramebufferInfoTest, GetStatus) {
+ const GLuint kRenderbufferClient1Id = 33;
+ const GLuint kRenderbufferService1Id = 333;
+ const GLuint kTextureClient2Id = 34;
+ const GLuint kTextureService2Id = 334;
+ const GLenum kTarget1 = GL_TEXTURE_2D;
+ const GLint kLevel1 = 0;
+ const GLint kSamples1 = 0;
+
+ renderbuffer_manager_.CreateRenderbuffer(
+ kRenderbufferClient1Id, kRenderbufferService1Id);
+ Renderbuffer* renderbuffer1 =
+ renderbuffer_manager_.GetRenderbuffer(kRenderbufferClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+ texture_manager_.CreateTexture(kTextureClient2Id, kTextureService2Id);
+ scoped_refptr<TextureRef> texture2(
+ texture_manager_.GetTexture(kTextureClient2Id));
+ ASSERT_TRUE(texture2.get() != NULL);
+ texture_manager_.SetTarget(texture2.get(), GL_TEXTURE_2D);
+
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+ // Check a second call for the same type does not call anything
+ if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+ framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+ // Check changing the attachments calls CheckFramebufferStatus.
+ framebuffer_->AttachTexture(
+ GL_COLOR_ATTACHMENT0, texture2.get(), kTarget1, kLevel1, kSamples1);
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE)).RetiresOnSaturation();
+ framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+ // Check a second call for the same type does not call anything.
+ if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+ framebuffer_->GetStatus(&texture_manager_, GL_FRAMEBUFFER);
+
+ // Check a second call with a different target calls CheckFramebufferStatus.
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check a second call for the same type does not call anything.
+ if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check adding another attachment calls CheckFramebufferStatus.
+ framebuffer_->AttachRenderbuffer(GL_DEPTH_ATTACHMENT, renderbuffer1);
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check a second call for the same type does not call anything.
+ if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check changing the format calls CheckFramebuffferStatus.
+ TestHelper::SetTexParameterWithExpectations(gl_.get(),
+ error_state_.get(),
+ &texture_manager_,
+ texture2.get(),
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE,
+ GL_NO_ERROR);
+
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check since it did not return FRAMEBUFFER_COMPLETE that it calls
+ // CheckFramebufferStatus
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check putting it back does not call CheckFramebufferStatus.
+ if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+ TestHelper::SetTexParameterWithExpectations(gl_.get(),
+ error_state_.get(),
+ &texture_manager_,
+ texture2.get(),
+ GL_TEXTURE_WRAP_S,
+ GL_REPEAT,
+ GL_NO_ERROR);
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+
+ // Check Unbinding does not call CheckFramebufferStatus
+ framebuffer_->UnbindRenderbuffer(GL_RENDERBUFFER, renderbuffer1);
+ if (!framebuffer_->AllowFramebufferComboCompleteMapForTesting()) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+ framebuffer_->GetStatus(&texture_manager_, GL_READ_FRAMEBUFFER);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/gl_context_virtual.cc b/chromium/gpu/command_buffer/service/gl_context_virtual.cc
new file mode 100644
index 00000000000..e7a4c043bf7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_context_virtual.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gl_context_virtual.h"
+
+#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "ui/gl/gl_surface.h"
+
+namespace gpu {
+
+GLContextVirtual::GLContextVirtual(
+ gfx::GLShareGroup* share_group,
+ gfx::GLContext* shared_context,
+ base::WeakPtr<gles2::GLES2Decoder> decoder)
+ : GLContext(share_group),
+ shared_context_(shared_context),
+ display_(NULL),
+ decoder_(decoder) {
+}
+
+gfx::Display* GLContextVirtual::display() {
+ return display_;
+}
+
+bool GLContextVirtual::Initialize(
+ gfx::GLSurface* compatible_surface, gfx::GpuPreference gpu_preference) {
+ SetGLStateRestorer(new GLStateRestorerImpl(decoder_));
+
+ display_ = static_cast<gfx::Display*>(compatible_surface->GetDisplay());
+
+ // Virtual contexts obviously can't make a context that is compatible
+ // with the surface (the context already exists), but we do need to
+ // make a context current for SetupForVirtualization() below.
+ if (!IsCurrent(compatible_surface)) {
+ if (!shared_context_->MakeCurrent(compatible_surface)) {
+ // This is likely an error. The real context should be made as
+ // compatible with all required surfaces when it was created.
+ LOG(ERROR) << "Failed MakeCurrent(compatible_surface)";
+ return false;
+ }
+ }
+
+ shared_context_->SetupForVirtualization();
+ shared_context_->MakeVirtuallyCurrent(this, compatible_surface);
+ return true;
+}
+
+void GLContextVirtual::Destroy() {
+ shared_context_->OnReleaseVirtuallyCurrent(this);
+ shared_context_ = NULL;
+ display_ = NULL;
+}
+
+bool GLContextVirtual::MakeCurrent(gfx::GLSurface* surface) {
+ if (decoder_.get())
+ return shared_context_->MakeVirtuallyCurrent(this, surface);
+
+ LOG(ERROR) << "Trying to make virtual context current without decoder.";
+ return false;
+}
+
+void GLContextVirtual::ReleaseCurrent(gfx::GLSurface* surface) {
+ if (IsCurrent(surface)) {
+ shared_context_->OnReleaseVirtuallyCurrent(this);
+ shared_context_->ReleaseCurrent(surface);
+ }
+}
+
+bool GLContextVirtual::IsCurrent(gfx::GLSurface* surface) {
+ // If it's a real surface it needs to be current.
+ if (surface &&
+ !surface->IsOffscreen() &&
+ !surface->GetBackingFrameBufferObject())
+ return shared_context_->IsCurrent(surface);
+
+ // Otherwise, only insure the context itself is current.
+ return shared_context_->IsCurrent(NULL);
+}
+
+void* GLContextVirtual::GetHandle() {
+ return shared_context_->GetHandle();
+}
+
+void GLContextVirtual::SetSwapInterval(int interval) {
+ shared_context_->SetSwapInterval(interval);
+}
+
+std::string GLContextVirtual::GetExtensions() {
+ return shared_context_->GetExtensions();
+}
+
+bool GLContextVirtual::GetTotalGpuMemory(size_t* bytes) {
+ return shared_context_->GetTotalGpuMemory(bytes);
+}
+
+void GLContextVirtual::SetSafeToForceGpuSwitch() {
+ // TODO(ccameron): This will not work if two contexts that disagree
+ // about whether or not forced gpu switching may be done both share
+ // the same underlying shared_context_.
+ return shared_context_->SetSafeToForceGpuSwitch();
+}
+
+bool GLContextVirtual::WasAllocatedUsingRobustnessExtension() {
+ return shared_context_->WasAllocatedUsingRobustnessExtension();
+}
+
+void GLContextVirtual::SetUnbindFboOnMakeCurrent() {
+ shared_context_->SetUnbindFboOnMakeCurrent();
+}
+
+GLContextVirtual::~GLContextVirtual() {
+ Destroy();
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gl_context_virtual.h b/chromium/gpu/command_buffer/service/gl_context_virtual.h
new file mode 100644
index 00000000000..fdecbddbc46
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_context_virtual.h
@@ -0,0 +1,65 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_VIRTUAL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_VIRTUAL_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_context.h"
+
+namespace gfx {
+class Display;
+class GLSurface;
+class GLStateRestorer;
+}
+
+namespace gpu {
+namespace gles2 {
+class GLES2Decoder;
+}
+
+// Encapsulates a virtual OpenGL context.
+class GPU_EXPORT GLContextVirtual : public gfx::GLContext {
+ public:
+ GLContextVirtual(
+ gfx::GLShareGroup* share_group,
+ gfx::GLContext* shared_context,
+ base::WeakPtr<gles2::GLES2Decoder> decoder);
+
+ gfx::Display* display();
+
+ // Implement GLContext.
+ virtual bool Initialize(
+ gfx::GLSurface* compatible_surface,
+ gfx::GpuPreference gpu_preference) OVERRIDE;
+ virtual void Destroy() OVERRIDE;
+ virtual bool MakeCurrent(gfx::GLSurface* surface) OVERRIDE;
+ virtual void ReleaseCurrent(gfx::GLSurface* surface) OVERRIDE;
+ virtual bool IsCurrent(gfx::GLSurface* surface) OVERRIDE;
+ virtual void* GetHandle() OVERRIDE;
+ virtual void SetSwapInterval(int interval) OVERRIDE;
+ virtual std::string GetExtensions() OVERRIDE;
+ virtual bool GetTotalGpuMemory(size_t* bytes) OVERRIDE;
+ virtual void SetSafeToForceGpuSwitch() OVERRIDE;
+ virtual bool WasAllocatedUsingRobustnessExtension() OVERRIDE;
+ virtual void SetUnbindFboOnMakeCurrent() OVERRIDE;
+
+ protected:
+ virtual ~GLContextVirtual();
+
+ private:
+ scoped_refptr<gfx::GLContext> shared_context_;
+ gfx::Display* display_;
+ base::WeakPtr<gles2::GLES2Decoder> decoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLContextVirtual);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GL_CONTEXT_VIRTUAL_H_
diff --git a/chromium/gpu/command_buffer/service/gl_state_restorer_impl.cc b/chromium/gpu/command_buffer/service/gl_state_restorer_impl.cc
new file mode 100644
index 00000000000..7b3c5ed3841
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_state_restorer_impl.cc
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gl_state_restorer_impl.h"
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+namespace gpu {
+
+GLStateRestorerImpl::GLStateRestorerImpl(
+ base::WeakPtr<gles2::GLES2Decoder> decoder)
+ : decoder_(decoder) {
+}
+
+GLStateRestorerImpl::~GLStateRestorerImpl() {
+}
+
+bool GLStateRestorerImpl::IsInitialized() {
+ DCHECK(decoder_.get());
+ return decoder_->initialized();
+}
+
+void GLStateRestorerImpl::RestoreState() {
+ DCHECK(decoder_.get());
+ decoder_->RestoreState();
+}
+
+void GLStateRestorerImpl::RestoreAllTextureUnitBindings() {
+ DCHECK(decoder_.get());
+ decoder_->RestoreAllTextureUnitBindings();
+}
+
+void GLStateRestorerImpl::RestoreFramebufferBindings() {
+ DCHECK(decoder_.get());
+ decoder_->RestoreFramebufferBindings();
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gl_state_restorer_impl.h b/chromium/gpu/command_buffer/service/gl_state_restorer_impl.h
new file mode 100644
index 00000000000..032bf725186
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_state_restorer_impl.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the GLStateRestorerImpl class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_STATE_RESTORER_IMPL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_STATE_RESTORER_IMPL_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/weak_ptr.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_state_restorer.h"
+
+namespace gpu {
+namespace gles2 {
+class GLES2Decoder;
+}
+
+// This class implements a GLStateRestorer that forwards to a GLES2Decoder.
+class GPU_EXPORT GLStateRestorerImpl : public gfx::GLStateRestorer {
+ public:
+ explicit GLStateRestorerImpl(base::WeakPtr<gles2::GLES2Decoder> decoder);
+ virtual ~GLStateRestorerImpl();
+
+ virtual bool IsInitialized() OVERRIDE;
+ virtual void RestoreState() OVERRIDE;
+ virtual void RestoreAllTextureUnitBindings() OVERRIDE;
+ virtual void RestoreFramebufferBindings() OVERRIDE;
+
+ private:
+ base::WeakPtr<gles2::GLES2Decoder> decoder_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLStateRestorerImpl);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GL_STATE_RESTORER_IMPL_H_
diff --git a/chromium/gpu/command_buffer/service/gl_surface_mock.cc b/chromium/gpu/command_buffer/service/gl_surface_mock.cc
new file mode 100644
index 00000000000..9706a18efc5
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_surface_mock.cc
@@ -0,0 +1,14 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gl_surface_mock.h"
+
+namespace gpu {
+
+GLSurfaceMock::GLSurfaceMock() {
+}
+
+GLSurfaceMock::~GLSurfaceMock() {
+}
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gl_surface_mock.h b/chromium/gpu/command_buffer/service/gl_surface_mock.h
new file mode 100644
index 00000000000..372a9b3f41d
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_surface_mock.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_SURFACE_MOCK_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_SURFACE_MOCK_H_
+
+#include "ui/gl/gl_surface.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+class GLSurfaceMock : public gfx::GLSurface {
+ public:
+ GLSurfaceMock();
+
+ MOCK_METHOD0(Initialize, bool());
+ MOCK_METHOD0(Destroy, void());
+ MOCK_METHOD1(Resize, bool(const gfx::Size& size));
+ MOCK_METHOD0(IsOffscreen, bool());
+ MOCK_METHOD0(SwapBuffers, bool());
+ MOCK_METHOD4(PostSubBuffer, bool(int x, int y, int width, int height));
+ MOCK_METHOD0(GetExtensions, std::string());
+ MOCK_METHOD0(GetSize, gfx::Size());
+ MOCK_METHOD0(GetHandle, void*());
+ MOCK_METHOD0(GetBackingFrameBufferObject, unsigned int());
+ MOCK_METHOD1(OnMakeCurrent, bool(gfx::GLContext* context));
+ MOCK_METHOD1(SetBackbufferAllocation, bool(bool allocated));
+ MOCK_METHOD1(SetFrontbufferAllocation, void(bool allocated));
+ MOCK_METHOD0(GetShareHandle, void*());
+ MOCK_METHOD0(GetDisplay, void*());
+ MOCK_METHOD0(GetConfig, void*());
+ MOCK_METHOD0(GetFormat, unsigned());
+
+ protected:
+ virtual ~GLSurfaceMock();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GLSurfaceMock);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GL_SURFACE_MOCK_H_
diff --git a/chromium/gpu/command_buffer/service/gl_utils.h b/chromium/gpu/command_buffer/service/gl_utils.h
new file mode 100644
index 00000000000..ade4a3748a7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gl_utils.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file includes all the necessary GL headers and implements some useful
+// utilities.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
+
+#include "build/build_config.h"
+#include "ui/gl/gl_bindings.h"
+
+// Define this for extra GL error debugging (slower).
+// #define GL_ERROR_DEBUGGING
+#ifdef GL_ERROR_DEBUGGING
+#define CHECK_GL_ERROR() do { \
+ GLenum gl_error = glGetError(); \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+ } while (0)
+#else // GL_ERROR_DEBUGGING
+#define CHECK_GL_ERROR() void(0)
+#endif // GL_ERROR_DEBUGGING
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GL_UTILS_H_
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
new file mode 100644
index 00000000000..36f2b42bd6c
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -0,0 +1,436 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
+
+#include <string.h>
+#include "base/basictypes.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#define SHADER0(src) \
+ "#ifdef GL_ES\n"\
+ "precision mediump float;\n"\
+ "#endif\n"\
+ #src
+#define SHADER(src) { false, SHADER0(src), }
+#define SHADER_EXTERNAL_OES0(src) \
+ "#extension GL_OES_EGL_image_external : require\n"\
+ "#ifdef GL_ES\n"\
+ "precision mediump float;\n"\
+ "#endif\n"\
+ #src
+#define SHADER_EXTERNAL_OES(src) { true, SHADER_EXTERNAL_OES0(src), }
+
+namespace {
+
+const GLfloat kQuadVertices[] = { -1.0f, -1.0f, 0.0f, 1.0f,
+ 1.0f, -1.0f, 0.0f, 1.0f,
+ 1.0f, 1.0f, 0.0f, 1.0f,
+ -1.0f, 1.0f, 0.0f, 1.0f };
+
+enum ProgramId {
+ PROGRAM_COPY_TEXTURE,
+ PROGRAM_COPY_TEXTURE_FLIP_Y,
+ PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA,
+ PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA,
+ PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY,
+ PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY,
+ PROGRAM_COPY_TEXTURE_OES,
+ PROGRAM_COPY_TEXTURE_OES_FLIP_Y,
+ PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA,
+ PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA,
+ PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY,
+ PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY,
+};
+
+struct ShaderInfo {
+ bool needs_egl_image_external;
+ const char* source;
+};
+
+const ShaderInfo shader_infos[] = {
+ // VERTEX_SHADER_POS_TEX
+ SHADER(
+ uniform mat4 u_matrix;
+ attribute vec4 a_position;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_Position = u_matrix * a_position;
+ v_uv = a_position.xy * 0.5 + vec2(0.5, 0.5);
+ }),
+ // FRAGMENT_SHADER_TEX
+ SHADER(
+ uniform sampler2D u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, v_uv.st);
+ }),
+ // FRAGMENT_SHADER_TEX_FLIP_Y
+ SHADER(
+ uniform sampler2D u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+ }),
+ // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA
+ SHADER(
+ uniform sampler2D u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, v_uv.st);
+ gl_FragColor.rgb *= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA
+ SHADER(
+ uniform sampler2D u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, v_uv.st);
+ if (gl_FragColor.a > 0.0)
+ gl_FragColor.rgb /= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_PREMULTIPLY_ALPHA_FLIP_Y
+ SHADER(
+ uniform sampler2D u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+ gl_FragColor.rgb *= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_UNPREMULTIPLY_ALPHA_FLIP_Y
+ SHADER(
+ uniform sampler2D u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+ if (gl_FragColor.a > 0.0)
+ gl_FragColor.rgb /= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_OES
+ SHADER_EXTERNAL_OES(
+ precision mediump float;
+ uniform samplerExternalOES u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, v_uv.st);
+ }),
+ // FRAGMENT_SHADER_TEX_OES_FLIP_Y
+ SHADER_EXTERNAL_OES(
+ precision mediump float;
+ uniform samplerExternalOES u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor =
+ texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+ }),
+ // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA
+ SHADER_EXTERNAL_OES(
+ precision mediump float;
+ uniform samplerExternalOES u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, v_uv.st);
+ gl_FragColor.rgb *= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA
+ SHADER_EXTERNAL_OES(
+ precision mediump float;
+ uniform samplerExternalOES u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor = texture2D(u_texSampler, v_uv.st);
+ if (gl_FragColor.a > 0.0)
+ gl_FragColor.rgb /= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_OES_PREMULTIPLY_ALPHA_FLIP_Y
+ SHADER_EXTERNAL_OES(
+ precision mediump float;
+ uniform samplerExternalOES u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor =
+ texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+ gl_FragColor.rgb *= gl_FragColor.a;
+ }),
+ // FRAGMENT_SHADER_TEX_OES_UNPREMULTIPLY_ALPHA_FLIP_Y
+ SHADER_EXTERNAL_OES(
+ precision mediump float;
+ uniform samplerExternalOES u_texSampler;
+ varying vec2 v_uv;
+ void main(void) {
+ gl_FragColor =
+ texture2D(u_texSampler, vec2(v_uv.s, 1.0 - v_uv.t));
+ if (gl_FragColor.a > 0.0)
+ gl_FragColor.rgb /= gl_FragColor.a;
+ }),
+};
+
+const int kNumShaders = arraysize(shader_infos);
+
+// Returns the correct program to evaluate the copy operation for
+// the CHROMIUM_flipy and premultiply alpha pixel store settings.
+ProgramId GetProgram(
+ bool flip_y,
+ bool premultiply_alpha,
+ bool unpremultiply_alpha,
+ bool is_source_external_oes) {
+ // If both pre-multiply and unpremultiply are requested, then perform no
+ // alpha manipulation.
+ if (premultiply_alpha && unpremultiply_alpha) {
+ premultiply_alpha = false;
+ unpremultiply_alpha = false;
+ }
+
+ // bit 0: Flip_y
+ // bit 1: Premult
+ // bit 2: Unpremult
+ // bit 3: External_oes
+ static ProgramId program_ids[] = {
+ PROGRAM_COPY_TEXTURE,
+ PROGRAM_COPY_TEXTURE_FLIP_Y, // F
+ PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA, // P
+ PROGRAM_COPY_TEXTURE_PREMULTIPLY_ALPHA_FLIPY, // F P
+ PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA, // U
+ PROGRAM_COPY_TEXTURE_UNPREMULTIPLY_ALPHA_FLIPY, // F U
+ PROGRAM_COPY_TEXTURE, // P U
+ PROGRAM_COPY_TEXTURE, // F P U
+ PROGRAM_COPY_TEXTURE_OES, // E
+ PROGRAM_COPY_TEXTURE_OES_FLIP_Y, // F E
+ PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA, // P E
+ PROGRAM_COPY_TEXTURE_OES_PREMULTIPLY_ALPHA_FLIPY, // F P E
+ PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA, // U E
+ PROGRAM_COPY_TEXTURE_OES_UNPREMULTIPLY_ALPHA_FLIPY, // F U E
+ PROGRAM_COPY_TEXTURE_OES, // P U E
+ PROGRAM_COPY_TEXTURE_OES, // F P U E
+ };
+
+ unsigned index = (flip_y ? (1 << 0) : 0) |
+ (premultiply_alpha ? (1 << 1) : 0) |
+ (unpremultiply_alpha ? (1 << 2) : 0) |
+ (is_source_external_oes ? (1 << 3) : 0);
+ return program_ids[index];
+}
+
+} // namespace
+
+namespace gpu {
+
+CopyTextureCHROMIUMResourceManager::CopyTextureCHROMIUMResourceManager()
+ : initialized_(false),
+ buffer_id_(0),
+ framebuffer_(0) {
+ for (int i = 0; i < kNumPrograms; ++i) {
+ programs_[i] = 0;
+ matrix_handle_[i] = 0;
+ sampler_locations_[i] = 0;
+ }
+}
+
+void CopyTextureCHROMIUMResourceManager::Initialize(
+ const gles2::GLES2Decoder* decoder) {
+ COMPILE_ASSERT(
+ kVertexPositionAttrib == 0u,
+ Position_attribs_must_be_0);
+
+ const char* extensions =
+ reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
+ bool have_egl_image_external = extensions &&
+ strstr(extensions, "GL_OES_EGL_image_external");
+
+ // Initialize all of the GPU resources required to perform the copy.
+ glGenBuffersARB(1, &buffer_id_);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices,
+ GL_STATIC_DRAW);
+
+ glGenFramebuffersEXT(1, &framebuffer_);
+
+ // TODO(gman): Init these on demand.
+ GLuint shaders[kNumShaders];
+ for (int shader = 0; shader < kNumShaders; ++shader) {
+ shaders[shader] = glCreateShader(
+ shader == 0 ? GL_VERTEX_SHADER : GL_FRAGMENT_SHADER);
+ const ShaderInfo& info = shader_infos[shader];
+ if (info.needs_egl_image_external && !have_egl_image_external) {
+ continue;
+ }
+ const char* shader_source = shader_infos[shader].source;
+ glShaderSource(shaders[shader], 1, &shader_source, 0);
+ glCompileShader(shaders[shader]);
+#ifndef NDEBUG
+ GLint compile_status;
+ glGetShaderiv(shaders[shader], GL_COMPILE_STATUS, &compile_status);
+ if (GL_TRUE != compile_status)
+ DLOG(ERROR) << "CopyTextureCHROMIUM: shader compilation failure.";
+#endif
+ }
+
+ // TODO(gman): Init these on demand.
+ for (int program = 0; program < kNumPrograms; ++program) {
+ const ShaderInfo& info = shader_infos[program + 1];
+ if (info.needs_egl_image_external && !have_egl_image_external) {
+ continue;
+ }
+ programs_[program] = glCreateProgram();
+ glAttachShader(programs_[program], shaders[0]);
+ glAttachShader(programs_[program], shaders[program + 1]);
+
+ glBindAttribLocation(programs_[program], kVertexPositionAttrib,
+ "a_position");
+
+ glLinkProgram(programs_[program]);
+#ifndef NDEBUG
+ GLint linked;
+ glGetProgramiv(programs_[program], GL_LINK_STATUS, &linked);
+ if (!linked)
+ DLOG(ERROR) << "CopyTextureCHROMIUM: program link failure.";
+#endif
+
+ sampler_locations_[program] = glGetUniformLocation(programs_[program],
+ "u_texSampler");
+
+ matrix_handle_[program] = glGetUniformLocation(programs_[program],
+ "u_matrix");
+ }
+
+ for (int shader = 0; shader < kNumShaders; ++shader)
+ glDeleteShader(shaders[shader]);
+
+ decoder->RestoreBufferBindings();
+
+ initialized_ = true;
+}
+
+void CopyTextureCHROMIUMResourceManager::Destroy() {
+ if (!initialized_)
+ return;
+
+ glDeleteFramebuffersEXT(1, &framebuffer_);
+
+ for (int program = 0; program < kNumPrograms; ++program) {
+ if (programs_[program])
+ glDeleteProgram(programs_[program]);
+ }
+
+ glDeleteBuffersARB(1, &buffer_id_);
+}
+
+void CopyTextureCHROMIUMResourceManager::DoCopyTexture(
+ const gles2::GLES2Decoder* decoder,
+ GLenum source_target,
+ GLenum dest_target,
+ GLuint source_id,
+ GLuint dest_id,
+ GLint level,
+ GLsizei width,
+ GLsizei height,
+ bool flip_y,
+ bool premultiply_alpha,
+ bool unpremultiply_alpha) {
+ // Use default transform matrix if no transform passed in.
+ const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ DoCopyTextureWithTransform(decoder, source_target, dest_target, source_id,
+ dest_id, level, width, height, flip_y, premultiply_alpha,
+ unpremultiply_alpha, default_matrix);
+}
+
+void CopyTextureCHROMIUMResourceManager::DoCopyTextureWithTransform(
+ const gles2::GLES2Decoder* decoder,
+ GLenum source_target,
+ GLenum dest_target,
+ GLuint source_id,
+ GLuint dest_id,
+ GLint level,
+ GLsizei width,
+ GLsizei height,
+ bool flip_y,
+ bool premultiply_alpha,
+ bool unpremultiply_alpha,
+ const GLfloat transform_matrix[16]) {
+ DCHECK(source_target == GL_TEXTURE_2D ||
+ source_target == GL_TEXTURE_EXTERNAL_OES);
+ if (!initialized_) {
+ DLOG(ERROR) << "CopyTextureCHROMIUM: Uninitialized manager.";
+ return;
+ }
+
+ GLuint program = GetProgram(
+ flip_y, premultiply_alpha, unpremultiply_alpha,
+ source_target == GL_TEXTURE_EXTERNAL_OES);
+ glUseProgram(programs_[program]);
+
+#ifndef NDEBUG
+ glValidateProgram(programs_[program]);
+ GLint validation_status;
+ glGetProgramiv(programs_[program], GL_VALIDATE_STATUS, &validation_status);
+ if (GL_TRUE != validation_status) {
+ DLOG(ERROR) << "CopyTextureCHROMIUM: Invalid shader.";
+ return;
+ }
+#endif
+
+ glUniformMatrix4fv(matrix_handle_[program], 1, GL_FALSE, transform_matrix);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, dest_id);
+ // NVidia drivers require texture settings to be a certain way
+ // or they won't report FRAMEBUFFER_COMPLETE.
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer_);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, dest_target,
+ dest_id, level);
+
+#ifndef NDEBUG
+ GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+ if (GL_FRAMEBUFFER_COMPLETE != fb_status) {
+ DLOG(ERROR) << "CopyTextureCHROMIUM: Incomplete framebuffer.";
+ } else
+#endif
+ {
+ glEnableVertexAttribArray(kVertexPositionAttrib);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+ glVertexAttribPointer(kVertexPositionAttrib, 4, GL_FLOAT, GL_FALSE,
+ 4 * sizeof(GLfloat), 0);
+
+ glUniform1i(sampler_locations_[program], 0);
+
+ glBindTexture(source_target, source_id);
+ glTexParameterf(source_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(source_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(source_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(source_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_CULL_FACE);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, width, height);
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ decoder->RestoreAttribute(kVertexPositionAttrib);
+ decoder->RestoreTextureState(source_id);
+ decoder->RestoreTextureState(dest_id);
+ decoder->RestoreTextureUnitBindings(0);
+ decoder->RestoreActiveTexture();
+ decoder->RestoreProgramBindings();
+ decoder->RestoreBufferBindings();
+ decoder->RestoreFramebufferBindings();
+ decoder->RestoreGlobalState();
+}
+
+} // namespace
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h b/chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
new file mode 100644
index 00000000000..097eb2ce46e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_COPY_TEXTURE_CHROMIUM_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_COPY_TEXTURE_CHROMIUM_H_
+
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2Decoder;
+
+} // namespace gles2.
+
+// This class encapsulates the resources required to implement the
+// GL_CHROMIUM_copy_texture extension. The copy operation is performed
+// via a blit to a framebuffer object.
+class GPU_EXPORT CopyTextureCHROMIUMResourceManager {
+ public:
+ CopyTextureCHROMIUMResourceManager();
+
+ void Initialize(const gles2::GLES2Decoder* decoder);
+ void Destroy();
+
+ void DoCopyTexture(const gles2::GLES2Decoder* decoder, GLenum source_target,
+ GLenum dest_target, GLuint source_id, GLuint dest_id,
+ GLint level, GLsizei width, GLsizei height,
+ bool flip_y, bool premultiply_alpha,
+ bool unpremultiply_alpha);
+
+ // This will apply a transform on the source texture before copying to
+ // destination texture.
+ void DoCopyTextureWithTransform(const gles2::GLES2Decoder* decoder,
+ GLenum source_target, GLenum dest_target,
+ GLuint source_id, GLuint dest_id, GLint level,
+ GLsizei width, GLsizei height, bool flip_y,
+ bool premultiply_alpha,
+ bool unpremultiply_alpha,
+ const GLfloat transform_matrix[16]);
+
+ // The attributes used during invocation of the extension.
+ static const GLuint kVertexPositionAttrib = 0;
+
+ private:
+ bool initialized_;
+
+ static const int kNumPrograms = 12;
+ GLuint programs_[kNumPrograms];
+ GLuint buffer_id_;
+ GLuint framebuffer_;
+ GLuint matrix_handle_[kNumPrograms];
+ GLuint sampler_locations_[kNumPrograms];
+
+ DISALLOW_COPY_AND_ASSIGN(CopyTextureCHROMIUMResourceManager);
+};
+
+} // namespace gpu.
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_COPY_TEXTURE_CHROMIUM_H_
+
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc
new file mode 100644
index 00000000000..44a01345372
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -0,0 +1,10261 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include <stdio.h>
+
+#include <algorithm>
+#include <list>
+#include <map>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include "base/at_exit.h"
+#include "base/atomicops.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_cftyperef.h"
+#endif
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+#define GLES2_GPU_SERVICE 1
+#include "gpu/command_buffer/common/debug_marker_manager.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/context_state.h"
+#include "gpu/command_buffer/service/error_state.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
+#include "gpu/command_buffer/service/gles2_cmd_validation.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/gpu_tracer.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "gpu/command_buffer/service/shader_translator_cache.h"
+#include "gpu/command_buffer/service/stream_texture.h"
+#include "gpu/command_buffer/service/stream_texture_manager.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/vertex_array_manager.h"
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_fence.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+
+#if defined(OS_MACOSX)
+#include "ui/gl/io_surface_support_mac.h"
+#endif
+
+// TODO(zmo): we can't include "City.h" due to type def conflicts.
+extern uint64 CityHash64(const char*, size_t);
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+static const char kOESDerivativeExtension[] = "GL_OES_standard_derivatives";
+static const char kEXTFragDepthExtension[] = "GL_EXT_frag_depth";
+static const char kEXTDrawBuffersExtension[] = "GL_EXT_draw_buffers";
+
+#if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
+khronos_uint64_t CityHashForAngle(const char* name, unsigned int len) {
+ return static_cast<khronos_uint64_t>(
+ CityHash64(name, static_cast<size_t>(len)));
+}
+#endif
+
+static bool PrecisionMeetsSpecForHighpFloat(GLint rangeMin,
+ GLint rangeMax,
+ GLint precision) {
+ return (rangeMin >= 62) && (rangeMax >= 62) && (precision >= 16);
+}
+
+static void GetShaderPrecisionFormatImpl(GLenum shader_type,
+ GLenum precision_type,
+ GLint *range, GLint *precision) {
+ switch (precision_type) {
+ case GL_LOW_INT:
+ case GL_MEDIUM_INT:
+ case GL_HIGH_INT:
+ // These values are for a 32-bit twos-complement integer format.
+ range[0] = 31;
+ range[1] = 30;
+ *precision = 0;
+ break;
+ case GL_LOW_FLOAT:
+ case GL_MEDIUM_FLOAT:
+ case GL_HIGH_FLOAT:
+ // These values are for an IEEE single-precision floating-point format.
+ range[0] = 127;
+ range[1] = 127;
+ *precision = 23;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 &&
+ gfx::g_driver_gl.fn.glGetShaderPrecisionFormatFn) {
+ // This function is sometimes defined even though it's really just
+ // a stub, so we need to set range and precision as if it weren't
+ // defined before calling it.
+ // On Mac OS with some GPUs, calling this generates a
+ // GL_INVALID_OPERATION error. Avoid calling it on non-GLES2
+ // platforms.
+ glGetShaderPrecisionFormat(shader_type, precision_type,
+ range, precision);
+
+ // TODO(brianderson): Make the following official workarounds.
+
+ // Some drivers have bugs where they report the ranges as a negative number.
+ // Taking the absolute value here shouldn't hurt because negative numbers
+ // aren't expected anyway.
+ range[0] = abs(range[0]);
+ range[1] = abs(range[1]);
+
+ // If the driver reports a precision for highp float that isn't actually
+ // highp, don't pretend like it's supported because shader compilation will
+ // fail anyway.
+ if (precision_type == GL_HIGH_FLOAT &&
+ !PrecisionMeetsSpecForHighpFloat(range[0], range[1], *precision)) {
+ range[0] = 0;
+ range[1] = 0;
+ *precision = 0;
+ }
+ }
+}
+
+} // namespace
+
+class GLES2DecoderImpl;
+
+// Local versions of the SET_GL_ERROR macros
+#define LOCAL_SET_GL_ERROR(error, function_name, msg) \
+ ERRORSTATE_SET_GL_ERROR(state_.GetErrorState(), error, function_name, msg)
+#define LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, value, label) \
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(state_.GetErrorState(), \
+ function_name, value, label)
+#define LOCAL_SET_GL_ERROR_INVALID_PARAM(error, function_name, pname) \
+ ERRORSTATE_SET_GL_ERROR_INVALID_PARAM(state_.GetErrorState(), error, \
+ function_name, pname)
+#define LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(function_name) \
+ ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(state_.GetErrorState(), \
+ function_name)
+#define LOCAL_PEEK_GL_ERROR(function_name) \
+ ERRORSTATE_PEEK_GL_ERROR(state_.GetErrorState(), function_name)
+#define LOCAL_CLEAR_REAL_GL_ERRORS(function_name) \
+ ERRORSTATE_CLEAR_REAL_GL_ERRORS(state_.GetErrorState(), function_name)
+#define LOCAL_PERFORMANCE_WARNING(msg) \
+ PerformanceWarning(__FILE__, __LINE__, msg)
+#define LOCAL_RENDER_WARNING(msg) \
+ RenderWarning(__FILE__, __LINE__, msg)
+
+// Check that certain assumptions the code makes are true. There are places in
+// the code where shared memory is passed direclty to GL. Example, glUniformiv,
+// glShaderSource. The command buffer code assumes GLint and GLsizei (and maybe
+// a few others) are 32bits. If they are not 32bits the code will have to change
+// to call those GL functions with service side memory and then copy the results
+// to shared memory, converting the sizes.
+COMPILE_ASSERT(sizeof(GLint) == sizeof(uint32), // NOLINT
+ GLint_not_same_size_as_uint32);
+COMPILE_ASSERT(sizeof(GLsizei) == sizeof(uint32), // NOLINT
+ GLint_not_same_size_as_uint32);
+COMPILE_ASSERT(sizeof(GLfloat) == sizeof(float), // NOLINT
+ GLfloat_not_same_size_as_float);
+
+// TODO(kbr): the use of this anonymous namespace core dumps the
+// linker on Mac OS X 10.6 when the symbol ordering file is used
+// namespace {
+
+// Returns the address of the first byte after a struct.
+template <typename T>
+const void* AddressAfterStruct(const T& pod) {
+ return reinterpret_cast<const uint8*>(&pod) + sizeof(pod);
+}
+
+// Returns the address of the frst byte after the struct or NULL if size >
+// immediate_data_size.
+template <typename RETURN_TYPE, typename COMMAND_TYPE>
+RETURN_TYPE GetImmediateDataAs(const COMMAND_TYPE& pod,
+ uint32 size,
+ uint32 immediate_data_size) {
+ return (size <= immediate_data_size) ?
+ static_cast<RETURN_TYPE>(const_cast<void*>(AddressAfterStruct(pod))) :
+ NULL;
+}
+
+// Computes the data size for certain gl commands like glUniform.
+bool ComputeDataSize(
+ GLuint count,
+ size_t size,
+ unsigned int elements_per_unit,
+ uint32* dst) {
+ uint32 value;
+ if (!SafeMultiplyUint32(count, size, &value)) {
+ return false;
+ }
+ if (!SafeMultiplyUint32(value, elements_per_unit, &value)) {
+ return false;
+ }
+ *dst = value;
+ return true;
+}
+
+// A struct to hold info about each command.
+struct CommandInfo {
+ int arg_flags; // How to handle the arguments for this command
+ int arg_count; // How many arguments are expected for this command.
+};
+
+// A table of CommandInfo for all the commands.
+const CommandInfo g_command_info[] = {
+ #define GLES2_CMD_OP(name) { \
+ cmds::name::kArgFlags, \
+ sizeof(cmds::name) / sizeof(CommandBufferEntry) - 1, }, /* NOLINT */ \
+
+ GLES2_COMMAND_LIST(GLES2_CMD_OP)
+
+ #undef GLES2_CMD_OP
+};
+
+// Return true if a character belongs to the ASCII subset as defined in
+// GLSL ES 1.0 spec section 3.1.
+static bool CharacterIsValidForGLES(unsigned char c) {
+ // Printing characters are valid except " $ ` @ \ ' DEL.
+ if (c >= 32 && c <= 126 &&
+ c != '"' &&
+ c != '$' &&
+ c != '`' &&
+ c != '@' &&
+ c != '\\' &&
+ c != '\'') {
+ return true;
+ }
+ // Horizontal tab, line feed, vertical tab, form feed, carriage return
+ // are also valid.
+ if (c >= 9 && c <= 13) {
+ return true;
+ }
+
+ return false;
+}
+
+static bool StringIsValidForGLES(const char* str) {
+ for (; *str; ++str) {
+ if (!CharacterIsValidForGLES(*str)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+// Wrapper for glEnable/glDisable that doesn't suck.
+static void EnableDisable(GLenum pname, bool enable) {
+ if (enable) {
+ glEnable(pname);
+ } else {
+ glDisable(pname);
+ }
+}
+
+// This class prevents any GL errors that occur when it is in scope from
+// being reported to the client.
+class ScopedGLErrorSuppressor {
+ public:
+ explicit ScopedGLErrorSuppressor(
+ const char* function_name, GLES2DecoderImpl* decoder);
+ ~ScopedGLErrorSuppressor();
+ private:
+ const char* function_name_;
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedGLErrorSuppressor);
+};
+
+// Temporarily changes a decoder's bound 2D texture and restore it when this
+// object goes out of scope. Also temporarily switches to using active texture
+// unit zero in case the client has changed that to something invalid.
+class ScopedTexture2DBinder {
+ public:
+ ScopedTexture2DBinder(GLES2DecoderImpl* decoder, GLuint id);
+ ~ScopedTexture2DBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedTexture2DBinder);
+};
+
+// Temporarily changes a decoder's bound render buffer and restore it when this
+// object goes out of scope.
+class ScopedRenderBufferBinder {
+ public:
+ ScopedRenderBufferBinder(GLES2DecoderImpl* decoder, GLuint id);
+ ~ScopedRenderBufferBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedRenderBufferBinder);
+};
+
+// Temporarily changes a decoder's bound frame buffer and restore it when this
+// object goes out of scope.
+class ScopedFrameBufferBinder {
+ public:
+ ScopedFrameBufferBinder(GLES2DecoderImpl* decoder, GLuint id);
+ ~ScopedFrameBufferBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedFrameBufferBinder);
+};
+
+// Temporarily changes a decoder's bound frame buffer to a resolved version of
+// the multisampled offscreen render buffer if that buffer is multisampled, and,
+// if it is bound or enforce_internal_framebuffer is true. If internal is
+// true, the resolved framebuffer is not visible to the parent.
+class ScopedResolvedFrameBufferBinder {
+ public:
+ ScopedResolvedFrameBufferBinder(GLES2DecoderImpl* decoder,
+ bool enforce_internal_framebuffer,
+ bool internal);
+ ~ScopedResolvedFrameBufferBinder();
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ bool resolve_and_bind_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedResolvedFrameBufferBinder);
+};
+
+// Encapsulates an OpenGL texture.
+class BackTexture {
+ public:
+ explicit BackTexture(GLES2DecoderImpl* decoder);
+ ~BackTexture();
+
+ // Create a new render texture.
+ void Create();
+
+ // Set the initial size and format of a render texture or resize it.
+ bool AllocateStorage(const gfx::Size& size, GLenum format, bool zero);
+
+ // Copy the contents of the currently bound frame buffer.
+ void Copy(const gfx::Size& size, GLenum format);
+
+ // Destroy the render texture. This must be explicitly called before
+ // destroying this object.
+ void Destroy();
+
+ // Invalidate the texture. This can be used when a context is lost and it is
+ // not possible to make it current in order to free the resource.
+ void Invalidate();
+
+ GLuint id() const {
+ return id_;
+ }
+
+ gfx::Size size() const {
+ return size_;
+ }
+
+ size_t estimated_size() const {
+ return memory_tracker_.GetMemRepresented();
+ }
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ MemoryTypeTracker memory_tracker_;
+ size_t bytes_allocated_;
+ GLuint id_;
+ gfx::Size size_;
+ DISALLOW_COPY_AND_ASSIGN(BackTexture);
+};
+
+// Encapsulates an OpenGL render buffer of any format.
+class BackRenderbuffer {
+ public:
+ explicit BackRenderbuffer(GLES2DecoderImpl* decoder);
+ ~BackRenderbuffer();
+
+ // Create a new render buffer.
+ void Create();
+
+ // Set the initial size and format of a render buffer or resize it.
+ bool AllocateStorage(const gfx::Size& size, GLenum format, GLsizei samples);
+
+ // Destroy the render buffer. This must be explicitly called before destroying
+ // this object.
+ void Destroy();
+
+ // Invalidate the render buffer. This can be used when a context is lost and
+ // it is not possible to make it current in order to free the resource.
+ void Invalidate();
+
+ GLuint id() const {
+ return id_;
+ }
+
+ size_t estimated_size() const {
+ return memory_tracker_.GetMemRepresented();
+ }
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ MemoryTypeTracker memory_tracker_;
+ size_t bytes_allocated_;
+ GLuint id_;
+ DISALLOW_COPY_AND_ASSIGN(BackRenderbuffer);
+};
+
+// Encapsulates an OpenGL frame buffer.
+class BackFramebuffer {
+ public:
+ explicit BackFramebuffer(GLES2DecoderImpl* decoder);
+ ~BackFramebuffer();
+
+ // Create a new frame buffer.
+ void Create();
+
+ // Attach a color render buffer to a frame buffer.
+ void AttachRenderTexture(BackTexture* texture);
+
+ // Attach a render buffer to a frame buffer. Note that this unbinds any
+ // currently bound frame buffer.
+ void AttachRenderBuffer(GLenum target, BackRenderbuffer* render_buffer);
+
+ // Destroy the frame buffer. This must be explicitly called before destroying
+ // this object.
+ void Destroy();
+
+ // Invalidate the frame buffer. This can be used when a context is lost and it
+ // is not possible to make it current in order to free the resource.
+ void Invalidate();
+
+ // See glCheckFramebufferStatusEXT.
+ GLenum CheckStatus();
+
+ GLuint id() const {
+ return id_;
+ }
+
+ private:
+ GLES2DecoderImpl* decoder_;
+ GLuint id_;
+ DISALLOW_COPY_AND_ASSIGN(BackFramebuffer);
+};
+
+struct FenceCallback {
+ explicit FenceCallback()
+ : fence(gfx::GLFence::Create()) {
+ DCHECK(fence);
+ }
+ void AddCallback(base::Closure cb) {
+ callbacks.push_back(cb);
+ }
+ std::vector<base::Closure> callbacks;
+ scoped_ptr<gfx::GLFence> fence;
+};
+
+
+// } // anonymous namespace.
+
+bool GLES2Decoder::GetServiceTextureId(uint32 client_texture_id,
+ uint32* service_texture_id) {
+ return false;
+}
+
+GLES2Decoder::GLES2Decoder()
+ : initialized_(false),
+ debug_(false),
+ log_commands_(false) {
+}
+
+GLES2Decoder::~GLES2Decoder() {
+}
+
+bool GLES2Decoder::testing_force_is_angle_;
+
+void GLES2Decoder::set_testing_force_is_angle(bool force) {
+ testing_force_is_angle_ = force;
+}
+
+bool GLES2Decoder::IsAngle() {
+#if defined(OS_WIN)
+ return testing_force_is_angle_ ||
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
+#else
+ return testing_force_is_angle_;
+#endif
+}
+
+// This class implements GLES2Decoder so we don't have to expose all the GLES2
+// cmd stuff to outside this class.
+class GLES2DecoderImpl : public GLES2Decoder {
+ public:
+ // Used by PrepForSetUniformByLocation to validate types.
+ struct BaseUniformInfo {
+ const GLenum* const valid_types;
+ size_t num_valid_types;
+ };
+
+ explicit GLES2DecoderImpl(ContextGroup* group);
+ virtual ~GLES2DecoderImpl();
+
+ // Overridden from AsyncAPIInterface.
+ virtual Error DoCommand(unsigned int command,
+ unsigned int arg_count,
+ const void* args) OVERRIDE;
+
+ // Overridden from AsyncAPIInterface.
+ virtual const char* GetCommandName(unsigned int command_id) const OVERRIDE;
+
+ // Overridden from GLES2Decoder.
+ virtual bool Initialize(const scoped_refptr<gfx::GLSurface>& surface,
+ const scoped_refptr<gfx::GLContext>& context,
+ bool offscreen,
+ const gfx::Size& size,
+ const DisallowedFeatures& disallowed_features,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs) OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+ virtual void SetSurface(
+ const scoped_refptr<gfx::GLSurface>& surface) OVERRIDE;
+ virtual bool ProduceFrontBuffer(const Mailbox& mailbox) OVERRIDE;
+ virtual bool ResizeOffscreenFrameBuffer(const gfx::Size& size) OVERRIDE;
+ void UpdateParentTextureInfo();
+ virtual bool MakeCurrent() OVERRIDE;
+ virtual void ReleaseCurrent() OVERRIDE;
+ virtual GLES2Util* GetGLES2Util() OVERRIDE { return &util_; }
+ virtual gfx::GLContext* GetGLContext() OVERRIDE { return context_.get(); }
+ virtual ContextGroup* GetContextGroup() OVERRIDE { return group_.get(); }
+ virtual void RestoreState() const OVERRIDE;
+
+ virtual void RestoreActiveTexture() const OVERRIDE {
+ state_.RestoreActiveTexture();
+ }
+ virtual void RestoreAllTextureUnitBindings() const OVERRIDE {
+ state_.RestoreAllTextureUnitBindings();
+ }
+ virtual void RestoreAttribute(unsigned index) const OVERRIDE {
+ state_.RestoreAttribute(index);
+ }
+ virtual void RestoreBufferBindings() const OVERRIDE {
+ state_.RestoreBufferBindings();
+ }
+ virtual void RestoreGlobalState() const OVERRIDE {
+ state_.RestoreGlobalState();
+ }
+ virtual void RestoreProgramBindings() const OVERRIDE {
+ state_.RestoreProgramBindings();
+ }
+ virtual void RestoreRenderbufferBindings() const OVERRIDE {
+ state_.RestoreRenderbufferBindings();
+ }
+ virtual void RestoreTextureUnitBindings(unsigned unit) const OVERRIDE {
+ state_.RestoreTextureUnitBindings(unit);
+ }
+ virtual void RestoreFramebufferBindings() const OVERRIDE;
+ virtual void RestoreTextureState(unsigned service_id) const OVERRIDE;
+
+ virtual QueryManager* GetQueryManager() OVERRIDE {
+ return query_manager_.get();
+ }
+ virtual VertexArrayManager* GetVertexArrayManager() OVERRIDE {
+ return vertex_array_manager_.get();
+ }
+ virtual bool ProcessPendingQueries() OVERRIDE;
+ virtual bool HasMoreIdleWork() OVERRIDE;
+ virtual void PerformIdleWork() OVERRIDE;
+
+ virtual void WaitForReadPixels(base::Closure callback) OVERRIDE;
+
+ virtual void SetResizeCallback(
+ const base::Callback<void(gfx::Size, float)>& callback) OVERRIDE;
+
+ virtual Logger* GetLogger() OVERRIDE;
+ virtual ErrorState* GetErrorState() OVERRIDE;
+
+ virtual void SetShaderCacheCallback(
+ const ShaderCacheCallback& callback) OVERRIDE;
+ virtual void SetWaitSyncPointCallback(
+ const WaitSyncPointCallback& callback) OVERRIDE;
+
+ virtual AsyncPixelTransferManager*
+ GetAsyncPixelTransferManager() OVERRIDE;
+ virtual void ResetAsyncPixelTransferManagerForTest() OVERRIDE;
+ virtual void SetAsyncPixelTransferManagerForTest(
+ AsyncPixelTransferManager* manager) OVERRIDE;
+ void ProcessFinishedAsyncTransfers();
+
+ virtual bool GetServiceTextureId(uint32 client_texture_id,
+ uint32* service_texture_id) OVERRIDE;
+
+ virtual uint32 GetTextureUploadCount() OVERRIDE;
+ virtual base::TimeDelta GetTotalTextureUploadTime() OVERRIDE;
+ virtual base::TimeDelta GetTotalProcessingCommandsTime() OVERRIDE;
+ virtual void AddProcessingCommandsTime(base::TimeDelta) OVERRIDE;
+
+ // Restores the current state to the user's settings.
+ void RestoreCurrentFramebufferBindings();
+ void RestoreCurrentRenderbufferBindings();
+ void RestoreCurrentTexture2DBindings();
+
+ // Sets DEPTH_TEST, STENCIL_TEST and color mask for the current framebuffer.
+ void ApplyDirtyState();
+
+ // These check the state of the currently bound framebuffer or the
+ // backbuffer if no framebuffer is bound.
+ // If all_draw_buffers is false, only check with COLOR_ATTACHMENT0, otherwise
+ // check with all attached and enabled color attachments.
+ bool BoundFramebufferHasColorAttachmentWithAlpha(bool all_draw_buffers);
+ bool BoundFramebufferHasDepthAttachment();
+ bool BoundFramebufferHasStencilAttachment();
+
+ virtual error::ContextLostReason GetContextLostReason() OVERRIDE;
+
+ private:
+ friend class ScopedFrameBufferBinder;
+ friend class ScopedGLErrorSuppressor;
+ friend class ScopedResolvedFrameBufferBinder;
+ friend class BackTexture;
+ friend class BackRenderbuffer;
+ friend class BackFramebuffer;
+
+ // Initialize or re-initialize the shader translator.
+ bool InitializeShaderTranslator();
+
+ void UpdateCapabilities();
+
+ // Helpers for the glGen and glDelete functions.
+ bool GenTexturesHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteTexturesHelper(GLsizei n, const GLuint* client_ids);
+ bool GenBuffersHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteBuffersHelper(GLsizei n, const GLuint* client_ids);
+ bool GenFramebuffersHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteFramebuffersHelper(GLsizei n, const GLuint* client_ids);
+ bool GenRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
+ bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
+ bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
+
+ // Workarounds
+ void OnFboChanged() const;
+ void OnUseFramebuffer() const;
+
+ // TODO(gman): Cache these pointers?
+ BufferManager* buffer_manager() {
+ return group_->buffer_manager();
+ }
+
+ RenderbufferManager* renderbuffer_manager() {
+ return group_->renderbuffer_manager();
+ }
+
+ FramebufferManager* framebuffer_manager() {
+ return group_->framebuffer_manager();
+ }
+
+ ProgramManager* program_manager() {
+ return group_->program_manager();
+ }
+
+ ShaderManager* shader_manager() {
+ return group_->shader_manager();
+ }
+
+ const TextureManager* texture_manager() const {
+ return group_->texture_manager();
+ }
+
+ TextureManager* texture_manager() {
+ return group_->texture_manager();
+ }
+
+ MailboxManager* mailbox_manager() {
+ return group_->mailbox_manager();
+ }
+
+ ImageManager* image_manager() {
+ return group_->image_manager();
+ }
+
+ VertexArrayManager* vertex_array_manager() {
+ return vertex_array_manager_.get();
+ }
+
+ MemoryTracker* memory_tracker() {
+ return group_->memory_tracker();
+ }
+
+ StreamTextureManager* stream_texture_manager() const {
+ return group_->stream_texture_manager();
+ }
+
+ bool EnsureGPUMemoryAvailable(size_t estimated_size) {
+ MemoryTracker* tracker = memory_tracker();
+ if (tracker) {
+ return tracker->EnsureGPUMemoryAvailable(estimated_size);
+ }
+ return true;
+ }
+
+ bool IsOffscreenBufferMultisampled() const {
+ return offscreen_target_samples_ > 1;
+ }
+
+ // Creates a Texture for the given texture.
+ TextureRef* CreateTexture(
+ GLuint client_id, GLuint service_id) {
+ return texture_manager()->CreateTexture(client_id, service_id);
+ }
+
+ // Gets the texture info for the given texture. Returns NULL if none exists.
+ TextureRef* GetTexture(GLuint client_id) const {
+ return texture_manager()->GetTexture(client_id);
+ }
+
+ // Deletes the texture info for the given texture.
+ void RemoveTexture(GLuint client_id) {
+ texture_manager()->RemoveTexture(client_id);
+ }
+
+ // Get the size (in pixels) of the currently bound frame buffer (either FBO
+ // or regular back buffer).
+ gfx::Size GetBoundReadFrameBufferSize();
+
+ // Get the format of the currently bound frame buffer (either FBO or regular
+ // back buffer)
+ GLenum GetBoundReadFrameBufferInternalFormat();
+ GLenum GetBoundDrawFrameBufferInternalFormat();
+
+ // Wrapper for CompressedTexImage2D commands.
+ error::Error DoCompressedTexImage2D(
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLsizei image_size,
+ const void* data);
+
+ // Wrapper for CompressedTexSubImage2D.
+ void DoCompressedTexSubImage2D(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLsizei imageSize,
+ const void * data);
+
+ // Wrapper for CopyTexImage2D.
+ void DoCopyTexImage2D(
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border);
+
+ // Wrapper for SwapBuffers.
+ void DoSwapBuffers();
+
+ // Wrapper for CopyTexSubImage2D.
+ void DoCopyTexSubImage2D(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height);
+
+ // Validation for TexSubImage2D.
+ bool ValidateTexSubImage2D(
+ error::Error* error,
+ const char* function_name,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void * data);
+
+ // Wrapper for TexSubImage2D.
+ error::Error DoTexSubImage2D(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void * data);
+
+ // Extra validation for async tex(Sub)Image2D.
+ bool ValidateAsyncTransfer(
+ const char* function_name,
+ TextureRef* texture_ref,
+ GLenum target,
+ GLint level,
+ const void * data);
+
+ // Wrapper for TexImageIOSurface2DCHROMIUM.
+ void DoTexImageIOSurface2DCHROMIUM(
+ GLenum target,
+ GLsizei width,
+ GLsizei height,
+ GLuint io_surface_id,
+ GLuint plane);
+
+ void DoCopyTextureCHROMIUM(
+ GLenum target,
+ GLuint source_id,
+ GLuint target_id,
+ GLint level,
+ GLenum internal_format,
+ GLenum dest_type);
+
+ // Wrapper for TexStorage2DEXT.
+ void DoTexStorage2DEXT(
+ GLenum target,
+ GLint levels,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height);
+
+ void DoProduceTextureCHROMIUM(GLenum target, const GLbyte* key);
+ void DoConsumeTextureCHROMIUM(GLenum target, const GLbyte* key);
+
+ void DoBindTexImage2DCHROMIUM(
+ GLenum target,
+ GLint image_id);
+ void DoReleaseTexImage2DCHROMIUM(
+ GLenum target,
+ GLint image_id);
+
+ void DoTraceEndCHROMIUM(void);
+
+ void DoDrawBuffersEXT(GLsizei count, const GLenum* bufs);
+
+ // Creates a Program for the given program.
+ Program* CreateProgram(
+ GLuint client_id, GLuint service_id) {
+ return program_manager()->CreateProgram(client_id, service_id);
+ }
+
+ // Gets the program info for the given program. Returns NULL if none exists.
+ Program* GetProgram(GLuint client_id) {
+ return program_manager()->GetProgram(client_id);
+ }
+
+#if defined(NDEBUG)
+ void LogClientServiceMapping(
+ const char* /* function_name */,
+ GLuint /* client_id */,
+ GLuint /* service_id */) {
+ }
+ template<typename T>
+ void LogClientServiceForInfo(
+ T* /* info */, GLuint /* client_id */, const char* /* function_name */) {
+ }
+#else
+ void LogClientServiceMapping(
+ const char* function_name, GLuint client_id, GLuint service_id) {
+ if (service_logging_) {
+ DLOG(INFO) << "[" << logger_.GetLogPrefix() << "] " << function_name
+ << ": client_id = " << client_id
+ << ", service_id = " << service_id;
+ }
+ }
+ template<typename T>
+ void LogClientServiceForInfo(
+ T* info, GLuint client_id, const char* function_name) {
+ if (info) {
+ LogClientServiceMapping(function_name, client_id, info->service_id());
+ }
+ }
+#endif
+
+ // Gets the program info for the given program. If it's not a program
+ // generates a GL error. Returns NULL if not program.
+ Program* GetProgramInfoNotShader(
+ GLuint client_id, const char* function_name) {
+ Program* program = GetProgram(client_id);
+ if (!program) {
+ if (GetShader(client_id)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "shader passed for program");
+ } else {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "unknown program");
+ }
+ }
+ LogClientServiceForInfo(program, client_id, function_name);
+ return program;
+ }
+
+
+ // Creates a Shader for the given shader.
+ Shader* CreateShader(
+ GLuint client_id,
+ GLuint service_id,
+ GLenum shader_type) {
+ return shader_manager()->CreateShader(
+ client_id, service_id, shader_type);
+ }
+
+ // Gets the shader info for the given shader. Returns NULL if none exists.
+ Shader* GetShader(GLuint client_id) {
+ return shader_manager()->GetShader(client_id);
+ }
+
+ // Gets the shader info for the given shader. If it's not a shader generates a
+ // GL error. Returns NULL if not shader.
+ Shader* GetShaderInfoNotProgram(
+ GLuint client_id, const char* function_name) {
+ Shader* shader = GetShader(client_id);
+ if (!shader) {
+ if (GetProgram(client_id)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "program passed for shader");
+ } else {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, function_name, "unknown shader");
+ }
+ }
+ LogClientServiceForInfo(shader, client_id, function_name);
+ return shader;
+ }
+
+ // Creates a buffer info for the given buffer.
+ void CreateBuffer(GLuint client_id, GLuint service_id) {
+ return buffer_manager()->CreateBuffer(client_id, service_id);
+ }
+
+ // Gets the buffer info for the given buffer.
+ Buffer* GetBuffer(GLuint client_id) {
+ Buffer* buffer = buffer_manager()->GetBuffer(client_id);
+ return buffer;
+ }
+
+ // Removes any buffers in the VertexAtrribInfos and BufferInfos. This is used
+ // on glDeleteBuffers so we can make sure the user does not try to render
+ // with deleted buffers.
+ void RemoveBuffer(GLuint client_id);
+
+ // Creates a framebuffer info for the given framebuffer.
+ void CreateFramebuffer(GLuint client_id, GLuint service_id) {
+ return framebuffer_manager()->CreateFramebuffer(client_id, service_id);
+ }
+
+ // Gets the framebuffer info for the given framebuffer.
+ Framebuffer* GetFramebuffer(GLuint client_id) {
+ return framebuffer_manager()->GetFramebuffer(client_id);
+ }
+
+ // Removes the framebuffer info for the given framebuffer.
+ void RemoveFramebuffer(GLuint client_id) {
+ framebuffer_manager()->RemoveFramebuffer(client_id);
+ }
+
+ // Creates a renderbuffer info for the given renderbuffer.
+ void CreateRenderbuffer(GLuint client_id, GLuint service_id) {
+ return renderbuffer_manager()->CreateRenderbuffer(
+ client_id, service_id);
+ }
+
+ // Gets the renderbuffer info for the given renderbuffer.
+ Renderbuffer* GetRenderbuffer(GLuint client_id) {
+ return renderbuffer_manager()->GetRenderbuffer(client_id);
+ }
+
+ // Removes the renderbuffer info for the given renderbuffer.
+ void RemoveRenderbuffer(GLuint client_id) {
+ renderbuffer_manager()->RemoveRenderbuffer(client_id);
+ }
+
+ // Gets the vertex attrib manager for the given vertex array.
+ VertexAttribManager* GetVertexAttribManager(GLuint client_id) {
+ VertexAttribManager* info =
+ vertex_array_manager()->GetVertexAttribManager(client_id);
+ return info;
+ }
+
+ // Removes the vertex attrib manager for the given vertex array.
+ void RemoveVertexAttribManager(GLuint client_id) {
+ vertex_array_manager()->RemoveVertexAttribManager(client_id);
+ }
+
+ // Creates a vertex attrib manager for the given vertex array.
+ void CreateVertexAttribManager(GLuint client_id, GLuint service_id) {
+ return vertex_array_manager()->CreateVertexAttribManager(
+ client_id, service_id, group_->max_vertex_attribs());
+ }
+
+ void DoBindAttribLocation(GLuint client_id, GLuint index, const char* name);
+ void DoBindUniformLocationCHROMIUM(
+ GLuint client_id, GLint location, const char* name);
+
+ error::Error GetAttribLocationHelper(
+ GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
+ const std::string& name_str);
+
+ error::Error GetUniformLocationHelper(
+ GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
+ const std::string& name_str);
+
+ // Helper for glShaderSource.
+ error::Error ShaderSourceHelper(
+ GLuint client_id, const char* data, uint32 data_size);
+
+ // Clear any textures used by the current program.
+ bool ClearUnclearedTextures();
+
+ // Clear any uncleared level in texture.
+ // Returns false if there was a generated GL error.
+ bool ClearTexture(Texture* texture);
+
+ // Clears any uncleared attachments attached to the given frame buffer.
+ // Returns false if there was a generated GL error.
+ void ClearUnclearedAttachments(GLenum target, Framebuffer* framebuffer);
+
+ // overridden from GLES2Decoder
+ virtual bool ClearLevel(unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height,
+ bool is_texture_immutable) OVERRIDE;
+
+ // Restore all GL state that affects clearing.
+ void RestoreClearState();
+
+ // Remembers the state of some capabilities.
+ // Returns: true if glEnable/glDisable should actually be called.
+ bool SetCapabilityState(GLenum cap, bool enabled);
+
+ // Check that the currently bound framebuffers are valid.
+ // Generates GL error if not.
+ bool CheckBoundFramebuffersValid(const char* func_name);
+
+ // Check if a framebuffer meets our requirements.
+ bool CheckFramebufferValid(
+ Framebuffer* framebuffer,
+ GLenum target,
+ const char* func_name);
+
+ // Checks if the current program exists and is valid. If not generates the
+ // appropriate GL error. Returns true if the current program is in a usable
+ // state.
+ bool CheckCurrentProgram(const char* function_name);
+
+ // Checks if the current program exists and is valid and that location is not
+ // -1. If the current program is not valid generates the appropriate GL
+ // error. Returns true if the current program is in a usable state and
+ // location is not -1.
+ bool CheckCurrentProgramForUniform(GLint location, const char* function_name);
+
+ // Gets the type of a uniform for a location in the current program. Sets GL
+ // errors if the current program is not valid. Returns true if the current
+ // program is valid and the location exists. Adjusts count so it
+ // does not overflow the uniform.
+ bool PrepForSetUniformByLocation(
+ GLint fake_location, const char* function_name,
+ const BaseUniformInfo& base_info,
+ GLint* real_location, GLenum* type, GLsizei* count);
+
+ // Gets the service id for any simulated backbuffer fbo.
+ GLuint GetBackbufferServiceId() const;
+
+ // Helper for glGetBooleanv, glGetFloatv and glGetIntegerv
+ bool GetHelper(GLenum pname, GLint* params, GLsizei* num_written);
+
+ // Helper for glGetVertexAttrib
+ void GetVertexAttribHelper(
+ const VertexAttrib* attrib, GLenum pname, GLint* param);
+
+ // Wrapper for glCreateProgram
+ bool CreateProgramHelper(GLuint client_id);
+
+ // Wrapper for glCreateShader
+ bool CreateShaderHelper(GLenum type, GLuint client_id);
+
+ // Wrapper for glActiveTexture
+ void DoActiveTexture(GLenum texture_unit);
+
+ // Wrapper for glAttachShader
+ void DoAttachShader(GLuint client_program_id, GLint client_shader_id);
+
+ // Wrapper for glBindBuffer since we need to track the current targets.
+ void DoBindBuffer(GLenum target, GLuint buffer);
+
+ // Wrapper for glBindFramebuffer since we need to track the current targets.
+ void DoBindFramebuffer(GLenum target, GLuint framebuffer);
+
+ // Wrapper for glBindRenderbuffer since we need to track the current targets.
+ void DoBindRenderbuffer(GLenum target, GLuint renderbuffer);
+
+ // Wrapper for glBindTexture since we need to track the current targets.
+ void DoBindTexture(GLenum target, GLuint texture);
+
+ // Wrapper for glBindVertexArrayOES
+ void DoBindVertexArrayOES(GLuint array);
+ void EmulateVertexArrayState();
+
+ // Wrapper for glBlitFramebufferEXT.
+ void DoBlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter);
+
+ // Wrapper for glBufferSubData.
+ void DoBufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data);
+
+ // Wrapper for glCheckFramebufferStatus
+ GLenum DoCheckFramebufferStatus(GLenum target);
+
+ // Wrapper for glClear
+ error::Error DoClear(GLbitfield mask);
+
+ // Wrappers for various state.
+ void DoDepthRangef(GLclampf znear, GLclampf zfar);
+ void DoSampleCoverage(GLclampf value, GLboolean invert);
+
+ // Wrapper for glCompileShader.
+ void DoCompileShader(GLuint shader);
+
+ // Helper for DeleteSharedIdsCHROMIUM commands.
+ void DoDeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids);
+
+ // Wrapper for glDetachShader
+ void DoDetachShader(GLuint client_program_id, GLint client_shader_id);
+
+ // Wrapper for glDisable
+ void DoDisable(GLenum cap);
+
+ // Wrapper for glDisableVertexAttribArray.
+ void DoDisableVertexAttribArray(GLuint index);
+
+ // Wrapper for glDiscardFramebufferEXT, since we need to track undefined
+ // attachments.
+ void DoDiscardFramebufferEXT(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments);
+
+ // Wrapper for glEnable
+ void DoEnable(GLenum cap);
+
+ // Wrapper for glEnableVertexAttribArray.
+ void DoEnableVertexAttribArray(GLuint index);
+
+ // Wrapper for glFinish.
+ void DoFinish();
+
+ // Wrapper for glFlush.
+ void DoFlush();
+
+ // Wrapper for glFramebufferRenderbufffer.
+ void DoFramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint renderbuffer);
+
+ // Wrapper for glFramebufferTexture2D.
+ void DoFramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget, GLuint texture,
+ GLint level);
+
+ // Wrapper for glFramebufferTexture2DMultisampleEXT.
+ void DoFramebufferTexture2DMultisample(
+ GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture, GLint level, GLsizei samples);
+
+ // Common implementation for both DoFramebufferTexture2D wrappers.
+ void DoFramebufferTexture2DCommon(const char* name,
+ GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture, GLint level, GLsizei samples);
+
+ // Wrapper for glGenerateMipmap
+ void DoGenerateMipmap(GLenum target);
+
+ // Helper for GenSharedIdsCHROMIUM commands.
+ void DoGenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids);
+
+ // Helper for DoGetBooleanv, Floatv, and Intergerv to adjust pname
+ // to account for different pname values defined in different extension
+ // variants.
+ GLenum AdjustGetPname(GLenum pname);
+
+ // Wrapper for DoGetBooleanv.
+ void DoGetBooleanv(GLenum pname, GLboolean* params);
+
+ // Wrapper for DoGetFloatv.
+ void DoGetFloatv(GLenum pname, GLfloat* params);
+
+ // Wrapper for glGetFramebufferAttachmentParameteriv.
+ void DoGetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params);
+
+ // Wrapper for glGetIntegerv.
+ void DoGetIntegerv(GLenum pname, GLint* params);
+
+ // Gets the max value in a range in a buffer.
+ GLuint DoGetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset);
+
+ // Wrapper for glGetBufferParameteriv.
+ void DoGetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params);
+
+ // Wrapper for glGetProgramiv.
+ void DoGetProgramiv(
+ GLuint program_id, GLenum pname, GLint* params);
+
+ // Wrapper for glRenderbufferParameteriv.
+ void DoGetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params);
+
+ // Wrapper for glGetShaderiv
+ void DoGetShaderiv(GLuint shader, GLenum pname, GLint* params);
+
+ // Wrappers for glGetVertexAttrib.
+ void DoGetVertexAttribfv(GLuint index, GLenum pname, GLfloat *params);
+ void DoGetVertexAttribiv(GLuint index, GLenum pname, GLint *params);
+
+ // Wrappers for glIsXXX functions.
+ bool DoIsEnabled(GLenum cap);
+ bool DoIsBuffer(GLuint client_id);
+ bool DoIsFramebuffer(GLuint client_id);
+ bool DoIsProgram(GLuint client_id);
+ bool DoIsRenderbuffer(GLuint client_id);
+ bool DoIsShader(GLuint client_id);
+ bool DoIsTexture(GLuint client_id);
+ bool DoIsVertexArrayOES(GLuint client_id);
+
+ // Wrapper for glLinkProgram
+ void DoLinkProgram(GLuint program);
+
+ // Helper for RegisterSharedIdsCHROMIUM.
+ void DoRegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids);
+
+ // Wrapper for glRenderbufferStorage.
+ void DoRenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+
+ // Wrapper for glRenderbufferStorageMultisampleEXT.
+ void DoRenderbufferStorageMultisample(
+ GLenum target, GLsizei samples, GLenum internalformat,
+ GLsizei width, GLsizei height);
+
+ // Wrapper for glReleaseShaderCompiler.
+ void DoReleaseShaderCompiler() { }
+
+ // Wrappers for glTexParameter functions.
+ void DoTexParameterf(GLenum target, GLenum pname, GLfloat param);
+ void DoTexParameteri(GLenum target, GLenum pname, GLint param);
+ void DoTexParameterfv(GLenum target, GLenum pname, const GLfloat* params);
+ void DoTexParameteriv(GLenum target, GLenum pname, const GLint* params);
+
+ // Wrappers for glUniform1i and glUniform1iv as according to the GLES2
+ // spec only these 2 functions can be used to set sampler uniforms.
+ void DoUniform1i(GLint fake_location, GLint v0);
+ void DoUniform1iv(GLint fake_location, GLsizei count, const GLint* value);
+ void DoUniform2iv(GLint fake_location, GLsizei count, const GLint* value);
+ void DoUniform3iv(GLint fake_location, GLsizei count, const GLint* value);
+ void DoUniform4iv(GLint fake_location, GLsizei count, const GLint* value);
+
+ // Wrappers for glUniformfv because some drivers don't correctly accept
+ // bool uniforms.
+ void DoUniform1fv(GLint fake_location, GLsizei count, const GLfloat* value);
+ void DoUniform2fv(GLint fake_location, GLsizei count, const GLfloat* value);
+ void DoUniform3fv(GLint fake_location, GLsizei count, const GLfloat* value);
+ void DoUniform4fv(GLint fake_location, GLsizei count, const GLfloat* value);
+
+ void DoUniformMatrix2fv(
+ GLint fake_location, GLsizei count, GLboolean transpose,
+ const GLfloat* value);
+ void DoUniformMatrix3fv(
+ GLint fake_location, GLsizei count, GLboolean transpose,
+ const GLfloat* value);
+ void DoUniformMatrix4fv(
+ GLint fake_location, GLsizei count, GLboolean transpose,
+ const GLfloat* value);
+
+ bool SetVertexAttribValue(
+ const char* function_name, GLuint index, const GLfloat* value);
+
+ // Wrappers for glVertexAttrib??
+ void DoVertexAttrib1f(GLuint index, GLfloat v0);
+ void DoVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1);
+ void DoVertexAttrib3f(GLuint index, GLfloat v0, GLfloat v1, GLfloat v2);
+ void DoVertexAttrib4f(
+ GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+ void DoVertexAttrib1fv(GLuint index, const GLfloat *v);
+ void DoVertexAttrib2fv(GLuint index, const GLfloat *v);
+ void DoVertexAttrib3fv(GLuint index, const GLfloat *v);
+ void DoVertexAttrib4fv(GLuint index, const GLfloat *v);
+
+ // Wrapper for glViewport
+ void DoViewport(GLint x, GLint y, GLsizei width, GLsizei height);
+
+ // Wrapper for glUseProgram
+ void DoUseProgram(GLuint program);
+
+ // Wrapper for glValidateProgram.
+ void DoValidateProgram(GLuint program_client_id);
+
+ void DoInsertEventMarkerEXT(GLsizei length, const GLchar* marker);
+ void DoPushGroupMarkerEXT(GLsizei length, const GLchar* group);
+ void DoPopGroupMarkerEXT(void);
+
+ // Gets the number of values that will be returned by glGetXXX. Returns
+ // false if pname is unknown.
+ bool GetNumValuesReturnedForGLGet(GLenum pname, GLsizei* num_values);
+
+ // Checks if the current program and vertex attributes are valid for drawing.
+ bool IsDrawValid(
+ const char* function_name, GLuint max_vertex_accessed, GLsizei primcount);
+
+ // Returns true if successful, simulated will be true if attrib0 was
+ // simulated.
+ bool SimulateAttrib0(
+ const char* function_name, GLuint max_vertex_accessed, bool* simulated);
+ void RestoreStateForAttrib(GLuint attrib);
+
+ // If texture is a stream texture, this will update the stream to the newest
+ // buffer.
+ void UpdateStreamTextureIfNeeded(Texture* texture);
+
+ // Returns false if unrenderable textures were replaced.
+ bool PrepareTexturesForRender();
+ void RestoreStateForNonRenderableTextures();
+
+ // Returns true if GL_FIXED attribs were simulated.
+ bool SimulateFixedAttribs(
+ const char* function_name,
+ GLuint max_vertex_accessed, bool* simulated, GLsizei primcount);
+ void RestoreStateForSimulatedFixedAttribs();
+
+ // Handle DrawArrays and DrawElements for both instanced and non-instanced
+ // cases (primcount is 0 for non-instanced).
+ error::Error DoDrawArrays(
+ const char* function_name,
+ bool instanced, GLenum mode, GLint first, GLsizei count,
+ GLsizei primcount);
+ error::Error DoDrawElements(
+ const char* function_name,
+ bool instanced, GLenum mode, GLsizei count, GLenum type,
+ int32 offset, GLsizei primcount);
+
+ GLenum GetBindTargetForSamplerType(GLenum type) {
+ DCHECK(type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE ||
+ type == GL_SAMPLER_EXTERNAL_OES || type == GL_SAMPLER_2D_RECT_ARB);
+ switch (type) {
+ case GL_SAMPLER_2D:
+ return GL_TEXTURE_2D;
+ case GL_SAMPLER_CUBE:
+ return GL_TEXTURE_CUBE_MAP;
+ case GL_SAMPLER_EXTERNAL_OES:
+ return GL_TEXTURE_EXTERNAL_OES;
+ case GL_SAMPLER_2D_RECT_ARB:
+ return GL_TEXTURE_RECTANGLE_ARB;
+ }
+
+ NOTREACHED();
+ return 0;
+ }
+
+ // Gets the framebuffer info for a particular target.
+ Framebuffer* GetFramebufferInfoForTarget(GLenum target) {
+ Framebuffer* framebuffer = NULL;
+ switch (target) {
+ case GL_FRAMEBUFFER:
+ case GL_DRAW_FRAMEBUFFER_EXT:
+ framebuffer = state_.bound_draw_framebuffer.get();
+ break;
+ case GL_READ_FRAMEBUFFER_EXT:
+ framebuffer = state_.bound_read_framebuffer.get();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return framebuffer;
+ }
+
+ Renderbuffer* GetRenderbufferInfoForTarget(
+ GLenum target) {
+ Renderbuffer* renderbuffer = NULL;
+ switch (target) {
+ case GL_RENDERBUFFER:
+ renderbuffer = state_.bound_renderbuffer.get();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ return renderbuffer;
+ }
+
+ // Validates the program and location for a glGetUniform call and returns
+ // a SizeResult setup to receive the result. Returns true if glGetUniform
+ // should be called.
+ bool GetUniformSetup(
+ GLuint program, GLint fake_location,
+ uint32 shm_id, uint32 shm_offset,
+ error::Error* error, GLint* real_location, GLuint* service_id,
+ void** result, GLenum* result_type);
+
+ // Computes the estimated memory used for the backbuffer and passes it to
+ // the tracing system.
+ size_t GetBackbufferMemoryTotal();
+
+ virtual bool WasContextLost() OVERRIDE;
+ virtual bool WasContextLostByRobustnessExtension() OVERRIDE;
+ virtual void LoseContext(uint32 reset_status) OVERRIDE;
+
+#if defined(OS_MACOSX)
+ void ReleaseIOSurfaceForTexture(GLuint texture_id);
+#endif
+
+ // Validates the combination of texture parameters. For example validates that
+ // for a given format the specific type, level and targets are valid.
+ // Synthesizes the correct GL error if invalid. Returns true if valid.
+ bool ValidateTextureParameters(
+ const char* function_name,
+ GLenum target, GLenum format, GLenum type, GLint level);
+
+ bool ValidateCompressedTexDimensions(
+ const char* function_name,
+ GLint level, GLsizei width, GLsizei height, GLenum format);
+ bool ValidateCompressedTexFuncData(
+ const char* function_name,
+ GLsizei width, GLsizei height, GLenum format, size_t size);
+ bool ValidateCompressedTexSubDimensions(
+ const char* function_name,
+ GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format,
+ Texture* texture);
+
+ void RenderWarning(const char* filename, int line, const std::string& msg);
+ void PerformanceWarning(
+ const char* filename, int line, const std::string& msg);
+
+ const FeatureInfo::FeatureFlags& features() const {
+ return feature_info_->feature_flags();
+ }
+
+ const FeatureInfo::Workarounds& workarounds() const {
+ return feature_info_->workarounds();
+ }
+
+ bool ShouldDeferDraws() {
+ return !offscreen_target_frame_buffer_.get() &&
+ state_.bound_draw_framebuffer.get() == NULL &&
+ surface_->DeferDraws();
+ }
+
+ bool ShouldDeferReads() {
+ return !offscreen_target_frame_buffer_.get() &&
+ state_.bound_read_framebuffer.get() == NULL &&
+ surface_->DeferDraws();
+ }
+
+ void ProcessPendingReadPixels();
+ void FinishReadPixels(const cmds::ReadPixels& c, GLuint buffer);
+
+ // Generate a member function prototype for each command in an automated and
+ // typesafe way.
+ #define GLES2_CMD_OP(name) \
+ Error Handle ## name( \
+ uint32 immediate_data_size, \
+ const cmds::name& args); \
+
+ GLES2_COMMAND_LIST(GLES2_CMD_OP)
+
+ #undef GLES2_CMD_OP
+
+ // The GL context this decoder renders to on behalf of the client.
+ scoped_refptr<gfx::GLSurface> surface_;
+ scoped_refptr<gfx::GLContext> context_;
+
+ // The ContextGroup for this decoder uses to track resources.
+ scoped_refptr<ContextGroup> group_;
+
+ DebugMarkerManager debug_marker_manager_;
+ Logger logger_;
+
+ // All the state for this context.
+ ContextState state_;
+
+ // Current width and height of the offscreen frame buffer.
+ gfx::Size offscreen_size_;
+
+ // Util to help with GL.
+ GLES2Util util_;
+
+ // unpack flip y as last set by glPixelStorei
+ bool unpack_flip_y_;
+
+ // unpack (un)premultiply alpha as last set by glPixelStorei
+ bool unpack_premultiply_alpha_;
+ bool unpack_unpremultiply_alpha_;
+
+ // Default vertex attribs manager, used when no VAOs are bound.
+ scoped_refptr<VertexAttribManager> default_vertex_attrib_manager_;
+
+ // The buffer we bind to attrib 0 since OpenGL requires it (ES does not).
+ GLuint attrib_0_buffer_id_;
+
+ // The value currently in attrib_0.
+ Vec4 attrib_0_value_;
+
+ // Whether or not the attrib_0 buffer holds the attrib_0_value.
+ bool attrib_0_buffer_matches_value_;
+
+ // The size of attrib 0.
+ GLsizei attrib_0_size_;
+
+ // The buffer used to simulate GL_FIXED attribs.
+ GLuint fixed_attrib_buffer_id_;
+
+ // The size of fiixed attrib buffer.
+ GLsizei fixed_attrib_buffer_size_;
+
+ // The offscreen frame buffer that the client renders to. With EGL, the
+ // depth and stencil buffers are separate. With regular GL there is a single
+ // packed depth stencil buffer in offscreen_target_depth_render_buffer_.
+ // offscreen_target_stencil_render_buffer_ is unused.
+ scoped_ptr<BackFramebuffer> offscreen_target_frame_buffer_;
+ scoped_ptr<BackTexture> offscreen_target_color_texture_;
+ scoped_ptr<BackRenderbuffer> offscreen_target_color_render_buffer_;
+ scoped_ptr<BackRenderbuffer> offscreen_target_depth_render_buffer_;
+ scoped_ptr<BackRenderbuffer> offscreen_target_stencil_render_buffer_;
+ GLenum offscreen_target_color_format_;
+ GLenum offscreen_target_depth_format_;
+ GLenum offscreen_target_stencil_format_;
+ GLsizei offscreen_target_samples_;
+ GLboolean offscreen_target_buffer_preserved_;
+
+ // The copy that is saved when SwapBuffers is called.
+ scoped_ptr<BackFramebuffer> offscreen_saved_frame_buffer_;
+ scoped_ptr<BackTexture> offscreen_saved_color_texture_;
+ scoped_refptr<TextureRef>
+ offscreen_saved_color_texture_info_;
+
+ // The copy that is used as the destination for multi-sample resolves.
+ scoped_ptr<BackFramebuffer> offscreen_resolved_frame_buffer_;
+ scoped_ptr<BackTexture> offscreen_resolved_color_texture_;
+ GLenum offscreen_saved_color_format_;
+
+ scoped_ptr<QueryManager> query_manager_;
+
+ scoped_ptr<VertexArrayManager> vertex_array_manager_;
+
+ base::Callback<void(gfx::Size, float)> resize_callback_;
+
+ WaitSyncPointCallback wait_sync_point_callback_;
+
+ ShaderCacheCallback shader_cache_callback_;
+
+ scoped_ptr<AsyncPixelTransferManager> async_pixel_transfer_manager_;
+
+ // The format of the back buffer_
+ GLenum back_buffer_color_format_;
+ bool back_buffer_has_depth_;
+ bool back_buffer_has_stencil_;
+
+ // Backbuffer attachments that are currently undefined.
+ uint32 backbuffer_needs_clear_bits_;
+
+ // The current decoder error.
+ error::Error current_decoder_error_;
+
+ bool use_shader_translator_;
+ scoped_refptr<ShaderTranslator> vertex_translator_;
+ scoped_refptr<ShaderTranslator> fragment_translator_;
+
+ DisallowedFeatures disallowed_features_;
+
+ // Cached from ContextGroup
+ const Validators* validators_;
+ scoped_refptr<FeatureInfo> feature_info_;
+
+ int frame_number_;
+
+ bool has_robustness_extension_;
+ GLenum reset_status_;
+ bool reset_by_robustness_extension_;
+
+ // These flags are used to override the state of the shared feature_info_
+ // member. Because the same FeatureInfo instance may be shared among many
+ // contexts, the assumptions on the availablity of extensions in WebGL
+ // contexts may be broken. These flags override the shared state to preserve
+ // WebGL semantics.
+ bool force_webgl_glsl_validation_;
+ bool derivatives_explicitly_enabled_;
+ bool frag_depth_explicitly_enabled_;
+ bool draw_buffers_explicitly_enabled_;
+
+ bool compile_shader_always_succeeds_;
+
+ // Log extra info.
+ bool service_logging_;
+
+#if defined(OS_MACOSX)
+ typedef std::map<GLuint, CFTypeRef> TextureToIOSurfaceMap;
+ TextureToIOSurfaceMap texture_to_io_surface_map_;
+#endif
+
+ scoped_ptr<CopyTextureCHROMIUMResourceManager> copy_texture_CHROMIUM_;
+
+ // Cached values of the currently assigned viewport dimensions.
+ GLsizei viewport_max_width_;
+ GLsizei viewport_max_height_;
+
+ // Command buffer stats.
+ base::TimeDelta total_processing_commands_time_;
+
+ // States related to each manager.
+ DecoderTextureState texture_state_;
+ DecoderFramebufferState framebuffer_state_;
+
+ scoped_ptr<GPUTracer> gpu_tracer_;
+
+ std::queue<linked_ptr<FenceCallback> > pending_readpixel_fences_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLES2DecoderImpl);
+};
+
+ScopedGLErrorSuppressor::ScopedGLErrorSuppressor(
+ const char* function_name, GLES2DecoderImpl* decoder)
+ : function_name_(function_name),
+ decoder_(decoder) {
+ ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(decoder_->GetErrorState(),
+ function_name_);
+}
+
+ScopedGLErrorSuppressor::~ScopedGLErrorSuppressor() {
+ ERRORSTATE_CLEAR_REAL_GL_ERRORS(decoder_->GetErrorState(), function_name_);
+}
+
+ScopedTexture2DBinder::ScopedTexture2DBinder(GLES2DecoderImpl* decoder,
+ GLuint id)
+ : decoder_(decoder) {
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedTexture2DBinder::ctor", decoder_);
+
+ // TODO(apatrick): Check if there are any other states that need to be reset
+ // before binding a new texture.
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, id);
+}
+
+ScopedTexture2DBinder::~ScopedTexture2DBinder() {
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedTexture2DBinder::dtor", decoder_);
+ decoder_->RestoreCurrentTexture2DBindings();
+}
+
+ScopedRenderBufferBinder::ScopedRenderBufferBinder(GLES2DecoderImpl* decoder,
+ GLuint id)
+ : decoder_(decoder) {
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedRenderBufferBinder::ctor", decoder_);
+ glBindRenderbufferEXT(GL_RENDERBUFFER, id);
+}
+
+ScopedRenderBufferBinder::~ScopedRenderBufferBinder() {
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedRenderBufferBinder::dtor", decoder_);
+ decoder_->RestoreCurrentRenderbufferBindings();
+}
+
+ScopedFrameBufferBinder::ScopedFrameBufferBinder(GLES2DecoderImpl* decoder,
+ GLuint id)
+ : decoder_(decoder) {
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedFrameBufferBinder::ctor", decoder_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER, id);
+ decoder->OnFboChanged();
+}
+
+ScopedFrameBufferBinder::~ScopedFrameBufferBinder() {
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedFrameBufferBinder::dtor", decoder_);
+ decoder_->RestoreCurrentFramebufferBindings();
+}
+
+ScopedResolvedFrameBufferBinder::ScopedResolvedFrameBufferBinder(
+ GLES2DecoderImpl* decoder, bool enforce_internal_framebuffer, bool internal)
+ : decoder_(decoder) {
+ resolve_and_bind_ = (decoder_->offscreen_target_frame_buffer_.get() &&
+ decoder_->IsOffscreenBufferMultisampled() &&
+ (!decoder_->state_.bound_read_framebuffer.get() ||
+ enforce_internal_framebuffer));
+ if (!resolve_and_bind_)
+ return;
+
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedResolvedFrameBufferBinder::ctor", decoder_);
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT,
+ decoder_->offscreen_target_frame_buffer_->id());
+ GLuint targetid;
+ if (internal) {
+ if (!decoder_->offscreen_resolved_frame_buffer_.get()) {
+ decoder_->offscreen_resolved_frame_buffer_.reset(
+ new BackFramebuffer(decoder_));
+ decoder_->offscreen_resolved_frame_buffer_->Create();
+ decoder_->offscreen_resolved_color_texture_.reset(
+ new BackTexture(decoder_));
+ decoder_->offscreen_resolved_color_texture_->Create();
+
+ DCHECK(decoder_->offscreen_saved_color_format_);
+ decoder_->offscreen_resolved_color_texture_->AllocateStorage(
+ decoder_->offscreen_size_, decoder_->offscreen_saved_color_format_,
+ false);
+ decoder_->offscreen_resolved_frame_buffer_->AttachRenderTexture(
+ decoder_->offscreen_resolved_color_texture_.get());
+ if (decoder_->offscreen_resolved_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "ScopedResolvedFrameBufferBinder failed "
+ << "because offscreen resolved FBO was incomplete.";
+ return;
+ }
+ }
+ targetid = decoder_->offscreen_resolved_frame_buffer_->id();
+ } else {
+ targetid = decoder_->offscreen_saved_frame_buffer_->id();
+ }
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, targetid);
+ const int width = decoder_->offscreen_size_.width();
+ const int height = decoder_->offscreen_size_.height();
+ glDisable(GL_SCISSOR_TEST);
+ if (GLES2Decoder::IsAngle()) {
+ glBlitFramebufferANGLE(0, 0, width, height, 0, 0, width, height,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ } else {
+ glBlitFramebufferEXT(0, 0, width, height, 0, 0, width, height,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+ }
+ glBindFramebufferEXT(GL_FRAMEBUFFER, targetid);
+}
+
+ScopedResolvedFrameBufferBinder::~ScopedResolvedFrameBufferBinder() {
+ if (!resolve_and_bind_)
+ return;
+
+ ScopedGLErrorSuppressor suppressor(
+ "ScopedResolvedFrameBufferBinder::dtor", decoder_);
+ decoder_->RestoreCurrentFramebufferBindings();
+ if (decoder_->state_.enable_flags.scissor_test) {
+ glEnable(GL_SCISSOR_TEST);
+ }
+}
+
+BackTexture::BackTexture(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged),
+ bytes_allocated_(0),
+ id_(0) {
+}
+
+BackTexture::~BackTexture() {
+ // This does not destroy the render texture because that would require that
+ // the associated GL context was current. Just check that it was explicitly
+ // destroyed.
+ DCHECK_EQ(id_, 0u);
+}
+
+void BackTexture::Create() {
+ ScopedGLErrorSuppressor suppressor("BackTexture::Create", decoder_);
+ Destroy();
+ glGenTextures(1, &id_);
+ ScopedTexture2DBinder binder(decoder_, id_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ // TODO(apatrick): Attempt to diagnose crbug.com/97775. If SwapBuffers is
+ // never called on an offscreen context, no data will ever be uploaded to the
+ // saved offscreen color texture (it is deferred until to when SwapBuffers
+ // is called). My idea is that some nvidia drivers might have a bug where
+ // deleting a texture that has never been populated might cause a
+ // crash.
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ bytes_allocated_ = 16u * 16u * 4u;
+ memory_tracker_.TrackMemAlloc(bytes_allocated_);
+}
+
+bool BackTexture::AllocateStorage(
+ const gfx::Size& size, GLenum format, bool zero) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor("BackTexture::AllocateStorage", decoder_);
+ ScopedTexture2DBinder binder(decoder_, id_);
+ uint32 image_size = 0;
+ GLES2Util::ComputeImageDataSizes(
+ size.width(), size.height(), format, GL_UNSIGNED_BYTE, 8, &image_size,
+ NULL, NULL);
+
+ if (!memory_tracker_.EnsureGPUMemoryAvailable(image_size)) {
+ return false;
+ }
+
+ scoped_ptr<char[]> zero_data;
+ if (zero) {
+ zero_data.reset(new char[image_size]);
+ memset(zero_data.get(), 0, image_size);
+ }
+
+ glTexImage2D(GL_TEXTURE_2D,
+ 0, // mip level
+ format,
+ size.width(),
+ size.height(),
+ 0, // border
+ format,
+ GL_UNSIGNED_BYTE,
+ zero_data.get());
+
+ size_ = size;
+
+ bool success = glGetError() == GL_NO_ERROR;
+ if (success) {
+ memory_tracker_.TrackMemFree(bytes_allocated_);
+ bytes_allocated_ = image_size;
+ memory_tracker_.TrackMemAlloc(bytes_allocated_);
+ }
+ return success;
+}
+
+void BackTexture::Copy(const gfx::Size& size, GLenum format) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor("BackTexture::Copy", decoder_);
+ ScopedTexture2DBinder binder(decoder_, id_);
+ glCopyTexImage2D(GL_TEXTURE_2D,
+ 0, // level
+ format,
+ 0, 0,
+ size.width(),
+ size.height(),
+ 0); // border
+}
+
+void BackTexture::Destroy() {
+ if (id_ != 0) {
+ ScopedGLErrorSuppressor suppressor("BackTexture::Destroy", decoder_);
+ glDeleteTextures(1, &id_);
+ id_ = 0;
+ }
+ memory_tracker_.TrackMemFree(bytes_allocated_);
+ bytes_allocated_ = 0;
+}
+
+void BackTexture::Invalidate() {
+ id_ = 0;
+}
+
+BackRenderbuffer::BackRenderbuffer(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ memory_tracker_(decoder->memory_tracker(), MemoryTracker::kUnmanaged),
+ bytes_allocated_(0),
+ id_(0) {
+}
+
+BackRenderbuffer::~BackRenderbuffer() {
+ // This does not destroy the render buffer because that would require that
+ // the associated GL context was current. Just check that it was explicitly
+ // destroyed.
+ DCHECK_EQ(id_, 0u);
+}
+
+void BackRenderbuffer::Create() {
+ ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Create", decoder_);
+ Destroy();
+ glGenRenderbuffersEXT(1, &id_);
+}
+
+bool BackRenderbuffer::AllocateStorage(const gfx::Size& size, GLenum format,
+ GLsizei samples) {
+ ScopedGLErrorSuppressor suppressor(
+ "BackRenderbuffer::AllocateStorage", decoder_);
+ ScopedRenderBufferBinder binder(decoder_, id_);
+
+ uint32 estimated_size = 0;
+ if (!RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ size.width(), size.height(), samples, format, &estimated_size)) {
+ return false;
+ }
+
+ if (!memory_tracker_.EnsureGPUMemoryAvailable(estimated_size)) {
+ return false;
+ }
+
+ if (samples <= 1) {
+ glRenderbufferStorageEXT(GL_RENDERBUFFER,
+ format,
+ size.width(),
+ size.height());
+ } else {
+ if (GLES2Decoder::IsAngle()) {
+ glRenderbufferStorageMultisampleANGLE(GL_RENDERBUFFER,
+ samples,
+ format,
+ size.width(),
+ size.height());
+ } else {
+ glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER,
+ samples,
+ format,
+ size.width(),
+ size.height());
+ }
+ }
+ bool success = glGetError() == GL_NO_ERROR;
+ if (success) {
+ memory_tracker_.TrackMemFree(bytes_allocated_);
+ bytes_allocated_ = estimated_size;
+ memory_tracker_.TrackMemAlloc(bytes_allocated_);
+ }
+ return success;
+}
+
+void BackRenderbuffer::Destroy() {
+ if (id_ != 0) {
+ ScopedGLErrorSuppressor suppressor("BackRenderbuffer::Destroy", decoder_);
+ glDeleteRenderbuffersEXT(1, &id_);
+ id_ = 0;
+ }
+ memory_tracker_.TrackMemFree(bytes_allocated_);
+ bytes_allocated_ = 0;
+}
+
+void BackRenderbuffer::Invalidate() {
+ id_ = 0;
+}
+
+BackFramebuffer::BackFramebuffer(GLES2DecoderImpl* decoder)
+ : decoder_(decoder),
+ id_(0) {
+}
+
+BackFramebuffer::~BackFramebuffer() {
+ // This does not destroy the frame buffer because that would require that
+ // the associated GL context was current. Just check that it was explicitly
+ // destroyed.
+ DCHECK_EQ(id_, 0u);
+}
+
+void BackFramebuffer::Create() {
+ ScopedGLErrorSuppressor suppressor("BackFramebuffer::Create", decoder_);
+ Destroy();
+ glGenFramebuffersEXT(1, &id_);
+}
+
+void BackFramebuffer::AttachRenderTexture(BackTexture* texture) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(
+ "BackFramebuffer::AttachRenderTexture", decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ GLuint attach_id = texture ? texture->id() : 0;
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER,
+ GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D,
+ attach_id,
+ 0);
+}
+
+void BackFramebuffer::AttachRenderBuffer(GLenum target,
+ BackRenderbuffer* render_buffer) {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor(
+ "BackFramebuffer::AttachRenderBuffer", decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ GLuint attach_id = render_buffer ? render_buffer->id() : 0;
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER,
+ target,
+ GL_RENDERBUFFER,
+ attach_id);
+}
+
+void BackFramebuffer::Destroy() {
+ if (id_ != 0) {
+ ScopedGLErrorSuppressor suppressor("BackFramebuffer::Destroy", decoder_);
+ glDeleteFramebuffersEXT(1, &id_);
+ id_ = 0;
+ }
+}
+
+void BackFramebuffer::Invalidate() {
+ id_ = 0;
+}
+
+GLenum BackFramebuffer::CheckStatus() {
+ DCHECK_NE(id_, 0u);
+ ScopedGLErrorSuppressor suppressor("BackFramebuffer::CheckStatus", decoder_);
+ ScopedFrameBufferBinder binder(decoder_, id_);
+ return glCheckFramebufferStatusEXT(GL_FRAMEBUFFER);
+}
+
+GLES2Decoder* GLES2Decoder::Create(ContextGroup* group) {
+ return new GLES2DecoderImpl(group);
+}
+
+GLES2DecoderImpl::GLES2DecoderImpl(ContextGroup* group)
+ : GLES2Decoder(),
+ group_(group),
+ logger_(&debug_marker_manager_),
+ state_(group_->feature_info(), &logger_),
+ unpack_flip_y_(false),
+ unpack_premultiply_alpha_(false),
+ unpack_unpremultiply_alpha_(false),
+ attrib_0_buffer_id_(0),
+ attrib_0_buffer_matches_value_(true),
+ attrib_0_size_(0),
+ fixed_attrib_buffer_id_(0),
+ fixed_attrib_buffer_size_(0),
+ offscreen_target_color_format_(0),
+ offscreen_target_depth_format_(0),
+ offscreen_target_stencil_format_(0),
+ offscreen_target_samples_(0),
+ offscreen_target_buffer_preserved_(true),
+ offscreen_saved_color_format_(0),
+ back_buffer_color_format_(0),
+ back_buffer_has_depth_(false),
+ back_buffer_has_stencil_(false),
+ backbuffer_needs_clear_bits_(0),
+ current_decoder_error_(error::kNoError),
+ use_shader_translator_(true),
+ validators_(group_->feature_info()->validators()),
+ feature_info_(group_->feature_info()),
+ frame_number_(0),
+ has_robustness_extension_(false),
+ reset_status_(GL_NO_ERROR),
+ reset_by_robustness_extension_(false),
+ force_webgl_glsl_validation_(false),
+ derivatives_explicitly_enabled_(false),
+ frag_depth_explicitly_enabled_(false),
+ draw_buffers_explicitly_enabled_(false),
+ compile_shader_always_succeeds_(false),
+ service_logging_(CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUServiceLoggingGPU)),
+ viewport_max_width_(0),
+ viewport_max_height_(0) {
+ DCHECK(group);
+
+ attrib_0_value_.v[0] = 0.0f;
+ attrib_0_value_.v[1] = 0.0f;
+ attrib_0_value_.v[2] = 0.0f;
+ attrib_0_value_.v[3] = 1.0f;
+
+ // The shader translator is used for WebGL even when running on EGL
+ // because additional restrictions are needed (like only enabling
+ // GL_OES_standard_derivatives on demand). It is used for the unit
+ // tests because GLES2DecoderWithShaderTest.GetShaderInfoLogValidArgs passes
+ // the empty string to CompileShader and this is not a valid shader.
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationMockGL ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGLSLTranslator)) {
+ use_shader_translator_ = false;
+ }
+
+ // TODO(gman): Consider setting this based on GPU and/or driver.
+ if (IsAngle()) {
+ texture_state_.teximage2d_faster_than_texsubimage2d = false;
+ }
+}
+
+GLES2DecoderImpl::~GLES2DecoderImpl() {
+}
+
+bool GLES2DecoderImpl::Initialize(
+ const scoped_refptr<gfx::GLSurface>& surface,
+ const scoped_refptr<gfx::GLContext>& context,
+ bool offscreen,
+ const gfx::Size& size,
+ const DisallowedFeatures& disallowed_features,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::Initialize");
+ DCHECK(context->IsCurrent(surface.get()));
+ DCHECK(!context_.get());
+
+ set_initialized();
+ gpu_tracer_ = GPUTracer::Create();
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUDebugging)) {
+ set_debug(true);
+ }
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUCommandLogging)) {
+ set_log_commands(true);
+ }
+
+ compile_shader_always_succeeds_ = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kCompileShaderAlwaysSucceeds);
+
+
+ // Take ownership of the context and surface. The surface can be replaced with
+ // SetSurface.
+ context_ = context;
+ surface_ = surface;
+
+ if (!group_->Initialize(this, disallowed_features, allowed_extensions)) {
+ LOG(ERROR) << "GpuScheduler::InitializeCommon failed because group "
+ << "failed to initialize.";
+ group_ = NULL; // Must not destroy ContextGroup if it is not initialized.
+ Destroy(true);
+ return false;
+ }
+ CHECK_GL_ERROR();
+
+ disallowed_features_ = disallowed_features;
+
+ state_.attrib_values.resize(group_->max_vertex_attribs());
+ default_vertex_attrib_manager_ = new VertexAttribManager();
+ default_vertex_attrib_manager_->Initialize(group_->max_vertex_attribs());
+
+ // vertex_attrib_manager is set to default_vertex_attrib_manager_ by this call
+ DoBindVertexArrayOES(0);
+
+ query_manager_.reset(new QueryManager(this, feature_info_.get()));
+ vertex_array_manager_.reset(new VertexArrayManager());
+
+ util_.set_num_compressed_texture_formats(
+ validators_->compressed_texture_format.GetValues().size());
+
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
+ // We have to enable vertex array 0 on OpenGL or it won't render. Note that
+ // OpenGL ES 2.0 does not have this issue.
+ glEnableVertexAttribArray(0);
+ }
+ glGenBuffersARB(1, &attrib_0_buffer_id_);
+ glBindBuffer(GL_ARRAY_BUFFER, attrib_0_buffer_id_);
+ glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glGenBuffersARB(1, &fixed_attrib_buffer_id_);
+
+ state_.texture_units.resize(group_->max_texture_units());
+ for (uint32 tt = 0; tt < state_.texture_units.size(); ++tt) {
+ glActiveTexture(GL_TEXTURE0 + tt);
+ // We want the last bind to be 2D.
+ TextureRef* ref;
+ if (features().oes_egl_image_external) {
+ ref = texture_manager()->GetDefaultTextureInfo(
+ GL_TEXTURE_EXTERNAL_OES);
+ state_.texture_units[tt].bound_texture_external_oes = ref;
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, ref->service_id());
+ }
+ if (features().arb_texture_rectangle) {
+ ref = texture_manager()->GetDefaultTextureInfo(
+ GL_TEXTURE_RECTANGLE_ARB);
+ state_.texture_units[tt].bound_texture_rectangle_arb = ref;
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ref->service_id());
+ }
+ ref = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_CUBE_MAP);
+ state_.texture_units[tt].bound_texture_cube_map = ref;
+ glBindTexture(GL_TEXTURE_CUBE_MAP, ref->service_id());
+ ref = texture_manager()->GetDefaultTextureInfo(GL_TEXTURE_2D);
+ state_.texture_units[tt].bound_texture_2d = ref;
+ glBindTexture(GL_TEXTURE_2D, ref->service_id());
+ }
+ glActiveTexture(GL_TEXTURE0);
+ CHECK_GL_ERROR();
+
+ ContextCreationAttribParser attrib_parser;
+ if (!attrib_parser.Parse(attribs))
+ return false;
+
+ if (offscreen) {
+ if (attrib_parser.samples_ > 0 && attrib_parser.sample_buffers_ > 0 &&
+ features().chromium_framebuffer_multisample) {
+ // Per ext_framebuffer_multisample spec, need max bound on sample count.
+ // max_sample_count must be initialized to a sane value. If
+ // glGetIntegerv() throws a GL error, it leaves its argument unchanged.
+ GLint max_sample_count = 1;
+ glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_sample_count);
+ offscreen_target_samples_ = std::min(attrib_parser.samples_,
+ max_sample_count);
+ } else {
+ offscreen_target_samples_ = 1;
+ }
+ offscreen_target_buffer_preserved_ = attrib_parser.buffer_preserved_;
+
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ const bool rgb8_supported =
+ context_->HasExtension("GL_OES_rgb8_rgba8");
+ // The only available default render buffer formats in GLES2 have very
+ // little precision. Don't enable multisampling unless 8-bit render
+ // buffer formats are available--instead fall back to 8-bit textures.
+ if (rgb8_supported && offscreen_target_samples_ > 1) {
+ offscreen_target_color_format_ = attrib_parser.alpha_size_ > 0 ?
+ GL_RGBA8 : GL_RGB8;
+ } else {
+ offscreen_target_samples_ = 1;
+ offscreen_target_color_format_ = attrib_parser.alpha_size_ > 0 ?
+ GL_RGBA : GL_RGB;
+ }
+
+ // ANGLE only supports packed depth/stencil formats, so use it if it is
+ // available.
+ const bool depth24_stencil8_supported =
+ context_->HasExtension("GL_OES_packed_depth_stencil");
+ VLOG(1) << "GL_OES_packed_depth_stencil "
+ << (depth24_stencil8_supported ? "" : "not ") << "supported.";
+ if ((attrib_parser.depth_size_ > 0 || attrib_parser.stencil_size_ > 0) &&
+ depth24_stencil8_supported) {
+ offscreen_target_depth_format_ = GL_DEPTH24_STENCIL8;
+ offscreen_target_stencil_format_ = 0;
+ } else {
+ // It may be the case that this depth/stencil combination is not
+ // supported, but this will be checked later by CheckFramebufferStatus.
+ offscreen_target_depth_format_ = attrib_parser.depth_size_ > 0 ?
+ GL_DEPTH_COMPONENT16 : 0;
+ offscreen_target_stencil_format_ = attrib_parser.stencil_size_ > 0 ?
+ GL_STENCIL_INDEX8 : 0;
+ }
+ } else {
+ offscreen_target_color_format_ = attrib_parser.alpha_size_ > 0 ?
+ GL_RGBA : GL_RGB;
+
+ // If depth is requested at all, use the packed depth stencil format if
+ // it's available, as some desktop GL drivers don't support any non-packed
+ // formats for depth attachments.
+ const bool depth24_stencil8_supported =
+ context_->HasExtension("GL_EXT_packed_depth_stencil");
+ VLOG(1) << "GL_EXT_packed_depth_stencil "
+ << (depth24_stencil8_supported ? "" : "not ") << "supported.";
+
+ if ((attrib_parser.depth_size_ > 0 || attrib_parser.stencil_size_ > 0) &&
+ depth24_stencil8_supported) {
+ offscreen_target_depth_format_ = GL_DEPTH24_STENCIL8;
+ offscreen_target_stencil_format_ = 0;
+ } else {
+ offscreen_target_depth_format_ = attrib_parser.depth_size_ > 0 ?
+ GL_DEPTH_COMPONENT : 0;
+ offscreen_target_stencil_format_ = attrib_parser.stencil_size_ > 0 ?
+ GL_STENCIL_INDEX : 0;
+ }
+ }
+
+ offscreen_saved_color_format_ = attrib_parser.alpha_size_ > 0 ?
+ GL_RGBA : GL_RGB;
+
+ // Create the target frame buffer. This is the one that the client renders
+ // directly to.
+ offscreen_target_frame_buffer_.reset(new BackFramebuffer(this));
+ offscreen_target_frame_buffer_->Create();
+ // Due to GLES2 format limitations, either the color texture (for
+ // non-multisampling) or the color render buffer (for multisampling) will be
+ // attached to the offscreen frame buffer. The render buffer has more
+ // limited formats available to it, but the texture can't do multisampling.
+ if (IsOffscreenBufferMultisampled()) {
+ offscreen_target_color_render_buffer_.reset(new BackRenderbuffer(this));
+ offscreen_target_color_render_buffer_->Create();
+ } else {
+ offscreen_target_color_texture_.reset(new BackTexture(this));
+ offscreen_target_color_texture_->Create();
+ }
+ offscreen_target_depth_render_buffer_.reset(new BackRenderbuffer(this));
+ offscreen_target_depth_render_buffer_->Create();
+ offscreen_target_stencil_render_buffer_.reset(new BackRenderbuffer(this));
+ offscreen_target_stencil_render_buffer_->Create();
+
+ // Create the saved offscreen texture. The target frame buffer is copied
+ // here when SwapBuffers is called.
+ offscreen_saved_frame_buffer_.reset(new BackFramebuffer(this));
+ offscreen_saved_frame_buffer_->Create();
+ //
+ offscreen_saved_color_texture_.reset(new BackTexture(this));
+ offscreen_saved_color_texture_->Create();
+
+ // Allocate the render buffers at their initial size and check the status
+ // of the frame buffers is okay.
+ if (!ResizeOffscreenFrameBuffer(size)) {
+ LOG(ERROR) << "Could not allocate offscreen buffer storage.";
+ Destroy(true);
+ return false;
+ }
+
+ // Allocate the offscreen saved color texture.
+ DCHECK(offscreen_saved_color_format_);
+ offscreen_saved_color_texture_->AllocateStorage(
+ gfx::Size(1, 1), offscreen_saved_color_format_, true);
+
+ offscreen_saved_frame_buffer_->AttachRenderTexture(
+ offscreen_saved_color_texture_.get());
+ if (offscreen_saved_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "Offscreen saved FBO was incomplete.";
+ Destroy(true);
+ return false;
+ }
+
+ // Bind to the new default frame buffer (the offscreen target frame buffer).
+ // This should now be associated with ID zero.
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0);
+ } else {
+ glBindFramebufferEXT(GL_FRAMEBUFFER, GetBackbufferServiceId());
+ // These are NOT if the back buffer has these proprorties. They are
+ // if we want the command buffer to enforce them regardless of what
+ // the real backbuffer is assuming the real back buffer gives us more than
+ // we ask for. In other words, if we ask for RGB and we get RGBA then we'll
+ // make it appear RGB. If on the other hand we ask for RGBA nd get RGB we
+ // can't do anything about that.
+
+ GLint v = 0;
+ glGetIntegerv(GL_ALPHA_BITS, &v);
+ // This checks if the user requested RGBA and we have RGBA then RGBA. If the
+ // user requested RGB then RGB. If the user did not specify a preference
+ // than use whatever we were given. Same for DEPTH and STENCIL.
+ back_buffer_color_format_ =
+ (attrib_parser.alpha_size_ != 0 && v > 0) ? GL_RGBA : GL_RGB;
+ glGetIntegerv(GL_DEPTH_BITS, &v);
+ back_buffer_has_depth_ = attrib_parser.depth_size_ != 0 && v > 0;
+ glGetIntegerv(GL_STENCIL_BITS, &v);
+ back_buffer_has_stencil_ = attrib_parser.stencil_size_ != 0 && v > 0;
+ }
+
+ // OpenGL ES 2.0 implicitly enables the desktop GL capability
+ // VERTEX_PROGRAM_POINT_SIZE and doesn't expose this enum. This fact
+ // isn't well documented; it was discovered in the Khronos OpenGL ES
+ // mailing list archives. It also implicitly enables the desktop GL
+ // capability GL_POINT_SPRITE to provide access to the gl_PointCoord
+ // variable in fragment shaders.
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
+ glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
+ glEnable(GL_POINT_SPRITE);
+ }
+
+ has_robustness_extension_ =
+ context->HasExtension("GL_ARB_robustness") ||
+ context->HasExtension("GL_EXT_robustness");
+
+ if (!InitializeShaderTranslator()) {
+ return false;
+ }
+
+ state_.viewport_width = size.width();
+ state_.viewport_height = size.height();
+
+ GLint viewport_params[4] = { 0 };
+ glGetIntegerv(GL_MAX_VIEWPORT_DIMS, viewport_params);
+ viewport_max_width_ = viewport_params[0];
+ viewport_max_height_ = viewport_params[1];
+
+ state_.scissor_width = state_.viewport_width;
+ state_.scissor_height = state_.viewport_height;
+
+ // Set all the default state because some GL drivers get it wrong.
+ state_.InitCapabilities();
+ state_.InitState();
+ glActiveTexture(GL_TEXTURE0 + state_.active_texture_unit);
+
+ DoBindBuffer(GL_ARRAY_BUFFER, 0);
+ DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0);
+ DoBindRenderbuffer(GL_RENDERBUFFER, 0);
+
+ bool call_gl_clear = true;
+#if defined(OS_ANDROID)
+ // Temporary workaround for Android WebView because this clear ignores the
+ // clip and corrupts that external UI of the App. Not calling glClear is ok
+ // because the system already clears the buffer before each draw. Proper
+ // fix might be setting the scissor clip properly before initialize. See
+ // crbug.com/259023 for details.
+ call_gl_clear = surface_->GetHandle();
+#endif
+ if (call_gl_clear) {
+ // Clear the backbuffer.
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ }
+
+ if (feature_info_->workarounds().reverse_point_sprite_coord_origin) {
+ glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);
+ }
+
+ if (feature_info_->workarounds().unbind_fbo_on_context_switch) {
+ context_->SetUnbindFboOnMakeCurrent();
+ }
+
+ // Only compositor contexts are known to use only the subset of GL
+ // that can be safely migrated between the iGPU and the dGPU. Mark
+ // those contexts as safe to forcibly transition between the GPUs.
+ // http://crbug.com/180876, http://crbug.com/227228
+ if (!offscreen)
+ context_->SetSafeToForceGpuSwitch();
+
+ async_pixel_transfer_manager_.reset(
+ AsyncPixelTransferManager::Create(context.get()));
+ async_pixel_transfer_manager_->Initialize(texture_manager());
+
+ return true;
+}
+
+void GLES2DecoderImpl::UpdateCapabilities() {
+ util_.set_num_compressed_texture_formats(
+ validators_->compressed_texture_format.GetValues().size());
+ util_.set_num_shader_binary_formats(
+ validators_->shader_binary_format.GetValues().size());
+}
+
+bool GLES2DecoderImpl::InitializeShaderTranslator() {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::InitializeShaderTranslator");
+
+ if (!use_shader_translator_) {
+ return true;
+ }
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+ resources.MaxVertexAttribs = group_->max_vertex_attribs();
+ resources.MaxVertexUniformVectors =
+ group_->max_vertex_uniform_vectors();
+ resources.MaxVaryingVectors = group_->max_varying_vectors();
+ resources.MaxVertexTextureImageUnits =
+ group_->max_vertex_texture_image_units();
+ resources.MaxCombinedTextureImageUnits = group_->max_texture_units();
+ resources.MaxTextureImageUnits = group_->max_texture_image_units();
+ resources.MaxFragmentUniformVectors =
+ group_->max_fragment_uniform_vectors();
+ resources.MaxDrawBuffers = group_->max_draw_buffers();
+ resources.MaxExpressionComplexity = 256;
+ resources.MaxCallStackDepth = 256;
+
+#if (ANGLE_SH_VERSION >= 110)
+ GLint range[2] = { 0, 0 };
+ GLint precision = 0;
+ GetShaderPrecisionFormatImpl(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
+ range, &precision);
+ resources.FragmentPrecisionHigh =
+ PrecisionMeetsSpecForHighpFloat(range[0], range[1], precision);
+#endif
+
+ if (force_webgl_glsl_validation_) {
+ resources.OES_standard_derivatives = derivatives_explicitly_enabled_;
+ resources.EXT_frag_depth = frag_depth_explicitly_enabled_;
+ resources.EXT_draw_buffers = draw_buffers_explicitly_enabled_;
+ } else {
+ resources.OES_standard_derivatives =
+ features().oes_standard_derivatives ? 1 : 0;
+ resources.ARB_texture_rectangle =
+ features().arb_texture_rectangle ? 1 : 0;
+ resources.OES_EGL_image_external =
+ features().oes_egl_image_external ? 1 : 0;
+ resources.EXT_draw_buffers =
+ features().ext_draw_buffers ? 1 : 0;
+ resources.EXT_frag_depth =
+ features().ext_frag_depth ? 1 : 0;
+ }
+
+ ShShaderSpec shader_spec = force_webgl_glsl_validation_ ? SH_WEBGL_SPEC
+ : SH_GLES2_SPEC;
+ if (shader_spec == SH_WEBGL_SPEC && features().enable_shader_name_hashing)
+#if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
+ resources.HashFunction = &CityHashForAngle;
+#else
+ resources.HashFunction = &CityHash64;
+#endif
+ else
+ resources.HashFunction = NULL;
+ ShaderTranslatorInterface::GlslImplementationType implementation_type =
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2 ?
+ ShaderTranslatorInterface::kGlslES : ShaderTranslatorInterface::kGlsl;
+ ShaderTranslatorInterface::GlslBuiltInFunctionBehavior function_behavior =
+ workarounds().needs_glsl_built_in_function_emulation ?
+ ShaderTranslatorInterface::kGlslBuiltInFunctionEmulated :
+ ShaderTranslatorInterface::kGlslBuiltInFunctionOriginal;
+
+ ShaderTranslatorCache* cache = ShaderTranslatorCache::GetInstance();
+ vertex_translator_ = cache->GetTranslator(
+ SH_VERTEX_SHADER, shader_spec, &resources,
+ implementation_type, function_behavior);
+ if (!vertex_translator_.get()) {
+ LOG(ERROR) << "Could not initialize vertex shader translator.";
+ Destroy(true);
+ return false;
+ }
+
+ fragment_translator_ = cache->GetTranslator(
+ SH_FRAGMENT_SHADER, shader_spec, &resources,
+ implementation_type, function_behavior);
+ if (!fragment_translator_.get()) {
+ LOG(ERROR) << "Could not initialize fragment shader translator.";
+ Destroy(true);
+ return false;
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::GenBuffersHelper(GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (GetBuffer(client_ids[ii])) {
+ return false;
+ }
+ }
+ scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+ glGenBuffersARB(n, service_ids.get());
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateBuffer(client_ids[ii], service_ids[ii]);
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::GenFramebuffersHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (GetFramebuffer(client_ids[ii])) {
+ return false;
+ }
+ }
+ scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+ glGenFramebuffersEXT(n, service_ids.get());
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateFramebuffer(client_ids[ii], service_ids[ii]);
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::GenRenderbuffersHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (GetRenderbuffer(client_ids[ii])) {
+ return false;
+ }
+ }
+ scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+ glGenRenderbuffersEXT(n, service_ids.get());
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateRenderbuffer(client_ids[ii], service_ids[ii]);
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::GenTexturesHelper(GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (GetTexture(client_ids[ii])) {
+ return false;
+ }
+ }
+ scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+ glGenTextures(n, service_ids.get());
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateTexture(client_ids[ii], service_ids[ii]);
+ }
+ return true;
+}
+
+void GLES2DecoderImpl::DeleteBuffersHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ Buffer* buffer = GetBuffer(client_ids[ii]);
+ if (buffer && !buffer->IsDeleted()) {
+ state_.vertex_attrib_manager->Unbind(buffer);
+ if (state_.bound_array_buffer.get() == buffer) {
+ state_.bound_array_buffer = NULL;
+ }
+ RemoveBuffer(client_ids[ii]);
+ }
+ }
+}
+
+void GLES2DecoderImpl::DeleteFramebuffersHelper(
+ GLsizei n, const GLuint* client_ids) {
+ bool supports_separate_framebuffer_binds =
+ features().chromium_framebuffer_multisample;
+
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ Framebuffer* framebuffer =
+ GetFramebuffer(client_ids[ii]);
+ if (framebuffer && !framebuffer->IsDeleted()) {
+ if (framebuffer == state_.bound_draw_framebuffer.get()) {
+ state_.bound_draw_framebuffer = NULL;
+ framebuffer_state_.clear_state_dirty = true;
+ GLenum target = supports_separate_framebuffer_binds ?
+ GL_DRAW_FRAMEBUFFER_EXT : GL_FRAMEBUFFER;
+ glBindFramebufferEXT(target, GetBackbufferServiceId());
+ }
+ if (framebuffer == state_.bound_read_framebuffer.get()) {
+ state_.bound_read_framebuffer = NULL;
+ GLenum target = supports_separate_framebuffer_binds ?
+ GL_READ_FRAMEBUFFER_EXT : GL_FRAMEBUFFER;
+ glBindFramebufferEXT(target, GetBackbufferServiceId());
+ }
+ OnFboChanged();
+ RemoveFramebuffer(client_ids[ii]);
+ }
+ }
+}
+
+void GLES2DecoderImpl::DeleteRenderbuffersHelper(
+ GLsizei n, const GLuint* client_ids) {
+ bool supports_separate_framebuffer_binds =
+ features().chromium_framebuffer_multisample;
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ Renderbuffer* renderbuffer =
+ GetRenderbuffer(client_ids[ii]);
+ if (renderbuffer && !renderbuffer->IsDeleted()) {
+ if (state_.bound_renderbuffer.get() == renderbuffer) {
+ state_.bound_renderbuffer = NULL;
+ }
+ // Unbind from current framebuffers.
+ if (supports_separate_framebuffer_binds) {
+ if (state_.bound_read_framebuffer.get()) {
+ state_.bound_read_framebuffer
+ ->UnbindRenderbuffer(GL_READ_FRAMEBUFFER_EXT, renderbuffer);
+ }
+ if (state_.bound_draw_framebuffer.get()) {
+ state_.bound_draw_framebuffer
+ ->UnbindRenderbuffer(GL_DRAW_FRAMEBUFFER_EXT, renderbuffer);
+ }
+ } else {
+ if (state_.bound_draw_framebuffer.get()) {
+ state_.bound_draw_framebuffer
+ ->UnbindRenderbuffer(GL_FRAMEBUFFER, renderbuffer);
+ }
+ }
+ framebuffer_state_.clear_state_dirty = true;
+ RemoveRenderbuffer(client_ids[ii]);
+ }
+ }
+}
+
+void GLES2DecoderImpl::DeleteTexturesHelper(
+ GLsizei n, const GLuint* client_ids) {
+ bool supports_separate_framebuffer_binds =
+ features().chromium_framebuffer_multisample;
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ TextureRef* texture_ref = GetTexture(client_ids[ii]);
+ if (texture_ref) {
+ Texture* texture = texture_ref->texture();
+ if (texture->IsAttachedToFramebuffer()) {
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ // Unbind texture_ref from texture_ref units.
+ for (size_t jj = 0; jj < state_.texture_units.size(); ++jj) {
+ state_.texture_units[jj].Unbind(texture_ref);
+ }
+ // Unbind from current framebuffers.
+ if (supports_separate_framebuffer_binds) {
+ if (state_.bound_read_framebuffer.get()) {
+ state_.bound_read_framebuffer
+ ->UnbindTexture(GL_READ_FRAMEBUFFER_EXT, texture_ref);
+ }
+ if (state_.bound_draw_framebuffer.get()) {
+ state_.bound_draw_framebuffer
+ ->UnbindTexture(GL_DRAW_FRAMEBUFFER_EXT, texture_ref);
+ }
+ } else {
+ if (state_.bound_draw_framebuffer.get()) {
+ state_.bound_draw_framebuffer
+ ->UnbindTexture(GL_FRAMEBUFFER, texture_ref);
+ }
+ }
+#if defined(OS_MACOSX)
+ GLuint service_id = texture->service_id();
+ if (texture->target() == GL_TEXTURE_RECTANGLE_ARB) {
+ ReleaseIOSurfaceForTexture(service_id);
+ }
+#endif
+ RemoveTexture(client_ids[ii]);
+ }
+ }
+}
+
+// } // anonymous namespace
+
+bool GLES2DecoderImpl::MakeCurrent() {
+ if (!context_.get() || !context_->MakeCurrent(surface_.get()))
+ return false;
+
+ if (WasContextLost()) {
+ LOG(ERROR) << " GLES2DecoderImpl: Context lost during MakeCurrent.";
+
+ // Some D3D drivers cannot recover from device lost in the GPU process
+ // sandbox. Allow a new GPU process to launch.
+ if (workarounds().exit_on_context_lost) {
+ LOG(ERROR) << "Exiting GPU process because some drivers cannot reset"
+ << " a D3D device in the Chrome GPU process sandbox.";
+ exit(0);
+ }
+
+ return false;
+ }
+
+ ProcessFinishedAsyncTransfers();
+
+ // Rebind the FBO if it was unbound by the context.
+ if (workarounds().unbind_fbo_on_context_switch)
+ RestoreFramebufferBindings();
+
+ framebuffer_state_.clear_state_dirty = true;
+
+ return true;
+}
+
+void GLES2DecoderImpl::ProcessFinishedAsyncTransfers() {
+ ProcessPendingReadPixels();
+ if (engine() && query_manager_.get())
+ query_manager_->ProcessPendingTransferQueries();
+
+ // TODO(epenner): Is there a better place to do this?
+ // This needs to occur before we execute any batch of commands
+ // from the client, as the client may have recieved an async
+ // completion while issuing those commands.
+ // "DidFlushStart" would be ideal if we had such a callback.
+ async_pixel_transfer_manager_->BindCompletedAsyncTransfers();
+}
+
+void GLES2DecoderImpl::ReleaseCurrent() {
+ if (context_.get())
+ context_->ReleaseCurrent(surface_.get());
+}
+
+void GLES2DecoderImpl::RestoreCurrentRenderbufferBindings() {
+ Renderbuffer* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ glBindRenderbufferEXT(
+ GL_RENDERBUFFER, renderbuffer ? renderbuffer->service_id() : 0);
+}
+
+static void RebindCurrentFramebuffer(
+ GLenum target,
+ Framebuffer* framebuffer,
+ GLuint back_buffer_service_id) {
+ GLuint framebuffer_id = framebuffer ? framebuffer->service_id() : 0;
+
+ if (framebuffer_id == 0) {
+ framebuffer_id = back_buffer_service_id;
+ }
+
+ glBindFramebufferEXT(target, framebuffer_id);
+}
+
+void GLES2DecoderImpl::RestoreCurrentFramebufferBindings() {
+ framebuffer_state_.clear_state_dirty = true;
+
+ if (!features().chromium_framebuffer_multisample) {
+ RebindCurrentFramebuffer(
+ GL_FRAMEBUFFER,
+ state_.bound_draw_framebuffer.get(),
+ GetBackbufferServiceId());
+ } else {
+ RebindCurrentFramebuffer(
+ GL_READ_FRAMEBUFFER_EXT,
+ state_.bound_read_framebuffer.get(),
+ GetBackbufferServiceId());
+ RebindCurrentFramebuffer(
+ GL_DRAW_FRAMEBUFFER_EXT,
+ state_.bound_draw_framebuffer.get(),
+ GetBackbufferServiceId());
+ }
+ OnFboChanged();
+}
+
+void GLES2DecoderImpl::RestoreCurrentTexture2DBindings() {
+ TextureUnit& info = state_.texture_units[0];
+ GLuint last_id;
+ if (info.bound_texture_2d.get()) {
+ last_id = info.bound_texture_2d->service_id();
+ } else {
+ last_id = 0;
+ }
+
+ glBindTexture(GL_TEXTURE_2D, last_id);
+ glActiveTexture(GL_TEXTURE0 + state_.active_texture_unit);
+}
+
+bool GLES2DecoderImpl::CheckFramebufferValid(
+ Framebuffer* framebuffer,
+ GLenum target, const char* func_name) {
+ if (!framebuffer) {
+ if (backbuffer_needs_clear_bits_) {
+ glClearColor(0, 0, 0, (GLES2Util::GetChannelsForFormat(
+ offscreen_target_color_format_) & 0x0008) != 0 ? 0 : 1);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearStencil(0);
+ glStencilMask(-1);
+ glClearDepth(1.0f);
+ glDepthMask(true);
+ glDisable(GL_SCISSOR_TEST);
+ glClear(backbuffer_needs_clear_bits_);
+ backbuffer_needs_clear_bits_ = 0;
+ RestoreClearState();
+ }
+ return true;
+ }
+
+ if (framebuffer_manager()->IsComplete(framebuffer)) {
+ return true;
+ }
+
+ GLenum completeness = framebuffer->IsPossiblyComplete();
+ if (completeness != GL_FRAMEBUFFER_COMPLETE) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_FRAMEBUFFER_OPERATION, func_name, "framebuffer incomplete");
+ return false;
+ }
+
+ // Are all the attachments cleared?
+ if (renderbuffer_manager()->HaveUnclearedRenderbuffers() ||
+ texture_manager()->HaveUnclearedMips()) {
+ if (!framebuffer->IsCleared()) {
+ // Can we clear them?
+ if (framebuffer->GetStatus(texture_manager(), target) !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_FRAMEBUFFER_OPERATION, func_name,
+ "framebuffer incomplete (clear)");
+ return false;
+ }
+ ClearUnclearedAttachments(target, framebuffer);
+ }
+ }
+
+ if (!framebuffer_manager()->IsComplete(framebuffer)) {
+ if (framebuffer->GetStatus(texture_manager(), target) !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_FRAMEBUFFER_OPERATION, func_name,
+ "framebuffer incomplete (check)");
+ return false;
+ }
+ framebuffer_manager()->MarkAsComplete(framebuffer);
+ }
+
+ // NOTE: At this point we don't know if the framebuffer is complete but
+ // we DO know that everything that needs to be cleared has been cleared.
+ return true;
+}
+
+bool GLES2DecoderImpl::CheckBoundFramebuffersValid(const char* func_name) {
+ if (!features().chromium_framebuffer_multisample) {
+ bool valid = CheckFramebufferValid(
+ state_.bound_draw_framebuffer.get(), GL_FRAMEBUFFER_EXT, func_name);
+
+ if (valid)
+ OnUseFramebuffer();
+
+ return valid;
+ }
+ return CheckFramebufferValid(state_.bound_draw_framebuffer.get(),
+ GL_DRAW_FRAMEBUFFER_EXT,
+ func_name) &&
+ CheckFramebufferValid(state_.bound_read_framebuffer.get(),
+ GL_READ_FRAMEBUFFER_EXT,
+ func_name);
+}
+
+gfx::Size GLES2DecoderImpl::GetBoundReadFrameBufferSize() {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT);
+ if (framebuffer != NULL) {
+ const Framebuffer::Attachment* attachment =
+ framebuffer->GetAttachment(GL_COLOR_ATTACHMENT0);
+ if (attachment) {
+ return gfx::Size(attachment->width(), attachment->height());
+ }
+ return gfx::Size(0, 0);
+ } else if (offscreen_target_frame_buffer_.get()) {
+ return offscreen_size_;
+ } else {
+ return surface_->GetSize();
+ }
+}
+
+GLenum GLES2DecoderImpl::GetBoundReadFrameBufferInternalFormat() {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT);
+ if (framebuffer != NULL) {
+ return framebuffer->GetColorAttachmentFormat();
+ } else if (offscreen_target_frame_buffer_.get()) {
+ return offscreen_target_color_format_;
+ } else {
+ return back_buffer_color_format_;
+ }
+}
+
+GLenum GLES2DecoderImpl::GetBoundDrawFrameBufferInternalFormat() {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+ if (framebuffer != NULL) {
+ return framebuffer->GetColorAttachmentFormat();
+ } else if (offscreen_target_frame_buffer_.get()) {
+ return offscreen_target_color_format_;
+ } else {
+ return back_buffer_color_format_;
+ }
+}
+
+void GLES2DecoderImpl::UpdateParentTextureInfo() {
+ if (!offscreen_saved_color_texture_info_.get())
+ return;
+ GLenum target = offscreen_saved_color_texture_info_->texture()->target();
+ glBindTexture(target, offscreen_saved_color_texture_info_->service_id());
+ texture_manager()->SetLevelInfo(
+ offscreen_saved_color_texture_info_.get(),
+ GL_TEXTURE_2D,
+ 0, // level
+ GL_RGBA,
+ offscreen_size_.width(),
+ offscreen_size_.height(),
+ 1, // depth
+ 0, // border
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ texture_manager()->SetParameter(
+ "UpdateParentTextureInfo",
+ GetErrorState(),
+ offscreen_saved_color_texture_info_.get(),
+ GL_TEXTURE_MAG_FILTER,
+ GL_NEAREST);
+ texture_manager()->SetParameter(
+ "UpdateParentTextureInfo",
+ GetErrorState(),
+ offscreen_saved_color_texture_info_.get(),
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ texture_manager()->SetParameter(
+ "UpdateParentTextureInfo",
+ GetErrorState(),
+ offscreen_saved_color_texture_info_.get(),
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ texture_manager()->SetParameter(
+ "UpdateParentTextureInfo",
+ GetErrorState(),
+ offscreen_saved_color_texture_info_.get(),
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ glBindTexture(target, texture_ref ? texture_ref->service_id() : 0);
+}
+
+void GLES2DecoderImpl::SetResizeCallback(
+ const base::Callback<void(gfx::Size, float)>& callback) {
+ resize_callback_ = callback;
+}
+
+Logger* GLES2DecoderImpl::GetLogger() {
+ return &logger_;
+}
+
+ErrorState* GLES2DecoderImpl::GetErrorState() {
+ return state_.GetErrorState();
+}
+
+void GLES2DecoderImpl::SetShaderCacheCallback(
+ const ShaderCacheCallback& callback) {
+ shader_cache_callback_ = callback;
+}
+
+void GLES2DecoderImpl::SetWaitSyncPointCallback(
+ const WaitSyncPointCallback& callback) {
+ wait_sync_point_callback_ = callback;
+}
+
+AsyncPixelTransferManager*
+ GLES2DecoderImpl::GetAsyncPixelTransferManager() {
+ return async_pixel_transfer_manager_.get();
+}
+
+void GLES2DecoderImpl::ResetAsyncPixelTransferManagerForTest() {
+ async_pixel_transfer_manager_.reset();
+}
+
+void GLES2DecoderImpl::SetAsyncPixelTransferManagerForTest(
+ AsyncPixelTransferManager* manager) {
+ async_pixel_transfer_manager_ = make_scoped_ptr(manager);
+}
+
+bool GLES2DecoderImpl::GetServiceTextureId(uint32 client_texture_id,
+ uint32* service_texture_id) {
+ TextureRef* texture_ref = texture_manager()->GetTexture(client_texture_id);
+ if (texture_ref) {
+ *service_texture_id = texture_ref->service_id();
+ return true;
+ }
+ return false;
+}
+
+uint32 GLES2DecoderImpl::GetTextureUploadCount() {
+ return texture_state_.texture_upload_count +
+ async_pixel_transfer_manager_->GetTextureUploadCount();
+}
+
+base::TimeDelta GLES2DecoderImpl::GetTotalTextureUploadTime() {
+ return texture_state_.total_texture_upload_time +
+ async_pixel_transfer_manager_->GetTotalTextureUploadTime();
+}
+
+base::TimeDelta GLES2DecoderImpl::GetTotalProcessingCommandsTime() {
+ return total_processing_commands_time_;
+}
+
+void GLES2DecoderImpl::AddProcessingCommandsTime(base::TimeDelta time) {
+ total_processing_commands_time_ += time;
+}
+
+void GLES2DecoderImpl::Destroy(bool have_context) {
+ if (!initialized())
+ return;
+
+ DCHECK(!have_context || context_->IsCurrent(NULL));
+
+ // Unbind everything.
+ state_.vertex_attrib_manager = NULL;
+ default_vertex_attrib_manager_ = NULL;
+ state_.texture_units.clear();
+ state_.bound_array_buffer = NULL;
+ state_.current_query = NULL;
+ state_.bound_read_framebuffer = NULL;
+ state_.bound_draw_framebuffer = NULL;
+ state_.bound_renderbuffer = NULL;
+
+ if (offscreen_saved_color_texture_info_.get()) {
+ DCHECK(offscreen_target_color_texture_);
+ DCHECK_EQ(offscreen_saved_color_texture_info_->service_id(),
+ offscreen_saved_color_texture_->id());
+ offscreen_saved_color_texture_->Invalidate();
+ offscreen_saved_color_texture_info_ = NULL;
+ }
+ if (have_context) {
+ if (copy_texture_CHROMIUM_.get()) {
+ copy_texture_CHROMIUM_->Destroy();
+ copy_texture_CHROMIUM_.reset();
+ }
+
+ if (state_.current_program.get()) {
+ program_manager()->UnuseProgram(shader_manager(),
+ state_.current_program.get());
+ }
+
+ if (attrib_0_buffer_id_) {
+ glDeleteBuffersARB(1, &attrib_0_buffer_id_);
+ }
+ if (fixed_attrib_buffer_id_) {
+ glDeleteBuffersARB(1, &fixed_attrib_buffer_id_);
+ }
+
+ if (offscreen_target_frame_buffer_.get())
+ offscreen_target_frame_buffer_->Destroy();
+ if (offscreen_target_color_texture_.get())
+ offscreen_target_color_texture_->Destroy();
+ if (offscreen_target_color_render_buffer_.get())
+ offscreen_target_color_render_buffer_->Destroy();
+ if (offscreen_target_depth_render_buffer_.get())
+ offscreen_target_depth_render_buffer_->Destroy();
+ if (offscreen_target_stencil_render_buffer_.get())
+ offscreen_target_stencil_render_buffer_->Destroy();
+ if (offscreen_saved_frame_buffer_.get())
+ offscreen_saved_frame_buffer_->Destroy();
+ if (offscreen_saved_color_texture_.get())
+ offscreen_saved_color_texture_->Destroy();
+ if (offscreen_resolved_frame_buffer_.get())
+ offscreen_resolved_frame_buffer_->Destroy();
+ if (offscreen_resolved_color_texture_.get())
+ offscreen_resolved_color_texture_->Destroy();
+ } else {
+ if (offscreen_target_frame_buffer_.get())
+ offscreen_target_frame_buffer_->Invalidate();
+ if (offscreen_target_color_texture_.get())
+ offscreen_target_color_texture_->Invalidate();
+ if (offscreen_target_color_render_buffer_.get())
+ offscreen_target_color_render_buffer_->Invalidate();
+ if (offscreen_target_depth_render_buffer_.get())
+ offscreen_target_depth_render_buffer_->Invalidate();
+ if (offscreen_target_stencil_render_buffer_.get())
+ offscreen_target_stencil_render_buffer_->Invalidate();
+ if (offscreen_saved_frame_buffer_.get())
+ offscreen_saved_frame_buffer_->Invalidate();
+ if (offscreen_saved_color_texture_.get())
+ offscreen_saved_color_texture_->Invalidate();
+ if (offscreen_resolved_frame_buffer_.get())
+ offscreen_resolved_frame_buffer_->Invalidate();
+ if (offscreen_resolved_color_texture_.get())
+ offscreen_resolved_color_texture_->Invalidate();
+ }
+
+ // Current program must be cleared after calling ProgramManager::UnuseProgram.
+ // Otherwise, we can leak objects. http://crbug.com/258772.
+ // state_.current_program must be reset before group_ is reset because
+ // the later deletes the ProgramManager object that referred by
+ // state_.current_program object.
+ state_.current_program = NULL;
+
+ copy_texture_CHROMIUM_.reset();
+
+ if (query_manager_.get()) {
+ query_manager_->Destroy(have_context);
+ query_manager_.reset();
+ }
+
+ if (vertex_array_manager_ .get()) {
+ vertex_array_manager_->Destroy(have_context);
+ vertex_array_manager_.reset();
+ }
+
+ offscreen_target_frame_buffer_.reset();
+ offscreen_target_color_texture_.reset();
+ offscreen_target_color_render_buffer_.reset();
+ offscreen_target_depth_render_buffer_.reset();
+ offscreen_target_stencil_render_buffer_.reset();
+ offscreen_saved_frame_buffer_.reset();
+ offscreen_saved_color_texture_.reset();
+ offscreen_resolved_frame_buffer_.reset();
+ offscreen_resolved_color_texture_.reset();
+
+ // Should destroy the transfer manager before the texture manager held
+ // by the context group.
+ async_pixel_transfer_manager_.reset();
+
+ if (group_.get()) {
+ group_->Destroy(this, have_context);
+ group_ = NULL;
+ }
+
+ if (context_.get()) {
+ context_->ReleaseCurrent(NULL);
+ context_ = NULL;
+ }
+
+#if defined(OS_MACOSX)
+ for (TextureToIOSurfaceMap::iterator it = texture_to_io_surface_map_.begin();
+ it != texture_to_io_surface_map_.end(); ++it) {
+ CFRelease(it->second);
+ }
+ texture_to_io_surface_map_.clear();
+#endif
+}
+
+void GLES2DecoderImpl::SetSurface(
+ const scoped_refptr<gfx::GLSurface>& surface) {
+ DCHECK(context_->IsCurrent(NULL));
+ DCHECK(surface_.get());
+ surface_ = surface;
+ RestoreCurrentFramebufferBindings();
+}
+
+bool GLES2DecoderImpl::ProduceFrontBuffer(const Mailbox& mailbox) {
+ if (!offscreen_saved_color_texture_.get())
+ return false;
+ if (!offscreen_saved_color_texture_info_.get()) {
+ GLuint service_id = offscreen_saved_color_texture_->id();
+ offscreen_saved_color_texture_info_ = TextureRef::Create(
+ texture_manager(), 0, service_id);
+ texture_manager()->SetTarget(offscreen_saved_color_texture_info_.get(),
+ GL_TEXTURE_2D);
+ UpdateParentTextureInfo();
+ }
+ gpu::gles2::MailboxName name;
+ memcpy(name.key, mailbox.name, sizeof(mailbox.name));
+ return mailbox_manager()->ProduceTexture(
+ GL_TEXTURE_2D, name, offscreen_saved_color_texture_info_->texture());
+}
+
+size_t GLES2DecoderImpl::GetBackbufferMemoryTotal() {
+ size_t total = 0;
+ if (offscreen_target_frame_buffer_.get()) {
+ if (offscreen_target_color_texture_.get()) {
+ total += offscreen_target_color_texture_->estimated_size();
+ }
+ if (offscreen_target_color_render_buffer_.get()) {
+ total += offscreen_target_color_render_buffer_->estimated_size();
+ }
+ if (offscreen_target_depth_render_buffer_.get()) {
+ total += offscreen_target_depth_render_buffer_->estimated_size();
+ }
+ if (offscreen_target_stencil_render_buffer_.get()) {
+ total += offscreen_target_stencil_render_buffer_->estimated_size();
+ }
+ if (offscreen_saved_color_texture_.get()) {
+ total += offscreen_saved_color_texture_->estimated_size();
+ }
+ if (offscreen_resolved_color_texture_.get()) {
+ total += offscreen_resolved_color_texture_->estimated_size();
+ }
+ } else {
+ gfx::Size size = surface_->GetSize();
+ total += size.width() * size.height() *
+ GLES2Util::RenderbufferBytesPerPixel(back_buffer_color_format_);
+ }
+ return total;
+}
+
+bool GLES2DecoderImpl::ResizeOffscreenFrameBuffer(const gfx::Size& size) {
+ bool is_offscreen = !!offscreen_target_frame_buffer_.get();
+ if (!is_offscreen) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer called "
+ << " with an onscreen framebuffer.";
+ return false;
+ }
+
+ if (offscreen_size_ == size)
+ return true;
+
+ offscreen_size_ = size;
+ int w = offscreen_size_.width();
+ int h = offscreen_size_.height();
+ if (w < 0 || h < 0 || h >= (INT_MAX / 4) / (w ? w : 1)) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "to allocate storage due to excessive dimensions.";
+ return false;
+ }
+
+ // Reallocate the offscreen target buffers.
+ DCHECK(offscreen_target_color_format_);
+ if (IsOffscreenBufferMultisampled()) {
+ if (!offscreen_target_color_render_buffer_->AllocateStorage(
+ offscreen_size_, offscreen_target_color_format_,
+ offscreen_target_samples_)) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "to allocate storage for offscreen target color buffer.";
+ return false;
+ }
+ } else {
+ if (!offscreen_target_color_texture_->AllocateStorage(
+ offscreen_size_, offscreen_target_color_format_, false)) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "to allocate storage for offscreen target color texture.";
+ return false;
+ }
+ }
+ if (offscreen_target_depth_format_ &&
+ !offscreen_target_depth_render_buffer_->AllocateStorage(
+ offscreen_size_, offscreen_target_depth_format_,
+ offscreen_target_samples_)) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "to allocate storage for offscreen target depth buffer.";
+ return false;
+ }
+ if (offscreen_target_stencil_format_ &&
+ !offscreen_target_stencil_render_buffer_->AllocateStorage(
+ offscreen_size_, offscreen_target_stencil_format_,
+ offscreen_target_samples_)) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "to allocate storage for offscreen target stencil buffer.";
+ return false;
+ }
+
+ // Attach the offscreen target buffers to the target frame buffer.
+ if (IsOffscreenBufferMultisampled()) {
+ offscreen_target_frame_buffer_->AttachRenderBuffer(
+ GL_COLOR_ATTACHMENT0,
+ offscreen_target_color_render_buffer_.get());
+ } else {
+ offscreen_target_frame_buffer_->AttachRenderTexture(
+ offscreen_target_color_texture_.get());
+ }
+ if (offscreen_target_depth_format_) {
+ offscreen_target_frame_buffer_->AttachRenderBuffer(
+ GL_DEPTH_ATTACHMENT,
+ offscreen_target_depth_render_buffer_.get());
+ }
+ const bool packed_depth_stencil =
+ offscreen_target_depth_format_ == GL_DEPTH24_STENCIL8;
+ if (packed_depth_stencil) {
+ offscreen_target_frame_buffer_->AttachRenderBuffer(
+ GL_STENCIL_ATTACHMENT,
+ offscreen_target_depth_render_buffer_.get());
+ } else if (offscreen_target_stencil_format_) {
+ offscreen_target_frame_buffer_->AttachRenderBuffer(
+ GL_STENCIL_ATTACHMENT,
+ offscreen_target_stencil_render_buffer_.get());
+ }
+
+ if (offscreen_target_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "because offscreen FBO was incomplete.";
+ return false;
+ }
+
+ // Clear the target frame buffer.
+ {
+ ScopedFrameBufferBinder binder(this, offscreen_target_frame_buffer_->id());
+ glClearColor(0, 0, 0, (GLES2Util::GetChannelsForFormat(
+ offscreen_target_color_format_) & 0x0008) != 0 ? 0 : 1);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glClearStencil(0);
+ glStencilMaskSeparate(GL_FRONT, -1);
+ glStencilMaskSeparate(GL_BACK, -1);
+ glClearDepth(0);
+ glDepthMask(GL_TRUE);
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ RestoreClearState();
+ }
+
+ // Destroy the offscreen resolved framebuffers.
+ if (offscreen_resolved_frame_buffer_.get())
+ offscreen_resolved_frame_buffer_->Destroy();
+ if (offscreen_resolved_color_texture_.get())
+ offscreen_resolved_color_texture_->Destroy();
+ offscreen_resolved_color_texture_.reset();
+ offscreen_resolved_frame_buffer_.reset();
+
+ return true;
+}
+
+error::Error GLES2DecoderImpl::HandleResizeCHROMIUM(
+ uint32 immediate_data_size, const cmds::ResizeCHROMIUM& c) {
+ if (!offscreen_target_frame_buffer_.get() && surface_->DeferDraws())
+ return error::kDeferCommandUntilLater;
+
+ GLuint width = static_cast<GLuint>(c.width);
+ GLuint height = static_cast<GLuint>(c.height);
+ GLfloat scale_factor = c.scale_factor;
+ TRACE_EVENT2("gpu", "glResizeChromium", "width", width, "height", height);
+
+ width = std::max(1U, width);
+ height = std::max(1U, height);
+
+#if defined(OS_POSIX) && !defined(OS_MACOSX) && \
+ !defined(UI_COMPOSITOR_IMAGE_TRANSPORT)
+ // Make sure that we are done drawing to the back buffer before resizing.
+ glFinish();
+#endif
+ bool is_offscreen = !!offscreen_target_frame_buffer_.get();
+ if (is_offscreen) {
+ if (!ResizeOffscreenFrameBuffer(gfx::Size(width, height))) {
+ LOG(ERROR) << "GLES2DecoderImpl: Context lost because "
+ << "ResizeOffscreenFrameBuffer failed.";
+ return error::kLostContext;
+ }
+ }
+
+ if (!resize_callback_.is_null()) {
+ resize_callback_.Run(gfx::Size(width, height), scale_factor);
+ DCHECK(context_->IsCurrent(surface_.get()));
+ if (!context_->IsCurrent(surface_.get())) {
+ LOG(ERROR) << "GLES2DecoderImpl: Context lost because context no longer "
+ << "current after resize callback.";
+ return error::kLostContext;
+ }
+ }
+
+ return error::kNoError;
+}
+
+const char* GLES2DecoderImpl::GetCommandName(unsigned int command_id) const {
+ if (command_id > kStartPoint && command_id < kNumCommands) {
+ return gles2::GetCommandName(static_cast<CommandId>(command_id));
+ }
+ return GetCommonCommandName(static_cast<cmd::CommandId>(command_id));
+}
+
+// Decode command with its arguments, and call the corresponding GL function.
+// Note: args is a pointer to the command buffer. As such, it could be changed
+// by a (malicious) client at any time, so if validation has to happen, it
+// should operate on a copy of them.
+error::Error GLES2DecoderImpl::DoCommand(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data) {
+ error::Error result = error::kNoError;
+ if (log_commands()) {
+ // TODO(notme): Change this to a LOG/VLOG that works in release. Tried
+ // LOG(INFO), tried VLOG(1), no luck.
+ LOG(ERROR) << "[" << logger_.GetLogPrefix() << "]" << "cmd: "
+ << GetCommandName(command);
+ }
+ unsigned int command_index = command - kStartPoint - 1;
+ if (command_index < arraysize(g_command_info)) {
+ const CommandInfo& info = g_command_info[command_index];
+ unsigned int info_arg_count = static_cast<unsigned int>(info.arg_count);
+ if ((info.arg_flags == cmd::kFixed && arg_count == info_arg_count) ||
+ (info.arg_flags == cmd::kAtLeastN && arg_count >= info_arg_count)) {
+ uint32 immediate_data_size =
+ (arg_count - info_arg_count) * sizeof(CommandBufferEntry); // NOLINT
+ switch (command) {
+ #define GLES2_CMD_OP(name) \
+ case cmds::name::kCmdId: \
+ result = Handle ## name( \
+ immediate_data_size, \
+ *static_cast<const gles2::cmds::name*>(cmd_data)); \
+ break; \
+
+ GLES2_COMMAND_LIST(GLES2_CMD_OP)
+ #undef GLES2_CMD_OP
+ }
+ if (debug()) {
+ GLenum error;
+ while ((error = glGetError()) != GL_NO_ERROR) {
+ LOG(ERROR) << "[" << logger_.GetLogPrefix() << "] "
+ << "GL ERROR: " << GLES2Util::GetStringEnum(error) << " : "
+ << GetCommandName(command);
+ LOCAL_SET_GL_ERROR(error, "DoCommand", "GL error from driver");
+ }
+ }
+ } else {
+ result = error::kInvalidArguments;
+ }
+ } else {
+ result = DoCommonCommand(command, arg_count, cmd_data);
+ }
+ if (result == error::kNoError && current_decoder_error_ != error::kNoError) {
+ result = current_decoder_error_;
+ current_decoder_error_ = error::kNoError;
+ }
+ return result;
+}
+
+void GLES2DecoderImpl::RemoveBuffer(GLuint client_id) {
+ buffer_manager()->RemoveBuffer(client_id);
+}
+
+bool GLES2DecoderImpl::CreateProgramHelper(GLuint client_id) {
+ if (GetProgram(client_id)) {
+ return false;
+ }
+ GLuint service_id = glCreateProgram();
+ if (service_id != 0) {
+ CreateProgram(client_id, service_id);
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::CreateShaderHelper(GLenum type, GLuint client_id) {
+ if (GetShader(client_id)) {
+ return false;
+ }
+ GLuint service_id = glCreateShader(type);
+ if (service_id != 0) {
+ CreateShader(client_id, service_id, type);
+ }
+ return true;
+}
+
+void GLES2DecoderImpl::DoFinish() {
+ glFinish();
+ ProcessPendingReadPixels();
+ ProcessPendingQueries();
+}
+
+void GLES2DecoderImpl::DoFlush() {
+ glFlush();
+ ProcessPendingQueries();
+}
+
+void GLES2DecoderImpl::DoActiveTexture(GLenum texture_unit) {
+ GLuint texture_index = texture_unit - GL_TEXTURE0;
+ if (texture_index >= state_.texture_units.size()) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glActiveTexture", texture_unit, "texture_unit");
+ return;
+ }
+ state_.active_texture_unit = texture_index;
+ glActiveTexture(texture_unit);
+}
+
+void GLES2DecoderImpl::DoBindBuffer(GLenum target, GLuint client_id) {
+ Buffer* buffer = NULL;
+ GLuint service_id = 0;
+ if (client_id != 0) {
+ buffer = GetBuffer(client_id);
+ if (!buffer) {
+ if (!group_->bind_generates_resource()) {
+ LOG(ERROR) << "glBindBuffer: id not generated by glGenBuffers";
+ current_decoder_error_ = error::kGenericError;
+ return;
+ }
+
+ // It's a new id so make a buffer buffer for it.
+ glGenBuffersARB(1, &service_id);
+ CreateBuffer(client_id, service_id);
+ buffer = GetBuffer(client_id);
+ IdAllocatorInterface* id_allocator =
+ group_->GetIdAllocator(id_namespaces::kBuffers);
+ id_allocator->MarkAsUsed(client_id);
+ }
+ }
+ LogClientServiceForInfo(buffer, client_id, "glBindBuffer");
+ if (buffer) {
+ if (!buffer_manager()->SetTarget(buffer, target)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindBuffer", "buffer bound to more than 1 target");
+ return;
+ }
+ service_id = buffer->service_id();
+ }
+ switch (target) {
+ case GL_ARRAY_BUFFER:
+ state_.bound_array_buffer = buffer;
+ break;
+ case GL_ELEMENT_ARRAY_BUFFER:
+ state_.vertex_attrib_manager->SetElementArrayBuffer(buffer);
+ break;
+ default:
+ NOTREACHED(); // Validation should prevent us getting here.
+ break;
+ }
+ glBindBuffer(target, service_id);
+}
+
+bool GLES2DecoderImpl::BoundFramebufferHasColorAttachmentWithAlpha(
+ bool all_draw_buffers) {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+ if (!all_draw_buffers || !framebuffer) {
+ return (GLES2Util::GetChannelsForFormat(
+ GetBoundDrawFrameBufferInternalFormat()) & 0x0008) != 0;
+ }
+ return framebuffer->HasAlphaMRT();
+}
+
+bool GLES2DecoderImpl::BoundFramebufferHasDepthAttachment() {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+ if (framebuffer) {
+ return framebuffer->HasDepthAttachment();
+ }
+ if (offscreen_target_frame_buffer_.get()) {
+ return offscreen_target_depth_format_ != 0;
+ }
+ return back_buffer_has_depth_;
+}
+
+bool GLES2DecoderImpl::BoundFramebufferHasStencilAttachment() {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+ if (framebuffer) {
+ return framebuffer->HasStencilAttachment();
+ }
+ if (offscreen_target_frame_buffer_.get()) {
+ return offscreen_target_stencil_format_ != 0 ||
+ offscreen_target_depth_format_ == GL_DEPTH24_STENCIL8;
+ }
+ return back_buffer_has_stencil_;
+}
+
+void GLES2DecoderImpl::ApplyDirtyState() {
+ if (framebuffer_state_.clear_state_dirty) {
+ glColorMask(
+ state_.color_mask_red, state_.color_mask_green, state_.color_mask_blue,
+ state_.color_mask_alpha &&
+ BoundFramebufferHasColorAttachmentWithAlpha(true));
+ bool have_depth = BoundFramebufferHasDepthAttachment();
+ glDepthMask(state_.depth_mask && have_depth);
+ EnableDisable(GL_DEPTH_TEST, state_.enable_flags.depth_test && have_depth);
+ bool have_stencil = BoundFramebufferHasStencilAttachment();
+ glStencilMaskSeparate(
+ GL_FRONT, have_stencil ? state_.stencil_front_writemask : 0);
+ glStencilMaskSeparate(
+ GL_BACK, have_stencil ? state_.stencil_back_writemask : 0);
+ EnableDisable(
+ GL_STENCIL_TEST, state_.enable_flags.stencil_test && have_stencil);
+ EnableDisable(GL_CULL_FACE, state_.enable_flags.cull_face);
+ EnableDisable(GL_SCISSOR_TEST, state_.enable_flags.scissor_test);
+ EnableDisable(GL_BLEND, state_.enable_flags.blend);
+ framebuffer_state_.clear_state_dirty = false;
+ }
+}
+
+GLuint GLES2DecoderImpl::GetBackbufferServiceId() const {
+ return (offscreen_target_frame_buffer_.get())
+ ? offscreen_target_frame_buffer_->id()
+ : (surface_.get() ? surface_->GetBackingFrameBufferObject() : 0);
+}
+
+void GLES2DecoderImpl::RestoreState() const {
+ TRACE_EVENT1("gpu", "GLES2DecoderImpl::RestoreState",
+ "context", logger_.GetLogPrefix());
+ // Restore the Framebuffer first because of bugs in Intel drivers.
+ // Intel drivers incorrectly clip the viewport settings to
+ // the size of the current framebuffer object.
+ RestoreFramebufferBindings();
+ state_.RestoreState();
+}
+
+void GLES2DecoderImpl::RestoreFramebufferBindings() const {
+ GLuint service_id = state_.bound_draw_framebuffer.get()
+ ? state_.bound_draw_framebuffer->service_id()
+ : GetBackbufferServiceId();
+ if (!features().chromium_framebuffer_multisample) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER, service_id);
+ } else {
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, service_id);
+ service_id = state_.bound_read_framebuffer.get()
+ ? state_.bound_read_framebuffer->service_id()
+ : GetBackbufferServiceId();
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER, service_id);
+ }
+ OnFboChanged();
+}
+
+void GLES2DecoderImpl::RestoreTextureState(unsigned service_id) const {
+ Texture* texture = texture_manager()->GetTextureForServiceId(service_id);
+ if (texture) {
+ GLenum target = texture->target();
+ glBindTexture(target, service_id);
+ glTexParameteri(
+ target, GL_TEXTURE_WRAP_S, texture->wrap_s());
+ glTexParameteri(
+ target, GL_TEXTURE_WRAP_T, texture->wrap_t());
+ glTexParameteri(
+ target, GL_TEXTURE_MIN_FILTER, texture->min_filter());
+ glTexParameteri(
+ target, GL_TEXTURE_MAG_FILTER, texture->mag_filter());
+ RestoreTextureUnitBindings(state_.active_texture_unit);
+ }
+}
+
+void GLES2DecoderImpl::OnFboChanged() const {
+ if (workarounds().restore_scissor_on_fbo_change)
+ state_.fbo_binding_for_scissor_workaround_dirty_ = true;
+}
+
+// Called after the FBO is checked for completeness.
+void GLES2DecoderImpl::OnUseFramebuffer() const {
+ if (state_.fbo_binding_for_scissor_workaround_dirty_) {
+ state_.fbo_binding_for_scissor_workaround_dirty_ = false;
+ // The driver forgets the correct scissor when modifying the FBO binding.
+ glScissor(state_.scissor_x,
+ state_.scissor_y,
+ state_.scissor_width,
+ state_.scissor_height);
+
+ // crbug.com/222018 - Also on QualComm, the flush here avoids flicker,
+ // it's unclear how this bug works.
+ glFlush();
+ }
+}
+
+void GLES2DecoderImpl::DoBindFramebuffer(GLenum target, GLuint client_id) {
+ Framebuffer* framebuffer = NULL;
+ GLuint service_id = 0;
+ if (client_id != 0) {
+ framebuffer = GetFramebuffer(client_id);
+ if (!framebuffer) {
+ if (!group_->bind_generates_resource()) {
+ LOG(ERROR)
+ << "glBindFramebuffer: id not generated by glGenFramebuffers";
+ current_decoder_error_ = error::kGenericError;
+ return;
+ }
+
+ // It's a new id so make a framebuffer framebuffer for it.
+ glGenFramebuffersEXT(1, &service_id);
+ CreateFramebuffer(client_id, service_id);
+ framebuffer = GetFramebuffer(client_id);
+ IdAllocatorInterface* id_allocator =
+ group_->GetIdAllocator(id_namespaces::kFramebuffers);
+ id_allocator->MarkAsUsed(client_id);
+ } else {
+ service_id = framebuffer->service_id();
+ }
+ framebuffer->MarkAsValid();
+ }
+ LogClientServiceForInfo(framebuffer, client_id, "glBindFramebuffer");
+
+ if (target == GL_FRAMEBUFFER || target == GL_DRAW_FRAMEBUFFER_EXT) {
+ state_.bound_draw_framebuffer = framebuffer;
+ }
+ if (target == GL_FRAMEBUFFER || target == GL_READ_FRAMEBUFFER_EXT) {
+ state_.bound_read_framebuffer = framebuffer;
+ }
+
+ framebuffer_state_.clear_state_dirty = true;
+
+ // If we are rendering to the backbuffer get the FBO id for any simulated
+ // backbuffer.
+ if (framebuffer == NULL) {
+ service_id = GetBackbufferServiceId();
+ }
+
+ glBindFramebufferEXT(target, service_id);
+ OnFboChanged();
+}
+
+void GLES2DecoderImpl::DoBindRenderbuffer(GLenum target, GLuint client_id) {
+ Renderbuffer* renderbuffer = NULL;
+ GLuint service_id = 0;
+ if (client_id != 0) {
+ renderbuffer = GetRenderbuffer(client_id);
+ if (!renderbuffer) {
+ if (!group_->bind_generates_resource()) {
+ LOG(ERROR)
+ << "glBindRenderbuffer: id not generated by glGenRenderbuffers";
+ current_decoder_error_ = error::kGenericError;
+ return;
+ }
+
+ // It's a new id so make a renderbuffer renderbuffer for it.
+ glGenRenderbuffersEXT(1, &service_id);
+ CreateRenderbuffer(client_id, service_id);
+ renderbuffer = GetRenderbuffer(client_id);
+ IdAllocatorInterface* id_allocator =
+ group_->GetIdAllocator(id_namespaces::kRenderbuffers);
+ id_allocator->MarkAsUsed(client_id);
+ } else {
+ service_id = renderbuffer->service_id();
+ }
+ renderbuffer->MarkAsValid();
+ }
+ LogClientServiceForInfo(renderbuffer, client_id, "glBindRenerbuffer");
+ state_.bound_renderbuffer = renderbuffer;
+ glBindRenderbufferEXT(target, service_id);
+}
+
+void GLES2DecoderImpl::DoBindTexture(GLenum target, GLuint client_id) {
+ TextureRef* texture_ref = NULL;
+ GLuint service_id = 0;
+ if (client_id != 0) {
+ texture_ref = GetTexture(client_id);
+ if (!texture_ref) {
+ if (!group_->bind_generates_resource()) {
+ LOG(ERROR) << "glBindTexture: id not generated by glGenTextures";
+ current_decoder_error_ = error::kGenericError;
+ return;
+ }
+
+ // It's a new id so make a texture texture for it.
+ glGenTextures(1, &service_id);
+ DCHECK_NE(0u, service_id);
+ CreateTexture(client_id, service_id);
+ texture_ref = GetTexture(client_id);
+ IdAllocatorInterface* id_allocator =
+ group_->GetIdAllocator(id_namespaces::kTextures);
+ id_allocator->MarkAsUsed(client_id);
+ }
+ } else {
+ texture_ref = texture_manager()->GetDefaultTextureInfo(target);
+ }
+ Texture* texture = texture_ref->texture();
+
+ // Check the texture exists
+ // Check that we are not trying to bind it to a different target.
+ if (texture->target() != 0 && texture->target() != target) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindTexture", "texture bound to more than 1 target.");
+ return;
+ }
+ if (texture->IsStreamTexture() && target != GL_TEXTURE_EXTERNAL_OES) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindTexture", "illegal target for stream texture.");
+ return;
+ }
+ LogClientServiceForInfo(texture, client_id, "glBindTexture");
+ if (texture->target() == 0) {
+ texture_manager()->SetTarget(texture_ref, target);
+ }
+ glBindTexture(target, texture->service_id());
+
+ TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+ unit.bind_target = target;
+ switch (target) {
+ case GL_TEXTURE_2D:
+ unit.bound_texture_2d = texture_ref;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ unit.bound_texture_cube_map = texture_ref;
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ unit.bound_texture_external_oes = texture_ref;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ unit.bound_texture_rectangle_arb = texture_ref;
+ break;
+ default:
+ NOTREACHED(); // Validation should prevent us getting here.
+ break;
+ }
+}
+
+void GLES2DecoderImpl::DoDisableVertexAttribArray(GLuint index) {
+ if (state_.vertex_attrib_manager->Enable(index, false)) {
+ if (index != 0 ||
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ glDisableVertexAttribArray(index);
+ }
+ } else {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glDisableVertexAttribArray", "index out of range");
+ }
+}
+
+void GLES2DecoderImpl::DoDiscardFramebufferEXT(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments) {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_FRAMEBUFFER);
+
+ // Validates the attachments. If one of them fails
+ // the whole command fails.
+ for (GLsizei i = 0; i < numAttachments; ++i) {
+ if ((framebuffer &&
+ !validators_->attachment.IsValid(attachments[i])) ||
+ (!framebuffer &&
+ !validators_->backbuffer_attachment.IsValid(attachments[i]))) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glDiscardFramebufferEXT", attachments[i], "attachments");
+ return;
+ }
+ }
+
+ // Marks each one of them as not cleared
+ for (GLsizei i = 0; i < numAttachments; ++i) {
+ if (framebuffer) {
+ framebuffer->MarkAttachmentAsCleared(renderbuffer_manager(),
+ texture_manager(),
+ attachments[i],
+ false);
+ } else {
+ switch (attachments[i]) {
+ case GL_COLOR_EXT:
+ backbuffer_needs_clear_bits_ |= GL_COLOR_BUFFER_BIT;
+ break;
+ case GL_DEPTH_EXT:
+ backbuffer_needs_clear_bits_ |= GL_DEPTH_BUFFER_BIT;
+ case GL_STENCIL_EXT:
+ backbuffer_needs_clear_bits_ |= GL_STENCIL_BUFFER_BIT;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+ }
+
+ glDiscardFramebufferEXT(target, numAttachments, attachments);
+}
+
+void GLES2DecoderImpl::DoEnableVertexAttribArray(GLuint index) {
+ if (state_.vertex_attrib_manager->Enable(index, true)) {
+ glEnableVertexAttribArray(index);
+ } else {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glEnableVertexAttribArray", "index out of range");
+ }
+}
+
+void GLES2DecoderImpl::DoGenerateMipmap(GLenum target) {
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref ||
+ !texture_manager()->CanGenerateMipmaps(texture_ref)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glGenerateMipmap", "Can not generate mips");
+ return;
+ }
+
+ if (target == GL_TEXTURE_CUBE_MAP) {
+ for (int i = 0; i < 6; ++i) {
+ GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i;
+ if (!texture_manager()->ClearTextureLevel(this, texture_ref, face, 0)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glGenerateMipmap", "dimensions too big");
+ return;
+ }
+ }
+ } else {
+ if (!texture_manager()->ClearTextureLevel(this, texture_ref, target, 0)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glGenerateMipmap", "dimensions too big");
+ return;
+ }
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glGenerateMipmap");
+ // Workaround for Mac driver bug. In the large scheme of things setting
+ // glTexParamter twice for glGenerateMipmap is probably not a lage performance
+ // hit so there's probably no need to make this conditional. The bug appears
+ // to be that if the filtering mode is set to something that doesn't require
+ // mipmaps for rendering, or is never set to something other than the default,
+ // then glGenerateMipmap misbehaves.
+ if (workarounds().set_texture_filter_before_generating_mipmap) {
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
+ }
+ glGenerateMipmapEXT(target);
+ if (workarounds().set_texture_filter_before_generating_mipmap) {
+ glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
+ texture_ref->texture()->min_filter());
+ }
+ GLenum error = LOCAL_PEEK_GL_ERROR("glGenerateMipmap");
+ if (error == GL_NO_ERROR) {
+ texture_manager()->MarkMipmapsGenerated(texture_ref);
+ }
+}
+
+bool GLES2DecoderImpl::GetHelper(
+ GLenum pname, GLint* params, GLsizei* num_written) {
+ DCHECK(num_written);
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
+ switch (pname) {
+ case GL_IMPLEMENTATION_COLOR_READ_FORMAT:
+ *num_written = 1;
+ if (params) {
+ *params = GL_RGBA; // We don't support other formats.
+ }
+ return true;
+ case GL_IMPLEMENTATION_COLOR_READ_TYPE:
+ *num_written = 1;
+ if (params) {
+ *params = GL_UNSIGNED_BYTE; // We don't support other types.
+ }
+ return true;
+ case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+ *num_written = 1;
+ if (params) {
+ *params = group_->max_fragment_uniform_vectors();
+ }
+ return true;
+ case GL_MAX_VARYING_VECTORS:
+ *num_written = 1;
+ if (params) {
+ *params = group_->max_varying_vectors();
+ }
+ return true;
+ case GL_MAX_VERTEX_UNIFORM_VECTORS:
+ *num_written = 1;
+ if (params) {
+ *params = group_->max_vertex_uniform_vectors();
+ }
+ return true;
+ }
+ }
+ switch (pname) {
+ case GL_MAX_VIEWPORT_DIMS:
+ if (offscreen_target_frame_buffer_.get()) {
+ *num_written = 2;
+ if (params) {
+ params[0] = renderbuffer_manager()->max_renderbuffer_size();
+ params[1] = renderbuffer_manager()->max_renderbuffer_size();
+ }
+ return true;
+ }
+ return false;
+ case GL_MAX_SAMPLES:
+ *num_written = 1;
+ if (params) {
+ params[0] = renderbuffer_manager()->max_samples();
+ }
+ return true;
+ case GL_MAX_RENDERBUFFER_SIZE:
+ *num_written = 1;
+ if (params) {
+ params[0] = renderbuffer_manager()->max_renderbuffer_size();
+ }
+ return true;
+ case GL_MAX_TEXTURE_SIZE:
+ *num_written = 1;
+ if (params) {
+ params[0] = texture_manager()->MaxSizeForTarget(GL_TEXTURE_2D);
+ }
+ return true;
+ case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
+ *num_written = 1;
+ if (params) {
+ params[0] = texture_manager()->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP);
+ }
+ return true;
+ case GL_MAX_COLOR_ATTACHMENTS_EXT:
+ *num_written = 1;
+ if (params) {
+ params[0] = group_->max_color_attachments();
+ }
+ return true;
+ case GL_MAX_DRAW_BUFFERS_ARB:
+ *num_written = 1;
+ if (params) {
+ params[0] = group_->max_draw_buffers();
+ }
+ return true;
+ case GL_ALPHA_BITS:
+ *num_written = 1;
+ if (params) {
+ GLint v = 0;
+ glGetIntegerv(GL_ALPHA_BITS, &v);
+ params[0] = BoundFramebufferHasColorAttachmentWithAlpha(false) ? v : 0;
+ }
+ return true;
+ case GL_DEPTH_BITS:
+ *num_written = 1;
+ if (params) {
+ GLint v = 0;
+ glGetIntegerv(GL_DEPTH_BITS, &v);
+ params[0] = BoundFramebufferHasDepthAttachment() ? v : 0;
+ }
+ return true;
+ case GL_STENCIL_BITS:
+ *num_written = 1;
+ if (params) {
+ GLint v = 0;
+ glGetIntegerv(GL_STENCIL_BITS, &v);
+ params[0] = BoundFramebufferHasStencilAttachment() ? v : 0;
+ }
+ return true;
+ case GL_COMPRESSED_TEXTURE_FORMATS:
+ *num_written = validators_->compressed_texture_format.GetValues().size();
+ if (params) {
+ for (GLint ii = 0; ii < *num_written; ++ii) {
+ params[ii] = validators_->compressed_texture_format.GetValues()[ii];
+ }
+ }
+ return true;
+ case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+ *num_written = 1;
+ if (params) {
+ *params = validators_->compressed_texture_format.GetValues().size();
+ }
+ return true;
+ case GL_NUM_SHADER_BINARY_FORMATS:
+ *num_written = 1;
+ if (params) {
+ *params = validators_->shader_binary_format.GetValues().size();
+ }
+ return true;
+ case GL_SHADER_BINARY_FORMATS:
+ *num_written = validators_->shader_binary_format.GetValues().size();
+ if (params) {
+ for (GLint ii = 0; ii < *num_written; ++ii) {
+ params[ii] = validators_->shader_binary_format.GetValues()[ii];
+ }
+ }
+ return true;
+ case GL_SHADER_COMPILER:
+ *num_written = 1;
+ if (params) {
+ *params = GL_TRUE;
+ }
+ return true;
+ case GL_ARRAY_BUFFER_BINDING:
+ *num_written = 1;
+ if (params) {
+ if (state_.bound_array_buffer.get()) {
+ GLuint client_id = 0;
+ buffer_manager()->GetClientId(state_.bound_array_buffer->service_id(),
+ &client_id);
+ *params = client_id;
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+ *num_written = 1;
+ if (params) {
+ if (state_.vertex_attrib_manager->element_array_buffer()) {
+ GLuint client_id = 0;
+ buffer_manager()->GetClientId(
+ state_.vertex_attrib_manager->element_array_buffer()->
+ service_id(), &client_id);
+ *params = client_id;
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_FRAMEBUFFER_BINDING:
+ // case GL_DRAW_FRAMEBUFFER_BINDING_EXT: (same as GL_FRAMEBUFFER_BINDING)
+ *num_written = 1;
+ if (params) {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_FRAMEBUFFER);
+ if (framebuffer) {
+ GLuint client_id = 0;
+ framebuffer_manager()->GetClientId(
+ framebuffer->service_id(), &client_id);
+ *params = client_id;
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_READ_FRAMEBUFFER_BINDING_EXT:
+ *num_written = 1;
+ if (params) {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_READ_FRAMEBUFFER_EXT);
+ if (framebuffer) {
+ GLuint client_id = 0;
+ framebuffer_manager()->GetClientId(
+ framebuffer->service_id(), &client_id);
+ *params = client_id;
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_RENDERBUFFER_BINDING:
+ *num_written = 1;
+ if (params) {
+ Renderbuffer* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (renderbuffer) {
+ *params = renderbuffer->client_id();
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_CURRENT_PROGRAM:
+ *num_written = 1;
+ if (params) {
+ if (state_.current_program.get()) {
+ GLuint client_id = 0;
+ program_manager()->GetClientId(
+ state_.current_program->service_id(), &client_id);
+ *params = client_id;
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_VERTEX_ARRAY_BINDING_OES:
+ *num_written = 1;
+ if (params) {
+ if (state_.vertex_attrib_manager.get() !=
+ default_vertex_attrib_manager_.get()) {
+ GLuint client_id = 0;
+ vertex_array_manager_->GetClientId(
+ state_.vertex_attrib_manager->service_id(), &client_id);
+ *params = client_id;
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_TEXTURE_BINDING_2D:
+ *num_written = 1;
+ if (params) {
+ TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+ if (unit.bound_texture_2d.get()) {
+ *params = unit.bound_texture_2d->client_id();
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_TEXTURE_BINDING_CUBE_MAP:
+ *num_written = 1;
+ if (params) {
+ TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+ if (unit.bound_texture_cube_map.get()) {
+ *params = unit.bound_texture_cube_map->client_id();
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_TEXTURE_BINDING_EXTERNAL_OES:
+ *num_written = 1;
+ if (params) {
+ TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+ if (unit.bound_texture_external_oes.get()) {
+ *params = unit.bound_texture_external_oes->client_id();
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_TEXTURE_BINDING_RECTANGLE_ARB:
+ *num_written = 1;
+ if (params) {
+ TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+ if (unit.bound_texture_rectangle_arb.get()) {
+ *params = unit.bound_texture_rectangle_arb->client_id();
+ } else {
+ *params = 0;
+ }
+ }
+ return true;
+ case GL_UNPACK_FLIP_Y_CHROMIUM:
+ *num_written = 1;
+ if (params) {
+ params[0] = unpack_flip_y_;
+ }
+ return true;
+ case GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM:
+ *num_written = 1;
+ if (params) {
+ params[0] = unpack_premultiply_alpha_;
+ }
+ return true;
+ case GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM:
+ *num_written = 1;
+ if (params) {
+ params[0] = unpack_unpremultiply_alpha_;
+ }
+ return true;
+ default:
+ if (pname >= GL_DRAW_BUFFER0_ARB &&
+ pname < GL_DRAW_BUFFER0_ARB + group_->max_draw_buffers()) {
+ *num_written = 1;
+ if (params) {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_FRAMEBUFFER);
+ if (framebuffer) {
+ params[0] = framebuffer->GetDrawBuffer(pname);
+ } else { // backbuffer
+ if (pname == GL_DRAW_BUFFER0_ARB)
+ params[0] = group_->draw_buffer();
+ else
+ params[0] = GL_NONE;
+ }
+ }
+ return true;
+ }
+ *num_written = util_.GLGetNumValuesReturned(pname);
+ return false;
+ }
+}
+
+bool GLES2DecoderImpl::GetNumValuesReturnedForGLGet(
+ GLenum pname, GLsizei* num_values) {
+ if (state_.GetStateAsGLint(pname, NULL, num_values)) {
+ return true;
+ }
+ return GetHelper(pname, NULL, num_values);
+}
+
+GLenum GLES2DecoderImpl::AdjustGetPname(GLenum pname) {
+ if (GL_MAX_SAMPLES == pname &&
+ features().use_img_for_multisampled_render_to_texture) {
+ return GL_MAX_SAMPLES_IMG;
+ }
+ return pname;
+}
+
+void GLES2DecoderImpl::DoGetBooleanv(GLenum pname, GLboolean* params) {
+ DCHECK(params);
+ GLsizei num_written = 0;
+ if (GetNumValuesReturnedForGLGet(pname, &num_written)) {
+ scoped_ptr<GLint[]> values(new GLint[num_written]);
+ if (!state_.GetStateAsGLint(pname, values.get(), &num_written)) {
+ GetHelper(pname, values.get(), &num_written);
+ }
+ for (GLsizei ii = 0; ii < num_written; ++ii) {
+ params[ii] = static_cast<GLboolean>(values[ii]);
+ }
+ } else {
+ pname = AdjustGetPname(pname);
+ glGetBooleanv(pname, params);
+ }
+}
+
+void GLES2DecoderImpl::DoGetFloatv(GLenum pname, GLfloat* params) {
+ DCHECK(params);
+ GLsizei num_written = 0;
+ if (!state_.GetStateAsGLfloat(pname, params, &num_written)) {
+ if (GetHelper(pname, NULL, &num_written)) {
+ scoped_ptr<GLint[]> values(new GLint[num_written]);
+ GetHelper(pname, values.get(), &num_written);
+ for (GLsizei ii = 0; ii < num_written; ++ii) {
+ params[ii] = static_cast<GLfloat>(values[ii]);
+ }
+ } else {
+ pname = AdjustGetPname(pname);
+ glGetFloatv(pname, params);
+ }
+ }
+}
+
+void GLES2DecoderImpl::DoGetIntegerv(GLenum pname, GLint* params) {
+ DCHECK(params);
+ GLsizei num_written;
+ if (!state_.GetStateAsGLint(pname, params, &num_written) &&
+ !GetHelper(pname, params, &num_written)) {
+ pname = AdjustGetPname(pname);
+ glGetIntegerv(pname, params);
+ }
+}
+
+void GLES2DecoderImpl::DoGetProgramiv(
+ GLuint program_id, GLenum pname, GLint* params) {
+ Program* program = GetProgramInfoNotShader(program_id, "glGetProgramiv");
+ if (!program) {
+ return;
+ }
+ program->GetProgramiv(pname, params);
+}
+
+void GLES2DecoderImpl::DoGetBufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ // Just delegate it. Some validation is actually done before this.
+ buffer_manager()->ValidateAndDoGetBufferParameteriv(
+ &state_, target, pname, params);
+}
+
+void GLES2DecoderImpl::DoBindAttribLocation(
+ GLuint program_id, GLuint index, const char* name) {
+ if (!StringIsValidForGLES(name)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glBindAttribLocation", "Invalid character");
+ return;
+ }
+ if (ProgramManager::IsInvalidPrefix(name, strlen(name))) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glBindAttribLocation", "reserved prefix");
+ return;
+ }
+ if (index >= group_->max_vertex_attribs()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glBindAttribLocation", "index out of range");
+ return;
+ }
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glBindAttribLocation");
+ if (!program) {
+ return;
+ }
+ program->SetAttribLocationBinding(name, static_cast<GLint>(index));
+ glBindAttribLocation(program->service_id(), index, name);
+}
+
+error::Error GLES2DecoderImpl::HandleBindAttribLocation(
+ uint32 immediate_data_size, const cmds::BindAttribLocation& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ GLuint index = static_cast<GLuint>(c.index);
+ uint32 name_size = c.data_size;
+ const char* name = GetSharedMemoryAs<const char*>(
+ c.name_shm_id, c.name_shm_offset, name_size);
+ if (name == NULL) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ DoBindAttribLocation(program, index, name_str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindAttribLocationImmediate(
+ uint32 immediate_data_size, const cmds::BindAttribLocationImmediate& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ GLuint index = static_cast<GLuint>(c.index);
+ uint32 name_size = c.data_size;
+ const char* name = GetImmediateDataAs<const char*>(
+ c, name_size, immediate_data_size);
+ if (name == NULL) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ DoBindAttribLocation(program, index, name_str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindAttribLocationBucket(
+ uint32 immediate_data_size, const cmds::BindAttribLocationBucket& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ GLuint index = static_cast<GLuint>(c.index);
+ Bucket* bucket = GetBucket(c.name_bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string name_str;
+ if (!bucket->GetAsString(&name_str)) {
+ return error::kInvalidArguments;
+ }
+ DoBindAttribLocation(program, index, name_str.c_str());
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoBindUniformLocationCHROMIUM(
+ GLuint program_id, GLint location, const char* name) {
+ if (!StringIsValidForGLES(name)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glBindUniformLocationCHROMIUM", "Invalid character");
+ return;
+ }
+ if (ProgramManager::IsInvalidPrefix(name, strlen(name))) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindUniformLocationCHROMIUM", "reserved prefix");
+ return;
+ }
+ if (location < 0 || static_cast<uint32>(location) >=
+ (group_->max_fragment_uniform_vectors() +
+ group_->max_vertex_uniform_vectors()) * 4) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glBindUniformLocationCHROMIUM", "location out of range");
+ return;
+ }
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glBindUniformLocationCHROMIUM");
+ if (!program) {
+ return;
+ }
+ if (!program->SetUniformLocationBinding(name, location)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glBindUniformLocationCHROMIUM", "location out of range");
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUM(
+ uint32 immediate_data_size, const cmds::BindUniformLocationCHROMIUM& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ GLint location = static_cast<GLint>(c.location);
+ uint32 name_size = c.data_size;
+ const char* name = GetSharedMemoryAs<const char*>(
+ c.name_shm_id, c.name_shm_offset, name_size);
+ if (name == NULL) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ DoBindUniformLocationCHROMIUM(program, location, name_str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUMImmediate(
+ uint32 immediate_data_size,
+ const cmds::BindUniformLocationCHROMIUMImmediate& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ GLint location = static_cast<GLint>(c.location);
+ uint32 name_size = c.data_size;
+ const char* name = GetImmediateDataAs<const char*>(
+ c, name_size, immediate_data_size);
+ if (name == NULL) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ DoBindUniformLocationCHROMIUM(program, location, name_str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUMBucket(
+ uint32 immediate_data_size,
+ const cmds::BindUniformLocationCHROMIUMBucket& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ GLint location = static_cast<GLint>(c.location);
+ Bucket* bucket = GetBucket(c.name_bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string name_str;
+ if (!bucket->GetAsString(&name_str)) {
+ return error::kInvalidArguments;
+ }
+ DoBindUniformLocationCHROMIUM(program, location, name_str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteShader(
+ uint32 immediate_data_size, const cmds::DeleteShader& c) {
+ GLuint client_id = c.shader;
+ if (client_id) {
+ Shader* shader = GetShader(client_id);
+ if (shader) {
+ if (!shader->IsDeleted()) {
+ glDeleteShader(shader->service_id());
+ shader_manager()->MarkAsDeleted(shader);
+ }
+ } else {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glDeleteShader", "unknown shader");
+ }
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteProgram(
+ uint32 immediate_data_size, const cmds::DeleteProgram& c) {
+ GLuint client_id = c.program;
+ if (client_id) {
+ Program* program = GetProgram(client_id);
+ if (program) {
+ if (!program->IsDeleted()) {
+ program_manager()->MarkAsDeleted(shader_manager(), program);
+ }
+ } else {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glDeleteProgram", "unknown program");
+ }
+ }
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoDeleteSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ IdAllocatorInterface* id_allocator = group_->GetIdAllocator(namespace_id);
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ id_allocator->FreeID(ids[ii]);
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteSharedIdsCHROMIUM(
+ uint32 immediate_data_size, const cmds::DeleteSharedIdsCHROMIUM& c) {
+ GLuint namespace_id = static_cast<GLuint>(c.namespace_id);
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* ids = GetSharedMemoryAs<const GLuint*>(
+ c.ids_shm_id, c.ids_shm_offset, data_size);
+ if (n < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "DeleteSharedIdsCHROMIUM", "n < 0");
+ return error::kNoError;
+ }
+ if (ids == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoDeleteSharedIdsCHROMIUM(namespace_id, n, ids);
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoGenSharedIdsCHROMIUM(
+ GLuint namespace_id, GLuint id_offset, GLsizei n, GLuint* ids) {
+ IdAllocatorInterface* id_allocator = group_->GetIdAllocator(namespace_id);
+ if (id_offset == 0) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ ids[ii] = id_allocator->AllocateID();
+ }
+ } else {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ ids[ii] = id_allocator->AllocateIDAtOrAbove(id_offset);
+ id_offset = ids[ii] + 1;
+ }
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleGenSharedIdsCHROMIUM(
+ uint32 immediate_data_size, const cmds::GenSharedIdsCHROMIUM& c) {
+ GLuint namespace_id = static_cast<GLuint>(c.namespace_id);
+ GLuint id_offset = static_cast<GLuint>(c.id_offset);
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* ids = GetSharedMemoryAs<GLuint*>(
+ c.ids_shm_id, c.ids_shm_offset, data_size);
+ if (n < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "GenSharedIdsCHROMIUM", "n < 0");
+ return error::kNoError;
+ }
+ if (ids == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoGenSharedIdsCHROMIUM(namespace_id, id_offset, n, ids);
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoRegisterSharedIdsCHROMIUM(
+ GLuint namespace_id, GLsizei n, const GLuint* ids) {
+ IdAllocatorInterface* id_allocator = group_->GetIdAllocator(namespace_id);
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (!id_allocator->MarkAsUsed(ids[ii])) {
+ for (GLsizei jj = 0; jj < ii; ++jj) {
+ id_allocator->FreeID(ids[jj]);
+ }
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "RegisterSharedIdsCHROMIUM",
+ "attempt to register id that already exists");
+ return;
+ }
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleRegisterSharedIdsCHROMIUM(
+ uint32 immediate_data_size, const cmds::RegisterSharedIdsCHROMIUM& c) {
+ GLuint namespace_id = static_cast<GLuint>(c.namespace_id);
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* ids = GetSharedMemoryAs<GLuint*>(
+ c.ids_shm_id, c.ids_shm_offset, data_size);
+ if (n < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "RegisterSharedIdsCHROMIUM", "n < 0");
+ return error::kNoError;
+ }
+ if (ids == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoRegisterSharedIdsCHROMIUM(namespace_id, n, ids);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::DoClear(GLbitfield mask) {
+ DCHECK(!ShouldDeferDraws());
+ if (CheckBoundFramebuffersValid("glClear")) {
+ ApplyDirtyState();
+ glClear(mask);
+ }
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoFramebufferRenderbuffer(
+ GLenum target, GLenum attachment, GLenum renderbuffertarget,
+ GLuint client_renderbuffer_id) {
+ Framebuffer* framebuffer = GetFramebufferInfoForTarget(target);
+ if (!framebuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glFramebufferRenderbuffer", "no framebuffer bound");
+ return;
+ }
+ GLuint service_id = 0;
+ Renderbuffer* renderbuffer = NULL;
+ if (client_renderbuffer_id) {
+ renderbuffer = GetRenderbuffer(client_renderbuffer_id);
+ if (!renderbuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glFramebufferRenderbuffer", "unknown renderbuffer");
+ return;
+ }
+ service_id = renderbuffer->service_id();
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glFramebufferRenderbuffer");
+ glFramebufferRenderbufferEXT(
+ target, attachment, renderbuffertarget, service_id);
+ GLenum error = LOCAL_PEEK_GL_ERROR("glFramebufferRenderbuffer");
+ if (error == GL_NO_ERROR) {
+ framebuffer->AttachRenderbuffer(attachment, renderbuffer);
+ }
+ if (framebuffer == state_.bound_draw_framebuffer.get()) {
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ OnFboChanged();
+}
+
+void GLES2DecoderImpl::DoDisable(GLenum cap) {
+ if (SetCapabilityState(cap, false)) {
+ glDisable(cap);
+ }
+}
+
+void GLES2DecoderImpl::DoEnable(GLenum cap) {
+ if (SetCapabilityState(cap, true)) {
+ glEnable(cap);
+ }
+}
+
+void GLES2DecoderImpl::DoDepthRangef(GLclampf znear, GLclampf zfar) {
+ state_.z_near = std::min(1.0f, std::max(0.0f, znear));
+ state_.z_far = std::min(1.0f, std::max(0.0f, zfar));
+ glDepthRange(znear, zfar);
+}
+
+void GLES2DecoderImpl::DoSampleCoverage(GLclampf value, GLboolean invert) {
+ state_.sample_coverage_value = std::min(1.0f, std::max(0.0f, value));
+ state_.sample_coverage_invert = (invert != 0);
+ glSampleCoverage(state_.sample_coverage_value, invert);
+}
+
+// Assumes framebuffer is complete.
+void GLES2DecoderImpl::ClearUnclearedAttachments(
+ GLenum target, Framebuffer* framebuffer) {
+ if (target == GL_READ_FRAMEBUFFER_EXT) {
+ // bind this to the DRAW point, clear then bind back to READ
+ // TODO(gman): I don't think there is any guarantee that an FBO that
+ // is complete on the READ attachment will be complete as a DRAW
+ // attachment.
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, framebuffer->service_id());
+ }
+ GLbitfield clear_bits = 0;
+ if (framebuffer->HasUnclearedAttachment(GL_COLOR_ATTACHMENT0)) {
+ glClearColor(
+ 0.0f, 0.0f, 0.0f,
+ (GLES2Util::GetChannelsForFormat(
+ framebuffer->GetColorAttachmentFormat()) & 0x0008) != 0 ? 0.0f :
+ 1.0f);
+ glColorMask(true, true, true, true);
+ clear_bits |= GL_COLOR_BUFFER_BIT;
+ }
+
+ if (framebuffer->HasUnclearedAttachment(GL_STENCIL_ATTACHMENT) ||
+ framebuffer->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)) {
+ glClearStencil(0);
+ glStencilMask(-1);
+ clear_bits |= GL_STENCIL_BUFFER_BIT;
+ }
+
+ if (framebuffer->HasUnclearedAttachment(GL_DEPTH_ATTACHMENT) ||
+ framebuffer->HasUnclearedAttachment(GL_DEPTH_STENCIL_ATTACHMENT)) {
+ glClearDepth(1.0f);
+ glDepthMask(true);
+ clear_bits |= GL_DEPTH_BUFFER_BIT;
+ }
+
+ glDisable(GL_SCISSOR_TEST);
+ glClear(clear_bits);
+
+ framebuffer_manager()->MarkAttachmentsAsCleared(
+ framebuffer, renderbuffer_manager(), texture_manager());
+
+ RestoreClearState();
+
+ if (target == GL_READ_FRAMEBUFFER_EXT) {
+ glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, framebuffer->service_id());
+ Framebuffer* draw_framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+ GLuint service_id = draw_framebuffer ? draw_framebuffer->service_id() :
+ GetBackbufferServiceId();
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, service_id);
+ }
+}
+
+void GLES2DecoderImpl::RestoreClearState() {
+ framebuffer_state_.clear_state_dirty = true;
+ glClearColor(
+ state_.color_clear_red, state_.color_clear_green, state_.color_clear_blue,
+ state_.color_clear_alpha);
+ glClearStencil(state_.stencil_clear);
+ glClearDepth(state_.depth_clear);
+ if (state_.enable_flags.scissor_test) {
+ glEnable(GL_SCISSOR_TEST);
+ }
+}
+
+GLenum GLES2DecoderImpl::DoCheckFramebufferStatus(GLenum target) {
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(target);
+ if (!framebuffer) {
+ return GL_FRAMEBUFFER_COMPLETE;
+ }
+ GLenum completeness = framebuffer->IsPossiblyComplete();
+ if (completeness != GL_FRAMEBUFFER_COMPLETE) {
+ return completeness;
+ }
+ return framebuffer->GetStatus(texture_manager(), target);
+}
+
+void GLES2DecoderImpl::DoFramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget,
+ GLuint client_texture_id, GLint level) {
+ DoFramebufferTexture2DCommon(
+ "glFramebufferTexture2D", target, attachment,
+ textarget, client_texture_id, level, 0);
+}
+
+void GLES2DecoderImpl::DoFramebufferTexture2DMultisample(
+ GLenum target, GLenum attachment, GLenum textarget,
+ GLuint client_texture_id, GLint level, GLsizei samples) {
+ if (!features().multisampled_render_to_texture) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glFramebufferTexture2DMultisample", "function not available");
+ return;
+ }
+ DoFramebufferTexture2DCommon(
+ "glFramebufferTexture2DMultisample", target, attachment,
+ textarget, client_texture_id, level, samples);
+}
+
+void GLES2DecoderImpl::DoFramebufferTexture2DCommon(
+ const char* name, GLenum target, GLenum attachment, GLenum textarget,
+ GLuint client_texture_id, GLint level, GLsizei samples) {
+ if (samples > renderbuffer_manager()->max_samples()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glFramebufferTexture2DMultisample", "samples too large");
+ return;
+ }
+ Framebuffer* framebuffer = GetFramebufferInfoForTarget(target);
+ if (!framebuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ name, "no framebuffer bound.");
+ return;
+ }
+ GLuint service_id = 0;
+ TextureRef* texture_ref = NULL;
+ if (client_texture_id) {
+ texture_ref = GetTexture(client_texture_id);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ name, "unknown texture_ref");
+ return;
+ }
+ service_id = texture_ref->service_id();
+ }
+
+ if (!texture_manager()->ValidForTarget(textarget, level, 0, 0, 1)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ name, "level out of range");
+ return;
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(name);
+ if (0 == samples) {
+ glFramebufferTexture2DEXT(target, attachment, textarget, service_id, level);
+ } else {
+ if (features().use_img_for_multisampled_render_to_texture) {
+ glFramebufferTexture2DMultisampleIMG(target, attachment, textarget,
+ service_id, level, samples);
+ } else {
+ glFramebufferTexture2DMultisampleEXT(target, attachment, textarget,
+ service_id, level, samples);
+ }
+ }
+ GLenum error = LOCAL_PEEK_GL_ERROR(name);
+ if (error == GL_NO_ERROR) {
+ framebuffer->AttachTexture(attachment, texture_ref, textarget, level,
+ samples);
+ }
+ if (framebuffer == state_.bound_draw_framebuffer.get()) {
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ OnFboChanged();
+}
+
+void GLES2DecoderImpl::DoGetFramebufferAttachmentParameteriv(
+ GLenum target, GLenum attachment, GLenum pname, GLint* params) {
+ Framebuffer* framebuffer = GetFramebufferInfoForTarget(target);
+ if (!framebuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glFramebufferAttachmentParameteriv", "no framebuffer bound");
+ return;
+ }
+ if (pname == GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME) {
+ const Framebuffer::Attachment* attachment_object =
+ framebuffer->GetAttachment(attachment);
+ *params = attachment_object ? attachment_object->object_name() : 0;
+ } else {
+ if (pname == GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT &&
+ features().use_img_for_multisampled_render_to_texture) {
+ pname = GL_TEXTURE_SAMPLES_IMG;
+ }
+ glGetFramebufferAttachmentParameterivEXT(target, attachment, pname, params);
+ }
+}
+
+void GLES2DecoderImpl::DoGetRenderbufferParameteriv(
+ GLenum target, GLenum pname, GLint* params) {
+ Renderbuffer* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (!renderbuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glGetRenderbufferParameteriv", "no renderbuffer bound");
+ return;
+ }
+ switch (pname) {
+ case GL_RENDERBUFFER_INTERNAL_FORMAT:
+ *params = renderbuffer->internal_format();
+ break;
+ case GL_RENDERBUFFER_WIDTH:
+ *params = renderbuffer->width();
+ break;
+ case GL_RENDERBUFFER_HEIGHT:
+ *params = renderbuffer->height();
+ break;
+ case GL_RENDERBUFFER_SAMPLES_EXT:
+ if (features().use_img_for_multisampled_render_to_texture) {
+ glGetRenderbufferParameterivEXT(target, GL_RENDERBUFFER_SAMPLES_IMG,
+ params);
+ } else {
+ glGetRenderbufferParameterivEXT(target, GL_RENDERBUFFER_SAMPLES_EXT,
+ params);
+ }
+ default:
+ glGetRenderbufferParameterivEXT(target, pname, params);
+ break;
+ }
+}
+
+void GLES2DecoderImpl::DoBlitFramebufferEXT(
+ GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
+ GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
+ GLbitfield mask, GLenum filter) {
+ DCHECK(!ShouldDeferReads() && !ShouldDeferDraws());
+ if (!features().chromium_framebuffer_multisample) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBlitFramebufferEXT", "function not available");
+ }
+
+ if (!CheckBoundFramebuffersValid("glBlitFramebufferEXT")) {
+ return;
+ }
+
+ glDisable(GL_SCISSOR_TEST);
+ if (IsAngle()) {
+ glBlitFramebufferANGLE(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ } else {
+ glBlitFramebufferEXT(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ }
+ EnableDisable(GL_SCISSOR_TEST, state_.enable_flags.scissor_test);
+}
+
+void GLES2DecoderImpl::DoRenderbufferStorageMultisample(
+ GLenum target, GLsizei samples, GLenum internalformat,
+ GLsizei width, GLsizei height) {
+ if (!features().chromium_framebuffer_multisample &&
+ !features().multisampled_render_to_texture) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glRenderbufferStorageMultisample", "function not available");
+ return;
+ }
+
+ Renderbuffer* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (!renderbuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glRenderbufferStorageMultisample", "no renderbuffer bound");
+ return;
+ }
+
+ if (samples > renderbuffer_manager()->max_samples()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glRenderbufferStorageMultisample", "samples too large");
+ return;
+ }
+
+ if (width > renderbuffer_manager()->max_renderbuffer_size() ||
+ height > renderbuffer_manager()->max_renderbuffer_size()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glRenderbufferStorageMultisample", "dimensions too large");
+ return;
+ }
+
+ uint32 estimated_size = 0;
+ if (!RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ width, height, samples, internalformat, &estimated_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY,
+ "glRenderbufferStorageMultsample", "dimensions too large");
+ return;
+ }
+
+ if (!EnsureGPUMemoryAvailable(estimated_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY,
+ "glRenderbufferStorageMultsample", "out of memory");
+ return;
+ }
+
+ GLenum impl_format = RenderbufferManager::
+ InternalRenderbufferFormatToImplFormat(internalformat);
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glRenderbufferStorageMultisample");
+ if (IsAngle()) {
+ glRenderbufferStorageMultisampleANGLE(
+ target, samples, impl_format, width, height);
+ } else if (features().use_img_for_multisampled_render_to_texture) {
+ glRenderbufferStorageMultisampleIMG(
+ target, samples, impl_format, width, height);
+ } else {
+ glRenderbufferStorageMultisampleEXT(
+ target, samples, impl_format, width, height);
+ }
+ GLenum error = LOCAL_PEEK_GL_ERROR("glRenderbufferStorageMultisample");
+ if (error == GL_NO_ERROR) {
+ // TODO(gman): If renderbuffers tracked which framebuffers they were
+ // attached to we could just mark those framebuffers as not complete.
+ framebuffer_manager()->IncFramebufferStateChangeCount();
+ renderbuffer_manager()->SetInfo(
+ renderbuffer, samples, internalformat, width, height);
+ }
+}
+
+void GLES2DecoderImpl::DoRenderbufferStorage(
+ GLenum target, GLenum internalformat, GLsizei width, GLsizei height) {
+ Renderbuffer* renderbuffer =
+ GetRenderbufferInfoForTarget(GL_RENDERBUFFER);
+ if (!renderbuffer) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glRenderbufferStorage", "no renderbuffer bound");
+ return;
+ }
+
+ if (width > renderbuffer_manager()->max_renderbuffer_size() ||
+ height > renderbuffer_manager()->max_renderbuffer_size()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glRenderbufferStorage", "dimensions too large");
+ return;
+ }
+
+ uint32 estimated_size = 0;
+ if (!RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ width, height, 1, internalformat, &estimated_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glRenderbufferStorage", "dimensions too large");
+ return;
+ }
+
+ if (!EnsureGPUMemoryAvailable(estimated_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glRenderbufferStorage", "out of memory");
+ return;
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glRenderbufferStorage");
+ glRenderbufferStorageEXT(
+ target, RenderbufferManager::
+ InternalRenderbufferFormatToImplFormat(internalformat),
+ width, height);
+ GLenum error = LOCAL_PEEK_GL_ERROR("glRenderbufferStorage");
+ if (error == GL_NO_ERROR) {
+ // TODO(gman): If tetxures tracked which framebuffers they were attached to
+ // we could just mark those framebuffers as not complete.
+ framebuffer_manager()->IncFramebufferStateChangeCount();
+ renderbuffer_manager()->SetInfo(
+ renderbuffer, 1, internalformat, width, height);
+ }
+}
+
+void GLES2DecoderImpl::DoLinkProgram(GLuint program_id) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoLinkProgram");
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glLinkProgram");
+ if (!program) {
+ return;
+ }
+
+ LogClientServiceForInfo(program, program_id, "glLinkProgram");
+ ShaderTranslator* vertex_translator = NULL;
+ ShaderTranslator* fragment_translator = NULL;
+ if (use_shader_translator_) {
+ vertex_translator = vertex_translator_.get();
+ fragment_translator = fragment_translator_.get();
+ }
+ if (program->Link(shader_manager(),
+ vertex_translator,
+ fragment_translator,
+ feature_info_.get(),
+ shader_cache_callback_)) {
+ if (program == state_.current_program.get()) {
+ if (workarounds().use_current_program_after_successful_link) {
+ glUseProgram(program->service_id());
+ }
+ program_manager()->ClearUniforms(program);
+ }
+ }
+};
+
+void GLES2DecoderImpl::DoTexParameterf(
+ GLenum target, GLenum pname, GLfloat param) {
+ TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameterf", "unknown texture");
+ return;
+ }
+
+ texture_manager()->SetParameter(
+ "glTexParameterf", GetErrorState(), texture, pname,
+ static_cast<GLint>(param));
+}
+
+void GLES2DecoderImpl::DoTexParameteri(
+ GLenum target, GLenum pname, GLint param) {
+ TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameteri", "unknown texture");
+ return;
+ }
+
+ texture_manager()->SetParameter(
+ "glTexParameteri", GetErrorState(), texture, pname, param);
+}
+
+void GLES2DecoderImpl::DoTexParameterfv(
+ GLenum target, GLenum pname, const GLfloat* params) {
+ TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexParameterfv", "unknown texture");
+ return;
+ }
+
+ texture_manager()->SetParameter(
+ "glTexParameterfv", GetErrorState(), texture, pname,
+ static_cast<GLint>(params[0]));
+}
+
+void GLES2DecoderImpl::DoTexParameteriv(
+ GLenum target, GLenum pname, const GLint* params) {
+ TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glTexParameteriv", "unknown texture");
+ return;
+ }
+
+ texture_manager()->SetParameter(
+ "glTexParameteriv", GetErrorState(), texture, pname, *params);
+}
+
+bool GLES2DecoderImpl::CheckCurrentProgram(const char* function_name) {
+ if (!state_.current_program.get()) {
+ // The program does not exist.
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "no program in use");
+ return false;
+ }
+ if (!state_.current_program->InUse()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "program not linked");
+ return false;
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::CheckCurrentProgramForUniform(
+ GLint location, const char* function_name) {
+ if (!CheckCurrentProgram(function_name)) {
+ return false;
+ }
+ return location != -1;
+}
+
+namespace {
+
+static const GLenum valid_int_vec1_types_list[] = {
+ GL_INT,
+ GL_BOOL,
+ GL_SAMPLER_2D,
+ GL_SAMPLER_2D_RECT_ARB,
+ GL_SAMPLER_CUBE,
+ GL_SAMPLER_EXTERNAL_OES,
+};
+
+static const GLenum valid_int_vec2_types_list[] = {
+ GL_INT_VEC2,
+ GL_BOOL_VEC2,
+};
+
+static const GLenum valid_int_vec3_types_list[] = {
+ GL_INT_VEC3,
+ GL_BOOL_VEC3,
+};
+
+static const GLenum valid_int_vec4_types_list[] = {
+ GL_INT_VEC4,
+ GL_BOOL_VEC4,
+};
+
+static const GLenum valid_float_vec1_types_list[] = {
+ GL_FLOAT,
+ GL_BOOL,
+};
+
+static const GLenum valid_float_vec2_types_list[] = {
+ GL_FLOAT_VEC2,
+ GL_BOOL_VEC2,
+};
+
+static const GLenum valid_float_vec3_types_list[] = {
+ GL_FLOAT_VEC3,
+ GL_BOOL_VEC3,
+};
+
+static const GLenum valid_float_vec4_types_list[] = {
+ GL_FLOAT_VEC4,
+ GL_BOOL_VEC4,
+};
+
+static const GLenum valid_float_mat2_types_list[] = {
+ GL_FLOAT_MAT2,
+};
+
+static const GLenum valid_float_mat3_types_list[] = {
+ GL_FLOAT_MAT3,
+};
+
+static const GLenum valid_float_mat4_types_list[] = {
+ GL_FLOAT_MAT4,
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_int_vec1_base_info = {
+ valid_int_vec1_types_list,
+ arraysize(valid_int_vec1_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_int_vec2_base_info = {
+ valid_int_vec2_types_list,
+ arraysize(valid_int_vec2_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_int_vec3_base_info = {
+ valid_int_vec3_types_list,
+ arraysize(valid_int_vec3_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_int_vec4_base_info = {
+ valid_int_vec4_types_list,
+ arraysize(valid_int_vec4_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_vec1_base_info = {
+ valid_float_vec1_types_list,
+ arraysize(valid_float_vec1_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_vec2_base_info = {
+ valid_float_vec2_types_list,
+ arraysize(valid_float_vec2_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_vec3_base_info = {
+ valid_float_vec3_types_list,
+ arraysize(valid_float_vec3_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_vec4_base_info = {
+ valid_float_vec4_types_list,
+ arraysize(valid_float_vec4_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_mat2_base_info = {
+ valid_float_mat2_types_list,
+ arraysize(valid_float_mat2_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_mat3_base_info = {
+ valid_float_mat3_types_list,
+ arraysize(valid_float_mat3_types_list),
+};
+
+static const GLES2DecoderImpl::BaseUniformInfo valid_float_mat4_base_info = {
+ valid_float_mat4_types_list,
+ arraysize(valid_float_mat4_types_list),
+};
+
+} // anonymous namespace.
+
+bool GLES2DecoderImpl::PrepForSetUniformByLocation(
+ GLint fake_location, const char* function_name,
+ const GLES2DecoderImpl::BaseUniformInfo& base_info,
+ GLint* real_location, GLenum* type, GLsizei* count) {
+ DCHECK(type);
+ DCHECK(count);
+ DCHECK(real_location);
+
+ if (!CheckCurrentProgramForUniform(fake_location, function_name)) {
+ return false;
+ }
+ GLint array_index = -1;
+ const Program::UniformInfo* info =
+ state_.current_program->GetUniformInfoByFakeLocation(
+ fake_location, real_location, &array_index);
+ if (!info) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "unknown location");
+ return false;
+ }
+ bool okay = false;
+ for (size_t ii = 0; ii < base_info.num_valid_types; ++ii) {
+ if (base_info.valid_types[ii] == info->type) {
+ okay = true;
+ break;
+ }
+ }
+ if (!okay) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name,
+ "wrong uniform function for type");
+ return false;
+ }
+ if (*count > 1 && !info->is_array) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "count > 1 for non-array");
+ return false;
+ }
+ *count = std::min(info->size - array_index, *count);
+ if (*count <= 0) {
+ return false;
+ }
+ *type = info->type;
+ return true;
+}
+
+void GLES2DecoderImpl::DoUniform1i(GLint fake_location, GLint v0) {
+ GLenum type = 0;
+ GLsizei count = 1;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform1iv", valid_int_vec1_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ if (!state_.current_program->SetSamplers(
+ state_.texture_units.size(), fake_location, 1, &v0)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniform1i", "texture unit out of range");
+ return;
+ }
+ glUniform1i(real_location, v0);
+}
+
+void GLES2DecoderImpl::DoUniform1iv(
+ GLint fake_location, GLsizei count, const GLint *value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform1iv", valid_int_vec1_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ if (type == GL_SAMPLER_2D || type == GL_SAMPLER_2D_RECT_ARB ||
+ type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES) {
+ if (!state_.current_program->SetSamplers(
+ state_.texture_units.size(), fake_location, count, value)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniform1iv", "texture unit out of range");
+ return;
+ }
+ }
+ glUniform1iv(real_location, count, value);
+}
+
+void GLES2DecoderImpl::DoUniform1fv(
+ GLint fake_location, GLsizei count, const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform1fv", valid_float_vec1_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ if (type == GL_BOOL) {
+ scoped_ptr<GLint[]> temp(new GLint[count]);
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ temp[ii] = static_cast<GLint>(value[ii] != 0.0f);
+ }
+ DoUniform1iv(real_location, count, temp.get());
+ } else {
+ glUniform1fv(real_location, count, value);
+ }
+}
+
+void GLES2DecoderImpl::DoUniform2fv(
+ GLint fake_location, GLsizei count, const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform2fv", valid_float_vec2_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ if (type == GL_BOOL_VEC2) {
+ GLsizei num_values = count * 2;
+ scoped_ptr<GLint[]> temp(new GLint[num_values]);
+ for (GLsizei ii = 0; ii < num_values; ++ii) {
+ temp[ii] = static_cast<GLint>(value[ii] != 0.0f);
+ }
+ glUniform2iv(real_location, count, temp.get());
+ } else {
+ glUniform2fv(real_location, count, value);
+ }
+}
+
+void GLES2DecoderImpl::DoUniform3fv(
+ GLint fake_location, GLsizei count, const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform3fv", valid_float_vec3_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ if (type == GL_BOOL_VEC3) {
+ GLsizei num_values = count * 3;
+ scoped_ptr<GLint[]> temp(new GLint[num_values]);
+ for (GLsizei ii = 0; ii < num_values; ++ii) {
+ temp[ii] = static_cast<GLint>(value[ii] != 0.0f);
+ }
+ glUniform3iv(real_location, count, temp.get());
+ } else {
+ glUniform3fv(real_location, count, value);
+ }
+}
+
+void GLES2DecoderImpl::DoUniform4fv(
+ GLint fake_location, GLsizei count, const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform4fv", valid_float_vec4_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ if (type == GL_BOOL_VEC4) {
+ GLsizei num_values = count * 4;
+ scoped_ptr<GLint[]> temp(new GLint[num_values]);
+ for (GLsizei ii = 0; ii < num_values; ++ii) {
+ temp[ii] = static_cast<GLint>(value[ii] != 0.0f);
+ }
+ glUniform4iv(real_location, count, temp.get());
+ } else {
+ glUniform4fv(real_location, count, value);
+ }
+}
+
+void GLES2DecoderImpl::DoUniform2iv(
+ GLint fake_location, GLsizei count, const GLint* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform2iv", valid_int_vec2_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ glUniform2iv(real_location, count, value);
+}
+
+void GLES2DecoderImpl::DoUniform3iv(
+ GLint fake_location, GLsizei count, const GLint* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform3iv", valid_int_vec3_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ glUniform3iv(real_location, count, value);
+}
+
+void GLES2DecoderImpl::DoUniform4iv(
+ GLint fake_location, GLsizei count, const GLint* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniform4iv", valid_int_vec4_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ glUniform4iv(real_location, count, value);
+}
+
+void GLES2DecoderImpl::DoUniformMatrix2fv(
+ GLint fake_location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniformMatrix2fv", valid_float_mat2_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ glUniformMatrix2fv(real_location, count, transpose, value);
+}
+
+void GLES2DecoderImpl::DoUniformMatrix3fv(
+ GLint fake_location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniformMatrix3fv", valid_float_mat3_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ glUniformMatrix3fv(real_location, count, transpose, value);
+}
+
+void GLES2DecoderImpl::DoUniformMatrix4fv(
+ GLint fake_location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) {
+ GLenum type = 0;
+ GLint real_location = -1;
+ if (!PrepForSetUniformByLocation(
+ fake_location, "glUniformMatrix4fv", valid_float_mat4_base_info,
+ &real_location, &type, &count)) {
+ return;
+ }
+ glUniformMatrix4fv(real_location, count, transpose, value);
+}
+
+void GLES2DecoderImpl::DoUseProgram(GLuint program_id) {
+ GLuint service_id = 0;
+ Program* program = NULL;
+ if (program_id) {
+ program = GetProgramInfoNotShader(program_id, "glUseProgram");
+ if (!program) {
+ return;
+ }
+ if (!program->IsValid()) {
+ // Program was not linked successfully. (ie, glLinkProgram)
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glUseProgram", "program not linked");
+ return;
+ }
+ service_id = program->service_id();
+ }
+ if (state_.current_program.get()) {
+ program_manager()->UnuseProgram(shader_manager(),
+ state_.current_program.get());
+ }
+ state_.current_program = program;
+ LogClientServiceMapping("glUseProgram", program_id, service_id);
+ glUseProgram(service_id);
+ if (state_.current_program.get()) {
+ program_manager()->UseProgram(state_.current_program.get());
+ }
+}
+
+void GLES2DecoderImpl::RenderWarning(
+ const char* filename, int line, const std::string& msg) {
+ logger_.LogMessage(filename, line, std::string("RENDER WARNING: ") + msg);
+}
+
+void GLES2DecoderImpl::PerformanceWarning(
+ const char* filename, int line, const std::string& msg) {
+ logger_.LogMessage(filename, line,
+ std::string("PERFORMANCE WARNING: ") + msg);
+}
+
+void GLES2DecoderImpl::UpdateStreamTextureIfNeeded(Texture* texture) {
+ if (texture && texture->IsStreamTexture()) {
+ DCHECK(stream_texture_manager());
+ StreamTexture* stream_tex =
+ stream_texture_manager()->LookupStreamTexture(texture->service_id());
+ if (stream_tex)
+ stream_tex->Update();
+ }
+}
+
+bool GLES2DecoderImpl::PrepareTexturesForRender() {
+ DCHECK(state_.current_program.get());
+ bool have_unrenderable_textures =
+ texture_manager()->HaveUnrenderableTextures();
+ if (!have_unrenderable_textures && !features().oes_egl_image_external) {
+ return true;
+ }
+
+ bool textures_set = false;
+ const Program::SamplerIndices& sampler_indices =
+ state_.current_program->sampler_indices();
+ for (size_t ii = 0; ii < sampler_indices.size(); ++ii) {
+ const Program::UniformInfo* uniform_info =
+ state_.current_program->GetUniformInfo(sampler_indices[ii]);
+ DCHECK(uniform_info);
+ for (size_t jj = 0; jj < uniform_info->texture_units.size(); ++jj) {
+ GLuint texture_unit_index = uniform_info->texture_units[jj];
+ if (texture_unit_index < state_.texture_units.size()) {
+ TextureUnit& texture_unit = state_.texture_units[texture_unit_index];
+ TextureRef* texture =
+ texture_unit.GetInfoForSamplerType(uniform_info->type).get();
+ if (texture)
+ UpdateStreamTextureIfNeeded(texture->texture());
+ if (have_unrenderable_textures &&
+ (!texture || !texture_manager()->CanRender(texture))) {
+ textures_set = true;
+ glActiveTexture(GL_TEXTURE0 + texture_unit_index);
+ glBindTexture(
+ GetBindTargetForSamplerType(uniform_info->type),
+ texture_manager()->black_texture_id(uniform_info->type));
+ LOCAL_RENDER_WARNING(
+ std::string("texture bound to texture unit ") +
+ base::IntToString(texture_unit_index) +
+ " is not renderable. It maybe non-power-of-2 and have"
+ " incompatible texture filtering or is not"
+ " 'texture complete'");
+ }
+ }
+ // else: should this be an error?
+ }
+ }
+ return !textures_set;
+}
+
+void GLES2DecoderImpl::RestoreStateForNonRenderableTextures() {
+ DCHECK(state_.current_program.get());
+ const Program::SamplerIndices& sampler_indices =
+ state_.current_program->sampler_indices();
+ for (size_t ii = 0; ii < sampler_indices.size(); ++ii) {
+ const Program::UniformInfo* uniform_info =
+ state_.current_program->GetUniformInfo(sampler_indices[ii]);
+ DCHECK(uniform_info);
+ for (size_t jj = 0; jj < uniform_info->texture_units.size(); ++jj) {
+ GLuint texture_unit_index = uniform_info->texture_units[jj];
+ if (texture_unit_index < state_.texture_units.size()) {
+ TextureUnit& texture_unit = state_.texture_units[texture_unit_index];
+ TextureRef* texture_ref =
+ uniform_info->type == GL_SAMPLER_2D
+ ? texture_unit.bound_texture_2d.get()
+ : texture_unit.bound_texture_cube_map.get();
+ if (!texture_ref || !texture_manager()->CanRender(texture_ref)) {
+ glActiveTexture(GL_TEXTURE0 + texture_unit_index);
+ // Get the texture_ref info that was previously bound here.
+ texture_ref = texture_unit.bind_target == GL_TEXTURE_2D
+ ? texture_unit.bound_texture_2d.get()
+ : texture_unit.bound_texture_cube_map.get();
+ glBindTexture(texture_unit.bind_target,
+ texture_ref ? texture_ref->service_id() : 0);
+ }
+ }
+ }
+ }
+ // Set the active texture back to whatever the user had it as.
+ glActiveTexture(GL_TEXTURE0 + state_.active_texture_unit);
+}
+
+bool GLES2DecoderImpl::ClearUnclearedTextures() {
+ // Only check if there are some uncleared textures.
+ if (!texture_manager()->HaveUnsafeTextures()) {
+ return true;
+ }
+
+ // 1: Check all textures we are about to render with.
+ if (state_.current_program.get()) {
+ const Program::SamplerIndices& sampler_indices =
+ state_.current_program->sampler_indices();
+ for (size_t ii = 0; ii < sampler_indices.size(); ++ii) {
+ const Program::UniformInfo* uniform_info =
+ state_.current_program->GetUniformInfo(sampler_indices[ii]);
+ DCHECK(uniform_info);
+ for (size_t jj = 0; jj < uniform_info->texture_units.size(); ++jj) {
+ GLuint texture_unit_index = uniform_info->texture_units[jj];
+ if (texture_unit_index < state_.texture_units.size()) {
+ TextureUnit& texture_unit = state_.texture_units[texture_unit_index];
+ TextureRef* texture_ref =
+ texture_unit.GetInfoForSamplerType(uniform_info->type).get();
+ if (texture_ref && !texture_ref->texture()->SafeToRenderFrom()) {
+ if (!texture_manager()->ClearRenderableLevels(this, texture_ref)) {
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::IsDrawValid(
+ const char* function_name, GLuint max_vertex_accessed, GLsizei primcount) {
+ // NOTE: We specifically do not check current_program->IsValid() because
+ // it could never be invalid since glUseProgram would have failed. While
+ // glLinkProgram could later mark the program as invalid the previous
+ // valid program will still function if it is still the current program.
+ if (!state_.current_program.get()) {
+ // The program does not exist.
+ // But GL says no ERROR.
+ LOCAL_RENDER_WARNING("Drawing with no current shader program.");
+ return false;
+ }
+
+ return state_.vertex_attrib_manager
+ ->ValidateBindings(function_name,
+ this,
+ feature_info_.get(),
+ state_.current_program.get(),
+ max_vertex_accessed,
+ primcount);
+}
+
+bool GLES2DecoderImpl::SimulateAttrib0(
+ const char* function_name, GLuint max_vertex_accessed, bool* simulated) {
+ DCHECK(simulated);
+ *simulated = false;
+
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
+ return true;
+
+ const VertexAttrib* attrib =
+ state_.vertex_attrib_manager->GetVertexAttrib(0);
+ // If it's enabled or it's not used then we don't need to do anything.
+ bool attrib_0_used =
+ state_.current_program->GetAttribInfoByLocation(0) != NULL;
+ if (attrib->enabled() && attrib_0_used) {
+ return true;
+ }
+
+ // Make a buffer with a single repeated vec4 value enough to
+ // simulate the constant value that is supposed to be here.
+ // This is required to emulate GLES2 on GL.
+ GLuint num_vertices = max_vertex_accessed + 1;
+ uint32 size_needed = 0;
+
+ if (num_vertices == 0 ||
+ !SafeMultiplyUint32(num_vertices, sizeof(Vec4), &size_needed) ||
+ size_needed > 0x7FFFFFFFU) {
+ LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, function_name, "Simulating attrib 0");
+ return false;
+ }
+
+ LOCAL_PERFORMANCE_WARNING(
+ "Attribute 0 is disabled. This has signficant performance penalty");
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(function_name);
+ glBindBuffer(GL_ARRAY_BUFFER, attrib_0_buffer_id_);
+
+ bool new_buffer = static_cast<GLsizei>(size_needed) > attrib_0_size_;
+ if (new_buffer) {
+ glBufferData(GL_ARRAY_BUFFER, size_needed, NULL, GL_DYNAMIC_DRAW);
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, function_name, "Simulating attrib 0");
+ return false;
+ }
+ }
+
+ const Vec4& value = state_.attrib_values[0];
+ if (new_buffer ||
+ (attrib_0_used &&
+ (!attrib_0_buffer_matches_value_ ||
+ (value.v[0] != attrib_0_value_.v[0] ||
+ value.v[1] != attrib_0_value_.v[1] ||
+ value.v[2] != attrib_0_value_.v[2] ||
+ value.v[3] != attrib_0_value_.v[3])))) {
+ std::vector<Vec4> temp(num_vertices, value);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, size_needed, &temp[0].v[0]);
+ attrib_0_buffer_matches_value_ = true;
+ attrib_0_value_ = value;
+ attrib_0_size_ = size_needed;
+ }
+
+ glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL);
+
+ if (attrib->divisor())
+ glVertexAttribDivisorANGLE(0, 0);
+
+ *simulated = true;
+ return true;
+}
+
+void GLES2DecoderImpl::RestoreStateForAttrib(GLuint attrib_index) {
+ const VertexAttrib* attrib =
+ state_.vertex_attrib_manager->GetVertexAttrib(attrib_index);
+ const void* ptr = reinterpret_cast<const void*>(attrib->offset());
+ Buffer* buffer = attrib->buffer();
+ glBindBuffer(GL_ARRAY_BUFFER, buffer ? buffer->service_id() : 0);
+ glVertexAttribPointer(
+ attrib_index, attrib->size(), attrib->type(), attrib->normalized(),
+ attrib->gl_stride(), ptr);
+ if (attrib->divisor())
+ glVertexAttribDivisorANGLE(attrib_index, attrib->divisor());
+ glBindBuffer(
+ GL_ARRAY_BUFFER,
+ state_.bound_array_buffer.get() ? state_.bound_array_buffer->service_id()
+ : 0);
+
+ // Never touch vertex attribute 0's state (in particular, never
+ // disable it) when running on desktop GL because it will never be
+ // re-enabled.
+ if (attrib_index != 0 ||
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ if (attrib->enabled()) {
+ glEnableVertexAttribArray(attrib_index);
+ } else {
+ glDisableVertexAttribArray(attrib_index);
+ }
+ }
+}
+
+bool GLES2DecoderImpl::SimulateFixedAttribs(
+ const char* function_name,
+ GLuint max_vertex_accessed, bool* simulated, GLsizei primcount) {
+ DCHECK(simulated);
+ *simulated = false;
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2)
+ return true;
+
+ if (!state_.vertex_attrib_manager->HaveFixedAttribs()) {
+ return true;
+ }
+
+ LOCAL_PERFORMANCE_WARNING(
+ "GL_FIXED attributes have a signficant performance penalty");
+
+ // NOTE: we could be smart and try to check if a buffer is used
+ // twice in 2 different attribs, find the overlapping parts and therefore
+ // duplicate the minimum amount of data but this whole code path is not meant
+ // to be used normally. It's just here to pass that OpenGL ES 2.0 conformance
+ // tests so we just add to the buffer attrib used.
+
+ GLuint elements_needed = 0;
+ const VertexAttribManager::VertexAttribList& enabled_attribs =
+ state_.vertex_attrib_manager->GetEnabledVertexAttribs();
+ for (VertexAttribManager::VertexAttribList::const_iterator it =
+ enabled_attribs.begin(); it != enabled_attribs.end(); ++it) {
+ const VertexAttrib* attrib = *it;
+ const Program::VertexAttrib* attrib_info =
+ state_.current_program->GetAttribInfoByLocation(attrib->index());
+ GLuint max_accessed = attrib->MaxVertexAccessed(primcount,
+ max_vertex_accessed);
+ GLuint num_vertices = max_accessed + 1;
+ if (num_vertices == 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, function_name, "Simulating attrib 0");
+ return false;
+ }
+ if (attrib_info &&
+ attrib->CanAccess(max_accessed) &&
+ attrib->type() == GL_FIXED) {
+ uint32 elements_used = 0;
+ if (!SafeMultiplyUint32(num_vertices, attrib->size(), &elements_used) ||
+ !SafeAddUint32(elements_needed, elements_used, &elements_needed)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, function_name, "simulating GL_FIXED attribs");
+ return false;
+ }
+ }
+ }
+
+ const uint32 kSizeOfFloat = sizeof(float); // NOLINT
+ uint32 size_needed = 0;
+ if (!SafeMultiplyUint32(elements_needed, kSizeOfFloat, &size_needed) ||
+ size_needed > 0x7FFFFFFFU) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, function_name, "simulating GL_FIXED attribs");
+ return false;
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER(function_name);
+
+ glBindBuffer(GL_ARRAY_BUFFER, fixed_attrib_buffer_id_);
+ if (static_cast<GLsizei>(size_needed) > fixed_attrib_buffer_size_) {
+ glBufferData(GL_ARRAY_BUFFER, size_needed, NULL, GL_DYNAMIC_DRAW);
+ GLenum error = glGetError();
+ if (error != GL_NO_ERROR) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, function_name, "simulating GL_FIXED attribs");
+ return false;
+ }
+ }
+
+ // Copy the elements and convert to float
+ GLintptr offset = 0;
+ for (VertexAttribManager::VertexAttribList::const_iterator it =
+ enabled_attribs.begin(); it != enabled_attribs.end(); ++it) {
+ const VertexAttrib* attrib = *it;
+ const Program::VertexAttrib* attrib_info =
+ state_.current_program->GetAttribInfoByLocation(attrib->index());
+ GLuint max_accessed = attrib->MaxVertexAccessed(primcount,
+ max_vertex_accessed);
+ GLuint num_vertices = max_accessed + 1;
+ if (num_vertices == 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, function_name, "Simulating attrib 0");
+ return false;
+ }
+ if (attrib_info &&
+ attrib->CanAccess(max_accessed) &&
+ attrib->type() == GL_FIXED) {
+ int num_elements = attrib->size() * kSizeOfFloat;
+ int size = num_elements * num_vertices;
+ scoped_ptr<float[]> data(new float[size]);
+ const int32* src = reinterpret_cast<const int32 *>(
+ attrib->buffer()->GetRange(attrib->offset(), size));
+ const int32* end = src + num_elements;
+ float* dst = data.get();
+ while (src != end) {
+ *dst++ = static_cast<float>(*src++) / 65536.0f;
+ }
+ glBufferSubData(GL_ARRAY_BUFFER, offset, size, data.get());
+ glVertexAttribPointer(
+ attrib->index(), attrib->size(), GL_FLOAT, false, 0,
+ reinterpret_cast<GLvoid*>(offset));
+ offset += size;
+ }
+ }
+ *simulated = true;
+ return true;
+}
+
+void GLES2DecoderImpl::RestoreStateForSimulatedFixedAttribs() {
+ // There's no need to call glVertexAttribPointer because we shadow all the
+ // settings and passing GL_FIXED to it will not work.
+ glBindBuffer(
+ GL_ARRAY_BUFFER,
+ state_.bound_array_buffer.get() ? state_.bound_array_buffer->service_id()
+ : 0);
+}
+
+error::Error GLES2DecoderImpl::DoDrawArrays(
+ const char* function_name,
+ bool instanced,
+ GLenum mode,
+ GLint first,
+ GLsizei count,
+ GLsizei primcount) {
+ if (ShouldDeferDraws())
+ return error::kDeferCommandUntilLater;
+ if (!validators_->draw_mode.IsValid(mode)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, mode, "mode");
+ return error::kNoError;
+ }
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "count < 0");
+ return error::kNoError;
+ }
+ if (primcount < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "primcount < 0");
+ return error::kNoError;
+ }
+ if (!CheckBoundFramebuffersValid(function_name)) {
+ return error::kNoError;
+ }
+ // We have to check this here because the prototype for glDrawArrays
+ // is GLint not GLsizei.
+ if (first < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "first < 0");
+ return error::kNoError;
+ }
+
+ if (count == 0 || (instanced && primcount == 0)) {
+ LOCAL_RENDER_WARNING("Render count or primcount is 0.");
+ return error::kNoError;
+ }
+
+ GLuint max_vertex_accessed = first + count - 1;
+ if (IsDrawValid(function_name, max_vertex_accessed, primcount)) {
+ if (!ClearUnclearedTextures()) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "out of memory");
+ return error::kNoError;
+ }
+ bool simulated_attrib_0 = false;
+ if (!SimulateAttrib0(
+ function_name, max_vertex_accessed, &simulated_attrib_0)) {
+ return error::kNoError;
+ }
+ bool simulated_fixed_attribs = false;
+ if (SimulateFixedAttribs(
+ function_name, max_vertex_accessed, &simulated_fixed_attribs,
+ primcount)) {
+ bool textures_set = !PrepareTexturesForRender();
+ ApplyDirtyState();
+ if (!instanced) {
+ glDrawArrays(mode, first, count);
+ } else {
+ glDrawArraysInstancedANGLE(mode, first, count, primcount);
+ }
+ ProcessPendingQueries();
+ if (textures_set) {
+ RestoreStateForNonRenderableTextures();
+ }
+ if (simulated_fixed_attribs) {
+ RestoreStateForSimulatedFixedAttribs();
+ }
+ }
+ if (simulated_attrib_0) {
+ RestoreStateForAttrib(0);
+ }
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDrawArrays(
+ uint32 immediate_data_size, const cmds::DrawArrays& c) {
+ return DoDrawArrays("glDrawArrays",
+ false,
+ static_cast<GLenum>(c.mode),
+ static_cast<GLint>(c.first),
+ static_cast<GLsizei>(c.count),
+ 0);
+}
+
+error::Error GLES2DecoderImpl::HandleDrawArraysInstancedANGLE(
+ uint32 immediate_data_size, const cmds::DrawArraysInstancedANGLE& c) {
+ if (!features().angle_instanced_arrays) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glDrawArraysInstancedANGLE", "function not available");
+ return error::kNoError;
+ }
+ return DoDrawArrays("glDrawArraysIntancedANGLE",
+ true,
+ static_cast<GLenum>(c.mode),
+ static_cast<GLint>(c.first),
+ static_cast<GLsizei>(c.count),
+ static_cast<GLsizei>(c.primcount));
+}
+
+error::Error GLES2DecoderImpl::DoDrawElements(
+ const char* function_name,
+ bool instanced,
+ GLenum mode,
+ GLsizei count,
+ GLenum type,
+ int32 offset,
+ GLsizei primcount) {
+ if (ShouldDeferDraws())
+ return error::kDeferCommandUntilLater;
+ if (!state_.vertex_attrib_manager->element_array_buffer()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "No element array buffer bound");
+ return error::kNoError;
+ }
+
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "count < 0");
+ return error::kNoError;
+ }
+ if (offset < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "offset < 0");
+ return error::kNoError;
+ }
+ if (!validators_->draw_mode.IsValid(mode)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, mode, "mode");
+ return error::kNoError;
+ }
+ if (!validators_->index_type.IsValid(type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type");
+ return error::kNoError;
+ }
+ if (primcount < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "primcount < 0");
+ return error::kNoError;
+ }
+
+ if (!CheckBoundFramebuffersValid(function_name)) {
+ return error::kNoError;
+ }
+
+ if (count == 0 || (instanced && primcount == 0)) {
+ return error::kNoError;
+ }
+
+ GLuint max_vertex_accessed;
+ Buffer* element_array_buffer =
+ state_.vertex_attrib_manager->element_array_buffer();
+
+ if (!element_array_buffer->GetMaxValueForRange(
+ offset, count, type, &max_vertex_accessed)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "range out of bounds for buffer");
+ return error::kNoError;
+ }
+
+ if (IsDrawValid(function_name, max_vertex_accessed, primcount)) {
+ if (!ClearUnclearedTextures()) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "out of memory");
+ return error::kNoError;
+ }
+ bool simulated_attrib_0 = false;
+ if (!SimulateAttrib0(
+ function_name, max_vertex_accessed, &simulated_attrib_0)) {
+ return error::kNoError;
+ }
+ bool simulated_fixed_attribs = false;
+ if (SimulateFixedAttribs(
+ function_name, max_vertex_accessed, &simulated_fixed_attribs,
+ primcount)) {
+ bool textures_set = !PrepareTexturesForRender();
+ ApplyDirtyState();
+ // TODO(gman): Refactor to hide these details in BufferManager or
+ // VertexAttribManager.
+ const GLvoid* indices = reinterpret_cast<const GLvoid*>(offset);
+ bool used_client_side_array = false;
+ if (element_array_buffer->IsClientSideArray()) {
+ used_client_side_array = true;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ indices = element_array_buffer->GetRange(offset, 0);
+ }
+
+ if (!instanced) {
+ glDrawElements(mode, count, type, indices);
+ } else {
+ glDrawElementsInstancedANGLE(mode, count, type, indices, primcount);
+ }
+
+ if (used_client_side_array) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
+ element_array_buffer->service_id());
+ }
+
+ ProcessPendingQueries();
+ if (textures_set) {
+ RestoreStateForNonRenderableTextures();
+ }
+ if (simulated_fixed_attribs) {
+ RestoreStateForSimulatedFixedAttribs();
+ }
+ }
+ if (simulated_attrib_0) {
+ RestoreStateForAttrib(0);
+ }
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDrawElements(
+ uint32 immediate_data_size, const cmds::DrawElements& c) {
+ return DoDrawElements("glDrawElements",
+ false,
+ static_cast<GLenum>(c.mode),
+ static_cast<GLsizei>(c.count),
+ static_cast<GLenum>(c.type),
+ static_cast<int32>(c.index_offset),
+ 0);
+}
+
+error::Error GLES2DecoderImpl::HandleDrawElementsInstancedANGLE(
+ uint32 immediate_data_size, const cmds::DrawElementsInstancedANGLE& c) {
+ if (!features().angle_instanced_arrays) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glDrawElementsInstancedANGLE", "function not available");
+ return error::kNoError;
+ }
+ return DoDrawElements("glDrawElementsInstancedANGLE",
+ true,
+ static_cast<GLenum>(c.mode),
+ static_cast<GLsizei>(c.count),
+ static_cast<GLenum>(c.type),
+ static_cast<int32>(c.index_offset),
+ static_cast<GLsizei>(c.primcount));
+}
+
+GLuint GLES2DecoderImpl::DoGetMaxValueInBufferCHROMIUM(
+ GLuint buffer_id, GLsizei count, GLenum type, GLuint offset) {
+ GLuint max_vertex_accessed = 0;
+ Buffer* buffer = GetBuffer(buffer_id);
+ if (!buffer) {
+ // TODO(gman): Should this be a GL error or a command buffer error?
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "GetMaxValueInBufferCHROMIUM", "unknown buffer");
+ } else {
+ if (!buffer->GetMaxValueForRange(
+ offset, count, type, &max_vertex_accessed)) {
+ // TODO(gman): Should this be a GL error or a command buffer error?
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "GetMaxValueInBufferCHROMIUM", "range out of bounds for buffer");
+ }
+ }
+ return max_vertex_accessed;
+}
+
+// Calls glShaderSource for the various versions of the ShaderSource command.
+// Assumes that data / data_size points to a piece of memory that is in range
+// of whatever context it came from (shared memory, immediate memory, bucket
+// memory.)
+error::Error GLES2DecoderImpl::ShaderSourceHelper(
+ GLuint client_id, const char* data, uint32 data_size) {
+ std::string str(data, data + data_size);
+ Shader* shader = GetShaderInfoNotProgram(client_id, "glShaderSource");
+ if (!shader) {
+ return error::kNoError;
+ }
+ // Note: We don't actually call glShaderSource here. We wait until
+ // the call to glCompileShader.
+ shader->UpdateSource(str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleShaderSource(
+ uint32 immediate_data_size, const cmds::ShaderSource& c) {
+ uint32 data_size = c.data_size;
+ const char* data = GetSharedMemoryAs<const char*>(
+ c.data_shm_id, c.data_shm_offset, data_size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ return ShaderSourceHelper(c.shader, data, data_size);
+}
+
+error::Error GLES2DecoderImpl::HandleShaderSourceImmediate(
+ uint32 immediate_data_size, const cmds::ShaderSourceImmediate& c) {
+ uint32 data_size = c.data_size;
+ const char* data = GetImmediateDataAs<const char*>(
+ c, data_size, immediate_data_size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ return ShaderSourceHelper(c.shader, data, data_size);
+}
+
+error::Error GLES2DecoderImpl::HandleShaderSourceBucket(
+ uint32 immediate_data_size, const cmds::ShaderSourceBucket& c) {
+ Bucket* bucket = GetBucket(c.data_bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ return ShaderSourceHelper(
+ c.shader, bucket->GetDataAs<const char*>(0, bucket->size() - 1),
+ bucket->size() - 1);
+}
+
+void GLES2DecoderImpl::DoCompileShader(GLuint client_id) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoCompileShader");
+ Shader* shader = GetShaderInfoNotProgram(client_id, "glCompileShader");
+ if (!shader) {
+ return;
+ }
+ ShaderTranslator* translator = NULL;
+ if (use_shader_translator_) {
+ translator = shader->shader_type() == GL_VERTEX_SHADER ?
+ vertex_translator_.get() : fragment_translator_.get();
+ }
+
+ program_manager()->DoCompileShader(shader, translator, feature_info_.get());
+};
+
+void GLES2DecoderImpl::DoGetShaderiv(
+ GLuint shader_id, GLenum pname, GLint* params) {
+ Shader* shader = GetShaderInfoNotProgram(shader_id, "glGetShaderiv");
+ if (!shader) {
+ return;
+ }
+ switch (pname) {
+ case GL_SHADER_SOURCE_LENGTH:
+ *params = shader->source() ? shader->source()->size() + 1 : 0;
+ return;
+ case GL_COMPILE_STATUS:
+ *params = compile_shader_always_succeeds_ ? true : shader->IsValid();
+ return;
+ case GL_INFO_LOG_LENGTH:
+ *params = shader->log_info() ? shader->log_info()->size() + 1 : 0;
+ return;
+ case GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE:
+ *params = shader->translated_source() ?
+ shader->translated_source()->size() + 1 : 0;
+ return;
+ default:
+ break;
+ }
+ glGetShaderiv(shader->service_id(), pname, params);
+}
+
+error::Error GLES2DecoderImpl::HandleGetShaderSource(
+ uint32 immediate_data_size, const cmds::GetShaderSource& c) {
+ GLuint shader_id = c.shader;
+ uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+ Bucket* bucket = CreateBucket(bucket_id);
+ Shader* shader = GetShaderInfoNotProgram(shader_id, "glGetShaderSource");
+ if (!shader || !shader->source()) {
+ bucket->SetSize(0);
+ return error::kNoError;
+ }
+ bucket->SetFromString(shader->source()->c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetTranslatedShaderSourceANGLE(
+ uint32 immediate_data_size,
+ const cmds::GetTranslatedShaderSourceANGLE& c) {
+ GLuint shader_id = c.shader;
+ uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+ Bucket* bucket = CreateBucket(bucket_id);
+ Shader* shader = GetShaderInfoNotProgram(
+ shader_id, "glTranslatedGetShaderSourceANGLE");
+ if (!shader) {
+ bucket->SetSize(0);
+ return error::kNoError;
+ }
+
+ bucket->SetFromString(shader->translated_source() ?
+ shader->translated_source()->c_str() : NULL);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetProgramInfoLog(
+ uint32 immediate_data_size, const cmds::GetProgramInfoLog& c) {
+ GLuint program_id = c.program;
+ uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+ Bucket* bucket = CreateBucket(bucket_id);
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glGetProgramInfoLog");
+ if (!program || !program->log_info()) {
+ bucket->SetFromString("");
+ return error::kNoError;
+ }
+ bucket->SetFromString(program->log_info()->c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetShaderInfoLog(
+ uint32 immediate_data_size, const cmds::GetShaderInfoLog& c) {
+ GLuint shader_id = c.shader;
+ uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+ Bucket* bucket = CreateBucket(bucket_id);
+ Shader* shader = GetShaderInfoNotProgram(shader_id, "glGetShaderInfoLog");
+ if (!shader || !shader->log_info()) {
+ bucket->SetFromString("");
+ return error::kNoError;
+ }
+ bucket->SetFromString(shader->log_info()->c_str());
+ return error::kNoError;
+}
+
+bool GLES2DecoderImpl::DoIsEnabled(GLenum cap) {
+ return state_.GetEnabled(cap);
+}
+
+bool GLES2DecoderImpl::DoIsBuffer(GLuint client_id) {
+ const Buffer* buffer = GetBuffer(client_id);
+ return buffer && buffer->IsValid() && !buffer->IsDeleted();
+}
+
+bool GLES2DecoderImpl::DoIsFramebuffer(GLuint client_id) {
+ const Framebuffer* framebuffer =
+ GetFramebuffer(client_id);
+ return framebuffer && framebuffer->IsValid() && !framebuffer->IsDeleted();
+}
+
+bool GLES2DecoderImpl::DoIsProgram(GLuint client_id) {
+ // IsProgram is true for programs as soon as they are created, until they are
+ // deleted and no longer in use.
+ const Program* program = GetProgram(client_id);
+ return program != NULL && !program->IsDeleted();
+}
+
+bool GLES2DecoderImpl::DoIsRenderbuffer(GLuint client_id) {
+ const Renderbuffer* renderbuffer =
+ GetRenderbuffer(client_id);
+ return renderbuffer && renderbuffer->IsValid() && !renderbuffer->IsDeleted();
+}
+
+bool GLES2DecoderImpl::DoIsShader(GLuint client_id) {
+ // IsShader is true for shaders as soon as they are created, until they
+ // are deleted and not attached to any programs.
+ const Shader* shader = GetShader(client_id);
+ return shader != NULL && !shader->IsDeleted();
+}
+
+bool GLES2DecoderImpl::DoIsTexture(GLuint client_id) {
+ const TextureRef* texture_ref = GetTexture(client_id);
+ return texture_ref && texture_ref->texture()->IsValid();
+}
+
+void GLES2DecoderImpl::DoAttachShader(
+ GLuint program_client_id, GLint shader_client_id) {
+ Program* program = GetProgramInfoNotShader(
+ program_client_id, "glAttachShader");
+ if (!program) {
+ return;
+ }
+ Shader* shader = GetShaderInfoNotProgram(shader_client_id, "glAttachShader");
+ if (!shader) {
+ return;
+ }
+ if (!program->AttachShader(shader_manager(), shader)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glAttachShader",
+ "can not attach more than one shader of the same type.");
+ return;
+ }
+ glAttachShader(program->service_id(), shader->service_id());
+}
+
+void GLES2DecoderImpl::DoDetachShader(
+ GLuint program_client_id, GLint shader_client_id) {
+ Program* program = GetProgramInfoNotShader(
+ program_client_id, "glDetachShader");
+ if (!program) {
+ return;
+ }
+ Shader* shader = GetShaderInfoNotProgram(shader_client_id, "glDetachShader");
+ if (!shader) {
+ return;
+ }
+ if (!program->DetachShader(shader_manager(), shader)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glDetachShader", "shader not attached to program");
+ return;
+ }
+ glDetachShader(program->service_id(), shader->service_id());
+}
+
+void GLES2DecoderImpl::DoValidateProgram(GLuint program_client_id) {
+ Program* program = GetProgramInfoNotShader(
+ program_client_id, "glValidateProgram");
+ if (!program) {
+ return;
+ }
+ program->Validate();
+}
+
+void GLES2DecoderImpl::GetVertexAttribHelper(
+ const VertexAttrib* attrib, GLenum pname, GLint* params) {
+ switch (pname) {
+ case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING: {
+ Buffer* buffer = attrib->buffer();
+ if (buffer && !buffer->IsDeleted()) {
+ GLuint client_id;
+ buffer_manager()->GetClientId(buffer->service_id(), &client_id);
+ *params = client_id;
+ }
+ break;
+ }
+ case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+ *params = attrib->enabled();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+ *params = attrib->size();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+ *params = attrib->gl_stride();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+ *params = attrib->type();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+ *params = attrib->normalized();
+ break;
+ case GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE:
+ *params = attrib->divisor();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+}
+
+void GLES2DecoderImpl::DoGetVertexAttribfv(
+ GLuint index, GLenum pname, GLfloat* params) {
+ VertexAttrib* attrib = state_.vertex_attrib_manager->GetVertexAttrib(index);
+ if (!attrib) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetVertexAttribfv", "index out of range");
+ return;
+ }
+ switch (pname) {
+ case GL_CURRENT_VERTEX_ATTRIB: {
+ const Vec4& value = state_.attrib_values[index];
+ params[0] = value.v[0];
+ params[1] = value.v[1];
+ params[2] = value.v[2];
+ params[3] = value.v[3];
+ break;
+ }
+ default: {
+ GLint value = 0;
+ GetVertexAttribHelper(attrib, pname, &value);
+ *params = static_cast<GLfloat>(value);
+ break;
+ }
+ }
+}
+
+void GLES2DecoderImpl::DoGetVertexAttribiv(
+ GLuint index, GLenum pname, GLint* params) {
+ VertexAttrib* attrib = state_.vertex_attrib_manager->GetVertexAttrib(index);
+ if (!attrib) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetVertexAttribiv", "index out of range");
+ return;
+ }
+ switch (pname) {
+ case GL_CURRENT_VERTEX_ATTRIB: {
+ const Vec4& value = state_.attrib_values[index];
+ params[0] = static_cast<GLint>(value.v[0]);
+ params[1] = static_cast<GLint>(value.v[1]);
+ params[2] = static_cast<GLint>(value.v[2]);
+ params[3] = static_cast<GLint>(value.v[3]);
+ break;
+ }
+ default:
+ GetVertexAttribHelper(attrib, pname, params);
+ break;
+ }
+}
+
+bool GLES2DecoderImpl::SetVertexAttribValue(
+ const char* function_name, GLuint index, const GLfloat* value) {
+ if (index >= state_.attrib_values.size()) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "index out of range");
+ return false;
+ }
+ Vec4& v = state_.attrib_values[index];
+ v.v[0] = value[0];
+ v.v[1] = value[1];
+ v.v[2] = value[2];
+ v.v[3] = value[3];
+ return true;
+}
+
+void GLES2DecoderImpl::DoVertexAttrib1f(GLuint index, GLfloat v0) {
+ GLfloat v[4] = { v0, 0.0f, 0.0f, 1.0f, };
+ if (SetVertexAttribValue("glVertexAttrib1f", index, v)) {
+ glVertexAttrib1f(index, v0);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib2f(GLuint index, GLfloat v0, GLfloat v1) {
+ GLfloat v[4] = { v0, v1, 0.0f, 1.0f, };
+ if (SetVertexAttribValue("glVertexAttrib2f", index, v)) {
+ glVertexAttrib2f(index, v0, v1);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib3f(
+ GLuint index, GLfloat v0, GLfloat v1, GLfloat v2) {
+ GLfloat v[4] = { v0, v1, v2, 1.0f, };
+ if (SetVertexAttribValue("glVertexAttrib3f", index, v)) {
+ glVertexAttrib3f(index, v0, v1, v2);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib4f(
+ GLuint index, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
+ GLfloat v[4] = { v0, v1, v2, v3, };
+ if (SetVertexAttribValue("glVertexAttrib4f", index, v)) {
+ glVertexAttrib4f(index, v0, v1, v2, v3);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib1fv(GLuint index, const GLfloat* v) {
+ GLfloat t[4] = { v[0], 0.0f, 0.0f, 1.0f, };
+ if (SetVertexAttribValue("glVertexAttrib1fv", index, t)) {
+ glVertexAttrib1fv(index, v);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib2fv(GLuint index, const GLfloat* v) {
+ GLfloat t[4] = { v[0], v[1], 0.0f, 1.0f, };
+ if (SetVertexAttribValue("glVertexAttrib2fv", index, t)) {
+ glVertexAttrib2fv(index, v);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib3fv(GLuint index, const GLfloat* v) {
+ GLfloat t[4] = { v[0], v[1], v[2], 1.0f, };
+ if (SetVertexAttribValue("glVertexAttrib3fv", index, t)) {
+ glVertexAttrib3fv(index, v);
+ }
+}
+
+void GLES2DecoderImpl::DoVertexAttrib4fv(GLuint index, const GLfloat* v) {
+ if (SetVertexAttribValue("glVertexAttrib4fv", index, v)) {
+ glVertexAttrib4fv(index, v);
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttribPointer(
+ uint32 immediate_data_size, const cmds::VertexAttribPointer& c) {
+
+ if (!state_.bound_array_buffer.get() ||
+ state_.bound_array_buffer->IsDeleted()) {
+ if (state_.vertex_attrib_manager.get() ==
+ default_vertex_attrib_manager_.get()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glVertexAttribPointer", "no array buffer bound");
+ return error::kNoError;
+ } else if (c.offset != 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glVertexAttribPointer", "client side arrays are not allowed");
+ return error::kNoError;
+ }
+ }
+
+ GLuint indx = c.indx;
+ GLint size = c.size;
+ GLenum type = c.type;
+ GLboolean normalized = c.normalized;
+ GLsizei stride = c.stride;
+ GLsizei offset = c.offset;
+ const void* ptr = reinterpret_cast<const void*>(offset);
+ if (!validators_->vertex_attrib_type.IsValid(type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glVertexAttribPointer", type, "type");
+ return error::kNoError;
+ }
+ if (!validators_->vertex_attrib_size.IsValid(size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glVertexAttribPointer", "size GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (indx >= group_->max_vertex_attribs()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glVertexAttribPointer", "index out of range");
+ return error::kNoError;
+ }
+ if (stride < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glVertexAttribPointer", "stride < 0");
+ return error::kNoError;
+ }
+ if (stride > 255) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glVertexAttribPointer", "stride > 255");
+ return error::kNoError;
+ }
+ if (offset < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glVertexAttribPointer", "offset < 0");
+ return error::kNoError;
+ }
+ GLsizei component_size =
+ GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type);
+ if (offset % component_size > 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glVertexAttribPointer", "offset not valid for type");
+ return error::kNoError;
+ }
+ if (stride % component_size > 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glVertexAttribPointer", "stride not valid for type");
+ return error::kNoError;
+ }
+ state_.vertex_attrib_manager
+ ->SetAttribInfo(indx,
+ state_.bound_array_buffer.get(),
+ size,
+ type,
+ normalized,
+ stride,
+ stride != 0 ? stride : component_size * size,
+ offset);
+ if (type != GL_FIXED) {
+ glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
+ }
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoViewport(GLint x, GLint y, GLsizei width,
+ GLsizei height) {
+ state_.viewport_x = x;
+ state_.viewport_y = y;
+ state_.viewport_width = std::min(width, viewport_max_width_);
+ state_.viewport_height = std::min(height, viewport_max_height_);
+ glViewport(x, y, width, height);
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttribDivisorANGLE(
+ uint32 immediate_data_size, const cmds::VertexAttribDivisorANGLE& c) {
+ if (!features().angle_instanced_arrays) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glVertexAttribDivisorANGLE", "function not available");
+ }
+ GLuint index = c.index;
+ GLuint divisor = c.divisor;
+ if (index >= group_->max_vertex_attribs()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glVertexAttribDivisorANGLE", "index out of range");
+ return error::kNoError;
+ }
+
+ state_.vertex_attrib_manager->SetDivisor(
+ index,
+ divisor);
+ glVertexAttribDivisorANGLE(index, divisor);
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::FinishReadPixels(
+ const cmds::ReadPixels& c,
+ GLuint buffer) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::FinishReadPixels");
+ GLsizei width = c.width;
+ GLsizei height = c.height;
+ GLenum format = c.format;
+ GLenum type = c.type;
+ typedef cmds::ReadPixels::Result Result;
+ uint32 pixels_size;
+ Result* result = NULL;
+ if (c.result_shm_id != 0) {
+ result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ if (buffer != 0) {
+ glDeleteBuffersARB(1, &buffer);
+ }
+ return;
+ }
+ }
+ GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.pack_alignment, &pixels_size,
+ NULL, NULL);
+ void* pixels = GetSharedMemoryAs<void*>(
+ c.pixels_shm_id, c.pixels_shm_offset, pixels_size);
+ if (!pixels) {
+ if (buffer != 0) {
+ glDeleteBuffersARB(1, &buffer);
+ }
+ return;
+ }
+
+ if (buffer != 0) {
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
+ void* data = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
+ memcpy(pixels, data, pixels_size);
+ // GL_PIXEL_PACK_BUFFER_ARB is currently unused, so we don't
+ // have to restore the state.
+ glUnmapBuffer(GL_PIXEL_PACK_BUFFER_ARB);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ glDeleteBuffersARB(1, &buffer);
+ }
+
+ if (result != NULL) {
+ *result = true;
+ }
+
+ GLenum read_format = GetBoundReadFrameBufferInternalFormat();
+ uint32 channels_exist = GLES2Util::GetChannelsForFormat(read_format);
+ if ((channels_exist & 0x0008) == 0 &&
+ workarounds().clear_alpha_in_readpixels) {
+ // Set the alpha to 255 because some drivers are buggy in this regard.
+ uint32 temp_size;
+
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, 2, format, type, state_.pack_alignment, &temp_size,
+ &unpadded_row_size, &padded_row_size)) {
+ return;
+ }
+ // NOTE: Assumes the type is GL_UNSIGNED_BYTE which was true at the time
+ // of this implementation.
+ if (type != GL_UNSIGNED_BYTE) {
+ return;
+ }
+ switch (format) {
+ case GL_RGBA:
+ case GL_BGRA_EXT:
+ case GL_ALPHA: {
+ int offset = (format == GL_ALPHA) ? 0 : 3;
+ int step = (format == GL_ALPHA) ? 1 : 4;
+ uint8* dst = static_cast<uint8*>(pixels) + offset;
+ for (GLint yy = 0; yy < height; ++yy) {
+ uint8* end = dst + unpadded_row_size;
+ for (uint8* d = dst; d < end; d += step) {
+ *d = 255;
+ }
+ dst += padded_row_size;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+
+error::Error GLES2DecoderImpl::HandleReadPixels(
+ uint32 immediate_data_size, const cmds::ReadPixels& c) {
+ if (ShouldDeferReads())
+ return error::kDeferCommandUntilLater;
+ GLint x = c.x;
+ GLint y = c.y;
+ GLsizei width = c.width;
+ GLsizei height = c.height;
+ GLenum format = c.format;
+ GLenum type = c.type;
+ GLboolean async = c.async;
+ if (width < 0 || height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glReadPixels", "dimensions < 0");
+ return error::kNoError;
+ }
+ typedef cmds::ReadPixels::Result Result;
+ uint32 pixels_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.pack_alignment, &pixels_size,
+ NULL, NULL)) {
+ return error::kOutOfBounds;
+ }
+ void* pixels = GetSharedMemoryAs<void*>(
+ c.pixels_shm_id, c.pixels_shm_offset, pixels_size);
+ if (!pixels) {
+ return error::kOutOfBounds;
+ }
+ Result* result = NULL;
+ if (c.result_shm_id != 0) {
+ result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ }
+
+ if (!validators_->read_pixel_format.IsValid(format)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glReadPixels", format, "format");
+ return error::kNoError;
+ }
+ if (!validators_->pixel_type.IsValid(type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glReadPixels", type, "type");
+ return error::kNoError;
+ }
+ if (width == 0 || height == 0) {
+ return error::kNoError;
+ }
+
+ // Get the size of the current fbo or backbuffer.
+ gfx::Size max_size = GetBoundReadFrameBufferSize();
+
+ int32 max_x;
+ int32 max_y;
+ if (!SafeAddInt32(x, width, &max_x) || !SafeAddInt32(y, height, &max_y)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glReadPixels", "dimensions out of range");
+ return error::kNoError;
+ }
+
+ if (!CheckBoundFramebuffersValid("glReadPixels")) {
+ return error::kNoError;
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glReadPixel");
+
+ ScopedResolvedFrameBufferBinder binder(this, false, true);
+
+ if (x < 0 || y < 0 || max_x > max_size.width() || max_y > max_size.height()) {
+ // The user requested an out of range area. Get the results 1 line
+ // at a time.
+ uint32 temp_size;
+ uint32 unpadded_row_size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, 2, format, type, state_.pack_alignment, &temp_size,
+ &unpadded_row_size, &padded_row_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glReadPixels", "dimensions out of range");
+ return error::kNoError;
+ }
+
+ GLint dest_x_offset = std::max(-x, 0);
+ uint32 dest_row_offset;
+ if (!GLES2Util::ComputeImageDataSizes(
+ dest_x_offset, 1, format, type, state_.pack_alignment, &dest_row_offset,
+ NULL, NULL)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glReadPixels", "dimensions out of range");
+ return error::kNoError;
+ }
+
+ // Copy each row into the larger dest rect.
+ int8* dst = static_cast<int8*>(pixels);
+ GLint read_x = std::max(0, x);
+ GLint read_end_x = std::max(0, std::min(max_size.width(), max_x));
+ GLint read_width = read_end_x - read_x;
+ for (GLint yy = 0; yy < height; ++yy) {
+ GLint ry = y + yy;
+
+ // Clear the row.
+ memset(dst, 0, unpadded_row_size);
+
+ // If the row is in range, copy it.
+ if (ry >= 0 && ry < max_size.height() && read_width > 0) {
+ glReadPixels(
+ read_x, ry, read_width, 1, format, type, dst + dest_row_offset);
+ }
+ dst += padded_row_size;
+ }
+ } else {
+ if (async && features().use_async_readpixels) {
+ GLuint buffer;
+ glGenBuffersARB(1, &buffer);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
+ glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, GL_STREAM_READ);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ glReadPixels(x, y, width, height, format, type, 0);
+ pending_readpixel_fences_.push(linked_ptr<FenceCallback>(
+ new FenceCallback()));
+ WaitForReadPixels(base::Bind(
+ &GLES2DecoderImpl::FinishReadPixels,
+ base::internal::SupportsWeakPtrBase::StaticAsWeakPtr
+ <GLES2DecoderImpl>(this),
+ c, buffer));
+ glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ return error::kNoError;
+ }
+ }
+ glReadPixels(x, y, width, height, format, type, pixels);
+ }
+ GLenum error = LOCAL_PEEK_GL_ERROR("glReadPixels");
+ if (error == GL_NO_ERROR) {
+ if (result != NULL) {
+ *result = true;
+ }
+ FinishReadPixels(c, 0);
+ }
+
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePixelStorei(
+ uint32 immediate_data_size, const cmds::PixelStorei& c) {
+ GLenum pname = c.pname;
+ GLenum param = c.param;
+ if (!validators_->pixel_store.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glPixelStorei", pname, "pname");
+ return error::kNoError;
+ }
+ switch (pname) {
+ case GL_PACK_ALIGNMENT:
+ case GL_UNPACK_ALIGNMENT:
+ if (!validators_->pixel_store_alignment.IsValid(param)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glPixelStore", "param GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ break;
+ case GL_UNPACK_FLIP_Y_CHROMIUM:
+ unpack_flip_y_ = (param != 0);
+ return error::kNoError;
+ case GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM:
+ unpack_premultiply_alpha_ = (param != 0);
+ return error::kNoError;
+ case GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM:
+ unpack_unpremultiply_alpha_ = (param != 0);
+ return error::kNoError;
+ default:
+ break;
+ }
+ glPixelStorei(pname, param);
+ switch (pname) {
+ case GL_PACK_ALIGNMENT:
+ state_.pack_alignment = param;
+ break;
+ case GL_PACK_REVERSE_ROW_ORDER_ANGLE:
+ state_.pack_reverse_row_order = (param != 0);
+ break;
+ case GL_UNPACK_ALIGNMENT:
+ state_.unpack_alignment = param;
+ break;
+ default:
+ // Validation should have prevented us from getting here.
+ NOTREACHED();
+ break;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePostSubBufferCHROMIUM(
+ uint32 immediate_data_size, const cmds::PostSubBufferCHROMIUM& c) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandlePostSubBufferCHROMIUM");
+ if (!surface_->HasExtension("GL_CHROMIUM_post_sub_buffer")) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glPostSubBufferCHROMIUM", "command not supported by surface");
+ return error::kNoError;
+ }
+ if (surface_->PostSubBuffer(c.x, c.y, c.width, c.height)) {
+ return error::kNoError;
+ } else {
+ LOG(ERROR) << "Context lost because PostSubBuffer failed.";
+ return error::kLostContext;
+ }
+}
+
+error::Error GLES2DecoderImpl::GetAttribLocationHelper(
+ GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
+ const std::string& name_str) {
+ if (!StringIsValidForGLES(name_str.c_str())) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetAttribLocation", "Invalid character");
+ return error::kNoError;
+ }
+ Program* program = GetProgramInfoNotShader(
+ client_id, "glGetAttribLocation");
+ if (!program) {
+ return error::kNoError;
+ }
+ if (!program->IsValid()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glGetAttribLocation", "program not linked");
+ return error::kNoError;
+ }
+ GLint* location = GetSharedMemoryAs<GLint*>(
+ location_shm_id, location_shm_offset, sizeof(GLint));
+ if (!location) {
+ return error::kOutOfBounds;
+ }
+ // Require the client to init this incase the context is lost and we are no
+ // longer executing commands.
+ if (*location != -1) {
+ return error::kGenericError;
+ }
+ *location = program->GetAttribLocation(name_str);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetAttribLocation(
+ uint32 immediate_data_size, const cmds::GetAttribLocation& c) {
+ uint32 name_size = c.data_size;
+ const char* name = GetSharedMemoryAs<const char*>(
+ c.name_shm_id, c.name_shm_offset, name_size);
+ if (!name) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ return GetAttribLocationHelper(
+ c.program, c.location_shm_id, c.location_shm_offset, name_str);
+}
+
+error::Error GLES2DecoderImpl::HandleGetAttribLocationImmediate(
+ uint32 immediate_data_size, const cmds::GetAttribLocationImmediate& c) {
+ uint32 name_size = c.data_size;
+ const char* name = GetImmediateDataAs<const char*>(
+ c, name_size, immediate_data_size);
+ if (!name) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ return GetAttribLocationHelper(
+ c.program, c.location_shm_id, c.location_shm_offset, name_str);
+}
+
+error::Error GLES2DecoderImpl::HandleGetAttribLocationBucket(
+ uint32 immediate_data_size, const cmds::GetAttribLocationBucket& c) {
+ Bucket* bucket = GetBucket(c.name_bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ std::string name_str;
+ if (!bucket->GetAsString(&name_str)) {
+ return error::kInvalidArguments;
+ }
+ return GetAttribLocationHelper(
+ c.program, c.location_shm_id, c.location_shm_offset, name_str);
+}
+
+error::Error GLES2DecoderImpl::GetUniformLocationHelper(
+ GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset,
+ const std::string& name_str) {
+ if (!StringIsValidForGLES(name_str.c_str())) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetUniformLocation", "Invalid character");
+ return error::kNoError;
+ }
+ Program* program = GetProgramInfoNotShader(
+ client_id, "glUniformLocation");
+ if (!program) {
+ return error::kNoError;
+ }
+ if (!program->IsValid()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glGetUniformLocation", "program not linked");
+ return error::kNoError;
+ }
+ GLint* location = GetSharedMemoryAs<GLint*>(
+ location_shm_id, location_shm_offset, sizeof(GLint));
+ if (!location) {
+ return error::kOutOfBounds;
+ }
+ // Require the client to init this incase the context is lost an we are no
+ // longer executing commands.
+ if (*location != -1) {
+ return error::kGenericError;
+ }
+ *location = program->GetUniformFakeLocation(name_str);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetUniformLocation(
+ uint32 immediate_data_size, const cmds::GetUniformLocation& c) {
+ uint32 name_size = c.data_size;
+ const char* name = GetSharedMemoryAs<const char*>(
+ c.name_shm_id, c.name_shm_offset, name_size);
+ if (!name) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ return GetUniformLocationHelper(
+ c.program, c.location_shm_id, c.location_shm_offset, name_str);
+}
+
+error::Error GLES2DecoderImpl::HandleGetUniformLocationImmediate(
+ uint32 immediate_data_size, const cmds::GetUniformLocationImmediate& c) {
+ uint32 name_size = c.data_size;
+ const char* name = GetImmediateDataAs<const char*>(
+ c, name_size, immediate_data_size);
+ if (!name) {
+ return error::kOutOfBounds;
+ }
+ String name_str(name, name_size);
+ return GetUniformLocationHelper(
+ c.program, c.location_shm_id, c.location_shm_offset, name_str);
+}
+
+error::Error GLES2DecoderImpl::HandleGetUniformLocationBucket(
+ uint32 immediate_data_size, const cmds::GetUniformLocationBucket& c) {
+ Bucket* bucket = GetBucket(c.name_bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ std::string name_str;
+ if (!bucket->GetAsString(&name_str)) {
+ return error::kInvalidArguments;
+ }
+ return GetUniformLocationHelper(
+ c.program, c.location_shm_id, c.location_shm_offset, name_str);
+}
+
+error::Error GLES2DecoderImpl::HandleGetString(
+ uint32 immediate_data_size, const cmds::GetString& c) {
+ GLenum name = static_cast<GLenum>(c.name);
+ if (!validators_->string_type.IsValid(name)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetString", name, "name");
+ return error::kNoError;
+ }
+ const char* gl_str = reinterpret_cast<const char*>(glGetString(name));
+ const char* str = NULL;
+ std::string extensions;
+ switch (name) {
+ case GL_VERSION:
+ str = "OpenGL ES 2.0 Chromium";
+ break;
+ case GL_SHADING_LANGUAGE_VERSION:
+ str = "OpenGL ES GLSL ES 1.0 Chromium";
+ break;
+ case GL_RENDERER:
+ str = "Chromium";
+ break;
+ case GL_VENDOR:
+ str = "Chromium";
+ break;
+ case GL_EXTENSIONS:
+ {
+ // For WebGL contexts, strip out the OES derivatives and
+ // EXT frag depth extensions if they have not been enabled.
+ if (force_webgl_glsl_validation_) {
+ extensions = feature_info_->extensions();
+ if (!derivatives_explicitly_enabled_) {
+ size_t offset = extensions.find(kOESDerivativeExtension);
+ if (std::string::npos != offset) {
+ extensions.replace(offset, arraysize(kOESDerivativeExtension),
+ std::string());
+ }
+ }
+ if (!frag_depth_explicitly_enabled_) {
+ size_t offset = extensions.find(kEXTFragDepthExtension);
+ if (std::string::npos != offset) {
+ extensions.replace(offset, arraysize(kEXTFragDepthExtension),
+ std::string());
+ }
+ }
+ if (!draw_buffers_explicitly_enabled_) {
+ size_t offset = extensions.find(kEXTDrawBuffersExtension);
+ if (std::string::npos != offset) {
+ extensions.replace(offset, arraysize(kEXTDrawBuffersExtension),
+ std::string());
+ }
+ }
+ } else {
+ extensions = feature_info_->extensions().c_str();
+ }
+ std::string surface_extensions = surface_->GetExtensions();
+ if (!surface_extensions.empty())
+ extensions += " " + surface_extensions;
+ str = extensions.c_str();
+ }
+ break;
+ default:
+ str = gl_str;
+ break;
+ }
+ Bucket* bucket = CreateBucket(c.bucket_id);
+ bucket->SetFromString(str);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBufferData(
+ uint32 immediate_data_size, const cmds::BufferData& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
+ uint32 data_shm_id = static_cast<uint32>(c.data_shm_id);
+ uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset);
+ GLenum usage = static_cast<GLenum>(c.usage);
+ const void* data = NULL;
+ if (data_shm_id != 0 || data_shm_offset != 0) {
+ data = GetSharedMemoryAs<const void*>(data_shm_id, data_shm_offset, size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ }
+ buffer_manager()->ValidateAndDoBufferData(&state_, target, size, data, usage);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBufferDataImmediate(
+ uint32 immediate_data_size, const cmds::BufferDataImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
+ const void* data = GetImmediateDataAs<const void*>(
+ c, size, immediate_data_size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ GLenum usage = static_cast<GLenum>(c.usage);
+ buffer_manager()->ValidateAndDoBufferData(&state_, target, size, data, usage);
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoBufferSubData(
+ GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid * data) {
+ // Just delegate it. Some validation is actually done before this.
+ buffer_manager()->ValidateAndDoBufferSubData(
+ &state_, target, offset, size, data);
+}
+
+bool GLES2DecoderImpl::ClearLevel(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height,
+ bool is_texture_immutable) {
+ uint32 channels = GLES2Util::GetChannelsForFormat(format);
+ if (IsAngle() && (channels & GLES2Util::kDepth) != 0) {
+ // It's a depth format and ANGLE doesn't allow texImage2D or texSubImage2D
+ // on depth formats.
+ GLuint fb = 0;
+ glGenFramebuffersEXT(1, &fb);
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fb);
+
+ bool have_stencil = (channels & GLES2Util::kStencil) != 0;
+ GLenum attachment = have_stencil ? GL_DEPTH_STENCIL_ATTACHMENT :
+ GL_DEPTH_ATTACHMENT;
+
+ glFramebufferTexture2DEXT(
+ GL_DRAW_FRAMEBUFFER_EXT, attachment, target, service_id, level);
+ // ANGLE promises a depth only attachment ok.
+ if (glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT) !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ return false;
+ }
+ glClearStencil(0);
+ glStencilMask(-1);
+ glClearDepth(1.0f);
+ glDepthMask(true);
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_DEPTH_BUFFER_BIT | (have_stencil ? GL_STENCIL_BUFFER_BIT : 0));
+
+ RestoreClearState();
+
+ glDeleteFramebuffersEXT(1, &fb);
+ Framebuffer* framebuffer =
+ GetFramebufferInfoForTarget(GL_DRAW_FRAMEBUFFER_EXT);
+ GLuint fb_service_id =
+ framebuffer ? framebuffer->service_id() : GetBackbufferServiceId();
+ glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fb_service_id);
+ return true;
+ }
+
+ static const uint32 kMaxZeroSize = 1024 * 1024 * 4;
+
+ uint32 size;
+ uint32 padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &size,
+ NULL, &padded_row_size)) {
+ return false;
+ }
+
+ TRACE_EVENT1("gpu", "GLES2DecoderImpl::ClearLevel", "size", size);
+
+ int tile_height;
+
+ if (size > kMaxZeroSize) {
+ if (kMaxZeroSize < padded_row_size) {
+ // That'd be an awfully large texture.
+ return false;
+ }
+ // We should never have a large total size with a zero row size.
+ DCHECK_GT(padded_row_size, 0U);
+ tile_height = kMaxZeroSize / padded_row_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, tile_height, format, type, state_.unpack_alignment, &size,
+ NULL, NULL)) {
+ return false;
+ }
+ } else {
+ tile_height = height;
+ }
+
+ // Assumes the size has already been checked.
+ scoped_ptr<char[]> zero(new char[size]);
+ memset(zero.get(), 0, size);
+ glBindTexture(bind_target, service_id);
+
+ GLint y = 0;
+ while (y < height) {
+ GLint h = y + tile_height > height ? height - y : tile_height;
+ if (is_texture_immutable || h != height) {
+ glTexSubImage2D(target, level, 0, y, width, h, format, type, zero.get());
+ } else {
+ glTexImage2D(
+ target, level, format, width, h, 0, format, type, zero.get());
+ }
+ y += tile_height;
+ }
+ TextureRef* texture = texture_manager()->GetTextureInfoForTarget(
+ &state_, bind_target);
+ glBindTexture(bind_target, texture ? texture->service_id() : 0);
+ return true;
+}
+
+namespace {
+
+const int kS3TCBlockWidth = 4;
+const int kS3TCBlockHeight = 4;
+const int kS3TCDXT1BlockSize = 8;
+const int kS3TCDXT3AndDXT5BlockSize = 16;
+const int kETC1BlockWidth = 4;
+const int kETC1BlockHeight = 4;
+const int kETC1BlockSize = 8;
+
+bool IsValidDXTSize(GLint level, GLsizei size) {
+ return (size == 1) ||
+ (size == 2) || !(size % kS3TCBlockWidth);
+}
+
+} // anonymous namespace.
+
+bool GLES2DecoderImpl::ValidateCompressedTexFuncData(
+ const char* function_name,
+ GLsizei width, GLsizei height, GLenum format, size_t size) {
+ unsigned int bytes_required = 0;
+
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: {
+ int num_blocks_across =
+ (width + kS3TCBlockWidth - 1) / kS3TCBlockWidth;
+ int num_blocks_down =
+ (height + kS3TCBlockHeight - 1) / kS3TCBlockHeight;
+ int num_blocks = num_blocks_across * num_blocks_down;
+ bytes_required = num_blocks * kS3TCDXT1BlockSize;
+ break;
+ }
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+ int num_blocks_across =
+ (width + kS3TCBlockWidth - 1) / kS3TCBlockWidth;
+ int num_blocks_down =
+ (height + kS3TCBlockHeight - 1) / kS3TCBlockHeight;
+ int num_blocks = num_blocks_across * num_blocks_down;
+ bytes_required = num_blocks * kS3TCDXT3AndDXT5BlockSize;
+ break;
+ }
+ case GL_ETC1_RGB8_OES: {
+ int num_blocks_across =
+ (width + kETC1BlockWidth - 1) / kETC1BlockWidth;
+ int num_blocks_down =
+ (height + kETC1BlockHeight - 1) / kETC1BlockHeight;
+ int num_blocks = num_blocks_across * num_blocks_down;
+ bytes_required = num_blocks * kETC1BlockSize;
+ break;
+ }
+ default:
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format");
+ return false;
+ }
+
+ if (size != bytes_required) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, function_name, "size is not correct for dimensions");
+ return false;
+ }
+
+ return true;
+}
+
+bool GLES2DecoderImpl::ValidateCompressedTexDimensions(
+ const char* function_name,
+ GLint level, GLsizei width, GLsizei height, GLenum format) {
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+ if (!IsValidDXTSize(level, width) || !IsValidDXTSize(level, height)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name,
+ "width or height invalid for level");
+ return false;
+ }
+ return true;
+ }
+ case GL_ETC1_RGB8_OES:
+ if (width <= 0 || height <= 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name,
+ "width or height invalid for level");
+ return false;
+ }
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool GLES2DecoderImpl::ValidateCompressedTexSubDimensions(
+ const char* function_name,
+ GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format,
+ Texture* texture) {
+ if (xoffset < 0 || yoffset < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, function_name, "xoffset or yoffset < 0");
+ return false;
+ }
+
+ switch (format) {
+ case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
+ case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: {
+ const int kBlockWidth = 4;
+ const int kBlockHeight = 4;
+ if ((xoffset % kBlockWidth) || (yoffset % kBlockHeight)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name,
+ "xoffset or yoffset not multiple of 4");
+ return false;
+ }
+ GLsizei tex_width = 0;
+ GLsizei tex_height = 0;
+ if (!texture->GetLevelSize(target, level, &tex_width, &tex_height) ||
+ width - xoffset > tex_width ||
+ height - yoffset > tex_height) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "dimensions out of range");
+ return false;
+ }
+ return ValidateCompressedTexDimensions(
+ function_name, level, width, height, format);
+ }
+ case GL_ETC1_RGB8_OES: {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name,
+ "TexsubImage2d not supported for ECT1_RGB8_OES textures");
+ return false;
+ }
+ default:
+ return false;
+ }
+}
+
+error::Error GLES2DecoderImpl::DoCompressedTexImage2D(
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLint border,
+ GLsizei image_size,
+ const void* data) {
+ // TODO(gman): Validate image_size is correct for width, height and format.
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glCompressedTexImage2D", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->compressed_texture_format.IsValid(
+ internal_format)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glCompressedTexImage2D", internal_format, "internal_format");
+ return error::kNoError;
+ }
+ if (!texture_manager()->ValidForTarget(target, level, width, height, 1) ||
+ border != 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCompressedTexImage2D", "dimensions out of range");
+ return error::kNoError;
+ }
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCompressedTexImage2D", "unknown texture target");
+ return error::kNoError;
+ }
+ Texture* texture = texture_ref->texture();
+ if (texture->IsImmutable()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCompressedTexImage2D", "texture is immutable");
+ return error::kNoError;
+ }
+
+ if (!ValidateCompressedTexDimensions(
+ "glCompressedTexImage2D", level, width, height, internal_format) ||
+ !ValidateCompressedTexFuncData(
+ "glCompressedTexImage2D", width, height, internal_format, image_size)) {
+ return error::kNoError;
+ }
+
+ if (!EnsureGPUMemoryAvailable(image_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glCompressedTexImage2D", "out of memory");
+ return error::kNoError;
+ }
+
+ if (texture->IsAttachedToFramebuffer()) {
+ framebuffer_state_.clear_state_dirty = true;
+ }
+
+ scoped_ptr<int8[]> zero;
+ if (!data) {
+ zero.reset(new int8[image_size]);
+ memset(zero.get(), 0, image_size);
+ data = zero.get();
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCompressedTexImage2D");
+ glCompressedTexImage2D(
+ target, level, internal_format, width, height, border, image_size, data);
+ GLenum error = LOCAL_PEEK_GL_ERROR("glCompressedTexImage2D");
+ if (error == GL_NO_ERROR) {
+ texture_manager()->SetLevelInfo(
+ texture_ref, target, level, internal_format,
+ width, height, 1, border, 0, 0, true);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCompressedTexImage2D(
+ uint32 immediate_data_size, const cmds::CompressedTexImage2D& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLenum internal_format = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ GLsizei image_size = static_cast<GLsizei>(c.imageSize);
+ uint32 data_shm_id = static_cast<uint32>(c.data_shm_id);
+ uint32 data_shm_offset = static_cast<uint32>(c.data_shm_offset);
+ const void* data = NULL;
+ if (data_shm_id != 0 || data_shm_offset != 0) {
+ data = GetSharedMemoryAs<const void*>(
+ data_shm_id, data_shm_offset, image_size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ }
+ return DoCompressedTexImage2D(
+ target, level, internal_format, width, height, border, image_size, data);
+}
+
+error::Error GLES2DecoderImpl::HandleCompressedTexImage2DImmediate(
+ uint32 immediate_data_size, const cmds::CompressedTexImage2DImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLenum internal_format = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ GLsizei image_size = static_cast<GLsizei>(c.imageSize);
+ const void* data = GetImmediateDataAs<const void*>(
+ c, image_size, immediate_data_size);
+ if (!data) {
+ return error::kOutOfBounds;
+ }
+ return DoCompressedTexImage2D(
+ target, level, internal_format, width, height, border, image_size, data);
+}
+
+error::Error GLES2DecoderImpl::HandleCompressedTexImage2DBucket(
+ uint32 immediate_data_size, const cmds::CompressedTexImage2DBucket& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLenum internal_format = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ Bucket* bucket = GetBucket(c.bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ uint32 data_size = bucket->size();
+ GLsizei imageSize = data_size;
+ const void* data = bucket->GetData(0, data_size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ return DoCompressedTexImage2D(
+ target, level, internal_format, width, height, border,
+ imageSize, data);
+}
+
+error::Error GLES2DecoderImpl::HandleCompressedTexSubImage2DBucket(
+ uint32 immediate_data_size,
+ const cmds::CompressedTexSubImage2DBucket& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLenum format = static_cast<GLenum>(c.format);
+ Bucket* bucket = GetBucket(c.bucket_id);
+ if (!bucket) {
+ return error::kInvalidArguments;
+ }
+ uint32 data_size = bucket->size();
+ GLsizei imageSize = data_size;
+ const void* data = bucket->GetData(0, data_size);
+ if (!data) {
+ return error::kInvalidArguments;
+ }
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_ENUM, "glCompressedTexSubImage2D", "target");
+ return error::kNoError;
+ }
+ if (!validators_->compressed_texture_format.IsValid(format)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glCompressedTexSubImage2D", format, "format");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "height < 0");
+ return error::kNoError;
+ }
+ if (imageSize < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "imageSize < 0");
+ return error::kNoError;
+ }
+ DoCompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexImage2D(
+ uint32 immediate_data_size, const cmds::TexImage2D& c) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleTexImage2D");
+ // Set as failed for now, but if it successed, this will be set to not failed.
+ texture_state_.tex_image_2d_failed = true;
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ // TODO(kloveless): Change TexImage2D command to use unsigned integer
+ // for internalformat.
+ GLenum internal_format = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLenum type = static_cast<GLenum>(c.type);
+ uint32 pixels_shm_id = static_cast<uint32>(c.pixels_shm_id);
+ uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset);
+ uint32 pixels_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &pixels_size, NULL,
+ NULL)) {
+ return error::kOutOfBounds;
+ }
+ const void* pixels = NULL;
+ if (pixels_shm_id != 0 || pixels_shm_offset != 0) {
+ pixels = GetSharedMemoryAs<const void*>(
+ pixels_shm_id, pixels_shm_offset, pixels_size);
+ if (!pixels) {
+ return error::kOutOfBounds;
+ }
+ }
+
+ TextureManager::DoTextImage2DArguments args = {
+ target, level, internal_format, width, height, border, format, type,
+ pixels, pixels_size};
+ texture_manager()->ValidateAndDoTexImage2D(
+ &texture_state_, &state_, &framebuffer_state_, args);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexImage2DImmediate(
+ uint32 immediate_data_size, const cmds::TexImage2DImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ // TODO(kloveless): Change TexImage2DImmediate command to use unsigned
+ // integer for internalformat.
+ GLenum internal_format = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLenum type = static_cast<GLenum>(c.type);
+ uint32 size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &size,
+ NULL, NULL)) {
+ return error::kOutOfBounds;
+ }
+ const void* pixels = GetImmediateDataAs<const void*>(
+ c, size, immediate_data_size);
+ if (!pixels) {
+ return error::kOutOfBounds;
+ }
+
+ TextureManager::DoTextImage2DArguments args = {
+ target, level, internal_format, width, height, border, format, type,
+ pixels, size};
+ texture_manager()->ValidateAndDoTexImage2D(
+ &texture_state_, &state_, &framebuffer_state_, args);
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoCompressedTexSubImage2D(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLsizei image_size,
+ const void * data) {
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCompressedTexSubImage2D", "unknown texture for target");
+ return;
+ }
+ Texture* texture = texture_ref->texture();
+ GLenum type = 0;
+ GLenum internal_format = 0;
+ if (!texture->GetLevelType(target, level, &type, &internal_format)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCompressedTexSubImage2D", "level does not exist.");
+ return;
+ }
+ if (internal_format != format) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCompressedTexSubImage2D", "format does not match internal format.");
+ return;
+ }
+ if (!texture->ValidForTexture(
+ target, level, xoffset, yoffset, width, height, format, type)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "bad dimensions.");
+ return;
+ }
+
+ if (!ValidateCompressedTexFuncData(
+ "glCompressedTexSubImage2D", width, height, format, image_size) ||
+ !ValidateCompressedTexSubDimensions(
+ "glCompressedTexSubImage2D",
+ target, level, xoffset, yoffset, width, height, format, texture)) {
+ return;
+ }
+
+
+ // Note: There is no need to deal with texture cleared tracking here
+ // because the validation above means you can only get here if the level
+ // is already a matching compressed format and in that case
+ // CompressedTexImage2D already cleared the texture.
+ glCompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, image_size, data);
+}
+
+static void Clip(
+ GLint start, GLint range, GLint sourceRange,
+ GLint* out_start, GLint* out_range) {
+ DCHECK(out_start);
+ DCHECK(out_range);
+ if (start < 0) {
+ range += start;
+ start = 0;
+ }
+ GLint end = start + range;
+ if (end > sourceRange) {
+ range -= end - sourceRange;
+ }
+ *out_start = start;
+ *out_range = range;
+}
+
+void GLES2DecoderImpl::DoCopyTexImage2D(
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height,
+ GLint border) {
+ DCHECK(!ShouldDeferReads());
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCopyTexImage2D", "unknown texture for target");
+ return;
+ }
+ Texture* texture = texture_ref->texture();
+ if (texture->IsImmutable()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glCopyTexImage2D", "texture is immutable");
+ }
+ if (!texture_manager()->ValidForTarget(target, level, width, height, 1) ||
+ border != 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTexImage2D", "dimensions out of range");
+ return;
+ }
+ if (!texture_manager()->ValidateTextureParameters(
+ state_.GetErrorState(), "glCopyTexImage2D", target, internal_format,
+ GL_UNSIGNED_BYTE, level)) {
+ return;
+ }
+
+ // Check we have compatible formats.
+ GLenum read_format = GetBoundReadFrameBufferInternalFormat();
+ uint32 channels_exist = GLES2Util::GetChannelsForFormat(read_format);
+ uint32 channels_needed = GLES2Util::GetChannelsForFormat(internal_format);
+
+ if ((channels_needed & channels_exist) != channels_needed) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glCopyTexImage2D", "incompatible format");
+ return;
+ }
+
+ if ((channels_needed & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCopyTexImage2D", "can not be used with depth or stencil textures");
+ return;
+ }
+
+ uint32 estimated_size = 0;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, internal_format, GL_UNSIGNED_BYTE, state_.unpack_alignment,
+ &estimated_size, NULL, NULL)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glCopyTexImage2D", "dimensions too large");
+ return;
+ }
+
+ if (!EnsureGPUMemoryAvailable(estimated_size)) {
+ LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glCopyTexImage2D", "out of memory");
+ return;
+ }
+
+ if (!CheckBoundFramebuffersValid("glCopyTexImage2D")) {
+ return;
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyTexImage2D");
+ ScopedResolvedFrameBufferBinder binder(this, false, true);
+ gfx::Size size = GetBoundReadFrameBufferSize();
+
+ if (texture->IsAttachedToFramebuffer()) {
+ framebuffer_state_.clear_state_dirty = true;
+ }
+
+ // Clip to size to source dimensions
+ GLint copyX = 0;
+ GLint copyY = 0;
+ GLint copyWidth = 0;
+ GLint copyHeight = 0;
+ Clip(x, width, size.width(), &copyX, &copyWidth);
+ Clip(y, height, size.height(), &copyY, &copyHeight);
+
+ if (copyX != x ||
+ copyY != y ||
+ copyWidth != width ||
+ copyHeight != height) {
+ // some part was clipped so clear the texture.
+ if (!ClearLevel(
+ texture->service_id(), texture->target(),
+ target, level, internal_format, GL_UNSIGNED_BYTE, width, height,
+ texture->IsImmutable())) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glCopyTexImage2D", "dimensions too big");
+ return;
+ }
+ if (copyHeight > 0 && copyWidth > 0) {
+ GLint dx = copyX - x;
+ GLint dy = copyY - y;
+ GLint destX = dx;
+ GLint destY = dy;
+ glCopyTexSubImage2D(target, level,
+ destX, destY, copyX, copyY,
+ copyWidth, copyHeight);
+ }
+ } else {
+ glCopyTexImage2D(target, level, internal_format,
+ copyX, copyY, copyWidth, copyHeight, border);
+ }
+ GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTexImage2D");
+ if (error == GL_NO_ERROR) {
+ texture_manager()->SetLevelInfo(
+ texture_ref, target, level, internal_format, width, height, 1,
+ border, internal_format, GL_UNSIGNED_BYTE, true);
+ }
+}
+
+void GLES2DecoderImpl::DoCopyTexSubImage2D(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLint x,
+ GLint y,
+ GLsizei width,
+ GLsizei height) {
+ DCHECK(!ShouldDeferReads());
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCopyTexSubImage2D", "unknown texture for target");
+ return;
+ }
+ Texture* texture = texture_ref->texture();
+ GLenum type = 0;
+ GLenum format = 0;
+ if (!texture->GetLevelType(target, level, &type, &format) ||
+ !texture->ValidForTexture(
+ target, level, xoffset, yoffset, width, height, format, type)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTexSubImage2D", "bad dimensions.");
+ return;
+ }
+ if (async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCopyTexSubImage2D", "async upload pending for texture");
+ return;
+ }
+
+ // Check we have compatible formats.
+ GLenum read_format = GetBoundReadFrameBufferInternalFormat();
+ uint32 channels_exist = GLES2Util::GetChannelsForFormat(read_format);
+ uint32 channels_needed = GLES2Util::GetChannelsForFormat(format);
+
+ if (!channels_needed ||
+ (channels_needed & channels_exist) != channels_needed) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glCopyTexSubImage2D", "incompatible format");
+ return;
+ }
+
+ if ((channels_needed & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCopySubImage2D", "can not be used with depth or stencil textures");
+ return;
+ }
+
+ if (!CheckBoundFramebuffersValid("glCopyTexSubImage2D")) {
+ return;
+ }
+
+ ScopedResolvedFrameBufferBinder binder(this, false, true);
+ gfx::Size size = GetBoundReadFrameBufferSize();
+ GLint copyX = 0;
+ GLint copyY = 0;
+ GLint copyWidth = 0;
+ GLint copyHeight = 0;
+ Clip(x, width, size.width(), &copyX, &copyWidth);
+ Clip(y, height, size.height(), &copyY, &copyHeight);
+
+ if (!texture_manager()->ClearTextureLevel(this, texture_ref, target, level)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glCopyTexSubImage2D", "dimensions too big");
+ return;
+ }
+
+ if (copyX != x ||
+ copyY != y ||
+ copyWidth != width ||
+ copyHeight != height) {
+ // some part was clipped so clear the sub rect.
+ uint32 pixels_size = 0;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &pixels_size,
+ NULL, NULL)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTexSubImage2D", "dimensions too large");
+ return;
+ }
+ scoped_ptr<char[]> zero(new char[pixels_size]);
+ memset(zero.get(), 0, pixels_size);
+ glTexSubImage2D(
+ target, level, xoffset, yoffset, width, height,
+ format, type, zero.get());
+ }
+
+ if (copyHeight > 0 && copyWidth > 0) {
+ GLint dx = copyX - x;
+ GLint dy = copyY - y;
+ GLint destX = xoffset + dx;
+ GLint destY = yoffset + dy;
+ glCopyTexSubImage2D(target, level,
+ destX, destY, copyX, copyY,
+ copyWidth, copyHeight);
+ }
+}
+
+bool GLES2DecoderImpl::ValidateTexSubImage2D(
+ error::Error* error,
+ const char* function_name,
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void * data) {
+ (*error) = error::kNoError;
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target");
+ return false;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "width < 0");
+ return false;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "height < 0");
+ return false;
+ }
+ if (!validators_->texture_format.IsValid(format)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, format, "format");
+ return false;
+ }
+ if (!validators_->pixel_type.IsValid(type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, type, "type");
+ return false;
+ }
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ function_name, "unknown texture for target");
+ return false;
+ }
+ Texture* texture = texture_ref->texture();
+ GLenum current_type = 0;
+ GLenum internal_format = 0;
+ if (!texture->GetLevelType(target, level, &current_type, &internal_format)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, function_name, "level does not exist.");
+ return false;
+ }
+ if (format != internal_format) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ function_name, "format does not match internal format.");
+ return false;
+ }
+ if (type != current_type) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ function_name, "type does not match type of texture.");
+ return false;
+ }
+ if (async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ function_name, "async upload pending for texture");
+ return false;
+ }
+ if (!texture->ValidForTexture(
+ target, level, xoffset, yoffset, width, height, format, type)) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "bad dimensions.");
+ return false;
+ }
+ if ((GLES2Util::GetChannelsForFormat(format) &
+ (GLES2Util::kDepth | GLES2Util::kStencil)) != 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ function_name, "can not supply data for depth or stencil textures");
+ return false;
+ }
+ if (data == NULL) {
+ (*error) = error::kOutOfBounds;
+ return false;
+ }
+ return true;
+}
+
+error::Error GLES2DecoderImpl::DoTexSubImage2D(
+ GLenum target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type,
+ const void * data) {
+ error::Error error = error::kNoError;
+ if (!ValidateTexSubImage2D(&error, "glTexSubImage2D", target, level,
+ xoffset, yoffset, width, height, format, type, data)) {
+ return error;
+ }
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ Texture* texture = texture_ref->texture();
+ GLsizei tex_width = 0;
+ GLsizei tex_height = 0;
+ bool ok = texture->GetLevelSize(target, level, &tex_width, &tex_height);
+ DCHECK(ok);
+ if (xoffset != 0 || yoffset != 0 ||
+ width != tex_width || height != tex_height) {
+ if (!texture_manager()->ClearTextureLevel(this, texture_ref,
+ target, level)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glTexSubImage2D", "dimensions too big");
+ return error::kNoError;
+ }
+ ScopedTextureUploadTimer timer(&texture_state_);
+ glTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type, data);
+ return error::kNoError;
+ }
+
+ if (texture_state_.teximage2d_faster_than_texsubimage2d &&
+ !texture->IsImmutable()) {
+ ScopedTextureUploadTimer timer(&texture_state_);
+ // NOTE: In OpenGL ES 2.0 border is always zero and format is always the
+ // same as internal_foramt. If that changes we'll need to look them up.
+ glTexImage2D(
+ target, level, format, width, height, 0, format, type, data);
+ } else {
+ ScopedTextureUploadTimer timer(&texture_state_);
+ glTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type, data);
+ }
+ texture_manager()->SetLevelCleared(texture_ref, target, level, true);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexSubImage2D(
+ uint32 immediate_data_size, const cmds::TexSubImage2D& c) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleTexSubImage2D");
+ GLboolean internal = static_cast<GLboolean>(c.internal);
+ if (internal == GL_TRUE && texture_state_.tex_image_2d_failed)
+ return error::kNoError;
+
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLenum type = static_cast<GLenum>(c.type);
+ uint32 data_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &data_size,
+ NULL, NULL)) {
+ return error::kOutOfBounds;
+ }
+ const void* pixels = GetSharedMemoryAs<const void*>(
+ c.pixels_shm_id, c.pixels_shm_offset, data_size);
+ return DoTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+error::Error GLES2DecoderImpl::HandleTexSubImage2DImmediate(
+ uint32 immediate_data_size, const cmds::TexSubImage2DImmediate& c) {
+ GLboolean internal = static_cast<GLboolean>(c.internal);
+ if (internal == GL_TRUE && texture_state_.tex_image_2d_failed)
+ return error::kNoError;
+
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLenum type = static_cast<GLenum>(c.type);
+ uint32 data_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &data_size,
+ NULL, NULL)) {
+ return error::kOutOfBounds;
+ }
+ const void* pixels = GetImmediateDataAs<const void*>(
+ c, data_size, immediate_data_size);
+ return DoTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, type, pixels);
+}
+
+error::Error GLES2DecoderImpl::HandleGetVertexAttribPointerv(
+ uint32 immediate_data_size, const cmds::GetVertexAttribPointerv& c) {
+ GLuint index = static_cast<GLuint>(c.index);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetVertexAttribPointerv::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.pointer_shm_id, c.pointer_shm_offset, Result::ComputeSize(1));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ if (!validators_->vertex_pointer.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glGetVertexAttribPointerv", pname, "pname");
+ return error::kNoError;
+ }
+ if (index >= group_->max_vertex_attribs()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetVertexAttribPointerv", "index out of range.");
+ return error::kNoError;
+ }
+ result->SetNumResults(1);
+ *result->GetData() =
+ state_.vertex_attrib_manager->GetVertexAttrib(index)->offset();
+ return error::kNoError;
+}
+
+bool GLES2DecoderImpl::GetUniformSetup(
+ GLuint program_id, GLint fake_location,
+ uint32 shm_id, uint32 shm_offset,
+ error::Error* error, GLint* real_location,
+ GLuint* service_id, void** result_pointer, GLenum* result_type) {
+ DCHECK(error);
+ DCHECK(service_id);
+ DCHECK(result_pointer);
+ DCHECK(result_type);
+ DCHECK(real_location);
+ *error = error::kNoError;
+ // Make sure we have enough room for the result on failure.
+ SizedResult<GLint>* result;
+ result = GetSharedMemoryAs<SizedResult<GLint>*>(
+ shm_id, shm_offset, SizedResult<GLint>::ComputeSize(0));
+ if (!result) {
+ *error = error::kOutOfBounds;
+ return false;
+ }
+ *result_pointer = result;
+ // Set the result size to 0 so the client does not have to check for success.
+ result->SetNumResults(0);
+ Program* program = GetProgramInfoNotShader(program_id, "glGetUniform");
+ if (!program) {
+ return false;
+ }
+ if (!program->IsValid()) {
+ // Program was not linked successfully. (ie, glLinkProgram)
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glGetUniform", "program not linked");
+ return false;
+ }
+ *service_id = program->service_id();
+ GLint array_index = -1;
+ const Program::UniformInfo* uniform_info =
+ program->GetUniformInfoByFakeLocation(
+ fake_location, real_location, &array_index);
+ if (!uniform_info) {
+ // No such location.
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glGetUniform", "unknown location");
+ return false;
+ }
+ GLenum type = uniform_info->type;
+ GLsizei size = GLES2Util::GetGLDataTypeSizeForUniforms(type);
+ if (size == 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glGetUniform", "unknown type");
+ return false;
+ }
+ result = GetSharedMemoryAs<SizedResult<GLint>*>(
+ shm_id, shm_offset, SizedResult<GLint>::ComputeSizeFromBytes(size));
+ if (!result) {
+ *error = error::kOutOfBounds;
+ return false;
+ }
+ result->size = size;
+ *result_type = type;
+ return true;
+}
+
+error::Error GLES2DecoderImpl::HandleGetUniformiv(
+ uint32 immediate_data_size, const cmds::GetUniformiv& c) {
+ GLuint program = c.program;
+ GLint fake_location = c.location;
+ GLuint service_id;
+ GLenum result_type;
+ GLint real_location = -1;
+ Error error;
+ void* result;
+ if (GetUniformSetup(
+ program, fake_location, c.params_shm_id, c.params_shm_offset,
+ &error, &real_location, &service_id, &result, &result_type)) {
+ glGetUniformiv(
+ service_id, real_location,
+ static_cast<cmds::GetUniformiv::Result*>(result)->GetData());
+ }
+ return error;
+}
+
+error::Error GLES2DecoderImpl::HandleGetUniformfv(
+ uint32 immediate_data_size, const cmds::GetUniformfv& c) {
+ GLuint program = c.program;
+ GLint fake_location = c.location;
+ GLuint service_id;
+ GLint real_location = -1;
+ Error error;
+ typedef cmds::GetUniformfv::Result Result;
+ Result* result;
+ GLenum result_type;
+ if (GetUniformSetup(
+ program, fake_location, c.params_shm_id, c.params_shm_offset,
+ &error, &real_location, &service_id,
+ reinterpret_cast<void**>(&result), &result_type)) {
+ if (result_type == GL_BOOL || result_type == GL_BOOL_VEC2 ||
+ result_type == GL_BOOL_VEC3 || result_type == GL_BOOL_VEC4) {
+ GLsizei num_values = result->GetNumResults();
+ scoped_ptr<GLint[]> temp(new GLint[num_values]);
+ glGetUniformiv(service_id, real_location, temp.get());
+ GLfloat* dst = result->GetData();
+ for (GLsizei ii = 0; ii < num_values; ++ii) {
+ dst[ii] = (temp[ii] != 0);
+ }
+ } else {
+ glGetUniformfv(service_id, real_location, result->GetData());
+ }
+ }
+ return error;
+}
+
+error::Error GLES2DecoderImpl::HandleGetShaderPrecisionFormat(
+ uint32 immediate_data_size, const cmds::GetShaderPrecisionFormat& c) {
+ GLenum shader_type = static_cast<GLenum>(c.shadertype);
+ GLenum precision_type = static_cast<GLenum>(c.precisiontype);
+ typedef cmds::GetShaderPrecisionFormat::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (result->success != 0) {
+ return error::kInvalidArguments;
+ }
+ if (!validators_->shader_type.IsValid(shader_type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glGetShaderPrecisionFormat", shader_type, "shader_type");
+ return error::kNoError;
+ }
+ if (!validators_->shader_precision.IsValid(precision_type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glGetShaderPrecisionFormat", precision_type, "precision_type");
+ return error::kNoError;
+ }
+
+ result->success = 1; // true
+
+ GLint range[2] = { 0, 0 };
+ GLint precision = 0;
+ GetShaderPrecisionFormatImpl(shader_type, precision_type, range, &precision);
+
+ result->min_range = range[0];
+ result->max_range = range[1];
+ result->precision = precision;
+
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetAttachedShaders(
+ uint32 immediate_data_size, const cmds::GetAttachedShaders& c) {
+ uint32 result_size = c.result_size;
+ GLuint program_id = static_cast<GLuint>(c.program);
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glGetAttachedShaders");
+ if (!program) {
+ return error::kNoError;
+ }
+ typedef cmds::GetAttachedShaders::Result Result;
+ uint32 max_count = Result::ComputeMaxResults(result_size);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, Result::ComputeSize(max_count));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ GLsizei count = 0;
+ glGetAttachedShaders(
+ program->service_id(), max_count, &count, result->GetData());
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ if (!shader_manager()->GetClientId(result->GetData()[ii],
+ &result->GetData()[ii])) {
+ NOTREACHED();
+ return error::kGenericError;
+ }
+ }
+ result->SetNumResults(count);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetActiveUniform(
+ uint32 immediate_data_size, const cmds::GetActiveUniform& c) {
+ GLuint program_id = c.program;
+ GLuint index = c.index;
+ uint32 name_bucket_id = c.name_bucket_id;
+ typedef cmds::GetActiveUniform::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (result->success != 0) {
+ return error::kInvalidArguments;
+ }
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glGetActiveUniform");
+ if (!program) {
+ return error::kNoError;
+ }
+ const Program::UniformInfo* uniform_info =
+ program->GetUniformInfo(index);
+ if (!uniform_info) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetActiveUniform", "index out of range");
+ return error::kNoError;
+ }
+ result->success = 1; // true.
+ result->size = uniform_info->size;
+ result->type = uniform_info->type;
+ Bucket* bucket = CreateBucket(name_bucket_id);
+ bucket->SetFromString(uniform_info->name.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetActiveAttrib(
+ uint32 immediate_data_size, const cmds::GetActiveAttrib& c) {
+ GLuint program_id = c.program;
+ GLuint index = c.index;
+ uint32 name_bucket_id = c.name_bucket_id;
+ typedef cmds::GetActiveAttrib::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (result->success != 0) {
+ return error::kInvalidArguments;
+ }
+ Program* program = GetProgramInfoNotShader(
+ program_id, "glGetActiveAttrib");
+ if (!program) {
+ return error::kNoError;
+ }
+ const Program::VertexAttrib* attrib_info =
+ program->GetAttribInfo(index);
+ if (!attrib_info) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetActiveAttrib", "index out of range");
+ return error::kNoError;
+ }
+ result->success = 1; // true.
+ result->size = attrib_info->size;
+ result->type = attrib_info->type;
+ Bucket* bucket = CreateBucket(name_bucket_id);
+ bucket->SetFromString(attrib_info->name.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleShaderBinary(
+ uint32 immediate_data_size, const cmds::ShaderBinary& c) {
+#if 1 // No binary shader support.
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glShaderBinary", "not supported");
+ return error::kNoError;
+#else
+ GLsizei n = static_cast<GLsizei>(c.n);
+ if (n < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glShaderBinary", "n < 0");
+ return error::kNoError;
+ }
+ GLsizei length = static_cast<GLsizei>(c.length);
+ if (length < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glShaderBinary", "length < 0");
+ return error::kNoError;
+ }
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* shaders = GetSharedMemoryAs<const GLuint*>(
+ c.shaders_shm_id, c.shaders_shm_offset, data_size);
+ GLenum binaryformat = static_cast<GLenum>(c.binaryformat);
+ const void* binary = GetSharedMemoryAs<const void*>(
+ c.binary_shm_id, c.binary_shm_offset, length);
+ if (shaders == NULL || binary == NULL) {
+ return error::kOutOfBounds;
+ }
+ scoped_array<GLuint> service_ids(new GLuint[n]);
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ Shader* shader = GetShader(shaders[ii]);
+ if (!shader) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glShaderBinary", "unknown shader");
+ return error::kNoError;
+ }
+ service_ids[ii] = shader->service_id();
+ }
+ // TODO(gman): call glShaderBinary
+ return error::kNoError;
+#endif
+}
+
+void GLES2DecoderImpl::DoSwapBuffers() {
+ bool is_offscreen = !!offscreen_target_frame_buffer_.get();
+
+ int this_frame_number = frame_number_++;
+ // TRACE_EVENT for gpu tests:
+ TRACE_EVENT_INSTANT2("test_gpu", "SwapBuffersLatency",
+ TRACE_EVENT_SCOPE_THREAD,
+ "GLImpl", static_cast<int>(gfx::GetGLImplementation()),
+ "width", (is_offscreen ? offscreen_size_.width() :
+ surface_->GetSize().width()));
+ TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoSwapBuffers",
+ "offscreen", is_offscreen,
+ "frame", this_frame_number);
+ // If offscreen then don't actually SwapBuffers to the display. Just copy
+ // the rendered frame to another frame buffer.
+ if (is_offscreen) {
+ TRACE_EVENT2("gpu", "Offscreen",
+ "width", offscreen_size_.width(), "height", offscreen_size_.height());
+ if (offscreen_size_ != offscreen_saved_color_texture_->size()) {
+ // Workaround for NVIDIA driver bug on OS X; crbug.com/89557,
+ // crbug.com/94163. TODO(kbr): figure out reproduction so Apple will
+ // fix this.
+ if (workarounds().needs_offscreen_buffer_workaround) {
+ offscreen_saved_frame_buffer_->Create();
+ glFinish();
+ }
+
+ // Allocate the offscreen saved color texture.
+ DCHECK(offscreen_saved_color_format_);
+ offscreen_saved_color_texture_->AllocateStorage(
+ offscreen_size_, offscreen_saved_color_format_, false);
+
+ offscreen_saved_frame_buffer_->AttachRenderTexture(
+ offscreen_saved_color_texture_.get());
+ if (offscreen_size_.width() != 0 && offscreen_size_.height() != 0) {
+ if (offscreen_saved_frame_buffer_->CheckStatus() !=
+ GL_FRAMEBUFFER_COMPLETE) {
+ LOG(ERROR) << "GLES2DecoderImpl::ResizeOffscreenFrameBuffer failed "
+ << "because offscreen saved FBO was incomplete.";
+ LoseContext(GL_UNKNOWN_CONTEXT_RESET_ARB);
+ return;
+ }
+
+ // Clear the offscreen color texture.
+ // TODO(piman): Is this still necessary?
+ {
+ ScopedFrameBufferBinder binder(this,
+ offscreen_saved_frame_buffer_->id());
+ glClearColor(0, 0, 0, 0);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDisable(GL_SCISSOR_TEST);
+ glClear(GL_COLOR_BUFFER_BIT);
+ RestoreClearState();
+ }
+ }
+
+ UpdateParentTextureInfo();
+ }
+
+ if (offscreen_size_.width() == 0 || offscreen_size_.height() == 0)
+ return;
+ ScopedGLErrorSuppressor suppressor(
+ "GLES2DecoderImpl::DoSwapBuffers", this);
+
+ if (IsOffscreenBufferMultisampled()) {
+ // For multisampled buffers, resolve the frame buffer.
+ ScopedResolvedFrameBufferBinder binder(this, true, false);
+ } else {
+ ScopedFrameBufferBinder binder(this,
+ offscreen_target_frame_buffer_->id());
+
+ if (offscreen_target_buffer_preserved_) {
+ // Copy the target frame buffer to the saved offscreen texture.
+ offscreen_saved_color_texture_->Copy(
+ offscreen_saved_color_texture_->size(),
+ offscreen_saved_color_format_);
+ } else {
+ // Flip the textures in the parent context via the texture manager.
+ if (!!offscreen_saved_color_texture_info_.get())
+ offscreen_saved_color_texture_info_->texture()->
+ SetServiceId(offscreen_target_color_texture_->id());
+
+ offscreen_saved_color_texture_.swap(offscreen_target_color_texture_);
+ offscreen_target_frame_buffer_->AttachRenderTexture(
+ offscreen_target_color_texture_.get());
+ }
+
+ // Ensure the side effects of the copy are visible to the parent
+ // context. There is no need to do this for ANGLE because it uses a
+ // single D3D device for all contexts.
+ if (!IsAngle())
+ glFlush();
+ }
+ } else {
+ TRACE_EVENT2("gpu", "Onscreen",
+ "width", surface_->GetSize().width(),
+ "height", surface_->GetSize().height());
+ if (!surface_->SwapBuffers()) {
+ LOG(ERROR) << "Context lost because SwapBuffers failed.";
+ LoseContext(GL_UNKNOWN_CONTEXT_RESET_ARB);
+ }
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleEnableFeatureCHROMIUM(
+ uint32 immediate_data_size, const cmds::EnableFeatureCHROMIUM& c) {
+ Bucket* bucket = GetBucket(c.bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ typedef cmds::EnableFeatureCHROMIUM::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+ if (!result) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (*result != 0) {
+ return error::kInvalidArguments;
+ }
+ std::string feature_str;
+ if (!bucket->GetAsString(&feature_str)) {
+ return error::kInvalidArguments;
+ }
+
+ // TODO(gman): make this some kind of table to function pointer thingy.
+ if (feature_str.compare("pepper3d_allow_buffers_on_multiple_targets") == 0) {
+ buffer_manager()->set_allow_buffers_on_multiple_targets(true);
+ } else if (feature_str.compare("pepper3d_support_fixed_attribs") == 0) {
+ buffer_manager()->set_allow_buffers_on_multiple_targets(true);
+ // TODO(gman): decide how to remove the need for this const_cast.
+ // I could make validators_ non const but that seems bad as this is the only
+ // place it is needed. I could make some special friend class of validators
+ // just to allow this to set them. That seems silly. I could refactor this
+ // code to use the extension mechanism or the initialization attributes to
+ // turn this feature on. Given that the only real point of this is to make
+ // the conformance tests pass and given that there is lots of real work that
+ // needs to be done it seems like refactoring for one to one of those
+ // methods is a very low priority.
+ const_cast<Validators*>(validators_)->vertex_attrib_type.AddValue(GL_FIXED);
+ } else if (feature_str.compare("webgl_enable_glsl_webgl_validation") == 0) {
+ force_webgl_glsl_validation_ = true;
+ InitializeShaderTranslator();
+ } else {
+ return error::kNoError;
+ }
+
+ *result = 1; // true.
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetRequestableExtensionsCHROMIUM(
+ uint32 immediate_data_size,
+ const cmds::GetRequestableExtensionsCHROMIUM& c) {
+ Bucket* bucket = CreateBucket(c.bucket_id);
+ scoped_refptr<FeatureInfo> info(new FeatureInfo());
+ info->Initialize(disallowed_features_, NULL);
+ bucket->SetFromString(info->extensions().c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleRequestExtensionCHROMIUM(
+ uint32 immediate_data_size, const cmds::RequestExtensionCHROMIUM& c) {
+ Bucket* bucket = GetBucket(c.bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string feature_str;
+ if (!bucket->GetAsString(&feature_str)) {
+ return error::kInvalidArguments;
+ }
+
+ bool desire_webgl_glsl_validation =
+ feature_str.find("GL_CHROMIUM_webglsl") != std::string::npos;
+ bool desire_standard_derivatives = false;
+ bool desire_frag_depth = false;
+ bool desire_draw_buffers = false;
+ if (force_webgl_glsl_validation_) {
+ desire_standard_derivatives =
+ feature_str.find("GL_OES_standard_derivatives") != std::string::npos;
+ desire_frag_depth =
+ feature_str.find("GL_EXT_frag_depth") != std::string::npos;
+ desire_draw_buffers =
+ feature_str.find("GL_EXT_draw_buffers") != std::string::npos;
+ }
+
+ if (desire_webgl_glsl_validation != force_webgl_glsl_validation_ ||
+ desire_standard_derivatives != derivatives_explicitly_enabled_ ||
+ desire_frag_depth != frag_depth_explicitly_enabled_ ||
+ desire_draw_buffers != draw_buffers_explicitly_enabled_) {
+ force_webgl_glsl_validation_ |= desire_webgl_glsl_validation;
+ derivatives_explicitly_enabled_ |= desire_standard_derivatives;
+ frag_depth_explicitly_enabled_ |= desire_frag_depth;
+ draw_buffers_explicitly_enabled_ |= desire_draw_buffers;
+ InitializeShaderTranslator();
+ }
+
+ UpdateCapabilities();
+
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetMultipleIntegervCHROMIUM(
+ uint32 immediate_data_size, const cmds::GetMultipleIntegervCHROMIUM& c) {
+ GLuint count = c.count;
+ uint32 pnames_size;
+ if (!SafeMultiplyUint32(count, sizeof(GLenum), &pnames_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLenum* pnames = GetSharedMemoryAs<const GLenum*>(
+ c.pnames_shm_id, c.pnames_shm_offset, pnames_size);
+ if (pnames == NULL) {
+ return error::kOutOfBounds;
+ }
+
+ // We have to copy them since we use them twice so the client
+ // can't change them between the time we validate them and the time we use
+ // them.
+ scoped_ptr<GLenum[]> enums(new GLenum[count]);
+ memcpy(enums.get(), pnames, pnames_size);
+
+ // Count up the space needed for the result.
+ uint32 num_results = 0;
+ for (GLuint ii = 0; ii < count; ++ii) {
+ uint32 num = util_.GLGetNumValuesReturned(enums[ii]);
+ if (num == 0) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glGetMulitpleCHROMIUM", enums[ii], "pname");
+ return error::kNoError;
+ }
+ // Num will never be more than 4.
+ DCHECK_LE(num, 4u);
+ if (!SafeAddUint32(num_results, num, &num_results)) {
+ return error::kOutOfBounds;
+ }
+ }
+
+ uint32 result_size = 0;
+ if (!SafeMultiplyUint32(num_results, sizeof(GLint), &result_size)) {
+ return error::kOutOfBounds;
+ }
+
+ if (result_size != static_cast<uint32>(c.size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glGetMulitpleCHROMIUM", "bad size GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+
+ GLint* results = GetSharedMemoryAs<GLint*>(
+ c.results_shm_id, c.results_shm_offset, result_size);
+ if (results == NULL) {
+ return error::kOutOfBounds;
+ }
+
+ // Check the results have been cleared in case the context was lost.
+ for (uint32 ii = 0; ii < num_results; ++ii) {
+ if (results[ii]) {
+ return error::kInvalidArguments;
+ }
+ }
+
+ // Get each result.
+ GLint* start = results;
+ for (GLuint ii = 0; ii < count; ++ii) {
+ GLsizei num_written = 0;
+ if (!state_.GetStateAsGLint(enums[ii], results, &num_written) &&
+ !GetHelper(enums[ii], results, &num_written)) {
+ DoGetIntegerv(enums[ii], results);
+ }
+ results += num_written;
+ }
+
+ // Just to verify. Should this be a DCHECK?
+ if (static_cast<uint32>(results - start) != num_results) {
+ return error::kOutOfBounds;
+ }
+
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetProgramInfoCHROMIUM(
+ uint32 immediate_data_size, const cmds::GetProgramInfoCHROMIUM& c) {
+ GLuint program_id = static_cast<GLuint>(c.program);
+ uint32 bucket_id = c.bucket_id;
+ Bucket* bucket = CreateBucket(bucket_id);
+ bucket->SetSize(sizeof(ProgramInfoHeader)); // in case we fail.
+ Program* program = NULL;
+ program = GetProgram(program_id);
+ if (!program || !program->IsValid()) {
+ return error::kNoError;
+ }
+ program->GetProgramInfo(program_manager(), bucket);
+ return error::kNoError;
+}
+
+error::ContextLostReason GLES2DecoderImpl::GetContextLostReason() {
+ switch (reset_status_) {
+ case GL_NO_ERROR:
+ // TODO(kbr): improve the precision of the error code in this case.
+ // Consider delegating to context for error code if MakeCurrent fails.
+ return error::kUnknown;
+ case GL_GUILTY_CONTEXT_RESET_ARB:
+ return error::kGuilty;
+ case GL_INNOCENT_CONTEXT_RESET_ARB:
+ return error::kInnocent;
+ case GL_UNKNOWN_CONTEXT_RESET_ARB:
+ return error::kUnknown;
+ }
+
+ NOTREACHED();
+ return error::kUnknown;
+}
+
+bool GLES2DecoderImpl::WasContextLost() {
+ if (reset_status_ != GL_NO_ERROR) {
+ return true;
+ }
+ if (context_->WasAllocatedUsingRobustnessExtension()) {
+ GLenum status = GL_NO_ERROR;
+ if (has_robustness_extension_)
+ status = glGetGraphicsResetStatusARB();
+ if (status != GL_NO_ERROR) {
+ // The graphics card was reset. Signal a lost context to the application.
+ reset_status_ = status;
+ reset_by_robustness_extension_ = true;
+ LOG(ERROR) << (surface_->IsOffscreen() ? "Offscreen" : "Onscreen")
+ << " context lost via ARB/EXT_robustness. Reset status = "
+ << GLES2Util::GetStringEnum(status);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GLES2DecoderImpl::WasContextLostByRobustnessExtension() {
+ return WasContextLost() && reset_by_robustness_extension_;
+}
+
+void GLES2DecoderImpl::LoseContext(uint32 reset_status) {
+ // Only loses the context once.
+ if (reset_status_ != GL_NO_ERROR) {
+ return;
+ }
+
+ // Marks this context as lost.
+ reset_status_ = reset_status;
+ current_decoder_error_ = error::kLostContext;
+}
+
+error::Error GLES2DecoderImpl::HandleLoseContextCHROMIUM(
+ uint32 immediate_data_size, const cmds::LoseContextCHROMIUM& c) {
+ GLenum current = static_cast<GLenum>(c.current);
+ GLenum other = static_cast<GLenum>(c.other);
+ if (!validators_->reset_status.IsValid(current)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(
+ "glLoseContextCHROMIUM", current, "current");
+ }
+ if (!validators_->reset_status.IsValid(other)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glLoseContextCHROMIUM", other, "other");
+ }
+ group_->LoseContexts(other);
+ reset_status_ = current;
+ current_decoder_error_ = error::kLostContext;
+ return error::kLostContext;
+}
+
+error::Error GLES2DecoderImpl::HandleInsertSyncPointCHROMIUM(
+ uint32 immediate_data_size, const cmds::InsertSyncPointCHROMIUM& c) {
+ return error::kUnknownCommand;
+}
+
+error::Error GLES2DecoderImpl::HandleWaitSyncPointCHROMIUM(
+ uint32 immediate_data_size, const cmds::WaitSyncPointCHROMIUM& c) {
+ if (wait_sync_point_callback_.is_null())
+ return error::kNoError;
+
+ return wait_sync_point_callback_.Run(c.sync_point) ?
+ error::kNoError : error::kDeferCommandUntilLater;
+}
+
+bool GLES2DecoderImpl::GenQueriesEXTHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (query_manager_->GetQuery(client_ids[ii])) {
+ return false;
+ }
+ }
+ // NOTE: We don't generate Query objects here. Only in BeginQueryEXT
+ return true;
+}
+
+void GLES2DecoderImpl::DeleteQueriesEXTHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ QueryManager::Query* query = query_manager_->GetQuery(client_ids[ii]);
+ if (query && !query->IsDeleted()) {
+ if (query == state_.current_query.get()) {
+ state_.current_query = NULL;
+ }
+ query->Destroy(true);
+ query_manager_->RemoveQuery(client_ids[ii]);
+ }
+ }
+}
+
+bool GLES2DecoderImpl::ProcessPendingQueries() {
+ if (query_manager_.get() == NULL) {
+ return false;
+ }
+ if (!query_manager_->ProcessPendingQueries()) {
+ current_decoder_error_ = error::kOutOfBounds;
+ }
+ return query_manager_->HavePendingQueries();
+}
+
+// Note that if there are no pending readpixels right now,
+// this function will call the callback immediately.
+void GLES2DecoderImpl::WaitForReadPixels(base::Closure callback) {
+ if (features().use_async_readpixels && !pending_readpixel_fences_.empty()) {
+ pending_readpixel_fences_.back()->callbacks.push_back(callback);
+ } else {
+ callback.Run();
+ }
+}
+
+void GLES2DecoderImpl::ProcessPendingReadPixels() {
+ while (!pending_readpixel_fences_.empty() &&
+ pending_readpixel_fences_.front()->fence->HasCompleted()) {
+ std::vector<base::Closure> callbacks =
+ pending_readpixel_fences_.front()->callbacks;
+ pending_readpixel_fences_.pop();
+ for (size_t i = 0; i < callbacks.size(); i++) {
+ callbacks[i].Run();
+ }
+ }
+}
+
+bool GLES2DecoderImpl::HasMoreIdleWork() {
+ return !pending_readpixel_fences_.empty() ||
+ async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers();
+}
+
+void GLES2DecoderImpl::PerformIdleWork() {
+ ProcessPendingReadPixels();
+ if (!async_pixel_transfer_manager_->NeedsProcessMorePendingTransfers())
+ return;
+ async_pixel_transfer_manager_->ProcessMorePendingTransfers();
+ ProcessFinishedAsyncTransfers();
+}
+
+error::Error GLES2DecoderImpl::HandleBeginQueryEXT(
+ uint32 immediate_data_size, const cmds::BeginQueryEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint client_id = static_cast<GLuint>(c.id);
+ int32 sync_shm_id = static_cast<int32>(c.sync_data_shm_id);
+ uint32 sync_shm_offset = static_cast<uint32>(c.sync_data_shm_offset);
+
+ switch (target) {
+ case GL_COMMANDS_ISSUED_CHROMIUM:
+ case GL_LATENCY_QUERY_CHROMIUM:
+ case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
+ case GL_GET_ERROR_QUERY_CHROMIUM:
+ break;
+ default:
+ if (!features().occlusion_query_boolean) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glBeginQueryEXT",
+ "not enabled for occlusion queries");
+ return error::kNoError;
+ }
+ break;
+ }
+
+ // TODO(hubbe): Make it possible to have one query per type running at the
+ // same time.
+ if (state_.current_query.get()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glBeginQueryEXT", "query already in progress");
+ return error::kNoError;
+ }
+
+ if (client_id == 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBeginQueryEXT", "id is 0");
+ return error::kNoError;
+ }
+
+ QueryManager::Query* query = query_manager_->GetQuery(client_id);
+ if (!query) {
+ // TODO(gman): Decide if we need this check.
+ //
+ // Checks id was made by glGenQueries
+ //
+ // From the POV of OpenGL ES 2.0 you need to call glGenQueriesEXT
+ // for all Query ids but from the POV of the command buffer service maybe
+ // you don't.
+ //
+ // The client can enforce this. I don't think the service cares.
+ //
+ // IdAllocatorInterface* id_allocator =
+ // group_->GetIdAllocator(id_namespaces::kQueries);
+ // if (!id_allocator->InUse(client_id)) {
+ // LOCAL_SET_GL_ERROR(
+ // GL_INVALID_OPERATION,
+ // "glBeginQueryEXT", "id not made by glGenQueriesEXT");
+ // return error::kNoError;
+ // }
+ query = query_manager_->CreateQuery(
+ target, client_id, sync_shm_id, sync_shm_offset);
+ }
+
+ if (query->target() != target) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glBeginQueryEXT", "target does not match");
+ return error::kNoError;
+ } else if (query->shm_id() != sync_shm_id ||
+ query->shm_offset() != sync_shm_offset) {
+ DLOG(ERROR) << "Shared memory used by query not the same as before";
+ return error::kInvalidArguments;
+ }
+
+ if (!query_manager_->BeginQuery(query)) {
+ return error::kOutOfBounds;
+ }
+
+ state_.current_query = query;
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleEndQueryEXT(
+ uint32 immediate_data_size, const cmds::EndQueryEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ uint32 submit_count = static_cast<GLuint>(c.submit_count);
+
+ if (!state_.current_query.get()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION, "glEndQueryEXT", "No active query");
+ return error::kNoError;
+ }
+ if (state_.current_query->target() != target) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glEndQueryEXT", "target does not match active query");
+ return error::kNoError;
+ }
+
+ if (!query_manager_->EndQuery(state_.current_query.get(), submit_count)) {
+ return error::kOutOfBounds;
+ }
+
+ query_manager_->ProcessPendingTransferQueries();
+
+ state_.current_query = NULL;
+ return error::kNoError;
+}
+
+bool GLES2DecoderImpl::GenVertexArraysOESHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (GetVertexAttribManager(client_ids[ii])) {
+ return false;
+ }
+ }
+
+ if (!features().native_vertex_array_object) {
+ // Emulated VAO
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateVertexAttribManager(client_ids[ii], 0);
+ }
+ } else {
+ scoped_ptr<GLuint[]> service_ids(new GLuint[n]);
+
+ glGenVertexArraysOES(n, service_ids.get());
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateVertexAttribManager(client_ids[ii], service_ids[ii]);
+ }
+ }
+
+ return true;
+}
+
+void GLES2DecoderImpl::DeleteVertexArraysOESHelper(
+ GLsizei n, const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ VertexAttribManager* vao =
+ GetVertexAttribManager(client_ids[ii]);
+ if (vao && !vao->IsDeleted()) {
+ if (state_.vertex_attrib_manager.get() == vao) {
+ state_.vertex_attrib_manager = default_vertex_attrib_manager_;
+ }
+ RemoveVertexAttribManager(client_ids[ii]);
+ }
+ }
+}
+
+void GLES2DecoderImpl::DoBindVertexArrayOES(GLuint client_id) {
+ VertexAttribManager* vao = NULL;
+ GLuint service_id = 0;
+ if (client_id != 0) {
+ vao = GetVertexAttribManager(client_id);
+ if (!vao) {
+ // Unlike most Bind* methods, the spec explicitly states that VertexArray
+ // only allows names that have been previously generated. As such, we do
+ // not generate new names here.
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindVertexArrayOES", "bad vertex array id.");
+ current_decoder_error_ = error::kNoError;
+ return;
+ } else {
+ service_id = vao->service_id();
+ }
+ } else {
+ vao = default_vertex_attrib_manager_.get();
+ }
+
+ // Only set the VAO state if it's changed
+ if (state_.vertex_attrib_manager.get() != vao) {
+ state_.vertex_attrib_manager = vao;
+ if (!features().native_vertex_array_object) {
+ EmulateVertexArrayState();
+ } else {
+ glBindVertexArrayOES(service_id);
+ }
+ }
+}
+
+// Used when OES_vertex_array_object isn't natively supported
+void GLES2DecoderImpl::EmulateVertexArrayState() {
+ // Setup the Vertex attribute state
+ for (uint32 vv = 0; vv < group_->max_vertex_attribs(); ++vv) {
+ RestoreStateForAttrib(vv);
+ }
+
+ // Setup the element buffer
+ Buffer* element_array_buffer =
+ state_.vertex_attrib_manager->element_array_buffer();
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
+ element_array_buffer ? element_array_buffer->service_id() : 0);
+}
+
+bool GLES2DecoderImpl::DoIsVertexArrayOES(GLuint client_id) {
+ const VertexAttribManager* vao =
+ GetVertexAttribManager(client_id);
+ return vao && vao->IsValid() && !vao->IsDeleted();
+}
+
+error::Error GLES2DecoderImpl::HandleCreateStreamTextureCHROMIUM(
+ uint32 immediate_data_size,
+ const cmds::CreateStreamTextureCHROMIUM& c) {
+ if (!features().chromium_stream_texture) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glOpenStreamTextureCHROMIUM", "not supported.");
+ return error::kNoError;
+ }
+
+ uint32 client_id = c.client_id;
+ typedef cmds::CreateStreamTextureCHROMIUM::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result));
+
+ if (!result)
+ return error::kOutOfBounds;
+ *result = GL_ZERO;
+ TextureRef* texture_ref = texture_manager()->GetTexture(client_id);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCreateStreamTextureCHROMIUM", "bad texture id.");
+ return error::kNoError;
+ }
+
+ Texture* texture = texture_ref->texture();
+ if (texture->IsStreamTexture()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCreateStreamTextureCHROMIUM", "is already a stream texture.");
+ return error::kNoError;
+ }
+
+ if (texture->target() && texture->target() != GL_TEXTURE_EXTERNAL_OES) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glCreateStreamTextureCHROMIUM",
+ "is already bound to incompatible target.");
+ return error::kNoError;
+ }
+
+ if (!stream_texture_manager())
+ return error::kInvalidArguments;
+
+ GLuint object_id = stream_texture_manager()->CreateStreamTexture(
+ texture->service_id(), client_id);
+
+ if (object_id) {
+ texture_manager()->SetStreamTexture(texture_ref, true);
+ } else {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY,
+ "glCreateStreamTextureCHROMIUM", "failed to create platform texture.");
+ }
+
+ *result = object_id;
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDestroyStreamTextureCHROMIUM(
+ uint32 immediate_data_size,
+ const cmds::DestroyStreamTextureCHROMIUM& c) {
+ GLuint client_id = c.texture;
+ TextureRef* texture_ref = texture_manager()->GetTexture(client_id);
+ if (texture_ref && texture_manager()->IsStreamTextureOwner(texture_ref)) {
+ if (!stream_texture_manager())
+ return error::kInvalidArguments;
+
+ stream_texture_manager()->DestroyStreamTexture(texture_ref->service_id());
+ texture_manager()->SetStreamTexture(texture_ref, false);
+ } else {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glDestroyStreamTextureCHROMIUM", "bad texture id.");
+ }
+
+ return error::kNoError;
+}
+
+#if defined(OS_MACOSX)
+void GLES2DecoderImpl::ReleaseIOSurfaceForTexture(GLuint texture_id) {
+ TextureToIOSurfaceMap::iterator it = texture_to_io_surface_map_.find(
+ texture_id);
+ if (it != texture_to_io_surface_map_.end()) {
+ // Found a previous IOSurface bound to this texture; release it.
+ CFTypeRef surface = it->second;
+ CFRelease(surface);
+ texture_to_io_surface_map_.erase(it);
+ }
+}
+#endif
+
+void GLES2DecoderImpl::DoTexImageIOSurface2DCHROMIUM(
+ GLenum target, GLsizei width, GLsizei height,
+ GLuint io_surface_id, GLuint plane) {
+#if defined(OS_MACOSX)
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationDesktopGL) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM", "only supported on desktop GL.");
+ return;
+ }
+
+ IOSurfaceSupport* surface_support = IOSurfaceSupport::Initialize();
+ if (!surface_support) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM", "only supported on 10.6.");
+ return;
+ }
+
+ if (target != GL_TEXTURE_RECTANGLE_ARB) {
+ // This might be supported in the future, and if we could require
+ // support for binding an IOSurface to a NPOT TEXTURE_2D texture, we
+ // could delete a lot of code. For now, perform strict validation so we
+ // know what's going on.
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM",
+ "requires TEXTURE_RECTANGLE_ARB target");
+ return;
+ }
+
+ // Default target might be conceptually valid, but disallow it to avoid
+ // accidents.
+ TextureRef* texture_ref =
+ texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM", "no rectangle texture bound");
+ return;
+ }
+
+ // Look up the new IOSurface. Note that because of asynchrony
+ // between processes this might fail; during live resizing the
+ // plugin process might allocate and release an IOSurface before
+ // this process gets a chance to look it up. Hold on to any old
+ // IOSurface in this case.
+ CFTypeRef surface = surface_support->IOSurfaceLookup(io_surface_id);
+ if (!surface) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM", "no IOSurface with the given ID");
+ return;
+ }
+
+ // Release any IOSurface previously bound to this texture.
+ ReleaseIOSurfaceForTexture(texture_ref->service_id());
+
+ // Make sure we release the IOSurface even if CGLTexImageIOSurface2D fails.
+ texture_to_io_surface_map_.insert(
+ std::make_pair(texture_ref->service_id(), surface));
+
+ CGLContextObj context =
+ static_cast<CGLContextObj>(context_->GetHandle());
+
+ CGLError err = surface_support->CGLTexImageIOSurface2D(
+ context,
+ target,
+ GL_RGBA,
+ width,
+ height,
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ surface,
+ plane);
+
+ if (err != kCGLNoError) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM", "error in CGLTexImageIOSurface2D");
+ return;
+ }
+
+ texture_manager()->SetLevelInfo(
+ texture_ref, target, 0, GL_RGBA, width, height, 1, 0,
+ GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, true);
+
+#else
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+ "glTexImageIOSurface2DCHROMIUM", "not supported.");
+#endif
+}
+
+static GLenum ExtractFormatFromStorageFormat(GLenum internalformat) {
+ switch (internalformat) {
+ case GL_RGB565:
+ return GL_RGB;
+ case GL_RGBA4:
+ return GL_RGBA;
+ case GL_RGB5_A1:
+ return GL_RGBA;
+ case GL_RGB8_OES:
+ return GL_RGB;
+ case GL_RGBA8_OES:
+ return GL_RGBA;
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ return GL_LUMINANCE_ALPHA;
+ case GL_LUMINANCE8_EXT:
+ return GL_LUMINANCE;
+ case GL_ALPHA8_EXT:
+ return GL_ALPHA;
+ case GL_RGBA32F_EXT:
+ return GL_RGBA;
+ case GL_RGB32F_EXT:
+ return GL_RGB;
+ case GL_ALPHA32F_EXT:
+ return GL_ALPHA;
+ case GL_LUMINANCE32F_EXT:
+ return GL_LUMINANCE;
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ return GL_LUMINANCE_ALPHA;
+ case GL_RGBA16F_EXT:
+ return GL_RGBA;
+ case GL_RGB16F_EXT:
+ return GL_RGB;
+ case GL_ALPHA16F_EXT:
+ return GL_ALPHA;
+ case GL_LUMINANCE16F_EXT:
+ return GL_LUMINANCE;
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ return GL_LUMINANCE_ALPHA;
+ case GL_BGRA8_EXT:
+ return GL_BGRA_EXT;
+ default:
+ return GL_NONE;
+ }
+}
+
+void GLES2DecoderImpl::DoCopyTextureCHROMIUM(
+ GLenum target, GLuint source_id, GLuint dest_id, GLint level,
+ GLenum internal_format, GLenum dest_type) {
+ TextureRef* dest_texture_ref = GetTexture(dest_id);
+ TextureRef* source_texture_ref = GetTexture(source_id);
+
+ if (!source_texture_ref || !dest_texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "unknown texture id");
+ return;
+ }
+
+ if (GL_TEXTURE_2D != target) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "invalid texture target");
+ return;
+ }
+
+ Texture* source_texture = source_texture_ref->texture();
+ Texture* dest_texture = dest_texture_ref->texture();
+ if (dest_texture->target() != GL_TEXTURE_2D ||
+ (source_texture->target() != GL_TEXTURE_2D &&
+ source_texture->target() != GL_TEXTURE_EXTERNAL_OES)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCopyTextureCHROMIUM", "invalid texture target binding");
+ return;
+ }
+
+ int source_width, source_height, dest_width, dest_height;
+
+ if (source_texture->target() == GL_TEXTURE_2D) {
+ if (!source_texture->GetLevelSize(GL_TEXTURE_2D, 0, &source_width,
+ &source_height)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCopyTextureChromium", "source texture has no level 0");
+ return;
+ }
+
+ // Check that this type of texture is allowed.
+ if (!texture_manager()->ValidForTarget(GL_TEXTURE_2D, level, source_width,
+ source_height, 1)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCopyTextureCHROMIUM", "Bad dimensions");
+ return;
+ }
+ }
+
+ if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) {
+ UpdateStreamTextureIfNeeded(source_texture);
+ DCHECK(stream_texture_manager());
+ StreamTexture* stream_tex =
+ stream_texture_manager()->LookupStreamTexture(
+ source_texture->service_id());
+ if (!stream_tex) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCopyTextureChromium", "Stream texture lookup failed");
+ return;
+ }
+ gfx::Size size = stream_tex->GetSize();
+ source_width = size.width();
+ source_height = size.height();
+ if (source_width <= 0 || source_height <= 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glCopyTextureChromium", "invalid streamtexture size");
+ return;
+ }
+ }
+
+ // Defer initializing the CopyTextureCHROMIUMResourceManager until it is
+ // needed because it takes 10s of milliseconds to initialize.
+ if (!copy_texture_CHROMIUM_.get()) {
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyTextureCHROMIUM");
+ copy_texture_CHROMIUM_.reset(new CopyTextureCHROMIUMResourceManager());
+ copy_texture_CHROMIUM_->Initialize(this);
+ RestoreCurrentFramebufferBindings();
+ if (LOCAL_PEEK_GL_ERROR("glCopyTextureCHROMIUM") != GL_NO_ERROR)
+ return;
+ }
+
+ GLenum dest_type_previous;
+ GLenum dest_internal_format;
+ bool dest_level_defined = dest_texture->GetLevelSize(
+ GL_TEXTURE_2D, level, &dest_width, &dest_height);
+
+ if (dest_level_defined) {
+ dest_texture->GetLevelType(GL_TEXTURE_2D, level, &dest_type_previous,
+ &dest_internal_format);
+ }
+
+ // Resize the destination texture to the dimensions of the source texture.
+ if (!dest_level_defined || dest_width != source_width ||
+ dest_height != source_height ||
+ dest_internal_format != internal_format ||
+ dest_type_previous != dest_type) {
+ // Ensure that the glTexImage2D succeeds.
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glCopyTextureCHROMIUM");
+ glBindTexture(GL_TEXTURE_2D, dest_texture->service_id());
+ glTexImage2D(
+ GL_TEXTURE_2D, level, internal_format, source_width, source_height,
+ 0, internal_format, dest_type, NULL);
+ GLenum error = LOCAL_PEEK_GL_ERROR("glCopyTextureCHROMIUM");
+ if (error != GL_NO_ERROR) {
+ RestoreCurrentTexture2DBindings();
+ return;
+ }
+
+ texture_manager()->SetLevelInfo(
+ dest_texture_ref, GL_TEXTURE_2D, level, internal_format, source_width,
+ source_height, 1, 0, internal_format, dest_type, true);
+ } else {
+ texture_manager()->SetLevelCleared(
+ dest_texture_ref, GL_TEXTURE_2D, level, true);
+ }
+
+ // GL_TEXTURE_EXTERNAL_OES texture requires apply a transform matrix
+ // before presenting.
+ if (source_texture->target() == GL_TEXTURE_EXTERNAL_OES) {
+ // TODO(hkuang): get the StreamTexture transform matrix in GPU process
+ // instead of using default matrix crbug.com/226218.
+ const static GLfloat default_matrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f};
+ copy_texture_CHROMIUM_->DoCopyTextureWithTransform(
+ this,
+ source_texture->target(),
+ dest_texture->target(),
+ source_texture->service_id(),
+ dest_texture->service_id(), level,
+ source_width, source_height,
+ unpack_flip_y_,
+ unpack_premultiply_alpha_,
+ unpack_unpremultiply_alpha_,
+ default_matrix);
+ } else {
+ copy_texture_CHROMIUM_->DoCopyTexture(
+ this,
+ source_texture->target(),
+ dest_texture->target(),
+ source_texture->service_id(),
+ dest_texture->service_id(), level,
+ source_width, source_height,
+ unpack_flip_y_,
+ unpack_premultiply_alpha_,
+ unpack_unpremultiply_alpha_);
+ }
+}
+
+static GLenum ExtractTypeFromStorageFormat(GLenum internalformat) {
+ switch (internalformat) {
+ case GL_RGB565:
+ return GL_UNSIGNED_SHORT_5_6_5;
+ case GL_RGBA4:
+ return GL_UNSIGNED_SHORT_4_4_4_4;
+ case GL_RGB5_A1:
+ return GL_UNSIGNED_SHORT_5_5_5_1;
+ case GL_RGB8_OES:
+ return GL_UNSIGNED_BYTE;
+ case GL_RGBA8_OES:
+ return GL_UNSIGNED_BYTE;
+ case GL_LUMINANCE8_ALPHA8_EXT:
+ return GL_UNSIGNED_BYTE;
+ case GL_LUMINANCE8_EXT:
+ return GL_UNSIGNED_BYTE;
+ case GL_ALPHA8_EXT:
+ return GL_UNSIGNED_BYTE;
+ case GL_RGBA32F_EXT:
+ return GL_FLOAT;
+ case GL_RGB32F_EXT:
+ return GL_FLOAT;
+ case GL_ALPHA32F_EXT:
+ return GL_FLOAT;
+ case GL_LUMINANCE32F_EXT:
+ return GL_FLOAT;
+ case GL_LUMINANCE_ALPHA32F_EXT:
+ return GL_FLOAT;
+ case GL_RGBA16F_EXT:
+ return GL_HALF_FLOAT_OES;
+ case GL_RGB16F_EXT:
+ return GL_HALF_FLOAT_OES;
+ case GL_ALPHA16F_EXT:
+ return GL_HALF_FLOAT_OES;
+ case GL_LUMINANCE16F_EXT:
+ return GL_HALF_FLOAT_OES;
+ case GL_LUMINANCE_ALPHA16F_EXT:
+ return GL_HALF_FLOAT_OES;
+ case GL_BGRA8_EXT:
+ return GL_UNSIGNED_BYTE;
+ default:
+ return GL_NONE;
+ }
+}
+
+void GLES2DecoderImpl::DoTexStorage2DEXT(
+ GLenum target,
+ GLint levels,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoTexStorage2DEXT");
+ if (!texture_manager()->ValidForTarget(target, 0, width, height, 1) ||
+ TextureManager::ComputeMipMapCount(width, height, 1) < levels) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glTexStorage2DEXT", "dimensions out of range");
+ return;
+ }
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexStorage2DEXT", "unknown texture for target");
+ return;
+ }
+ Texture* texture = texture_ref->texture();
+ if (texture->IsAttachedToFramebuffer()) {
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ if (texture->IsImmutable()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTexStorage2DEXT", "texture is immutable");
+ return;
+ }
+
+ GLenum format = ExtractFormatFromStorageFormat(internal_format);
+ GLenum type = ExtractTypeFromStorageFormat(internal_format);
+
+ {
+ GLsizei level_width = width;
+ GLsizei level_height = height;
+ uint32 estimated_size = 0;
+ for (int ii = 0; ii < levels; ++ii) {
+ uint32 level_size = 0;
+ if (!GLES2Util::ComputeImageDataSizes(
+ level_width, level_height, format, type, state_.unpack_alignment,
+ &estimated_size, NULL, NULL) ||
+ !SafeAddUint32(estimated_size, level_size, &estimated_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glTexStorage2DEXT", "dimensions too large");
+ return;
+ }
+ level_width = std::max(1, level_width >> 1);
+ level_height = std::max(1, level_height >> 1);
+ }
+ if (!EnsureGPUMemoryAvailable(estimated_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glTexStorage2DEXT", "out of memory");
+ return;
+ }
+ }
+
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glTexStorage2DEXT");
+ glTexStorage2DEXT(target, levels, internal_format, width, height);
+ GLenum error = LOCAL_PEEK_GL_ERROR("glTexStorage2DEXT");
+ if (error == GL_NO_ERROR) {
+ GLsizei level_width = width;
+ GLsizei level_height = height;
+ for (int ii = 0; ii < levels; ++ii) {
+ texture_manager()->SetLevelInfo(
+ texture_ref, target, ii, format,
+ level_width, level_height, 1, 0, format, type, false);
+ level_width = std::max(1, level_width >> 1);
+ level_height = std::max(1, level_height >> 1);
+ }
+ texture->SetImmutable(true);
+ }
+}
+
+error::Error GLES2DecoderImpl::HandleGenMailboxCHROMIUM(
+ uint32 immediate_data_size, const cmds::GenMailboxCHROMIUM& c) {
+ MailboxName name;
+ mailbox_manager()->GenerateMailboxName(&name);
+ uint32 bucket_id = static_cast<uint32>(c.bucket_id);
+ Bucket* bucket = CreateBucket(bucket_id);
+
+ bucket->SetSize(GL_MAILBOX_SIZE_CHROMIUM);
+ bucket->SetData(&name, 0, GL_MAILBOX_SIZE_CHROMIUM);
+
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoProduceTextureCHROMIUM(GLenum target,
+ const GLbyte* mailbox) {
+ TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoProduceTextureCHROMIUM",
+ "context", logger_.GetLogPrefix(),
+ "mailbox[0]", static_cast<unsigned char>(mailbox[0]));
+
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glProduceTextureCHROMIUM", "unknown texture for target");
+ return;
+ }
+
+ Texture* produced = texture_manager()->Produce(texture_ref);
+ if (!produced) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glProduceTextureCHROMIUM", "invalid texture");
+ return;
+ }
+
+ if (!group_->mailbox_manager()->ProduceTexture(
+ target,
+ *reinterpret_cast<const MailboxName*>(mailbox),
+ produced)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glProduceTextureCHROMIUM", "invalid mailbox name");
+ return;
+ }
+}
+
+void GLES2DecoderImpl::DoConsumeTextureCHROMIUM(GLenum target,
+ const GLbyte* mailbox) {
+ TRACE_EVENT2("gpu", "GLES2DecoderImpl::DoConsumeTextureCHROMIUM",
+ "context", logger_.GetLogPrefix(),
+ "mailbox[0]", static_cast<unsigned char>(mailbox[0]));
+
+ scoped_refptr<TextureRef> texture_ref =
+ texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
+ if (!texture_ref.get()) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION,
+ "glConsumeTextureCHROMIUM",
+ "unknown texture for target");
+ return;
+ }
+ GLuint client_id = texture_ref->client_id();
+ if (!client_id) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glConsumeTextureCHROMIUM", "unknown texture for target");
+ return;
+ }
+ Texture* texture =
+ group_->mailbox_manager()->ConsumeTexture(
+ target,
+ *reinterpret_cast<const MailboxName*>(mailbox));
+ if (!texture) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glConsumeTextureCHROMIUM", "invalid mailbox name");
+ return;
+ }
+ if (texture->target() != target) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glConsumeTextureCHROMIUM", "invalid target");
+ return;
+ }
+
+ DeleteTexturesHelper(1, &client_id);
+ texture_ref = texture_manager()->Consume(client_id, texture);
+ glBindTexture(target, texture_ref->service_id());
+
+ TextureUnit& unit = state_.texture_units[state_.active_texture_unit];
+ unit.bind_target = target;
+ switch (target) {
+ case GL_TEXTURE_2D:
+ unit.bound_texture_2d = texture_ref;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ unit.bound_texture_cube_map = texture_ref;
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ unit.bound_texture_external_oes = texture_ref;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ unit.bound_texture_rectangle_arb = texture_ref;
+ break;
+ default:
+ NOTREACHED(); // Validation should prevent us getting here.
+ break;
+ }
+}
+
+void GLES2DecoderImpl::DoInsertEventMarkerEXT(
+ GLsizei length, const GLchar* marker) {
+ if (!marker) {
+ marker = "";
+ }
+ debug_marker_manager_.SetMarker(
+ length ? std::string(marker, length) : std::string(marker));
+}
+
+void GLES2DecoderImpl::DoPushGroupMarkerEXT(
+ GLsizei length, const GLchar* marker) {
+ if (!marker) {
+ marker = "";
+ }
+ debug_marker_manager_.PushGroup(
+ length ? std::string(marker, length) : std::string(marker));
+}
+
+void GLES2DecoderImpl::DoPopGroupMarkerEXT(void) {
+ debug_marker_manager_.PopGroup();
+}
+
+void GLES2DecoderImpl::DoBindTexImage2DCHROMIUM(
+ GLenum target, GLint image_id) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoBindTexImage2DCHROMIUM");
+ if (target != GL_TEXTURE_2D) {
+ // This might be supported in the future.
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindTexImage2DCHROMIUM", "requires TEXTURE_2D target");
+ return;
+ }
+
+ // Default target might be conceptually valid, but disallow it to avoid
+ // accidents.
+ TextureRef* texture_ref =
+ texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindTexImage2DCHROMIUM", "no texture bound");
+ return;
+ }
+
+ gfx::GLImage* gl_image = image_manager()->LookupImage(image_id);
+ if (!gl_image) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindTexImage2DCHROMIUM", "no image found with the given ID");
+ return;
+ }
+
+ {
+ ScopedGLErrorSuppressor suppressor(
+ "GLES2DecoderImpl::DoBindTexImage2DCHROMIUM", this);
+ if (!gl_image->BindTexImage()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glBindTexImage2DCHROMIUM", "fail to bind image with the given ID");
+ return;
+ }
+ }
+
+ gfx::Size size = gl_image->GetSize();
+ texture_manager()->SetLevelInfo(
+ texture_ref, target, 0, GL_RGBA, size.width(), size.height(), 1, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, true);
+ texture_manager()->SetLevelImage(texture_ref, target, 0, gl_image);
+}
+
+void GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM(
+ GLenum target, GLint image_id) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM");
+ if (target != GL_TEXTURE_2D) {
+ // This might be supported in the future.
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glReleaseTexImage2DCHROMIUM", "requires TEXTURE_2D target");
+ return;
+ }
+
+ // Default target might be conceptually valid, but disallow it to avoid
+ // accidents.
+ TextureRef* texture_ref =
+ texture_manager()->GetTextureInfoForTargetUnlessDefault(&state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glReleaseTexImage2DCHROMIUM", "no texture bound");
+ return;
+ }
+
+ gfx::GLImage* gl_image = image_manager()->LookupImage(image_id);
+ if (!gl_image) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glReleaseTexImage2DCHROMIUM", "no image found with the given ID");
+ return;
+ }
+
+ // Do nothing when image is not currently bound.
+ if (texture_ref->texture()->GetLevelImage(target, 0) != gl_image)
+ return;
+
+ {
+ ScopedGLErrorSuppressor suppressor(
+ "GLES2DecoderImpl::DoReleaseTexImage2DCHROMIUM", this);
+ gl_image->ReleaseTexImage();
+ }
+
+ texture_manager()->SetLevelInfo(
+ texture_ref, target, 0, GL_RGBA, 0, 0, 1, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, false);
+}
+
+error::Error GLES2DecoderImpl::HandleTraceBeginCHROMIUM(
+ uint32 immediate_data_size, const cmds::TraceBeginCHROMIUM& c) {
+ Bucket* bucket = GetBucket(c.bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string command_name;
+ if (!bucket->GetAsString(&command_name)) {
+ return error::kInvalidArguments;
+ }
+ TRACE_EVENT_COPY_ASYNC_BEGIN0("gpu", command_name.c_str(), this);
+ if (!gpu_tracer_->Begin(command_name)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTraceBeginCHROMIUM", "unable to create begin trace");
+ return error::kNoError;
+ }
+ return error::kNoError;
+}
+
+void GLES2DecoderImpl::DoTraceEndCHROMIUM() {
+ if (gpu_tracer_->CurrentName().empty()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glTraceEndCHROMIUM", "no trace begin found");
+ return;
+ }
+ TRACE_EVENT_COPY_ASYNC_END0("gpu", gpu_tracer_->CurrentName().c_str(), this);
+ gpu_tracer_->End();
+}
+
+void GLES2DecoderImpl::DoDrawBuffersEXT(
+ GLsizei count, const GLenum* bufs) {
+ if (count > static_cast<GLsizei>(group_->max_draw_buffers())) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE,
+ "glDrawBuffersEXT", "greater than GL_MAX_DRAW_BUFFERS_EXT");
+ return;
+ }
+
+ Framebuffer* framebuffer = GetFramebufferInfoForTarget(GL_FRAMEBUFFER);
+ if (framebuffer) {
+ for (GLsizei i = 0; i < count; ++i) {
+ if (bufs[i] != static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + i) &&
+ bufs[i] != GL_NONE) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glDrawBuffersEXT",
+ "bufs[i] not GL_NONE or GL_COLOR_ATTACHMENTi_EXT");
+ return;
+ }
+ }
+ glDrawBuffersARB(count, bufs);
+ framebuffer->SetDrawBuffers(count, bufs);
+ } else { // backbuffer
+ if (count > 1 ||
+ (bufs[0] != GL_BACK && bufs[0] != GL_NONE)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glDrawBuffersEXT",
+ "more than one buffer or bufs not GL_NONE or GL_BACK");
+ return;
+ }
+ GLenum mapped_buf = bufs[0];
+ if (GetBackbufferServiceId() != 0 && // emulated backbuffer
+ bufs[0] == GL_BACK) {
+ mapped_buf = GL_COLOR_ATTACHMENT0;
+ }
+ glDrawBuffersARB(count, &mapped_buf);
+ group_->set_draw_buffer(bufs[0]);
+ }
+}
+
+bool GLES2DecoderImpl::ValidateAsyncTransfer(
+ const char* function_name,
+ TextureRef* texture_ref,
+ GLenum target,
+ GLint level,
+ const void * data) {
+ // We only support async uploads to 2D textures for now.
+ if (GL_TEXTURE_2D != target) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM(function_name, target, "target");
+ return false;
+ }
+ // We only support uploads to level zero for now.
+ if (level != 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, function_name, "level != 0");
+ return false;
+ }
+ // A transfer buffer must be bound, even for asyncTexImage2D.
+ if (data == NULL) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, "buffer == 0");
+ return false;
+ }
+ // We only support one async transfer in progress.
+ if (!texture_ref ||
+ async_pixel_transfer_manager_->AsyncTransferIsInProgress(texture_ref)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ function_name, "transfer already in progress");
+ return false;
+ }
+ return true;
+}
+
+error::Error GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM(
+ uint32 immediate_data_size, const cmds::AsyncTexImage2DCHROMIUM& c) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexImage2DCHROMIUM");
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ // TODO(kloveless): Change HandleAsyncTexImage2DCHROMIUM command to use
+ // unsigned integer for internalformat.
+ GLenum internal_format = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLenum type = static_cast<GLenum>(c.type);
+ uint32 pixels_shm_id = static_cast<uint32>(c.pixels_shm_id);
+ uint32 pixels_shm_offset = static_cast<uint32>(c.pixels_shm_offset);
+ uint32 pixels_size;
+
+ // TODO(epenner): Move this and copies of this memory validation
+ // into ValidateTexImage2D step.
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &pixels_size, NULL,
+ NULL)) {
+ return error::kOutOfBounds;
+ }
+ const void* pixels = NULL;
+ if (pixels_shm_id != 0 || pixels_shm_offset != 0) {
+ pixels = GetSharedMemoryAs<const void*>(
+ pixels_shm_id, pixels_shm_offset, pixels_size);
+ if (!pixels) {
+ return error::kOutOfBounds;
+ }
+ }
+
+ TextureManager::DoTextImage2DArguments args = {
+ target, level, internal_format, width, height, border, format, type,
+ pixels, pixels_size};
+ TextureRef* texture_ref;
+ // All the normal glTexSubImage2D validation.
+ if (!texture_manager()->ValidateTexImage2D(
+ &state_, "glAsyncTexImage2DCHROMIUM", args, &texture_ref)) {
+ return error::kNoError;
+ }
+
+ // Extra async validation.
+ Texture* texture = texture_ref->texture();
+ if (!ValidateAsyncTransfer(
+ "glAsyncTexImage2DCHROMIUM", texture_ref, target, level, pixels))
+ return error::kNoError;
+
+ // Don't allow async redefinition of a textures.
+ if (texture->IsDefined()) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glAsyncTexImage2DCHROMIUM", "already defined");
+ return error::kNoError;
+ }
+
+ if (!EnsureGPUMemoryAvailable(pixels_size)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY, "glAsyncTexImage2DCHROMIUM", "out of memory");
+ return error::kNoError;
+ }
+
+ // We know the memory/size is safe, so get the real shared memory since
+ // it might need to be duped to prevent use-after-free of the memory.
+ gpu::Buffer buffer = GetSharedMemoryBuffer(c.pixels_shm_id);
+ base::SharedMemory* shared_memory = buffer.shared_memory;
+ uint32 shm_size = buffer.size;
+ uint32 shm_data_offset = c.pixels_shm_offset;
+ uint32 shm_data_size = pixels_size;
+
+ // Setup the parameters.
+ AsyncTexImage2DParams tex_params = {
+ target, level, static_cast<GLenum>(internal_format),
+ width, height, border, format, type};
+ AsyncMemoryParams mem_params = {
+ shared_memory, shm_size, shm_data_offset, shm_data_size};
+
+ // Set up the async state if needed, and make the texture
+ // immutable so the async state stays valid. The level info
+ // is set up lazily when the transfer completes.
+ AsyncPixelTransferDelegate* delegate =
+ async_pixel_transfer_manager_->CreatePixelTransferDelegate(texture_ref,
+ tex_params);
+ texture->SetImmutable(true);
+
+ delegate->AsyncTexImage2D(
+ tex_params,
+ mem_params,
+ base::Bind(&TextureManager::SetLevelInfoFromParams,
+ // The callback is only invoked if the transfer delegate still
+ // exists, which implies through manager->texture_ref->state
+ // ownership that both of these pointers are valid.
+ base::Unretained(texture_manager()),
+ base::Unretained(texture_ref),
+ tex_params));
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM(
+ uint32 immediate_data_size, const cmds::AsyncTexSubImage2DCHROMIUM& c) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleAsyncTexSubImage2DCHROMIUM");
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLenum type = static_cast<GLenum>(c.type);
+
+ // TODO(epenner): Move this and copies of this memory validation
+ // into ValidateTexSubImage2D step.
+ uint32 data_size;
+ if (!GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, state_.unpack_alignment, &data_size,
+ NULL, NULL)) {
+ return error::kOutOfBounds;
+ }
+ const void* pixels = GetSharedMemoryAs<const void*>(
+ c.data_shm_id, c.data_shm_offset, data_size);
+
+ // All the normal glTexSubImage2D validation.
+ error::Error error = error::kNoError;
+ if (!ValidateTexSubImage2D(&error, "glAsyncTexSubImage2DCHROMIUM",
+ target, level, xoffset, yoffset, width, height, format, type, pixels)) {
+ return error;
+ }
+
+ // Extra async validation.
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ Texture* texture = texture_ref->texture();
+ if (!ValidateAsyncTransfer(
+ "glAsyncTexSubImage2DCHROMIUM", texture_ref, target, level, pixels))
+ return error::kNoError;
+
+ // Guarantee async textures are always 'cleared' as follows:
+ // - AsyncTexImage2D can not redefine an existing texture
+ // - AsyncTexImage2D must initialize the entire image via non-null buffer.
+ // - AsyncTexSubImage2D clears synchronously if not already cleared.
+ // - Textures become immutable after an async call.
+ // This way we know in all cases that an async texture is always clear.
+ if (!texture->SafeToRenderFrom()) {
+ if (!texture_manager()->ClearTextureLevel(this, texture_ref,
+ target, level)) {
+ LOCAL_SET_GL_ERROR(
+ GL_OUT_OF_MEMORY,
+ "glAsyncTexSubImage2DCHROMIUM", "dimensions too big");
+ return error::kNoError;
+ }
+ }
+
+ // We know the memory/size is safe, so get the real shared memory since
+ // it might need to be duped to prevent use-after-free of the memory.
+ gpu::Buffer buffer = GetSharedMemoryBuffer(c.data_shm_id);
+ base::SharedMemory* shared_memory = buffer.shared_memory;
+ uint32 shm_size = buffer.size;
+ uint32 shm_data_offset = c.data_shm_offset;
+ uint32 shm_data_size = data_size;
+
+ // Setup the parameters.
+ AsyncTexSubImage2DParams tex_params = {target, level, xoffset, yoffset,
+ width, height, format, type};
+ AsyncMemoryParams mem_params = {shared_memory, shm_size,
+ shm_data_offset, shm_data_size};
+ AsyncPixelTransferDelegate* delegate =
+ async_pixel_transfer_manager_->GetPixelTransferDelegate(texture_ref);
+ if (!delegate) {
+ // TODO(epenner): We may want to enforce exclusive use
+ // of async APIs in which case this should become an error,
+ // (the texture should have been async defined).
+ AsyncTexImage2DParams define_params = {target, level,
+ 0, 0, 0, 0, 0, 0};
+ texture->GetLevelSize(target, level, &define_params.width,
+ &define_params.height);
+ texture->GetLevelType(target, level, &define_params.type,
+ &define_params.internal_format);
+ // Set up the async state if needed, and make the texture
+ // immutable so the async state stays valid.
+ delegate = async_pixel_transfer_manager_->CreatePixelTransferDelegate(
+ texture_ref, define_params);
+ texture->SetImmutable(true);
+ }
+
+ delegate->AsyncTexSubImage2D(tex_params, mem_params);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM(
+ uint32 immediate_data_size, const cmds::WaitAsyncTexImage2DCHROMIUM& c) {
+ TRACE_EVENT0("gpu", "GLES2DecoderImpl::HandleWaitAsyncTexImage2DCHROMIUM");
+ GLenum target = static_cast<GLenum>(c.target);
+
+ if (GL_TEXTURE_2D != target) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_ENUM, "glWaitAsyncTexImage2DCHROMIUM", "target");
+ return error::kNoError;
+ }
+ TextureRef* texture_ref = texture_manager()->GetTextureInfoForTarget(
+ &state_, target);
+ if (!texture_ref) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glWaitAsyncTexImage2DCHROMIUM", "unknown texture");
+ return error::kNoError;
+ }
+ AsyncPixelTransferDelegate* delegate =
+ async_pixel_transfer_manager_->GetPixelTransferDelegate(texture_ref);
+ if (!delegate) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_OPERATION,
+ "glWaitAsyncTexImage2DCHROMIUM", "No async transfer started");
+ return error::kNoError;
+ }
+ delegate->WaitForTransferCompletion();
+ ProcessFinishedAsyncTransfers();
+ return error::kNoError;
+}
+
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/service/gles2_cmd_decoder_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder.h
new file mode 100644
index 00000000000..57445c79867
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -0,0 +1,253 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the GLES2Decoder class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/logger.h"
+#include "ui/gfx/size.h"
+#include "ui/gl/gl_context.h"
+
+namespace gfx {
+class GLContext;
+class GLSurface;
+}
+
+namespace gpu {
+
+class AsyncPixelTransferDelegate;
+class AsyncPixelTransferManager;
+class StreamTextureManager;
+struct Mailbox;
+
+namespace gles2 {
+
+class ContextGroup;
+class ErrorState;
+class GLES2Util;
+class Logger;
+class QueryManager;
+class VertexArrayManager;
+
+struct DisallowedFeatures {
+ DisallowedFeatures()
+ : multisampling(false),
+ swap_buffer_complete_callback(false),
+ gpu_memory_manager(false) {
+ }
+
+ bool multisampling;
+ bool swap_buffer_complete_callback;
+ bool gpu_memory_manager;
+};
+
+typedef base::Callback<void(const std::string& key,
+ const std::string& shader)> ShaderCacheCallback;
+
+// This class implements the AsyncAPIInterface interface, decoding GLES2
+// commands and calling GL.
+class GPU_EXPORT GLES2Decoder : public base::SupportsWeakPtr<GLES2Decoder>,
+ public CommonDecoder {
+ public:
+ typedef error::Error Error;
+ typedef base::Callback<bool(uint32 id)> WaitSyncPointCallback;
+
+ // Creates a decoder.
+ static GLES2Decoder* Create(ContextGroup* group);
+
+ virtual ~GLES2Decoder();
+
+ bool initialized() const {
+ return initialized_;
+ }
+
+ void set_initialized() {
+ initialized_ = true;
+ }
+
+ bool debug() const {
+ return debug_;
+ }
+
+ // Set to true to call glGetError after every command.
+ void set_debug(bool debug) {
+ debug_ = debug;
+ }
+
+ bool log_commands() const {
+ return log_commands_;
+ }
+
+ // Set to true to LOG every command.
+ void set_log_commands(bool log_commands) {
+ log_commands_ = log_commands;
+ }
+
+ // Initializes the graphics context. Can create an offscreen
+ // decoder with a frame buffer that can be referenced from the parent.
+ // Takes ownership of GLContext.
+ // Parameters:
+ // surface: the GL surface to render to.
+ // context: the GL context to render to.
+ // offscreen: whether to make the context offscreen or not. When FBO 0 is
+ // bound, offscreen contexts render to an internal buffer, onscreen ones
+ // to the surface.
+ // size: the size if the GL context is offscreen.
+ // allowed_extensions: A string in the same format as
+ // glGetString(GL_EXTENSIONS) that lists the extensions this context
+ // should allow. Passing NULL or "*" means allow all extensions.
+ // Returns:
+ // true if successful.
+ virtual bool Initialize(const scoped_refptr<gfx::GLSurface>& surface,
+ const scoped_refptr<gfx::GLContext>& context,
+ bool offscreen,
+ const gfx::Size& size,
+ const DisallowedFeatures& disallowed_features,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs) = 0;
+
+ // Destroys the graphics context.
+ virtual void Destroy(bool have_context) = 0;
+
+ // Set the surface associated with the default FBO.
+ virtual void SetSurface(const scoped_refptr<gfx::GLSurface>& surface) = 0;
+
+ virtual bool ProduceFrontBuffer(const Mailbox& mailbox) = 0;
+
+ // Resize an offscreen frame buffer.
+ virtual bool ResizeOffscreenFrameBuffer(const gfx::Size& size) = 0;
+
+ // Make this decoder's GL context current.
+ virtual bool MakeCurrent() = 0;
+
+ // Have the decoder release the context.
+ virtual void ReleaseCurrent() = 0;
+
+ // Gets the GLES2 Util which holds info.
+ virtual GLES2Util* GetGLES2Util() = 0;
+
+ // Gets the associated GLContext.
+ virtual gfx::GLContext* GetGLContext() = 0;
+
+ // Gets the associated ContextGroup
+ virtual ContextGroup* GetContextGroup() = 0;
+
+ // Restores all of the decoder GL state.
+ virtual void RestoreState() const = 0;
+
+ // Restore States.
+ virtual void RestoreActiveTexture() const = 0;
+ virtual void RestoreAllTextureUnitBindings() const = 0;
+ virtual void RestoreAttribute(unsigned index) const = 0;
+ virtual void RestoreBufferBindings() const = 0;
+ virtual void RestoreFramebufferBindings() const = 0;
+ virtual void RestoreGlobalState() const = 0;
+ virtual void RestoreProgramBindings() const = 0;
+ virtual void RestoreRenderbufferBindings() const = 0;
+ virtual void RestoreTextureState(unsigned service_id) const = 0;
+ virtual void RestoreTextureUnitBindings(unsigned unit) const = 0;
+
+ // Gets the QueryManager for this context.
+ virtual QueryManager* GetQueryManager() = 0;
+
+ // Gets the VertexArrayManager for this context.
+ virtual VertexArrayManager* GetVertexArrayManager() = 0;
+
+ // Process any pending queries. Returns false if there are no pending queries.
+ virtual bool ProcessPendingQueries() = 0;
+
+ // Returns false if there are no idle work to be made.
+ virtual bool HasMoreIdleWork() = 0;
+
+ virtual void PerformIdleWork() = 0;
+
+ // Sets a callback which is called when a glResizeCHROMIUM command
+ // is processed.
+ virtual void SetResizeCallback(
+ const base::Callback<void(gfx::Size, float)>& callback) = 0;
+
+ // Interface to performing async pixel transfers.
+ virtual AsyncPixelTransferManager* GetAsyncPixelTransferManager() = 0;
+ virtual void ResetAsyncPixelTransferManagerForTest() = 0;
+ virtual void SetAsyncPixelTransferManagerForTest(
+ AsyncPixelTransferManager* manager) = 0;
+
+ // Get the service texture ID corresponding to a client texture ID.
+ // If no such record is found then return false.
+ virtual bool GetServiceTextureId(uint32 client_texture_id,
+ uint32* service_texture_id);
+
+ // Provides detail about a lost context if one occurred.
+ virtual error::ContextLostReason GetContextLostReason() = 0;
+
+ // Clears a level of a texture
+ // Returns false if a GL error should be generated.
+ virtual bool ClearLevel(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height,
+ bool is_texture_immutable) = 0;
+
+ virtual ErrorState* GetErrorState() = 0;
+
+ // A callback for messages from the decoder.
+ virtual void SetShaderCacheCallback(const ShaderCacheCallback& callback) = 0;
+
+ // Sets the callback for waiting on a sync point. The callback returns the
+ // scheduling status (i.e. true if the channel is still scheduled).
+ virtual void SetWaitSyncPointCallback(
+ const WaitSyncPointCallback& callback) = 0;
+
+ virtual void WaitForReadPixels(base::Closure callback) = 0;
+ virtual uint32 GetTextureUploadCount() = 0;
+ virtual base::TimeDelta GetTotalTextureUploadTime() = 0;
+ virtual base::TimeDelta GetTotalProcessingCommandsTime() = 0;
+ virtual void AddProcessingCommandsTime(base::TimeDelta) = 0;
+
+ // Returns true if the context was lost either by GL_ARB_robustness, forced
+ // context loss or command buffer parse error.
+ virtual bool WasContextLost() = 0;
+
+ // Returns true if the context was lost specifically by GL_ARB_robustness.
+ virtual bool WasContextLostByRobustnessExtension() = 0;
+
+ // Lose this context.
+ virtual void LoseContext(uint32 reset_status) = 0;
+
+ static bool IsAngle();
+
+ // Used for testing only
+ static void set_testing_force_is_angle(bool force);
+
+ virtual Logger* GetLogger() = 0;
+
+ protected:
+ GLES2Decoder();
+
+ private:
+ bool initialized_;
+ bool debug_;
+ bool log_commands_;
+ static bool testing_force_is_angle_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLES2Decoder);
+};
+
+} // namespace gles2
+} // namespace gpu
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_H_
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
new file mode 100644
index 00000000000..393c90292c8
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -0,0 +1,3368 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by gles2_cmd_decoder.cc
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_AUTOGEN_H_
+
+error::Error GLES2DecoderImpl::HandleActiveTexture(
+ uint32 immediate_data_size, const gles2::cmds::ActiveTexture& c) {
+ GLenum texture = static_cast<GLenum>(c.texture);
+ DoActiveTexture(texture);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleAttachShader(
+ uint32 immediate_data_size, const gles2::cmds::AttachShader& c) {
+ GLuint program = c.program;
+ GLuint shader = c.shader;
+ DoAttachShader(program, shader);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindBuffer(
+ uint32 immediate_data_size, const gles2::cmds::BindBuffer& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint buffer = c.buffer;
+ if (!validators_->buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindBuffer", target, "target");
+ return error::kNoError;
+ }
+ DoBindBuffer(target, buffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindFramebuffer(
+ uint32 immediate_data_size, const gles2::cmds::BindFramebuffer& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint framebuffer = c.framebuffer;
+ if (!validators_->frame_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindFramebuffer", target, "target");
+ return error::kNoError;
+ }
+ DoBindFramebuffer(target, framebuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindRenderbuffer(
+ uint32 immediate_data_size, const gles2::cmds::BindRenderbuffer& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint renderbuffer = c.renderbuffer;
+ if (!validators_->render_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindRenderbuffer", target, "target");
+ return error::kNoError;
+ }
+ DoBindRenderbuffer(target, renderbuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindTexture(
+ uint32 immediate_data_size, const gles2::cmds::BindTexture& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint texture = c.texture;
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindTexture", target, "target");
+ return error::kNoError;
+ }
+ DoBindTexture(target, texture);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBlendColor(
+ uint32 immediate_data_size, const gles2::cmds::BlendColor& c) {
+ GLclampf red = static_cast<GLclampf>(c.red);
+ GLclampf green = static_cast<GLclampf>(c.green);
+ GLclampf blue = static_cast<GLclampf>(c.blue);
+ GLclampf alpha = static_cast<GLclampf>(c.alpha);
+ if (state_.blend_color_red != red ||
+ state_.blend_color_green != green ||
+ state_.blend_color_blue != blue ||
+ state_.blend_color_alpha != alpha) {
+ state_.blend_color_red = red;
+ state_.blend_color_green = green;
+ state_.blend_color_blue = blue;
+ state_.blend_color_alpha = alpha;
+ glBlendColor(red, green, blue, alpha);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBlendEquation(
+ uint32 immediate_data_size, const gles2::cmds::BlendEquation& c) {
+ GLenum mode = static_cast<GLenum>(c.mode);
+ if (!validators_->equation.IsValid(mode)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendEquation", mode, "mode");
+ return error::kNoError;
+ }
+ if (state_.blend_equation_rgb != mode ||
+ state_.blend_equation_alpha != mode) {
+ state_.blend_equation_rgb = mode;
+ state_.blend_equation_alpha = mode;
+ glBlendEquation(mode);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBlendEquationSeparate(
+ uint32 immediate_data_size, const gles2::cmds::BlendEquationSeparate& c) {
+ GLenum modeRGB = static_cast<GLenum>(c.modeRGB);
+ GLenum modeAlpha = static_cast<GLenum>(c.modeAlpha);
+ if (!validators_->equation.IsValid(modeRGB)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendEquationSeparate", modeRGB,
+ "modeRGB");
+ return error::kNoError;
+ }
+ if (!validators_->equation.IsValid(modeAlpha)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendEquationSeparate", modeAlpha,
+ "modeAlpha");
+ return error::kNoError;
+ }
+ if (state_.blend_equation_rgb != modeRGB ||
+ state_.blend_equation_alpha != modeAlpha) {
+ state_.blend_equation_rgb = modeRGB;
+ state_.blend_equation_alpha = modeAlpha;
+ glBlendEquationSeparate(modeRGB, modeAlpha);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBlendFunc(
+ uint32 immediate_data_size, const gles2::cmds::BlendFunc& c) {
+ GLenum sfactor = static_cast<GLenum>(c.sfactor);
+ GLenum dfactor = static_cast<GLenum>(c.dfactor);
+ if (!validators_->src_blend_factor.IsValid(sfactor)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendFunc", sfactor, "sfactor");
+ return error::kNoError;
+ }
+ if (!validators_->dst_blend_factor.IsValid(dfactor)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendFunc", dfactor, "dfactor");
+ return error::kNoError;
+ }
+ if (state_.blend_source_rgb != sfactor ||
+ state_.blend_dest_rgb != dfactor ||
+ state_.blend_source_alpha != sfactor ||
+ state_.blend_dest_alpha != dfactor) {
+ state_.blend_source_rgb = sfactor;
+ state_.blend_dest_rgb = dfactor;
+ state_.blend_source_alpha = sfactor;
+ state_.blend_dest_alpha = dfactor;
+ glBlendFunc(sfactor, dfactor);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBlendFuncSeparate(
+ uint32 immediate_data_size, const gles2::cmds::BlendFuncSeparate& c) {
+ GLenum srcRGB = static_cast<GLenum>(c.srcRGB);
+ GLenum dstRGB = static_cast<GLenum>(c.dstRGB);
+ GLenum srcAlpha = static_cast<GLenum>(c.srcAlpha);
+ GLenum dstAlpha = static_cast<GLenum>(c.dstAlpha);
+ if (!validators_->src_blend_factor.IsValid(srcRGB)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendFuncSeparate", srcRGB, "srcRGB");
+ return error::kNoError;
+ }
+ if (!validators_->dst_blend_factor.IsValid(dstRGB)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendFuncSeparate", dstRGB, "dstRGB");
+ return error::kNoError;
+ }
+ if (!validators_->src_blend_factor.IsValid(srcAlpha)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendFuncSeparate", srcAlpha,
+ "srcAlpha");
+ return error::kNoError;
+ }
+ if (!validators_->dst_blend_factor.IsValid(dstAlpha)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlendFuncSeparate", dstAlpha,
+ "dstAlpha");
+ return error::kNoError;
+ }
+ if (state_.blend_source_rgb != srcRGB ||
+ state_.blend_dest_rgb != dstRGB ||
+ state_.blend_source_alpha != srcAlpha ||
+ state_.blend_dest_alpha != dstAlpha) {
+ state_.blend_source_rgb = srcRGB;
+ state_.blend_dest_rgb = dstRGB;
+ state_.blend_source_alpha = srcAlpha;
+ state_.blend_dest_alpha = dstAlpha;
+ glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBufferSubData(
+ uint32 immediate_data_size, const gles2::cmds::BufferSubData& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLintptr offset = static_cast<GLintptr>(c.offset);
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
+ uint32 data_size = size;
+ const void* data = GetSharedMemoryAs<const void*>(
+ c.data_shm_id, c.data_shm_offset, data_size);
+ if (!validators_->buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBufferSubData", target, "target");
+ return error::kNoError;
+ }
+ if (size < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
+ return error::kNoError;
+ }
+ if (data == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoBufferSubData(target, offset, size, data);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBufferSubDataImmediate(
+ uint32 immediate_data_size, const gles2::cmds::BufferSubDataImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLintptr offset = static_cast<GLintptr>(c.offset);
+ GLsizeiptr size = static_cast<GLsizeiptr>(c.size);
+ uint32 data_size = size;
+ const void* data = GetImmediateDataAs<const void*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBufferSubData", target, "target");
+ return error::kNoError;
+ }
+ if (size < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glBufferSubData", "size < 0");
+ return error::kNoError;
+ }
+ if (data == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoBufferSubData(target, offset, size, data);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCheckFramebufferStatus(
+ uint32 immediate_data_size, const gles2::cmds::CheckFramebufferStatus& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ typedef cmds::CheckFramebufferStatus::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ if (!validators_->frame_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCheckFramebufferStatus", target,
+ "target");
+ return error::kNoError;
+ }
+ *result_dst = DoCheckFramebufferStatus(target);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleClear(
+ uint32 immediate_data_size, const gles2::cmds::Clear& c) {
+ if (ShouldDeferDraws())
+ return error::kDeferCommandUntilLater;
+ GLbitfield mask = static_cast<GLbitfield>(c.mask);
+ DoClear(mask);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleClearColor(
+ uint32 immediate_data_size, const gles2::cmds::ClearColor& c) {
+ GLclampf red = static_cast<GLclampf>(c.red);
+ GLclampf green = static_cast<GLclampf>(c.green);
+ GLclampf blue = static_cast<GLclampf>(c.blue);
+ GLclampf alpha = static_cast<GLclampf>(c.alpha);
+ if (state_.color_clear_red != red ||
+ state_.color_clear_green != green ||
+ state_.color_clear_blue != blue ||
+ state_.color_clear_alpha != alpha) {
+ state_.color_clear_red = red;
+ state_.color_clear_green = green;
+ state_.color_clear_blue = blue;
+ state_.color_clear_alpha = alpha;
+ glClearColor(red, green, blue, alpha);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleClearDepthf(
+ uint32 immediate_data_size, const gles2::cmds::ClearDepthf& c) {
+ GLclampf depth = static_cast<GLclampf>(c.depth);
+ if (state_.depth_clear != depth) {
+ state_.depth_clear = depth;
+ glClearDepth(depth);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleClearStencil(
+ uint32 immediate_data_size, const gles2::cmds::ClearStencil& c) {
+ GLint s = static_cast<GLint>(c.s);
+ if (state_.stencil_clear != s) {
+ state_.stencil_clear = s;
+ glClearStencil(s);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleColorMask(
+ uint32 immediate_data_size, const gles2::cmds::ColorMask& c) {
+ GLboolean red = static_cast<GLboolean>(c.red);
+ GLboolean green = static_cast<GLboolean>(c.green);
+ GLboolean blue = static_cast<GLboolean>(c.blue);
+ GLboolean alpha = static_cast<GLboolean>(c.alpha);
+ if (state_.color_mask_red != red ||
+ state_.color_mask_green != green ||
+ state_.color_mask_blue != blue ||
+ state_.color_mask_alpha != alpha) {
+ state_.color_mask_red = red;
+ state_.color_mask_green = green;
+ state_.color_mask_blue = blue;
+ state_.color_mask_alpha = alpha;
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCompileShader(
+ uint32 immediate_data_size, const gles2::cmds::CompileShader& c) {
+ GLuint shader = c.shader;
+ DoCompileShader(shader);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCompressedTexSubImage2D(
+ uint32 immediate_data_size,
+ const gles2::cmds::CompressedTexSubImage2D& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLsizei imageSize = static_cast<GLsizei>(c.imageSize);
+ uint32 data_size = imageSize;
+ const void* data = GetSharedMemoryAs<const void*>(
+ c.data_shm_id, c.data_shm_offset, data_size);
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCompressedTexSubImage2D", target,
+ "target");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "height < 0");
+ return error::kNoError;
+ }
+ if (!validators_->compressed_texture_format.IsValid(format)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCompressedTexSubImage2D", format,
+ "format");
+ return error::kNoError;
+ }
+ if (imageSize < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "imageSize < 0");
+ return error::kNoError;
+ }
+ if (data == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoCompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCompressedTexSubImage2DImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::CompressedTexSubImage2DImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLenum format = static_cast<GLenum>(c.format);
+ GLsizei imageSize = static_cast<GLsizei>(c.imageSize);
+ uint32 data_size = imageSize;
+ const void* data = GetImmediateDataAs<const void*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCompressedTexSubImage2D", target,
+ "target");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "height < 0");
+ return error::kNoError;
+ }
+ if (!validators_->compressed_texture_format.IsValid(format)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCompressedTexSubImage2D", format,
+ "format");
+ return error::kNoError;
+ }
+ if (imageSize < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCompressedTexSubImage2D", "imageSize < 0");
+ return error::kNoError;
+ }
+ if (data == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoCompressedTexSubImage2D(
+ target, level, xoffset, yoffset, width, height, format, imageSize, data);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCopyTexImage2D(
+ uint32 immediate_data_size, const gles2::cmds::CopyTexImage2D& c) {
+ if (ShouldDeferReads())
+ return error::kDeferCommandUntilLater;
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLenum internalformat = static_cast<GLenum>(c.internalformat);
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLint border = static_cast<GLint>(c.border);
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCopyTexImage2D", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_internal_format.IsValid(internalformat)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCopyTexImage2D", internalformat,
+ "internalformat");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyTexImage2D", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyTexImage2D", "height < 0");
+ return error::kNoError;
+ }
+ if (!validators_->texture_border.IsValid(border)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTexImage2D", "border GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ DoCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCopyTexSubImage2D(
+ uint32 immediate_data_size, const gles2::cmds::CopyTexSubImage2D& c) {
+ if (ShouldDeferReads())
+ return error::kDeferCommandUntilLater;
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint level = static_cast<GLint>(c.level);
+ GLint xoffset = static_cast<GLint>(c.xoffset);
+ GLint yoffset = static_cast<GLint>(c.yoffset);
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCopyTexSubImage2D", target, "target");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyTexSubImage2D", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glCopyTexSubImage2D", "height < 0");
+ return error::kNoError;
+ }
+ DoCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCreateProgram(
+ uint32 immediate_data_size, const gles2::cmds::CreateProgram& c) {
+ uint32 client_id = c.client_id;
+ if (!CreateProgramHelper(client_id)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCreateShader(
+ uint32 immediate_data_size, const gles2::cmds::CreateShader& c) {
+ GLenum type = static_cast<GLenum>(c.type);
+ if (!validators_->shader_type.IsValid(type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCreateShader", type, "type");
+ return error::kNoError;
+ }
+ uint32 client_id = c.client_id;
+ if (!CreateShaderHelper(type, client_id)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCullFace(
+ uint32 immediate_data_size, const gles2::cmds::CullFace& c) {
+ GLenum mode = static_cast<GLenum>(c.mode);
+ if (!validators_->face_type.IsValid(mode)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCullFace", mode, "mode");
+ return error::kNoError;
+ }
+ if (state_.cull_mode != mode) {
+ state_.cull_mode = mode;
+ glCullFace(mode);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteBuffers(
+ uint32 immediate_data_size, const gles2::cmds::DeleteBuffers& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* buffers = GetSharedMemoryAs<const GLuint*>(
+ c.buffers_shm_id, c.buffers_shm_offset, data_size);
+ if (buffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteBuffersHelper(n, buffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteBuffersImmediate(
+ uint32 immediate_data_size, const gles2::cmds::DeleteBuffersImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* buffers = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (buffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteBuffersHelper(n, buffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteFramebuffers(
+ uint32 immediate_data_size, const gles2::cmds::DeleteFramebuffers& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* framebuffers = GetSharedMemoryAs<const GLuint*>(
+ c.framebuffers_shm_id, c.framebuffers_shm_offset, data_size);
+ if (framebuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteFramebuffersHelper(n, framebuffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteFramebuffersImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DeleteFramebuffersImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* framebuffers = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (framebuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteFramebuffersHelper(n, framebuffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteRenderbuffers(
+ uint32 immediate_data_size, const gles2::cmds::DeleteRenderbuffers& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* renderbuffers = GetSharedMemoryAs<const GLuint*>(
+ c.renderbuffers_shm_id, c.renderbuffers_shm_offset, data_size);
+ if (renderbuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteRenderbuffersHelper(n, renderbuffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteRenderbuffersImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DeleteRenderbuffersImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* renderbuffers = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (renderbuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteRenderbuffersHelper(n, renderbuffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteTextures(
+ uint32 immediate_data_size, const gles2::cmds::DeleteTextures& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* textures = GetSharedMemoryAs<const GLuint*>(
+ c.textures_shm_id, c.textures_shm_offset, data_size);
+ if (textures == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteTexturesHelper(n, textures);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteTexturesImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DeleteTexturesImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* textures = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (textures == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteTexturesHelper(n, textures);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDepthFunc(
+ uint32 immediate_data_size, const gles2::cmds::DepthFunc& c) {
+ GLenum func = static_cast<GLenum>(c.func);
+ if (!validators_->cmp_function.IsValid(func)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glDepthFunc", func, "func");
+ return error::kNoError;
+ }
+ if (state_.depth_func != func) {
+ state_.depth_func = func;
+ glDepthFunc(func);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDepthMask(
+ uint32 immediate_data_size, const gles2::cmds::DepthMask& c) {
+ GLboolean flag = static_cast<GLboolean>(c.flag);
+ if (state_.depth_mask != flag) {
+ state_.depth_mask = flag;
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDepthRangef(
+ uint32 immediate_data_size, const gles2::cmds::DepthRangef& c) {
+ GLclampf zNear = static_cast<GLclampf>(c.zNear);
+ GLclampf zFar = static_cast<GLclampf>(c.zFar);
+ DoDepthRangef(zNear, zFar);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDetachShader(
+ uint32 immediate_data_size, const gles2::cmds::DetachShader& c) {
+ GLuint program = c.program;
+ GLuint shader = c.shader;
+ DoDetachShader(program, shader);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDisable(
+ uint32 immediate_data_size, const gles2::cmds::Disable& c) {
+ GLenum cap = static_cast<GLenum>(c.cap);
+ if (!validators_->capability.IsValid(cap)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glDisable", cap, "cap");
+ return error::kNoError;
+ }
+ DoDisable(cap);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDisableVertexAttribArray(
+ uint32 immediate_data_size,
+ const gles2::cmds::DisableVertexAttribArray& c) {
+ GLuint index = static_cast<GLuint>(c.index);
+ DoDisableVertexAttribArray(index);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleEnable(
+ uint32 immediate_data_size, const gles2::cmds::Enable& c) {
+ GLenum cap = static_cast<GLenum>(c.cap);
+ if (!validators_->capability.IsValid(cap)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glEnable", cap, "cap");
+ return error::kNoError;
+ }
+ DoEnable(cap);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleEnableVertexAttribArray(
+ uint32 immediate_data_size,
+ const gles2::cmds::EnableVertexAttribArray& c) {
+ GLuint index = static_cast<GLuint>(c.index);
+ DoEnableVertexAttribArray(index);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleFinish(
+ uint32 immediate_data_size, const gles2::cmds::Finish& c) {
+ if (ShouldDeferReads())
+ return error::kDeferCommandUntilLater;
+ DoFinish();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleFlush(
+ uint32 immediate_data_size, const gles2::cmds::Flush& c) {
+ DoFlush();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleFramebufferRenderbuffer(
+ uint32 immediate_data_size,
+ const gles2::cmds::FramebufferRenderbuffer& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum attachment = static_cast<GLenum>(c.attachment);
+ GLenum renderbuffertarget = static_cast<GLenum>(c.renderbuffertarget);
+ GLuint renderbuffer = c.renderbuffer;
+ if (!validators_->frame_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferRenderbuffer", target,
+ "target");
+ return error::kNoError;
+ }
+ if (!validators_->attachment.IsValid(attachment)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferRenderbuffer", attachment,
+ "attachment");
+ return error::kNoError;
+ }
+ if (!validators_->render_buffer_target.IsValid(renderbuffertarget)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferRenderbuffer", renderbuffertarget, "renderbuffertarget"); // NOLINT
+ return error::kNoError;
+ }
+ DoFramebufferRenderbuffer(
+ target, attachment, renderbuffertarget, renderbuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleFramebufferTexture2D(
+ uint32 immediate_data_size, const gles2::cmds::FramebufferTexture2D& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum attachment = static_cast<GLenum>(c.attachment);
+ GLenum textarget = static_cast<GLenum>(c.textarget);
+ GLuint texture = c.texture;
+ GLint level = static_cast<GLint>(c.level);
+ if (!validators_->frame_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferTexture2D", target,
+ "target");
+ return error::kNoError;
+ }
+ if (!validators_->attachment.IsValid(attachment)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferTexture2D", attachment,
+ "attachment");
+ return error::kNoError;
+ }
+ if (!validators_->texture_target.IsValid(textarget)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferTexture2D", textarget,
+ "textarget");
+ return error::kNoError;
+ }
+ if (!validators_->zero_only.IsValid(level)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glFramebufferTexture2D", "level GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ DoFramebufferTexture2D(target, attachment, textarget, texture, level);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleFrontFace(
+ uint32 immediate_data_size, const gles2::cmds::FrontFace& c) {
+ GLenum mode = static_cast<GLenum>(c.mode);
+ if (!validators_->face_mode.IsValid(mode)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFrontFace", mode, "mode");
+ return error::kNoError;
+ }
+ if (state_.front_face != mode) {
+ state_.front_face = mode;
+ glFrontFace(mode);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenBuffers(
+ uint32 immediate_data_size, const gles2::cmds::GenBuffers& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* buffers = GetSharedMemoryAs<GLuint*>(
+ c.buffers_shm_id, c.buffers_shm_offset, data_size);
+ if (buffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenBuffersHelper(n, buffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenBuffersImmediate(
+ uint32 immediate_data_size, const gles2::cmds::GenBuffersImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* buffers = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (buffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenBuffersHelper(n, buffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenerateMipmap(
+ uint32 immediate_data_size, const gles2::cmds::GenerateMipmap& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGenerateMipmap", target, "target");
+ return error::kNoError;
+ }
+ DoGenerateMipmap(target);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenFramebuffers(
+ uint32 immediate_data_size, const gles2::cmds::GenFramebuffers& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* framebuffers = GetSharedMemoryAs<GLuint*>(
+ c.framebuffers_shm_id, c.framebuffers_shm_offset, data_size);
+ if (framebuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenFramebuffersHelper(n, framebuffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenFramebuffersImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::GenFramebuffersImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* framebuffers = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (framebuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenFramebuffersHelper(n, framebuffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenRenderbuffers(
+ uint32 immediate_data_size, const gles2::cmds::GenRenderbuffers& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* renderbuffers = GetSharedMemoryAs<GLuint*>(
+ c.renderbuffers_shm_id, c.renderbuffers_shm_offset, data_size);
+ if (renderbuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenRenderbuffersHelper(n, renderbuffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenRenderbuffersImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::GenRenderbuffersImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* renderbuffers = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (renderbuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenRenderbuffersHelper(n, renderbuffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenTextures(
+ uint32 immediate_data_size, const gles2::cmds::GenTextures& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* textures = GetSharedMemoryAs<GLuint*>(
+ c.textures_shm_id, c.textures_shm_offset, data_size);
+ if (textures == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenTexturesHelper(n, textures)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenTexturesImmediate(
+ uint32 immediate_data_size, const gles2::cmds::GenTexturesImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* textures = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (textures == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenTexturesHelper(n, textures)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetBooleanv(
+ uint32 immediate_data_size, const gles2::cmds::GetBooleanv& c) {
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetBooleanv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLboolean* params = result ? result->GetData() : NULL;
+ if (!validators_->g_l_state.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetBooleanv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetBooleanv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetBooleanv(pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetBooleanv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetBufferParameteriv(
+ uint32 immediate_data_size, const gles2::cmds::GetBufferParameteriv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetBufferParameteriv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetBufferParameteriv", target,
+ "target");
+ return error::kNoError;
+ }
+ if (!validators_->buffer_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetBufferParameteriv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetBufferParameteriv(target, pname, params);
+ result->SetNumResults(num_values);
+ return error::kNoError;
+}
+error::Error GLES2DecoderImpl::HandleGetError(
+ uint32 immediate_data_size, const gles2::cmds::GetError& c) {
+ typedef cmds::GetError::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = GetErrorState()->GetGLError();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetFloatv(
+ uint32 immediate_data_size, const gles2::cmds::GetFloatv& c) {
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetFloatv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLfloat* params = result ? result->GetData() : NULL;
+ if (!validators_->g_l_state.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetFloatv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetFloatv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetFloatv(pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetFloatv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetFramebufferAttachmentParameteriv(
+ uint32 immediate_data_size,
+ const gles2::cmds::GetFramebufferAttachmentParameteriv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum attachment = static_cast<GLenum>(c.attachment);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetFramebufferAttachmentParameteriv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->frame_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetFramebufferAttachmentParameteriv", target, "target"); // NOLINT
+ return error::kNoError;
+ }
+ if (!validators_->attachment.IsValid(attachment)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetFramebufferAttachmentParameteriv", attachment, "attachment"); // NOLINT
+ return error::kNoError;
+ }
+ if (!validators_->frame_buffer_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetFramebufferAttachmentParameteriv", pname, "pname"); // NOLINT
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetFramebufferAttachmentParameteriv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetFramebufferAttachmentParameteriv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetIntegerv(
+ uint32 immediate_data_size, const gles2::cmds::GetIntegerv& c) {
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetIntegerv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->g_l_state.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetIntegerv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetIntegerv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetIntegerv(pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetIntegerv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetProgramiv(
+ uint32 immediate_data_size, const gles2::cmds::GetProgramiv& c) {
+ GLuint program = c.program;
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetProgramiv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->program_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetProgramiv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetProgramiv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetProgramiv(program, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetProgramiv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetRenderbufferParameteriv(
+ uint32 immediate_data_size,
+ const gles2::cmds::GetRenderbufferParameteriv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetRenderbufferParameteriv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->render_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetRenderbufferParameteriv", target,
+ "target");
+ return error::kNoError;
+ }
+ if (!validators_->render_buffer_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetRenderbufferParameteriv", pname,
+ "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetRenderbufferParameteriv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetRenderbufferParameteriv(target, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetRenderbufferParameteriv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetShaderiv(
+ uint32 immediate_data_size, const gles2::cmds::GetShaderiv& c) {
+ GLuint shader = c.shader;
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetShaderiv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->shader_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetShaderiv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetShaderiv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetShaderiv(shader, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetShaderiv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetTexParameterfv(
+ uint32 immediate_data_size, const gles2::cmds::GetTexParameterfv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetTexParameterfv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLfloat* params = result ? result->GetData() : NULL;
+ if (!validators_->get_tex_param_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetTexParameterfv", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetTexParameterfv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetTexParameterfv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ glGetTexParameterfv(target, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetTexParameterfv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetTexParameteriv(
+ uint32 immediate_data_size, const gles2::cmds::GetTexParameteriv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetTexParameteriv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->get_tex_param_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetTexParameteriv", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetTexParameteriv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetTexParameteriv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ glGetTexParameteriv(target, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetTexParameteriv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetVertexAttribfv(
+ uint32 immediate_data_size, const gles2::cmds::GetVertexAttribfv& c) {
+ GLuint index = static_cast<GLuint>(c.index);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetVertexAttribfv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLfloat* params = result ? result->GetData() : NULL;
+ if (!validators_->vertex_attribute.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetVertexAttribfv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetVertexAttribfv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetVertexAttribfv(index, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetVertexAttribfv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetVertexAttribiv(
+ uint32 immediate_data_size, const gles2::cmds::GetVertexAttribiv& c) {
+ GLuint index = static_cast<GLuint>(c.index);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ typedef cmds::GetVertexAttribiv::Result Result;
+ GLsizei num_values = 0;
+ GetNumValuesReturnedForGLGet(pname, &num_values);
+ Result* result = GetSharedMemoryAs<Result*>(
+ c.params_shm_id, c.params_shm_offset, Result::ComputeSize(num_values));
+ GLint* params = result ? result->GetData() : NULL;
+ if (!validators_->vertex_attribute.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetVertexAttribiv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("GetVertexAttribiv");
+ // Check that the client initialized the result.
+ if (result->size != 0) {
+ return error::kInvalidArguments;
+ }
+ DoGetVertexAttribiv(index, pname, params);
+ GLenum error = glGetError();
+ if (error == GL_NO_ERROR) {
+ result->SetNumResults(num_values);
+ } else {
+ LOCAL_SET_GL_ERROR(error, "GetVertexAttribiv", "");
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleHint(
+ uint32 immediate_data_size, const gles2::cmds::Hint& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum mode = static_cast<GLenum>(c.mode);
+ if (!validators_->hint_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glHint", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->hint_mode.IsValid(mode)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glHint", mode, "mode");
+ return error::kNoError;
+ }
+ switch (target) {
+ case GL_GENERATE_MIPMAP_HINT:
+ if (state_.hint_generate_mipmap != mode) {
+ state_.hint_generate_mipmap = mode;
+ glHint(target, mode);
+ }
+ break;
+ case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
+ if (state_.hint_fragment_shader_derivative != mode) {
+ state_.hint_fragment_shader_derivative = mode;
+ glHint(target, mode);
+ }
+ break;
+ default:
+ NOTREACHED();
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsBuffer(
+ uint32 immediate_data_size, const gles2::cmds::IsBuffer& c) {
+ GLuint buffer = c.buffer;
+ typedef cmds::IsBuffer::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsBuffer(buffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsEnabled(
+ uint32 immediate_data_size, const gles2::cmds::IsEnabled& c) {
+ GLenum cap = static_cast<GLenum>(c.cap);
+ typedef cmds::IsEnabled::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ if (!validators_->capability.IsValid(cap)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glIsEnabled", cap, "cap");
+ return error::kNoError;
+ }
+ *result_dst = DoIsEnabled(cap);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsFramebuffer(
+ uint32 immediate_data_size, const gles2::cmds::IsFramebuffer& c) {
+ GLuint framebuffer = c.framebuffer;
+ typedef cmds::IsFramebuffer::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsFramebuffer(framebuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsProgram(
+ uint32 immediate_data_size, const gles2::cmds::IsProgram& c) {
+ GLuint program = c.program;
+ typedef cmds::IsProgram::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsProgram(program);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsRenderbuffer(
+ uint32 immediate_data_size, const gles2::cmds::IsRenderbuffer& c) {
+ GLuint renderbuffer = c.renderbuffer;
+ typedef cmds::IsRenderbuffer::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsRenderbuffer(renderbuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsShader(
+ uint32 immediate_data_size, const gles2::cmds::IsShader& c) {
+ GLuint shader = c.shader;
+ typedef cmds::IsShader::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsShader(shader);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsTexture(
+ uint32 immediate_data_size, const gles2::cmds::IsTexture& c) {
+ GLuint texture = c.texture;
+ typedef cmds::IsTexture::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsTexture(texture);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleLineWidth(
+ uint32 immediate_data_size, const gles2::cmds::LineWidth& c) {
+ GLfloat width = static_cast<GLfloat>(c.width);
+ if (width <= 0.0f) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "LineWidth", "width out of range");
+ return error::kNoError;
+ }
+ if (state_.line_width != width) {
+ state_.line_width = width;
+ glLineWidth(width);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleLinkProgram(
+ uint32 immediate_data_size, const gles2::cmds::LinkProgram& c) {
+ GLuint program = c.program;
+ DoLinkProgram(program);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePolygonOffset(
+ uint32 immediate_data_size, const gles2::cmds::PolygonOffset& c) {
+ GLfloat factor = static_cast<GLfloat>(c.factor);
+ GLfloat units = static_cast<GLfloat>(c.units);
+ if (state_.polygon_offset_factor != factor ||
+ state_.polygon_offset_units != units) {
+ state_.polygon_offset_factor = factor;
+ state_.polygon_offset_units = units;
+ glPolygonOffset(factor, units);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleReleaseShaderCompiler(
+ uint32 immediate_data_size, const gles2::cmds::ReleaseShaderCompiler& c) {
+ DoReleaseShaderCompiler();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleRenderbufferStorage(
+ uint32 immediate_data_size, const gles2::cmds::RenderbufferStorage& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum internalformat = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ if (!validators_->render_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glRenderbufferStorage", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->render_buffer_format.IsValid(internalformat)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glRenderbufferStorage", internalformat,
+ "internalformat");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glRenderbufferStorage", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glRenderbufferStorage", "height < 0");
+ return error::kNoError;
+ }
+ DoRenderbufferStorage(target, internalformat, width, height);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSampleCoverage(
+ uint32 immediate_data_size, const gles2::cmds::SampleCoverage& c) {
+ GLclampf value = static_cast<GLclampf>(c.value);
+ GLboolean invert = static_cast<GLboolean>(c.invert);
+ DoSampleCoverage(value, invert);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleScissor(
+ uint32 immediate_data_size, const gles2::cmds::Scissor& c) {
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glScissor", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glScissor", "height < 0");
+ return error::kNoError;
+ }
+ if (state_.scissor_x != x ||
+ state_.scissor_y != y ||
+ state_.scissor_width != width ||
+ state_.scissor_height != height) {
+ state_.scissor_x = x;
+ state_.scissor_y = y;
+ state_.scissor_width = width;
+ state_.scissor_height = height;
+ glScissor(x, y, width, height);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleStencilFunc(
+ uint32 immediate_data_size, const gles2::cmds::StencilFunc& c) {
+ GLenum func = static_cast<GLenum>(c.func);
+ GLint ref = static_cast<GLint>(c.ref);
+ GLuint mask = static_cast<GLuint>(c.mask);
+ if (!validators_->cmp_function.IsValid(func)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilFunc", func, "func");
+ return error::kNoError;
+ }
+ if (state_.stencil_front_func != func ||
+ state_.stencil_front_ref != ref ||
+ state_.stencil_front_mask != mask ||
+ state_.stencil_back_func != func ||
+ state_.stencil_back_ref != ref ||
+ state_.stencil_back_mask != mask) {
+ state_.stencil_front_func = func;
+ state_.stencil_front_ref = ref;
+ state_.stencil_front_mask = mask;
+ state_.stencil_back_func = func;
+ state_.stencil_back_ref = ref;
+ state_.stencil_back_mask = mask;
+ glStencilFunc(func, ref, mask);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleStencilFuncSeparate(
+ uint32 immediate_data_size, const gles2::cmds::StencilFuncSeparate& c) {
+ GLenum face = static_cast<GLenum>(c.face);
+ GLenum func = static_cast<GLenum>(c.func);
+ GLint ref = static_cast<GLint>(c.ref);
+ GLuint mask = static_cast<GLuint>(c.mask);
+ if (!validators_->face_type.IsValid(face)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilFuncSeparate", face, "face");
+ return error::kNoError;
+ }
+ if (!validators_->cmp_function.IsValid(func)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilFuncSeparate", func, "func");
+ return error::kNoError;
+ }
+ bool changed = false;
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) {
+ changed |= state_.stencil_front_func != func ||
+ state_.stencil_front_ref != ref ||
+ state_.stencil_front_mask != mask;
+ }
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
+ changed |= state_.stencil_back_func != func ||
+ state_.stencil_back_ref != ref ||
+ state_.stencil_back_mask != mask;
+ }
+ if (changed) {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) {
+ state_.stencil_front_func = func;
+ state_.stencil_front_ref = ref;
+ state_.stencil_front_mask = mask;
+ }
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
+ state_.stencil_back_func = func;
+ state_.stencil_back_ref = ref;
+ state_.stencil_back_mask = mask;
+ }
+ glStencilFuncSeparate(face, func, ref, mask);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleStencilMask(
+ uint32 immediate_data_size, const gles2::cmds::StencilMask& c) {
+ GLuint mask = static_cast<GLuint>(c.mask);
+ if (state_.stencil_front_writemask != mask ||
+ state_.stencil_back_writemask != mask) {
+ state_.stencil_front_writemask = mask;
+ state_.stencil_back_writemask = mask;
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleStencilMaskSeparate(
+ uint32 immediate_data_size, const gles2::cmds::StencilMaskSeparate& c) {
+ GLenum face = static_cast<GLenum>(c.face);
+ GLuint mask = static_cast<GLuint>(c.mask);
+ if (!validators_->face_type.IsValid(face)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilMaskSeparate", face, "face");
+ return error::kNoError;
+ }
+ bool changed = false;
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) {
+ changed |= state_.stencil_front_writemask != mask;
+ }
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
+ changed |= state_.stencil_back_writemask != mask;
+ }
+ if (changed) {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) {
+ state_.stencil_front_writemask = mask;
+ }
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
+ state_.stencil_back_writemask = mask;
+ }
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleStencilOp(
+ uint32 immediate_data_size, const gles2::cmds::StencilOp& c) {
+ GLenum fail = static_cast<GLenum>(c.fail);
+ GLenum zfail = static_cast<GLenum>(c.zfail);
+ GLenum zpass = static_cast<GLenum>(c.zpass);
+ if (!validators_->stencil_op.IsValid(fail)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOp", fail, "fail");
+ return error::kNoError;
+ }
+ if (!validators_->stencil_op.IsValid(zfail)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOp", zfail, "zfail");
+ return error::kNoError;
+ }
+ if (!validators_->stencil_op.IsValid(zpass)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOp", zpass, "zpass");
+ return error::kNoError;
+ }
+ if (state_.stencil_front_fail_op != fail ||
+ state_.stencil_front_z_fail_op != zfail ||
+ state_.stencil_front_z_pass_op != zpass ||
+ state_.stencil_back_fail_op != fail ||
+ state_.stencil_back_z_fail_op != zfail ||
+ state_.stencil_back_z_pass_op != zpass) {
+ state_.stencil_front_fail_op = fail;
+ state_.stencil_front_z_fail_op = zfail;
+ state_.stencil_front_z_pass_op = zpass;
+ state_.stencil_back_fail_op = fail;
+ state_.stencil_back_z_fail_op = zfail;
+ state_.stencil_back_z_pass_op = zpass;
+ glStencilOp(fail, zfail, zpass);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleStencilOpSeparate(
+ uint32 immediate_data_size, const gles2::cmds::StencilOpSeparate& c) {
+ GLenum face = static_cast<GLenum>(c.face);
+ GLenum fail = static_cast<GLenum>(c.fail);
+ GLenum zfail = static_cast<GLenum>(c.zfail);
+ GLenum zpass = static_cast<GLenum>(c.zpass);
+ if (!validators_->face_type.IsValid(face)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOpSeparate", face, "face");
+ return error::kNoError;
+ }
+ if (!validators_->stencil_op.IsValid(fail)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOpSeparate", fail, "fail");
+ return error::kNoError;
+ }
+ if (!validators_->stencil_op.IsValid(zfail)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOpSeparate", zfail, "zfail");
+ return error::kNoError;
+ }
+ if (!validators_->stencil_op.IsValid(zpass)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glStencilOpSeparate", zpass, "zpass");
+ return error::kNoError;
+ }
+ bool changed = false;
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) {
+ changed |= state_.stencil_front_fail_op != fail ||
+ state_.stencil_front_z_fail_op != zfail ||
+ state_.stencil_front_z_pass_op != zpass;
+ }
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
+ changed |= state_.stencil_back_fail_op != fail ||
+ state_.stencil_back_z_fail_op != zfail ||
+ state_.stencil_back_z_pass_op != zpass;
+ }
+ if (changed) {
+ if (face == GL_FRONT || face == GL_FRONT_AND_BACK) {
+ state_.stencil_front_fail_op = fail;
+ state_.stencil_front_z_fail_op = zfail;
+ state_.stencil_front_z_pass_op = zpass;
+ }
+ if (face == GL_BACK || face == GL_FRONT_AND_BACK) {
+ state_.stencil_back_fail_op = fail;
+ state_.stencil_back_z_fail_op = zfail;
+ state_.stencil_back_z_pass_op = zpass;
+ }
+ glStencilOpSeparate(face, fail, zfail, zpass);
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexParameterf(
+ uint32 immediate_data_size, const gles2::cmds::TexParameterf& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ GLfloat param = static_cast<GLfloat>(c.param);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameterf", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameterf", pname, "pname");
+ return error::kNoError;
+ }
+ DoTexParameterf(target, pname, param);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexParameterfv(
+ uint32 immediate_data_size, const gles2::cmds::TexParameterfv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* params = GetSharedMemoryAs<const GLfloat*>(
+ c.params_shm_id, c.params_shm_offset, data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameterfv", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameterfv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoTexParameterfv(target, pname, params);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexParameterfvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::TexParameterfvImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* params = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameterfv", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameterfv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoTexParameterfv(target, pname, params);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexParameteri(
+ uint32 immediate_data_size, const gles2::cmds::TexParameteri& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ GLint param = static_cast<GLint>(c.param);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteri", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteri", pname, "pname");
+ return error::kNoError;
+ }
+ DoTexParameteri(target, pname, param);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexParameteriv(
+ uint32 immediate_data_size, const gles2::cmds::TexParameteriv& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLint* params = GetSharedMemoryAs<const GLint*>(
+ c.params_shm_id, c.params_shm_offset, data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteriv", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteriv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoTexParameteriv(target, pname, params);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexParameterivImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::TexParameterivImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum pname = static_cast<GLenum>(c.pname);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLint), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLint* params = GetImmediateDataAs<const GLint*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteriv", target, "target");
+ return error::kNoError;
+ }
+ if (!validators_->texture_parameter.IsValid(pname)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexParameteriv", pname, "pname");
+ return error::kNoError;
+ }
+ if (params == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoTexParameteriv(target, pname, params);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform1f(
+ uint32 immediate_data_size, const gles2::cmds::Uniform1f& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat temp[1] = { x, };
+ DoUniform1fv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform1fv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform1fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetSharedMemoryAs<const GLfloat*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform1fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform1fvImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform1fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform1fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform1i(
+ uint32 immediate_data_size, const gles2::cmds::Uniform1i& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLint x = static_cast<GLint>(c.x);
+ DoUniform1i(location, x);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform1iv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform1iv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetSharedMemoryAs<const GLint*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform1iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform1ivImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform1ivImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetImmediateDataAs<const GLint*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform1iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform2f(
+ uint32 immediate_data_size, const gles2::cmds::Uniform2f& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat y = static_cast<GLfloat>(c.y);
+ GLfloat temp[2] = { x, y, };
+ DoUniform2fv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform2fv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform2fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 2, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetSharedMemoryAs<const GLfloat*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform2fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform2fvImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform2fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 2, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform2fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform2i(
+ uint32 immediate_data_size, const gles2::cmds::Uniform2i& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLint temp[2] = { x, y, };
+ DoUniform2iv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform2iv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform2iv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 2, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetSharedMemoryAs<const GLint*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform2iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform2ivImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform2ivImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 2, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetImmediateDataAs<const GLint*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform2iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform3f(
+ uint32 immediate_data_size, const gles2::cmds::Uniform3f& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat y = static_cast<GLfloat>(c.y);
+ GLfloat z = static_cast<GLfloat>(c.z);
+ GLfloat temp[3] = { x, y, z, };
+ DoUniform3fv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform3fv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform3fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 3, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetSharedMemoryAs<const GLfloat*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform3fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform3fvImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform3fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 3, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform3fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform3i(
+ uint32 immediate_data_size, const gles2::cmds::Uniform3i& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLint z = static_cast<GLint>(c.z);
+ GLint temp[3] = { x, y, z, };
+ DoUniform3iv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform3iv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform3iv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 3, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetSharedMemoryAs<const GLint*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform3iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform3ivImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform3ivImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 3, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetImmediateDataAs<const GLint*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform3iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform4f(
+ uint32 immediate_data_size, const gles2::cmds::Uniform4f& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat y = static_cast<GLfloat>(c.y);
+ GLfloat z = static_cast<GLfloat>(c.z);
+ GLfloat w = static_cast<GLfloat>(c.w);
+ GLfloat temp[4] = { x, y, z, w, };
+ DoUniform4fv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform4fv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform4fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetSharedMemoryAs<const GLfloat*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform4fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform4fvImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform4fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* v = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform4fv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform4i(
+ uint32 immediate_data_size, const gles2::cmds::Uniform4i& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLint z = static_cast<GLint>(c.z);
+ GLint w = static_cast<GLint>(c.w);
+ GLint temp[4] = { x, y, z, w, };
+ DoUniform4iv(location, 1, &temp[0]);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform4iv(
+ uint32 immediate_data_size, const gles2::cmds::Uniform4iv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetSharedMemoryAs<const GLint*>(
+ c.v_shm_id, c.v_shm_offset, data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform4iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniform4ivImmediate(
+ uint32 immediate_data_size, const gles2::cmds::Uniform4ivImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLint), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLint* v = GetImmediateDataAs<const GLint*>(
+ c, data_size, immediate_data_size);
+ if (v == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniform4iv(location, count, v);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformMatrix2fv(
+ uint32 immediate_data_size, const gles2::cmds::UniformMatrix2fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLboolean transpose = static_cast<GLboolean>(c.transpose);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* value = GetSharedMemoryAs<const GLfloat*>(
+ c.value_shm_id, c.value_shm_offset, data_size);
+ if (!validators_->false_only.IsValid(transpose)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniformMatrix2fv", "transpose GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (value == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniformMatrix2fv(location, count, transpose, value);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformMatrix2fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::UniformMatrix2fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLboolean transpose = static_cast<GLboolean>(c.transpose);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* value = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->false_only.IsValid(transpose)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniformMatrix2fv", "transpose GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (value == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniformMatrix2fv(location, count, transpose, value);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformMatrix3fv(
+ uint32 immediate_data_size, const gles2::cmds::UniformMatrix3fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLboolean transpose = static_cast<GLboolean>(c.transpose);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 9, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* value = GetSharedMemoryAs<const GLfloat*>(
+ c.value_shm_id, c.value_shm_offset, data_size);
+ if (!validators_->false_only.IsValid(transpose)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniformMatrix3fv", "transpose GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (value == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniformMatrix3fv(location, count, transpose, value);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformMatrix3fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::UniformMatrix3fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLboolean transpose = static_cast<GLboolean>(c.transpose);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 9, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* value = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->false_only.IsValid(transpose)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniformMatrix3fv", "transpose GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (value == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniformMatrix3fv(location, count, transpose, value);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformMatrix4fv(
+ uint32 immediate_data_size, const gles2::cmds::UniformMatrix4fv& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLboolean transpose = static_cast<GLboolean>(c.transpose);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 16, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* value = GetSharedMemoryAs<const GLfloat*>(
+ c.value_shm_id, c.value_shm_offset, data_size);
+ if (!validators_->false_only.IsValid(transpose)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniformMatrix4fv", "transpose GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (value == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniformMatrix4fv(location, count, transpose, value);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformMatrix4fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::UniformMatrix4fvImmediate& c) {
+ GLint location = static_cast<GLint>(c.location);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLboolean transpose = static_cast<GLboolean>(c.transpose);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLfloat), 16, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* value = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->false_only.IsValid(transpose)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glUniformMatrix4fv", "transpose GL_INVALID_VALUE");
+ return error::kNoError;
+ }
+ if (value == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoUniformMatrix4fv(location, count, transpose, value);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUseProgram(
+ uint32 immediate_data_size, const gles2::cmds::UseProgram& c) {
+ GLuint program = c.program;
+ DoUseProgram(program);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleValidateProgram(
+ uint32 immediate_data_size, const gles2::cmds::ValidateProgram& c) {
+ GLuint program = c.program;
+ DoValidateProgram(program);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib1f(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib1f& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ DoVertexAttrib1f(indx, x);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib1fv(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib1fv& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetSharedMemoryAs<const GLfloat*>(
+ c.values_shm_id, c.values_shm_offset, data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib1fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib1fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::VertexAttrib1fvImmediate& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib1fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib2f(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib2f& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat y = static_cast<GLfloat>(c.y);
+ DoVertexAttrib2f(indx, x, y);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib2fv(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib2fv& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 2, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetSharedMemoryAs<const GLfloat*>(
+ c.values_shm_id, c.values_shm_offset, data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib2fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib2fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::VertexAttrib2fvImmediate& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 2, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib2fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib3f(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib3f& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat y = static_cast<GLfloat>(c.y);
+ GLfloat z = static_cast<GLfloat>(c.z);
+ DoVertexAttrib3f(indx, x, y, z);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib3fv(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib3fv& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 3, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetSharedMemoryAs<const GLfloat*>(
+ c.values_shm_id, c.values_shm_offset, data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib3fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib3fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::VertexAttrib3fvImmediate& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 3, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib3fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib4f(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib4f& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ GLfloat x = static_cast<GLfloat>(c.x);
+ GLfloat y = static_cast<GLfloat>(c.y);
+ GLfloat z = static_cast<GLfloat>(c.z);
+ GLfloat w = static_cast<GLfloat>(c.w);
+ DoVertexAttrib4f(indx, x, y, z, w);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib4fv(
+ uint32 immediate_data_size, const gles2::cmds::VertexAttrib4fv& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetSharedMemoryAs<const GLfloat*>(
+ c.values_shm_id, c.values_shm_offset, data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib4fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleVertexAttrib4fvImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::VertexAttrib4fvImmediate& c) {
+ GLuint indx = static_cast<GLuint>(c.indx);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLfloat), 4, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLfloat* values = GetImmediateDataAs<const GLfloat*>(
+ c, data_size, immediate_data_size);
+ if (values == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoVertexAttrib4fv(indx, values);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleViewport(
+ uint32 immediate_data_size, const gles2::cmds::Viewport& c) {
+ GLint x = static_cast<GLint>(c.x);
+ GLint y = static_cast<GLint>(c.y);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glViewport", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glViewport", "height < 0");
+ return error::kNoError;
+ }
+ DoViewport(x, y, width, height);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBlitFramebufferEXT(
+ uint32 immediate_data_size, const gles2::cmds::BlitFramebufferEXT& c) {
+ if (ShouldDeferDraws() || ShouldDeferReads())
+ return error::kDeferCommandUntilLater;
+ GLint srcX0 = static_cast<GLint>(c.srcX0);
+ GLint srcY0 = static_cast<GLint>(c.srcY0);
+ GLint srcX1 = static_cast<GLint>(c.srcX1);
+ GLint srcY1 = static_cast<GLint>(c.srcY1);
+ GLint dstX0 = static_cast<GLint>(c.dstX0);
+ GLint dstY0 = static_cast<GLint>(c.dstY0);
+ GLint dstX1 = static_cast<GLint>(c.dstX1);
+ GLint dstY1 = static_cast<GLint>(c.dstY1);
+ GLbitfield mask = static_cast<GLbitfield>(c.mask);
+ GLenum filter = static_cast<GLenum>(c.filter);
+ if (!validators_->blit_filter.IsValid(filter)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBlitFramebufferEXT", filter, "filter");
+ return error::kNoError;
+ }
+ DoBlitFramebufferEXT(
+ srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleRenderbufferStorageMultisampleEXT(
+ uint32 immediate_data_size,
+ const gles2::cmds::RenderbufferStorageMultisampleEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizei samples = static_cast<GLsizei>(c.samples);
+ GLenum internalformat = static_cast<GLenum>(c.internalformat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ if (!validators_->render_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glRenderbufferStorageMultisampleEXT", target, "target"); // NOLINT
+ return error::kNoError;
+ }
+ if (samples < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glRenderbufferStorageMultisampleEXT", "samples < 0");
+ return error::kNoError;
+ }
+ if (!validators_->render_buffer_format.IsValid(internalformat)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glRenderbufferStorageMultisampleEXT", internalformat, "internalformat"); // NOLINT
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glRenderbufferStorageMultisampleEXT", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glRenderbufferStorageMultisampleEXT", "height < 0");
+ return error::kNoError;
+ }
+ DoRenderbufferStorageMultisample(
+ target, samples, internalformat, width, height);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleFramebufferTexture2DMultisampleEXT(
+ uint32 immediate_data_size,
+ const gles2::cmds::FramebufferTexture2DMultisampleEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum attachment = static_cast<GLenum>(c.attachment);
+ GLenum textarget = static_cast<GLenum>(c.textarget);
+ GLuint texture = c.texture;
+ GLint level = static_cast<GLint>(c.level);
+ GLsizei samples = static_cast<GLsizei>(c.samples);
+ if (!validators_->frame_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferTexture2DMultisampleEXT", target, "target"); // NOLINT
+ return error::kNoError;
+ }
+ if (!validators_->attachment.IsValid(attachment)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferTexture2DMultisampleEXT", attachment, "attachment"); // NOLINT
+ return error::kNoError;
+ }
+ if (!validators_->texture_target.IsValid(textarget)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glFramebufferTexture2DMultisampleEXT", textarget, "textarget"); // NOLINT
+ return error::kNoError;
+ }
+ if (!validators_->zero_only.IsValid(level)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glFramebufferTexture2DMultisampleEXT", "level GL_INVALID_VALUE"); // NOLINT
+ return error::kNoError;
+ }
+ if (samples < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glFramebufferTexture2DMultisampleEXT", "samples < 0"); // NOLINT
+ return error::kNoError;
+ }
+ DoFramebufferTexture2DMultisample(
+ target, attachment, textarget, texture, level, samples);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexStorage2DEXT(
+ uint32 immediate_data_size, const gles2::cmds::TexStorage2DEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizei levels = static_cast<GLsizei>(c.levels);
+ GLenum internalFormat = static_cast<GLenum>(c.internalFormat);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ if (!validators_->texture_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexStorage2DEXT", target, "target");
+ return error::kNoError;
+ }
+ if (levels < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2DEXT", "levels < 0");
+ return error::kNoError;
+ }
+ if (!validators_->texture_internal_format_storage.IsValid(internalFormat)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexStorage2DEXT", internalFormat,
+ "internalFormat");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2DEXT", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexStorage2DEXT", "height < 0");
+ return error::kNoError;
+ }
+ DoTexStorage2DEXT(target, levels, internalFormat, width, height);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenQueriesEXT(
+ uint32 immediate_data_size, const gles2::cmds::GenQueriesEXT& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* queries = GetSharedMemoryAs<GLuint*>(
+ c.queries_shm_id, c.queries_shm_offset, data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenQueriesEXTHelper(n, queries)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenQueriesEXTImmediate(
+ uint32 immediate_data_size, const gles2::cmds::GenQueriesEXTImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* queries = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenQueriesEXTHelper(n, queries)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteQueriesEXT(
+ uint32 immediate_data_size, const gles2::cmds::DeleteQueriesEXT& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* queries = GetSharedMemoryAs<const GLuint*>(
+ c.queries_shm_id, c.queries_shm_offset, data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteQueriesEXTHelper(n, queries);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteQueriesEXTImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DeleteQueriesEXTImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* queries = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (queries == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteQueriesEXTHelper(n, queries);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleInsertEventMarkerEXT(
+ uint32 immediate_data_size, const gles2::cmds::InsertEventMarkerEXT& c) {
+ GLuint bucket_id = static_cast<GLuint>(c.bucket_id);
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string str;
+ if (!bucket->GetAsString(&str)) {
+ return error::kInvalidArguments;
+ }
+ DoInsertEventMarkerEXT(0, str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePushGroupMarkerEXT(
+ uint32 immediate_data_size, const gles2::cmds::PushGroupMarkerEXT& c) {
+ GLuint bucket_id = static_cast<GLuint>(c.bucket_id);
+ Bucket* bucket = GetBucket(bucket_id);
+ if (!bucket || bucket->size() == 0) {
+ return error::kInvalidArguments;
+ }
+ std::string str;
+ if (!bucket->GetAsString(&str)) {
+ return error::kInvalidArguments;
+ }
+ DoPushGroupMarkerEXT(0, str.c_str());
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePopGroupMarkerEXT(
+ uint32 immediate_data_size, const gles2::cmds::PopGroupMarkerEXT& c) {
+ DoPopGroupMarkerEXT();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenVertexArraysOES(
+ uint32 immediate_data_size, const gles2::cmds::GenVertexArraysOES& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* arrays = GetSharedMemoryAs<GLuint*>(
+ c.arrays_shm_id, c.arrays_shm_offset, data_size);
+ if (arrays == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenVertexArraysOESHelper(n, arrays)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGenVertexArraysOESImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::GenVertexArraysOESImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* arrays = GetImmediateDataAs<GLuint*>(
+ c, data_size, immediate_data_size);
+ if (arrays == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenVertexArraysOESHelper(n, arrays)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteVertexArraysOES(
+ uint32 immediate_data_size, const gles2::cmds::DeleteVertexArraysOES& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* arrays = GetSharedMemoryAs<const GLuint*>(
+ c.arrays_shm_id, c.arrays_shm_offset, data_size);
+ if (arrays == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteVertexArraysOESHelper(n, arrays);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteVertexArraysOESImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DeleteVertexArraysOESImmediate& c) {
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32 data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* arrays = GetImmediateDataAs<const GLuint*>(
+ c, data_size, immediate_data_size);
+ if (arrays == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteVertexArraysOESHelper(n, arrays);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsVertexArrayOES(
+ uint32 immediate_data_size, const gles2::cmds::IsVertexArrayOES& c) {
+ GLuint array = c.array;
+ typedef cmds::IsVertexArrayOES::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsVertexArrayOES(array);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindVertexArrayOES(
+ uint32 immediate_data_size, const gles2::cmds::BindVertexArrayOES& c) {
+ GLuint array = c.array;
+ DoBindVertexArrayOES(array);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSwapBuffers(
+ uint32 immediate_data_size, const gles2::cmds::SwapBuffers& c) {
+ DoSwapBuffers();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleGetMaxValueInBufferCHROMIUM(
+ uint32 immediate_data_size,
+ const gles2::cmds::GetMaxValueInBufferCHROMIUM& c) {
+ GLuint buffer_id = c.buffer_id;
+ GLsizei count = static_cast<GLsizei>(c.count);
+ GLenum type = static_cast<GLenum>(c.type);
+ GLuint offset = static_cast<GLuint>(c.offset);
+ typedef cmds::GetMaxValueInBufferCHROMIUM::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glGetMaxValueInBufferCHROMIUM", "count < 0");
+ return error::kNoError;
+ }
+ if (!validators_->get_max_index_type.IsValid(type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glGetMaxValueInBufferCHROMIUM", type,
+ "type");
+ return error::kNoError;
+ }
+ *result_dst = DoGetMaxValueInBufferCHROMIUM(buffer_id, count, type, offset);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTexImageIOSurface2DCHROMIUM(
+ uint32 immediate_data_size,
+ const gles2::cmds::TexImageIOSurface2DCHROMIUM& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizei width = static_cast<GLsizei>(c.width);
+ GLsizei height = static_cast<GLsizei>(c.height);
+ GLuint ioSurfaceId = static_cast<GLuint>(c.ioSurfaceId);
+ GLuint plane = static_cast<GLuint>(c.plane);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glTexImageIOSurface2DCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (width < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM", "width < 0");
+ return error::kNoError;
+ }
+ if (height < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glTexImageIOSurface2DCHROMIUM", "height < 0");
+ return error::kNoError;
+ }
+ DoTexImageIOSurface2DCHROMIUM(target, width, height, ioSurfaceId, plane);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleCopyTextureCHROMIUM(
+ uint32 immediate_data_size, const gles2::cmds::CopyTextureCHROMIUM& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum source_id = static_cast<GLenum>(c.source_id);
+ GLenum dest_id = static_cast<GLenum>(c.dest_id);
+ GLint level = static_cast<GLint>(c.level);
+ GLint internalformat = static_cast<GLint>(c.internalformat);
+ GLenum dest_type = static_cast<GLenum>(c.dest_type);
+ if (!validators_->texture_internal_format.IsValid(internalformat)) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glCopyTextureCHROMIUM", "internalformat GL_INVALID_VALUE"); // NOLINT
+ return error::kNoError;
+ }
+ if (!validators_->pixel_type.IsValid(dest_type)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glCopyTextureCHROMIUM", dest_type,
+ "dest_type");
+ return error::kNoError;
+ }
+ DoCopyTextureCHROMIUM(
+ target, source_id, dest_id, level, internalformat, dest_type);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleProduceTextureCHROMIUM(
+ uint32 immediate_data_size, const gles2::cmds::ProduceTextureCHROMIUM& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLbyte), 64, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLbyte* mailbox = GetSharedMemoryAs<const GLbyte*>(
+ c.mailbox_shm_id, c.mailbox_shm_offset, data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glProduceTextureCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (mailbox == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoProduceTextureCHROMIUM(target, mailbox);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleProduceTextureCHROMIUMImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::ProduceTextureCHROMIUMImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLbyte), 64, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLbyte* mailbox = GetImmediateDataAs<const GLbyte*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glProduceTextureCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (mailbox == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoProduceTextureCHROMIUM(target, mailbox);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleConsumeTextureCHROMIUM(
+ uint32 immediate_data_size, const gles2::cmds::ConsumeTextureCHROMIUM& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLbyte), 64, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLbyte* mailbox = GetSharedMemoryAs<const GLbyte*>(
+ c.mailbox_shm_id, c.mailbox_shm_offset, data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glConsumeTextureCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (mailbox == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoConsumeTextureCHROMIUM(target, mailbox);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleConsumeTextureCHROMIUMImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::ConsumeTextureCHROMIUMImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ uint32 data_size;
+ if (!ComputeDataSize(1, sizeof(GLbyte), 64, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLbyte* mailbox = GetImmediateDataAs<const GLbyte*>(
+ c, data_size, immediate_data_size);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glConsumeTextureCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (mailbox == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoConsumeTextureCHROMIUM(target, mailbox);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindTexImage2DCHROMIUM(
+ uint32 immediate_data_size, const gles2::cmds::BindTexImage2DCHROMIUM& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint imageId = static_cast<GLint>(c.imageId);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindTexImage2DCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ DoBindTexImage2DCHROMIUM(target, imageId);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleReleaseTexImage2DCHROMIUM(
+ uint32 immediate_data_size,
+ const gles2::cmds::ReleaseTexImage2DCHROMIUM& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLint imageId = static_cast<GLint>(c.imageId);
+ if (!validators_->texture_bind_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glReleaseTexImage2DCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ DoReleaseTexImage2DCHROMIUM(target, imageId);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleTraceEndCHROMIUM(
+ uint32 immediate_data_size, const gles2::cmds::TraceEndCHROMIUM& c) {
+ DoTraceEndCHROMIUM();
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDiscardFramebufferEXT(
+ uint32 immediate_data_size, const gles2::cmds::DiscardFramebufferEXT& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLenum* attachments = GetSharedMemoryAs<const GLenum*>(
+ c.attachments_shm_id, c.attachments_shm_offset, data_size);
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glDiscardFramebufferEXT", "count < 0");
+ return error::kNoError;
+ }
+ if (attachments == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoDiscardFramebufferEXT(target, count, attachments);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDiscardFramebufferEXTImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DiscardFramebufferEXTImmediate& c) {
+ GLenum target = static_cast<GLenum>(c.target);
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLenum* attachments = GetImmediateDataAs<const GLenum*>(
+ c, data_size, immediate_data_size);
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(
+ GL_INVALID_VALUE, "glDiscardFramebufferEXT", "count < 0");
+ return error::kNoError;
+ }
+ if (attachments == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoDiscardFramebufferEXT(target, count, attachments);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDrawBuffersEXT(
+ uint32 immediate_data_size, const gles2::cmds::DrawBuffersEXT& c) {
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLenum* bufs = GetSharedMemoryAs<const GLenum*>(
+ c.bufs_shm_id, c.bufs_shm_offset, data_size);
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glDrawBuffersEXT", "count < 0");
+ return error::kNoError;
+ }
+ if (bufs == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoDrawBuffersEXT(count, bufs);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDrawBuffersEXTImmediate(
+ uint32 immediate_data_size,
+ const gles2::cmds::DrawBuffersEXTImmediate& c) {
+ GLsizei count = static_cast<GLsizei>(c.count);
+ uint32 data_size;
+ if (!ComputeDataSize(count, sizeof(GLenum), 1, &data_size)) {
+ return error::kOutOfBounds;
+ }
+ if (data_size > immediate_data_size) {
+ return error::kOutOfBounds;
+ }
+ const GLenum* bufs = GetImmediateDataAs<const GLenum*>(
+ c, data_size, immediate_data_size);
+ if (count < 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glDrawBuffersEXT", "count < 0");
+ return error::kNoError;
+ }
+ if (bufs == NULL) {
+ return error::kOutOfBounds;
+ }
+ DoDrawBuffersEXT(count, bufs);
+ return error::kNoError;
+}
+
+
+bool GLES2DecoderImpl::SetCapabilityState(GLenum cap, bool enabled) {
+ switch (cap) {
+ case GL_BLEND:
+ state_.enable_flags.blend = enabled;
+ return true;
+ case GL_CULL_FACE:
+ state_.enable_flags.cull_face = enabled;
+ return true;
+ case GL_DEPTH_TEST:
+ if (state_.enable_flags.depth_test != enabled) {
+ state_.enable_flags.depth_test = enabled;
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return false;
+ case GL_DITHER:
+ state_.enable_flags.dither = enabled;
+ return true;
+ case GL_POLYGON_OFFSET_FILL:
+ state_.enable_flags.polygon_offset_fill = enabled;
+ return true;
+ case GL_SAMPLE_ALPHA_TO_COVERAGE:
+ state_.enable_flags.sample_alpha_to_coverage = enabled;
+ return true;
+ case GL_SAMPLE_COVERAGE:
+ state_.enable_flags.sample_coverage = enabled;
+ return true;
+ case GL_SCISSOR_TEST:
+ if (state_.enable_flags.scissor_test != enabled) {
+ state_.enable_flags.scissor_test = enabled;
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return false;
+ case GL_STENCIL_TEST:
+ if (state_.enable_flags.stencil_test != enabled) {
+ state_.enable_flags.stencil_test = enabled;
+ framebuffer_state_.clear_state_dirty = true;
+ }
+ return false;
+ default:
+ NOTREACHED();
+ return false;
+ }
+}
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
new file mode 100644
index 00000000000..a8e027d7276
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+MockGLES2Decoder::MockGLES2Decoder()
+ : GLES2Decoder() {
+ ON_CALL(*this, GetCommandName(testing::_))
+ .WillByDefault(testing::Return(""));
+ ON_CALL(*this, MakeCurrent())
+ .WillByDefault(testing::Return(true));
+}
+
+MockGLES2Decoder::~MockGLES2Decoder() {}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
new file mode 100644
index 00000000000..e6c497faca6
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -0,0 +1,121 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the mock GLES2Decoder class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
+
+#include <vector>
+
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "base/callback_forward.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "ui/gfx/size.h"
+
+namespace gfx {
+class GLContext;
+class GLSurface;
+}
+
+namespace gpu {
+class StreamTextureManager;
+
+namespace gles2 {
+
+class ContextGroup;
+class ErrorState;
+class QueryManager;
+
+class MockGLES2Decoder : public GLES2Decoder {
+ public:
+ MockGLES2Decoder();
+ virtual ~MockGLES2Decoder();
+
+ MOCK_METHOD7(Initialize,
+ bool(const scoped_refptr<gfx::GLSurface>& surface,
+ const scoped_refptr<gfx::GLContext>& context,
+ bool offscreen,
+ const gfx::Size& size,
+ const DisallowedFeatures& disallowed_features,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs));
+ MOCK_METHOD1(Destroy, void(bool have_context));
+ MOCK_METHOD1(SetSurface, void(const scoped_refptr<gfx::GLSurface>& surface));
+ MOCK_METHOD1(ProduceFrontBuffer, bool(const Mailbox& mailbox));
+ MOCK_METHOD1(ResizeOffscreenFrameBuffer, bool(const gfx::Size& size));
+ MOCK_METHOD0(MakeCurrent, bool());
+ MOCK_METHOD0(ReleaseCurrent, void());
+ MOCK_METHOD1(GetServiceIdForTesting, uint32(uint32 client_id));
+ MOCK_METHOD0(GetGLES2Util, GLES2Util*());
+ MOCK_METHOD0(GetGLSurface, gfx::GLSurface*());
+ MOCK_METHOD0(GetGLContext, gfx::GLContext*());
+ MOCK_METHOD0(GetContextGroup, ContextGroup*());
+ MOCK_METHOD0(ProcessPendingQueries, bool());
+ MOCK_METHOD0(HasMoreIdleWork, bool());
+ MOCK_METHOD0(PerformIdleWork, void());
+ MOCK_CONST_METHOD0(RestoreState, void());
+ MOCK_CONST_METHOD0(RestoreActiveTexture, void());
+ MOCK_CONST_METHOD0(RestoreAllTextureUnitBindings, void());
+ MOCK_CONST_METHOD1(RestoreAttribute, void(unsigned index));
+ MOCK_CONST_METHOD0(RestoreBufferBindings, void());
+ MOCK_CONST_METHOD0(RestoreFramebufferBindings, void());
+ MOCK_CONST_METHOD0(RestoreGlobalState, void());
+ MOCK_CONST_METHOD0(RestoreProgramBindings, void());
+ MOCK_CONST_METHOD0(RestoreRenderbufferBindings, void());
+ MOCK_CONST_METHOD1(RestoreTextureState, void(unsigned service_id));
+ MOCK_CONST_METHOD1(RestoreTextureUnitBindings, void(unsigned unit));
+ MOCK_METHOD0(GetQueryManager, gpu::gles2::QueryManager*());
+ MOCK_METHOD0(GetVertexArrayManager, gpu::gles2::VertexArrayManager*());
+ MOCK_METHOD1(
+ SetResizeCallback, void(const base::Callback<void(gfx::Size, float)>&));
+ MOCK_METHOD0(GetAsyncPixelTransferDelegate,
+ AsyncPixelTransferDelegate*());
+ MOCK_METHOD0(GetAsyncPixelTransferManager,
+ AsyncPixelTransferManager*());
+ MOCK_METHOD0(ResetAsyncPixelTransferManagerForTest, void());
+ MOCK_METHOD1(SetAsyncPixelTransferManagerForTest,
+ void(AsyncPixelTransferManager*));
+ MOCK_METHOD3(DoCommand, error::Error(unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data));
+ MOCK_METHOD2(GetServiceTextureId, bool(uint32 client_texture_id,
+ uint32* service_texture_id));
+ MOCK_METHOD0(GetContextLostReason, error::ContextLostReason());
+ MOCK_CONST_METHOD1(GetCommandName, const char*(unsigned int command_id));
+ MOCK_METHOD9(ClearLevel, bool(
+ unsigned service_id,
+ unsigned bind_target,
+ unsigned target,
+ int level,
+ unsigned format,
+ unsigned type,
+ int width,
+ int height,
+ bool is_texture_immutable));
+ MOCK_METHOD0(GetErrorState, ErrorState *());
+
+ MOCK_METHOD0(GetLogger, Logger*());
+ MOCK_METHOD1(SetShaderCacheCallback,
+ void(const ShaderCacheCallback& callback));
+ MOCK_METHOD1(SetWaitSyncPointCallback,
+ void(const WaitSyncPointCallback& callback));
+ MOCK_METHOD1(WaitForReadPixels,
+ void(base::Closure callback));
+ MOCK_METHOD0(GetTextureUploadCount, uint32());
+ MOCK_METHOD0(GetTotalTextureUploadTime, base::TimeDelta());
+ MOCK_METHOD0(GetTotalProcessingCommandsTime, base::TimeDelta());
+ MOCK_METHOD1(AddProcessingCommandsTime, void(base::TimeDelta));
+ MOCK_METHOD0(WasContextLost, bool());
+ MOCK_METHOD0(WasContextLostByRobustnessExtension, bool());
+ MOCK_METHOD1(LoseContext, void(uint32 reset_status));
+
+ DISALLOW_COPY_AND_ASSIGN(MockGLES2Decoder);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_MOCK_H_
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
new file mode 100644
index 00000000000..906eb88f8f6
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -0,0 +1,8670 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include "base/atomicops.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate_mock.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager_mock.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/gl_surface_mock.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/stream_texture_manager_mock.h"
+#include "gpu/command_buffer/service/stream_texture_mock.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+#include "ui/gl/gl_surface_stub.h"
+
+
+#if !defined(GL_DEPTH24_STENCIL8)
+#define GL_DEPTH24_STENCIL8 0x88F0
+#endif
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::Invoke;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SaveArg;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::SetArgPointee;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+using namespace cmds;
+
+class GLES2DecoderTest : public GLES2DecoderTestBase {
+ public:
+ GLES2DecoderTest() { }
+
+ protected:
+ void CheckReadPixelsOutOfRange(
+ GLint in_read_x, GLint in_read_y,
+ GLsizei in_read_width, GLsizei in_read_height,
+ bool init);
+};
+
+class GLES2DecoderANGLETest : public GLES2DecoderTestBase {
+ public:
+ GLES2DecoderANGLETest()
+ : GLES2DecoderTestBase() {
+ GLES2Decoder::set_testing_force_is_angle(true);
+ }
+
+ virtual ~GLES2DecoderANGLETest() {
+ GLES2Decoder::set_testing_force_is_angle(false);
+ }
+};
+
+class GLES2DecoderWithShaderTest : public GLES2DecoderWithShaderTestBase {
+ public:
+ GLES2DecoderWithShaderTest()
+ : GLES2DecoderWithShaderTestBase() {
+ }
+
+ void CheckTextureChangesMarkFBOAsNotComplete(bool bound_fbo);
+ void CheckRenderbufferChangesMarkFBOAsNotComplete(bool bound_fbo);
+};
+
+class GLES2DecoderGeometryInstancingTest : public GLES2DecoderWithShaderTest {
+ public:
+ GLES2DecoderGeometryInstancingTest()
+ : GLES2DecoderWithShaderTest() {
+ }
+
+ virtual void SetUp() {
+ InitDecoder(
+ "GL_ANGLE_instanced_arrays", // extensions
+ true, // has alpha
+ true, // has depth
+ false, // has stencil
+ true, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ SetupDefaultProgram();
+ }
+};
+
+class GLES2DecoderRGBBackbufferTest : public GLES2DecoderWithShaderTest {
+ public:
+ GLES2DecoderRGBBackbufferTest() { }
+
+ virtual void SetUp() {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ SetupDefaultProgram();
+ }
+};
+
+class GLES2DecoderManualInitTest : public GLES2DecoderWithShaderTest {
+ public:
+ GLES2DecoderManualInitTest() { }
+
+ // Override default setup so nothing gets setup.
+ virtual void SetUp() {
+ }
+};
+
+class GLES2DecoderANGLEManualInitTest : public GLES2DecoderANGLETest {
+ public:
+ // Override default setup so nothing gets setup.
+ virtual void SetUp() {
+ }
+};
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysNoAttributesSucceeds) {
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+// Tests when the math overflows (0x40000000 * sizeof GLfloat)
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0OverflowFails) {
+ const GLsizei kLargeCount = 0x40000000;
+ SetupTexture();
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kLargeCount);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+// Tests when the math overflows (0x7FFFFFFF + 1 = 0x8000000 verts)
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0PosToNegFails) {
+ const GLsizei kLargeCount = 0x7FFFFFFF;
+ SetupTexture();
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kLargeCount);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+// Tests when the driver returns an error
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysSimulatedAttrib0OOMFails) {
+ const GLsizei kFakeLargeCount = 0x1234;
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0WithError(
+ kFakeLargeCount, 0, GL_OUT_OF_MEMORY);
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kFakeLargeCount);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysBadTextureUsesBlack) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // This is an NPOT texture. As the default filtering requires mips
+ // this should trigger replacing with black textures before rendering.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ {
+ InSequence sequence;
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(
+ GL_TEXTURE_2D, TestHelper::kServiceBlackTexture2dId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysMissingAttributesFails) {
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0);
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ DrawArraysMissingAttributesZeroCountSucceeds) {
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0);
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysValidAttributesSucceeds) {
+ SetupTexture();
+ SetupVertexBuffer();
+ DoEnableVertexAttribArray(1);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedBufferFails) {
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ DeleteVertexBuffer();
+
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0);
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysDeletedProgramSucceeds) {
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoDeleteProgram(client_program_id_, kServiceProgramId);
+
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId))
+ .Times(1);
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysWithInvalidModeFails) {
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0);
+ DrawArrays cmd;
+ cmd.Init(GL_QUADS, 0, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_POLYGON, 0, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysInvalidCountFails) {
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ // Try start > 0
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0);
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 1, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Try with count > size
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Try with attrib offset > 0
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Try with size > 2 (ie, vec3 instead of vec2)
+ DoVertexAttribPointer(1, 3, GL_FLOAT, 0, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Try with stride > 8 (vec2 + vec2 byte)
+ DoVertexAttribPointer(1, 2, GL_FLOAT, sizeof(GLfloat) * 3, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysInstancedANGLEFails) {
+ SetupTexture();
+ SetupVertexBuffer();
+ DoEnableVertexAttribArray(1);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLENoAttributesFails) {
+ SetupTexture();
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLESimulatedAttrib0) {
+ SetupTexture();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 3))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, 3);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLEMissingAttributesFails) {
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0);
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLEMissingAttributesZeroCountSucceeds) {
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0);
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, 0, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLEValidAttributesSucceeds) {
+ SetupTexture();
+ SetupVertexBuffer();
+ DoEnableVertexAttribArray(1);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ AddExpectationsForSimulatedAttrib0(kNumVertices, kServiceBufferId);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLEWithInvalidModeFails) {
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0);
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_QUADS, 0, 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_POLYGON, 0, 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLEInvalidPrimcountFails) {
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0);
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, 1, -1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+// Per-instance data is twice as large, but number of instances is half
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLELargeInstanceSucceeds) {
+ SetupTexture();
+ SetupVertexBuffer();
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices,
+ kNumVertices / 2))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices / 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+// Per-instance data is twice as large, but divisor is twice
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLELargeDivisorSucceeds) {
+ SetupTexture();
+ SetupVertexBuffer();
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 2);
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices,
+ kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest, DrawArraysInstancedANGLELargeFails) {
+ SetupTexture();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, kNumVertices + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices + 1, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+// Per-index data is twice as large, but number of indices is half
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLELargeIndexSucceeds) {
+ SetupTexture();
+ SetupVertexBuffer();
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(GL_TRIANGLES, 0, kNumVertices / 2,
+ kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices / 2, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawArraysInstancedANGLENoDivisor0Fails) {
+ SetupTexture();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ DoVertexAttribDivisorANGLE(1, 1);
+ EXPECT_CALL(*gl_, DrawArraysInstancedANGLE(_, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArraysInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsNoAttributesSucceeds) {
+ SetupTexture();
+ SetupIndexBuffer();
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2)))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsMissingAttributesFails) {
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ DrawElementsMissingAttributesZeroCountSucceeds) {
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsExtraAttributesFails) {
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(6);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsValidAttributesSucceeds) {
+ SetupTexture();
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2)))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedBufferFails) {
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ DeleteIndexBuffer();
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsDeletedProgramSucceeds) {
+ SetupTexture();
+ SetupIndexBuffer();
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoDeleteProgram(client_program_id_, kServiceProgramId);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(1);
+ EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId))
+ .Times(1);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsWithInvalidModeFails) {
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_POLYGON, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsInvalidCountFails) {
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ // Try start > 0
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kNumIndices, GL_UNSIGNED_SHORT, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Try with count > size
+ cmd.Init(GL_TRIANGLES, kNumIndices + 1, GL_UNSIGNED_SHORT, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsOutOfRangeIndicesFails) {
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kInvalidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsOddOffsetForUint16Fails) {
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _)).Times(0);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsInstancedANGLEFails) {
+ SetupTexture();
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(1);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLENoAttributesFails) {
+ SetupTexture();
+ SetupIndexBuffer();
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLESimulatedAttrib0) {
+ SetupTexture();
+ SetupVertexBuffer();
+ SetupIndexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(
+ GL_TRIANGLES,
+ kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2),
+ 3))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(0, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 3);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLEMissingAttributesFails) {
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0);
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLEMissingAttributesZeroCountSucceeds) {
+ SetupIndexBuffer();
+ DoEnableVertexAttribArray(1);
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0);
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, 0, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLEValidAttributesSucceeds) {
+ SetupIndexBuffer();
+ SetupTexture();
+ SetupVertexBuffer();
+ DoEnableVertexAttribArray(1);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, kServiceBufferId);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(
+ GL_TRIANGLES,
+ kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2),
+ 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLEWithInvalidModeFails) {
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0);
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_QUADS, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_INVALID_ENUM, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+// Per-instance data is twice as large, but number of instances is half
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLELargeInstanceSucceeds) {
+ SetupTexture();
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ SetupExpectationsForApplyingDefaultDirtyState();
+ //Add offset so we're sure we're accessing data near the end of the buffer.
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0,
+ (kNumVertices - kMaxValidIndex - 1) * 2 *
+ sizeof(GLfloat));
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(
+ GL_TRIANGLES,
+ kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2),
+ kNumVertices / 2))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kNumVertices / 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+// Per-instance data is twice as large, but divisor is twice
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLELargeDivisorSucceeds) {
+ SetupTexture();
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 4, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 2);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(
+ GL_TRIANGLES,
+ kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2),
+ kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLELargeFails) {
+ SetupTexture();
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kNumVertices + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ cmd.Init(GL_TRIANGLES, kInvalidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kInvalidIndexRangeStart * 2, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLEInvalidPrimcountFails) {
+ SetupTexture();
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, -1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+// Per-index data is twice as large, but values of indices are smaller
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLELargeIndexSucceeds) {
+ SetupTexture();
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoVertexAttribPointer(1, 4, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(
+ GL_TRIANGLES,
+ kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2),
+ kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderGeometryInstancingTest,
+ DrawElementsInstancedANGLENoDivisor0Fails) {
+ SetupTexture();
+ SetupIndexBuffer();
+ SetupVertexBuffer();
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribDivisorANGLE(0, 1);
+ DoVertexAttribDivisorANGLE(1, 1);
+ EXPECT_CALL(*gl_, DrawElementsInstancedANGLE(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawElementsInstancedANGLE cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervSucceeds) {
+ const float dummy = 0;
+ const GLuint kOffsetToTestFor = sizeof(dummy) * 4;
+ const GLuint kIndexToTest = 1;
+ GetVertexAttribPointerv::Result* result =
+ static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_);
+ result->size = 0;
+ const GLuint* result_value = result->GetData();
+ // Test that initial value is 0.
+ GetVertexAttribPointerv cmd;
+ cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(sizeof(*result_value), result->size);
+ EXPECT_EQ(0u, *result_value);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Set the value and see that we get it.
+ SetupVertexBuffer();
+ DoVertexAttribPointer(kIndexToTest, 2, GL_FLOAT, 0, kOffsetToTestFor);
+ result->size = 0;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(sizeof(*result_value), result->size);
+ EXPECT_EQ(kOffsetToTestFor, *result_value);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetVertexAttribPointervBadArgsFails) {
+ const GLuint kIndexToTest = 1;
+ GetVertexAttribPointerv::Result* result =
+ static_cast<GetVertexAttribPointerv::Result*>(shared_memory_address_);
+ result->size = 0;
+ const GLuint* result_value = result->GetData();
+ // Test pname invalid fails.
+ GetVertexAttribPointerv cmd;
+ cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER + 1,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(kInitialResult, *result_value);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ // Test index out of range fails.
+ result->size = 0;
+ cmd.Init(kNumVertexAttribs, GL_VERTEX_ATTRIB_ARRAY_POINTER,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(kInitialResult, *result_value);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+ // Test memory id bad fails.
+ cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER,
+ kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ // Test memory offset bad fails.
+ cmd.Init(kIndexToTest, GL_VERTEX_ATTRIB_ARRAY_POINTER,
+ shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformivSucceeds) {
+ GetUniformiv::Result* result =
+ static_cast<GetUniformiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformiv cmd;
+ cmd.Init(client_program_id_,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformiv(kServiceProgramId, kUniform2RealLocation, _))
+ .Times(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
+ result->size);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformivArrayElementSucceeds) {
+ GetUniformiv::Result* result =
+ static_cast<GetUniformiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformiv cmd;
+ cmd.Init(client_program_id_,
+ kUniform2ElementFakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_,
+ GetUniformiv(kServiceProgramId, kUniform2ElementRealLocation, _))
+ .Times(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
+ result->size);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadProgramFails) {
+ GetUniformiv::Result* result =
+ static_cast<GetUniformiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformiv cmd;
+ // non-existant program
+ cmd.Init(kInvalidClientId,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformiv(_, _, _))
+ .Times(0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // Valid id that is not a program. The GL spec requires a different error for
+ // this case.
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ result->size = kInitialResult;
+ cmd.Init(client_shader_id_,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ // Unlinked program
+ EXPECT_CALL(*gl_, CreateProgram())
+ .Times(1)
+ .WillOnce(Return(kNewServiceId))
+ .RetiresOnSaturation();
+ CreateProgram cmd2;
+ cmd2.Init(kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ result->size = kInitialResult;
+ cmd.Init(kNewClientId,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadLocationFails) {
+ GetUniformiv::Result* result =
+ static_cast<GetUniformiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformiv cmd;
+ // invalid location
+ cmd.Init(client_program_id_, kInvalidUniformLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformiv(_, _, _))
+ .Times(0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformivBadSharedMemoryFails) {
+ GetUniformiv cmd;
+ cmd.Init(client_program_id_,
+ kUniform2FakeLocation,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformiv(_, _, _))
+ .Times(0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kUniform2FakeLocation,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+};
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformfvSucceeds) {
+ GetUniformfv::Result* result =
+ static_cast<GetUniformfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformfv cmd;
+ cmd.Init(client_program_id_,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformfv(kServiceProgramId, kUniform2RealLocation, _))
+ .Times(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
+ result->size);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformfvArrayElementSucceeds) {
+ GetUniformfv::Result* result =
+ static_cast<GetUniformfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformfv cmd;
+ cmd.Init(client_program_id_,
+ kUniform2ElementFakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_,
+ GetUniformfv(kServiceProgramId, kUniform2ElementRealLocation, _))
+ .Times(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GLES2Util::GetGLDataTypeSizeForUniforms(kUniform2Type),
+ result->size);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadProgramFails) {
+ GetUniformfv::Result* result =
+ static_cast<GetUniformfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformfv cmd;
+ // non-existant program
+ cmd.Init(kInvalidClientId,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformfv(_, _, _))
+ .Times(0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // Valid id that is not a program. The GL spec requires a different error for
+ // this case.
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ result->size = kInitialResult;
+ cmd.Init(client_shader_id_,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ // Unlinked program
+ EXPECT_CALL(*gl_, CreateProgram())
+ .Times(1)
+ .WillOnce(Return(kNewServiceId))
+ .RetiresOnSaturation();
+ CreateProgram cmd2;
+ cmd2.Init(kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ result->size = kInitialResult;
+ cmd.Init(kNewClientId,
+ kUniform2FakeLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadLocationFails) {
+ GetUniformfv::Result* result =
+ static_cast<GetUniformfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ GetUniformfv cmd;
+ // invalid location
+ cmd.Init(client_program_id_, kInvalidUniformLocation,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformfv(_, _, _))
+ .Times(0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformfvBadSharedMemoryFails) {
+ GetUniformfv cmd;
+ cmd.Init(client_program_id_,
+ kUniform2FakeLocation,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, GetUniformfv(_, _, _))
+ .Times(0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kUniform2FakeLocation,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+};
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersSucceeds) {
+ GetAttachedShaders cmd;
+ typedef GetAttachedShaders::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ EXPECT_CALL(*gl_, GetAttachedShaders(kServiceProgramId, 1, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(1),
+ SetArgumentPointee<3>(kServiceShaderId)));
+ cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_,
+ Result::ComputeSize(1));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(1, result->GetNumResults());
+ EXPECT_EQ(client_shader_id_, result->GetData()[0]);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersResultNotInitFail) {
+ GetAttachedShaders cmd;
+ typedef GetAttachedShaders::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 1;
+ EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _))
+ .Times(0);
+ cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_,
+ Result::ComputeSize(1));
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersBadProgramFails) {
+ GetAttachedShaders cmd;
+ typedef GetAttachedShaders::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _))
+ .Times(0);
+ cmd.Init(kInvalidClientId, shared_memory_id_, shared_memory_offset_,
+ Result::ComputeSize(1));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0U, result->size);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttachedShadersBadSharedMemoryFails) {
+ GetAttachedShaders cmd;
+ typedef GetAttachedShaders::Result Result;
+ cmd.Init(client_program_id_, kInvalidSharedMemoryId, shared_memory_offset_,
+ Result::ComputeSize(1));
+ EXPECT_CALL(*gl_, GetAttachedShaders(_, _, _, _))
+ .Times(0);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, shared_memory_id_, kInvalidSharedMemoryOffset,
+ Result::ComputeSize(1));
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatSucceeds) {
+ ScopedGLImplementationSetter gl_impl(::gfx::kGLImplementationEGLGLES2);
+ GetShaderPrecisionFormat cmd;
+ typedef GetShaderPrecisionFormat::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ const GLint range[2] = { 62, 62 };
+ const GLint precision = 16;
+ EXPECT_CALL(*gl_,GetShaderPrecisionFormat(_, _, _, _))
+ .WillOnce(DoAll(SetArrayArgument<2>(range,range+2),
+ SetArgumentPointee<3>(precision)))
+ .RetiresOnSaturation();
+ cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_NE(0, result->success);
+ EXPECT_EQ(range[0], result->min_range);
+ EXPECT_EQ(range[1], result->max_range);
+ EXPECT_EQ(precision, result->precision);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatResultNotInitFails) {
+ GetShaderPrecisionFormat cmd;
+ typedef GetShaderPrecisionFormat::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 1;
+ // NOTE: GL might not be called. There is no Desktop OpenGL equivalent
+ cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetShaderPrecisionFormatBadArgsFails) {
+ typedef GetShaderPrecisionFormat::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ GetShaderPrecisionFormat cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_HIGH_FLOAT,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ result->success = 0;
+ cmd.Init(GL_VERTEX_SHADER, GL_TEXTURE_2D,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ GetShaderPrecisionFormatBadSharedMemoryFails) {
+ GetShaderPrecisionFormat cmd;
+ cmd.Init(GL_VERTEX_SHADER, GL_HIGH_FLOAT,
+ kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(GL_VERTEX_SHADER, GL_TEXTURE_2D,
+ shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformSucceeds) {
+ const GLuint kUniformIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveUniform cmd;
+ typedef GetActiveUniform::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ cmd.Init(client_program_id_, kUniformIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_NE(0, result->success);
+ EXPECT_EQ(kUniform2Size, result->size);
+ EXPECT_EQ(kUniform2Type, result->type);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kUniform2Name,
+ bucket->size()));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformResultNotInitFails) {
+ const GLuint kUniformIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveUniform cmd;
+ typedef GetActiveUniform::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 1;
+ cmd.Init(client_program_id_, kUniformIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadProgramFails) {
+ const GLuint kUniformIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveUniform cmd;
+ typedef GetActiveUniform::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ cmd.Init(kInvalidClientId, kUniformIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, result->success);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ result->success = 0;
+ cmd.Init(client_shader_id_, kUniformIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, result->success);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadIndexFails) {
+ const uint32 kBucketId = 123;
+ GetActiveUniform cmd;
+ typedef GetActiveUniform::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ cmd.Init(client_program_id_, kBadUniformIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, result->success);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveUniformBadSharedMemoryFails) {
+ const GLuint kUniformIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveUniform cmd;
+ typedef GetActiveUniform::Result Result;
+ cmd.Init(client_program_id_, kUniformIndex, kBucketId,
+ kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kUniformIndex, kBucketId,
+ shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribSucceeds) {
+ const GLuint kAttribIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveAttrib cmd;
+ typedef GetActiveAttrib::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ cmd.Init(client_program_id_, kAttribIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_NE(0, result->success);
+ EXPECT_EQ(kAttrib2Size, result->size);
+ EXPECT_EQ(kAttrib2Type, result->type);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kAttrib2Name,
+ bucket->size()));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribResultNotInitFails) {
+ const GLuint kAttribIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveAttrib cmd;
+ typedef GetActiveAttrib::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 1;
+ cmd.Init(client_program_id_, kAttribIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadProgramFails) {
+ const GLuint kAttribIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveAttrib cmd;
+ typedef GetActiveAttrib::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ cmd.Init(kInvalidClientId, kAttribIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, result->success);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ result->success = 0;
+ cmd.Init(client_shader_id_, kAttribIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, result->success);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadIndexFails) {
+ const uint32 kBucketId = 123;
+ GetActiveAttrib cmd;
+ typedef GetActiveAttrib::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->success = 0;
+ cmd.Init(client_program_id_, kBadAttribIndex, kBucketId,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0, result->success);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetActiveAttribBadSharedMemoryFails) {
+ const GLuint kAttribIndex = 1;
+ const uint32 kBucketId = 123;
+ GetActiveAttrib cmd;
+ typedef GetActiveAttrib::Result Result;
+ cmd.Init(client_program_id_, kAttribIndex, kBucketId,
+ kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kAttribIndex, kBucketId,
+ shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetShaderInfoLogValidArgs) {
+ const char* kInfo = "hello";
+ const uint32 kBucketId = 123;
+ CompileShader compile_cmd;
+ GetShaderInfoLog cmd;
+ EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
+ EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
+ EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(GL_FALSE))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_INFO_LOG_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(strlen(kInfo) + 1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *gl_, GetShaderInfoLog(kServiceShaderId, strlen(kInfo) + 1, _, _))
+ .WillOnce(DoAll(SetArgumentPointee<2>(strlen(kInfo)),
+ SetArrayArgument<3>(kInfo, kInfo + strlen(kInfo) + 1)));
+ compile_cmd.Init(client_shader_id_);
+ cmd.Init(client_shader_id_, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(compile_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(strlen(kInfo) + 1, bucket->size());
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kInfo,
+ bucket->size()));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetShaderInfoLogInvalidArgs) {
+ const uint32 kBucketId = 123;
+ GetShaderInfoLog cmd;
+ cmd.Init(kInvalidClientId, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, GetIntegervCached) {
+ struct TestInfo {
+ GLenum pname;
+ GLint expected;
+ };
+ TestInfo tests[] = {
+ { GL_MAX_TEXTURE_SIZE, TestHelper::kMaxTextureSize, },
+ { GL_MAX_CUBE_MAP_TEXTURE_SIZE, TestHelper::kMaxCubeMapTextureSize, },
+ { GL_MAX_RENDERBUFFER_SIZE, TestHelper::kMaxRenderbufferSize, },
+ };
+ typedef GetIntegerv::Result Result;
+ for (size_t ii = 0; ii < sizeof(tests) / sizeof(tests[0]); ++ii) {
+ const TestInfo& test = tests[ii];
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetIntegerv(test.pname, _))
+ .Times(0);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(test.pname, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(test.pname),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(test.expected, result->GetData()[0]);
+ }
+}
+
+TEST_F(GLES2DecoderTest, CompileShaderValidArgs) {
+ EXPECT_CALL(*gl_, ShaderSource(kServiceShaderId, 1, _, _));
+ EXPECT_CALL(*gl_, CompileShader(kServiceShaderId));
+ EXPECT_CALL(*gl_, GetShaderiv(kServiceShaderId, GL_COMPILE_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(GL_TRUE))
+ .RetiresOnSaturation();
+ CompileShader cmd;
+ cmd.Init(client_shader_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, CompileShaderInvalidArgs) {
+ CompileShader cmd;
+ cmd.Init(kInvalidClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceAndGetShaderSourceValidArgs) {
+ const uint32 kBucketId = 123;
+ const char kSource[] = "hello";
+ const uint32 kSourceSize = sizeof(kSource) - 1;
+ memcpy(shared_memory_address_, kSource, kSourceSize);
+ ShaderSource cmd;
+ cmd.Init(client_shader_id_,
+ kSharedMemoryId, kSharedMemoryOffset, kSourceSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ memset(shared_memory_address_, 0, kSourceSize);
+ GetShaderSource get_cmd;
+ get_cmd.Init(client_shader_id_, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(kSourceSize + 1, bucket->size());
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource,
+ bucket->size()));
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceInvalidArgs) {
+ const char kSource[] = "hello";
+ const uint32 kSourceSize = sizeof(kSource) - 1;
+ memcpy(shared_memory_address_, kSource, kSourceSize);
+ ShaderSource cmd;
+ cmd.Init(kInvalidClientId,
+ kSharedMemoryId, kSharedMemoryOffset, kSourceSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kSharedMemoryOffset, kSourceSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ cmd.Init(client_shader_id_,
+ kInvalidSharedMemoryId, kSharedMemoryOffset, kSourceSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_shader_id_,
+ kSharedMemoryId, kInvalidSharedMemoryOffset, kSourceSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_shader_id_,
+ kSharedMemoryId, kSharedMemoryOffset, kSharedBufferSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceImmediateAndGetShaderSourceValidArgs) {
+ const uint32 kBucketId = 123;
+ const char kSource[] = "hello";
+ const uint32 kSourceSize = sizeof(kSource) - 1;
+ ShaderSourceImmediate& cmd = *GetImmediateAs<ShaderSourceImmediate>();
+ cmd.Init(client_shader_id_, kSourceSize);
+ memcpy(GetImmediateDataAs<void*>(&cmd), kSource, kSourceSize);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kSourceSize));
+ memset(shared_memory_address_, 0, kSourceSize);
+ // TODO(gman): GetShaderSource has to change format so result is always set.
+ GetShaderSource get_cmd;
+ get_cmd.Init(client_shader_id_, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(kSourceSize + 1, bucket->size());
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource,
+ bucket->size()));
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceImmediateInvalidArgs) {
+ const char kSource[] = "hello";
+ const uint32 kSourceSize = sizeof(kSource) - 1;
+ ShaderSourceImmediate& cmd = *GetImmediateAs<ShaderSourceImmediate>();
+ cmd.Init(kInvalidClientId, kSourceSize);
+ memcpy(GetImmediateDataAs<void*>(&cmd), kSource, kSourceSize);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kSourceSize));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+#if GLES2_TEST_SHADER_VS_PROGRAM_IDS
+ cmd.Init(client_program_id_, kSourceSize);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kSourceSize));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+#endif // GLES2_TEST_SHADER_VS_PROGRAM_IDS
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceBucketAndGetShaderSourceValidArgs) {
+ const uint32 kInBucketId = 123;
+ const uint32 kOutBucketId = 125;
+ const char kSource[] = "hello";
+ const uint32 kSourceSize = sizeof(kSource) - 1;
+ SetBucketAsCString(kInBucketId, kSource);
+ ShaderSourceBucket cmd;
+ cmd.Init(client_shader_id_, kInBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ ClearSharedMemory();
+ GetShaderSource get_cmd;
+ get_cmd.Init(client_shader_id_, kOutBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(get_cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kOutBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(kSourceSize + 1, bucket->size());
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kSource,
+ bucket->size()));
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceBucketInvalidArgs) {
+ const uint32 kBucketId = 123;
+ const char kSource[] = "hello";
+ const uint32 kSourceSize = sizeof(kSource) - 1;
+ memcpy(shared_memory_address_, kSource, kSourceSize);
+ ShaderSourceBucket cmd;
+ // Test no bucket.
+ cmd.Init(client_texture_id_, kBucketId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ // Test invalid client.
+ SetBucketAsCString(kBucketId, kSource);
+ cmd.Init(kInvalidClientId, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, ShaderSourceStripComments) {
+ const uint32 kInBucketId = 123;
+ const char kSource[] = "hello/*te\ast*/world//a\ab";
+ SetBucketAsCString(kInBucketId, kSource);
+ ShaderSourceBucket cmd;
+ cmd.Init(client_shader_id_, kInBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, GenerateMipmapWrongFormatsFails) {
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(_))
+ .Times(0);
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 16, 17, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_2D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, GenerateMipmapHandlesOutOfMemory) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ TextureManager* manager = group().texture_manager();
+ TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ GLint width = 0;
+ GLint height = 0;
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 2, &width, &height));
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D))
+ .Times(1);
+ EXPECT_CALL(*gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_2D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 2, &width, &height));
+}
+
+TEST_F(GLES2DecoderTest, GenerateMipmapClearsUnclearedTexture) {
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(_))
+ .Times(0);
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ EXPECT_CALL(*gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D));
+ EXPECT_CALL(*gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_2D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1iValidArgs) {
+ EXPECT_CALL(*gl_, Uniform1i(kUniform1RealLocation, 2));
+ Uniform1i cmd;
+ cmd.Init(kUniform1FakeLocation, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform1iv(kUniform1RealLocation, 1,
+ reinterpret_cast<const GLint*>(shared_memory_address_)));
+ Uniform1iv cmd;
+ cmd.Init(kUniform1FakeLocation,
+ 1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
+ Uniform1iv cmd;
+ cmd.Init(kUniform1FakeLocation,
+ 1, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
+ Uniform1iv cmd;
+ cmd.Init(kUniform1FakeLocation,
+ 1, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivImmediateValidArgs) {
+ Uniform1ivImmediate& cmd = *GetImmediateAs<Uniform1ivImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform1iv(kUniform1RealLocation, 1,
+ reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd))));
+ GLint temp[1 * 2] = { 0, };
+ cmd.Init(kUniform1FakeLocation, 1,
+ &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivInvalidValidArgs) {
+ EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
+ Uniform1iv cmd;
+ cmd.Init(kUniform1FakeLocation,
+ 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivZeroCount) {
+ EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
+ Uniform1iv cmd;
+ cmd.Init(kUniform1FakeLocation,
+ 0, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1iSamplerIsLmited) {
+ EXPECT_CALL(*gl_, Uniform1i(_, _)).Times(0);
+ Uniform1i cmd;
+ cmd.Init(
+ kUniform1FakeLocation,
+ kNumTextureUnits);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, Uniform1ivSamplerIsLimited) {
+ EXPECT_CALL(*gl_, Uniform1iv(_, _, _)).Times(0);
+ Uniform1ivImmediate& cmd = *GetImmediateAs<Uniform1ivImmediate>();
+ GLint temp[] = { kNumTextureUnits };
+ cmd.Init(kUniform1FakeLocation, 1,
+ &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, BindBufferToDifferentTargetFails) {
+ // Bind the buffer to GL_ARRAY_BUFFER
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ // Attempt to rebind to GL_ELEMENT_ARRAY_BUFFER
+ // NOTE: Real GLES2 does not have this restriction but WebGL and we do.
+ // This can be restriction can be removed at runtime.
+ EXPECT_CALL(*gl_, BindBuffer(_, _))
+ .Times(0);
+ BindBuffer cmd;
+ cmd.Init(GL_ELEMENT_ARRAY_BUFFER, client_buffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, ActiveTextureValidArgs) {
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE1));
+ SpecializedSetup<ActiveTexture, 0>(true);
+ ActiveTexture cmd;
+ cmd.Init(GL_TEXTURE1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, ActiveTextureInvalidArgs) {
+ EXPECT_CALL(*gl_, ActiveTexture(_)).Times(0);
+ SpecializedSetup<ActiveTexture, 0>(false);
+ ActiveTexture cmd;
+ cmd.Init(GL_TEXTURE0 - 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(kNumTextureUnits);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, CheckFramebufferStatusWithNoBoundTarget) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_))
+ .Times(0);
+ CheckFramebufferStatus::Result* result =
+ static_cast<CheckFramebufferStatus::Result*>(shared_memory_address_);
+ *result = 0;
+ CheckFramebufferStatus cmd;
+ cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, BindAndDeleteFramebuffer) {
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoDeleteFramebuffer(
+ client_framebuffer_id_, kServiceFramebufferId,
+ true, GL_FRAMEBUFFER, 0,
+ true, GL_FRAMEBUFFER, 0);
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, FramebufferRenderbufferWithNoBoundTarget) {
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _))
+ .Times(0);
+ FramebufferRenderbuffer cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, FramebufferTexture2DWithNoBoundTarget) {
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _))
+ .Times(0);
+ FramebufferTexture2D cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
+ 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithNoBoundTarget) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _))
+ .Times(0);
+ GetFramebufferAttachmentParameteriv cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithRenderbuffer) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ GetFramebufferAttachmentParameteriv::Result* result =
+ static_cast<GetFramebufferAttachmentParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ const GLint* result_value = result->GetData();
+ FramebufferRenderbuffer fbrb_cmd;
+ GetFramebufferAttachmentParameteriv cmd;
+ fbrb_cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(static_cast<GLuint>(*result_value), client_renderbuffer_id_);
+}
+
+TEST_F(GLES2DecoderTest, GetFramebufferAttachmentParameterivWithTexture) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kServiceTextureId, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ GetFramebufferAttachmentParameteriv::Result* result =
+ static_cast<GetFramebufferAttachmentParameteriv::Result*>(
+ shared_memory_address_);
+ result->SetNumResults(0);
+ const GLint* result_value = result->GetData();
+ FramebufferTexture2D fbtex_cmd;
+ GetFramebufferAttachmentParameteriv cmd;
+ fbtex_cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
+ 0);
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(static_cast<GLuint>(*result_value), client_texture_id_);
+}
+
+TEST_F(GLES2DecoderTest, GetRenderbufferParameterivWithNoBoundTarget) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetRenderbufferParameterivEXT(_, _, _))
+ .Times(0);
+ GetRenderbufferParameteriv cmd;
+ cmd.Init(
+ GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, RenderbufferStorageWithNoBoundTarget) {
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _))
+ .Times(0);
+ RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+namespace {
+
+// A class to emulate glReadPixels
+class ReadPixelsEmulator {
+ public:
+ // pack_alignment is the alignment you want ReadPixels to use
+ // when copying. The actual data passed in pixels should be contiguous.
+ ReadPixelsEmulator(GLsizei width, GLsizei height, GLint bytes_per_pixel,
+ const void* src_pixels, const void* expected_pixels,
+ GLint pack_alignment)
+ : width_(width),
+ height_(height),
+ pack_alignment_(pack_alignment),
+ bytes_per_pixel_(bytes_per_pixel),
+ src_pixels_(reinterpret_cast<const int8*>(src_pixels)),
+ expected_pixels_(reinterpret_cast<const int8*>(expected_pixels)) {
+ }
+
+ void ReadPixels(
+ GLint x, GLint y, GLsizei width, GLsizei height,
+ GLenum format, GLenum type, void* pixels) const {
+ DCHECK_GE(x, 0);
+ DCHECK_GE(y, 0);
+ DCHECK_LE(x + width, width_);
+ DCHECK_LE(y + height, height_);
+ for (GLint yy = 0; yy < height; ++yy) {
+ const int8* src = GetPixelAddress(src_pixels_, x, y + yy);
+ const void* dst = ComputePackAlignmentAddress(0, yy, width, pixels);
+ memcpy(const_cast<void*>(dst), src, width * bytes_per_pixel_);
+ }
+ }
+
+ bool CompareRowSegment(
+ GLint x, GLint y, GLsizei width, const void* data) const {
+ DCHECK(x + width <= width_ || width == 0);
+ return memcmp(data, GetPixelAddress(expected_pixels_, x, y),
+ width * bytes_per_pixel_) == 0;
+ }
+
+ // Helper to compute address of pixel in pack aligned data.
+ const void* ComputePackAlignmentAddress(
+ GLint x, GLint y, GLsizei width, const void* address) const {
+ GLint unpadded_row_size = ComputeImageDataSize(width, 1);
+ GLint two_rows_size = ComputeImageDataSize(width, 2);
+ GLsizei padded_row_size = two_rows_size - unpadded_row_size;
+ GLint offset = y * padded_row_size + x * bytes_per_pixel_;
+ return static_cast<const int8*>(address) + offset;
+ }
+
+ GLint ComputeImageDataSize(GLint width, GLint height) const {
+ GLint row_size = width * bytes_per_pixel_;
+ if (height > 1) {
+ GLint temp = row_size + pack_alignment_ - 1;
+ GLint padded_row_size = (temp / pack_alignment_) * pack_alignment_;
+ GLint size_of_all_but_last_row = (height - 1) * padded_row_size;
+ return size_of_all_but_last_row + row_size;
+ } else {
+ return height * row_size;
+ }
+ }
+
+ private:
+ const int8* GetPixelAddress(const int8* base, GLint x, GLint y) const {
+ return base + (width_ * y + x) * bytes_per_pixel_;
+ }
+
+ GLsizei width_;
+ GLsizei height_;
+ GLint pack_alignment_;
+ GLint bytes_per_pixel_;
+ const int8* src_pixels_;
+ const int8* expected_pixels_;
+};
+
+} // anonymous namespace
+
+void GLES2DecoderTest::CheckReadPixelsOutOfRange(
+ GLint in_read_x, GLint in_read_y,
+ GLsizei in_read_width, GLsizei in_read_height,
+ bool init) {
+ const GLsizei kWidth = 5;
+ const GLsizei kHeight = 3;
+ const GLint kBytesPerPixel = 3;
+ const GLint kPackAlignment = 4;
+ const GLenum kFormat = GL_RGB;
+ static const int8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = {
+ 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 18, 19, 13,
+ 29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, 22, 21, 28,
+ 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, 37, 32, 34,
+ };
+
+ ClearSharedMemory();
+
+ // We need to setup an FBO so we can know the max size that ReadPixels will
+ // access
+ if (init) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
+ kFormat, GL_UNSIGNED_BYTE, kSharedMemoryId,
+ kSharedMemoryOffset);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ client_texture_id_, kServiceTextureId, 0, GL_NO_ERROR);
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ }
+
+ ReadPixelsEmulator emu(
+ kWidth, kHeight, kBytesPerPixel, kSrcPixels, kSrcPixels, kPackAlignment);
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ void* dest = &result[1];
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ // ReadPixels will be called for valid size only even though the command
+ // is requesting a larger size.
+ GLint read_x = std::max(0, in_read_x);
+ GLint read_y = std::max(0, in_read_y);
+ GLint read_end_x = std::max(0, std::min(kWidth, in_read_x + in_read_width));
+ GLint read_end_y = std::max(0, std::min(kHeight, in_read_y + in_read_height));
+ GLint read_width = read_end_x - read_x;
+ GLint read_height = read_end_y - read_y;
+ if (read_width > 0 && read_height > 0) {
+ for (GLint yy = read_y; yy < read_end_y; ++yy) {
+ EXPECT_CALL(
+ *gl_, ReadPixels(read_x, yy, read_width, 1,
+ kFormat, GL_UNSIGNED_BYTE, _))
+ .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels))
+ .RetiresOnSaturation();
+ }
+ }
+ ReadPixels cmd;
+ cmd.Init(in_read_x, in_read_y, in_read_width, in_read_height,
+ kFormat, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+
+ GLint unpadded_row_size = emu.ComputeImageDataSize(in_read_width, 1);
+ scoped_ptr<int8[]> zero(new int8[unpadded_row_size]);
+ scoped_ptr<int8[]> pack(new int8[kPackAlignment]);
+ memset(zero.get(), 0, unpadded_row_size);
+ memset(pack.get(), kInitialMemoryValue, kPackAlignment);
+ for (GLint yy = 0; yy < in_read_height; ++yy) {
+ const int8* row = static_cast<const int8*>(
+ emu.ComputePackAlignmentAddress(0, yy, in_read_width, dest));
+ GLint y = in_read_y + yy;
+ if (y < 0 || y >= kHeight) {
+ EXPECT_EQ(0, memcmp(zero.get(), row, unpadded_row_size));
+ } else {
+ // check off left.
+ GLint num_left_pixels = std::max(-in_read_x, 0);
+ GLint num_left_bytes = num_left_pixels * kBytesPerPixel;
+ EXPECT_EQ(0, memcmp(zero.get(), row, num_left_bytes));
+
+ // check off right.
+ GLint num_right_pixels = std::max(in_read_x + in_read_width - kWidth, 0);
+ GLint num_right_bytes = num_right_pixels * kBytesPerPixel;
+ EXPECT_EQ(0, memcmp(zero.get(),
+ row + unpadded_row_size - num_right_bytes,
+ num_right_bytes));
+
+ // check middle.
+ GLint x = std::max(in_read_x, 0);
+ GLint num_middle_pixels =
+ std::max(in_read_width - num_left_pixels - num_right_pixels, 0);
+ EXPECT_TRUE(emu.CompareRowSegment(
+ x, y, num_middle_pixels, row + num_left_bytes));
+ }
+
+ // check padding
+ if (yy != in_read_height - 1) {
+ GLint num_padding_bytes =
+ (kPackAlignment - 1) - (unpadded_row_size % kPackAlignment);
+ EXPECT_EQ(0,
+ memcmp(pack.get(), row + unpadded_row_size, num_padding_bytes));
+ }
+ }
+}
+
+TEST_F(GLES2DecoderTest, ReadPixels) {
+ const GLsizei kWidth = 5;
+ const GLsizei kHeight = 3;
+ const GLint kBytesPerPixel = 3;
+ const GLint kPackAlignment = 4;
+ static const int8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = {
+ 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19, 18, 19, 13,
+ 29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21, 22, 21, 28,
+ 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32, 37, 32, 34,
+ };
+
+ surface_->SetSize(gfx::Size(INT_MAX, INT_MAX));
+
+ ReadPixelsEmulator emu(
+ kWidth, kHeight, kBytesPerPixel, kSrcPixels, kSrcPixels, kPackAlignment);
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ void* dest = &result[1];
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *gl_, ReadPixels(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, _))
+ .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels));
+ ReadPixels cmd;
+ cmd.Init(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ for (GLint yy = 0; yy < kHeight; ++yy) {
+ EXPECT_TRUE(emu.CompareRowSegment(
+ 0, yy, kWidth,
+ emu.ComputePackAlignmentAddress(0, yy, kWidth, dest)));
+ }
+}
+
+TEST_F(GLES2DecoderRGBBackbufferTest, ReadPixelsNoAlphaBackbuffer) {
+ const GLsizei kWidth = 3;
+ const GLsizei kHeight = 3;
+ const GLint kBytesPerPixel = 4;
+ const GLint kPackAlignment = 4;
+ static const uint8 kExpectedPixels[kWidth * kHeight * kBytesPerPixel] = {
+ 12, 13, 14, 255, 19, 18, 19, 255, 13, 14, 18, 255,
+ 29, 28, 23, 255, 21, 22, 21, 255, 28, 23, 22, 255,
+ 31, 34, 39, 255, 32, 37, 32, 255, 34, 39, 37, 255,
+ };
+ static const uint8 kSrcPixels[kWidth * kHeight * kBytesPerPixel] = {
+ 12, 13, 14, 18, 19, 18, 19, 12, 13, 14, 18, 19,
+ 29, 28, 23, 22, 21, 22, 21, 29, 28, 23, 22, 21,
+ 31, 34, 39, 37, 32, 37, 32, 31, 34, 39, 37, 32,
+ };
+
+ surface_->SetSize(gfx::Size(INT_MAX, INT_MAX));
+
+ ReadPixelsEmulator emu(
+ kWidth, kHeight, kBytesPerPixel, kSrcPixels, kExpectedPixels,
+ kPackAlignment);
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ void* dest = &result[1];
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *gl_, ReadPixels(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE, _))
+ .WillOnce(Invoke(&emu, &ReadPixelsEmulator::ReadPixels));
+ ReadPixels cmd;
+ cmd.Init(0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ for (GLint yy = 0; yy < kHeight; ++yy) {
+ EXPECT_TRUE(emu.CompareRowSegment(
+ 0, yy, kWidth,
+ emu.ComputePackAlignmentAddress(0, yy, kWidth, dest)));
+ }
+}
+
+TEST_F(GLES2DecoderTest, ReadPixelsOutOfRange) {
+ static GLint tests[][4] = {
+ { -2, -1, 9, 5, }, // out of range on all sides
+ { 2, 1, 9, 5, }, // out of range on right, bottom
+ { -7, -4, 9, 5, }, // out of range on left, top
+ { 0, -5, 9, 5, }, // completely off top
+ { 0, 3, 9, 5, }, // completely off bottom
+ { -9, 0, 9, 5, }, // completely off left
+ { 5, 0, 9, 5, }, // completely off right
+ };
+
+ for (size_t tt = 0; tt < arraysize(tests); ++tt) {
+ CheckReadPixelsOutOfRange(
+ tests[tt][0], tests[tt][1], tests[tt][2], tests[tt][3], tt == 0);
+ }
+}
+
+TEST_F(GLES2DecoderTest, ReadPixelsInvalidArgs) {
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ EXPECT_CALL(*gl_, ReadPixels(_, _, _, _, _, _, _)).Times(0);
+ ReadPixels cmd;
+ cmd.Init(0, 0, -1, 1, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(0, 0, 1, -1, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(0, 0, 1, 1, GL_RGB, GL_INT,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
+ kInvalidSharedMemoryId, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels_shm_id, kInvalidSharedMemoryOffset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ kInvalidSharedMemoryId, result_shm_offset,
+ false);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(0, 0, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, kInvalidSharedMemoryOffset,
+ false);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, BindAttribLocation) {
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ const uint32 kNameSize = strlen(kName);
+ EXPECT_CALL(
+ *gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName)))
+ .Times(1);
+ memcpy(shared_memory_address_, kName, kNameSize);
+ BindAttribLocation cmd;
+ cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, BindAttribLocationInvalidArgs) {
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ const char* kBadName = "test\aing";
+ const uint32 kNameSize = strlen(kName);
+ const uint32 kBadNameSize = strlen(kBadName);
+ EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0);
+ memcpy(shared_memory_address_, kName, kNameSize);
+ BindAttribLocation cmd;
+ cmd.Init(kInvalidClientId, kLocation,
+ kSharedMemoryId, kSharedMemoryOffset, kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(client_program_id_, kLocation,
+ kInvalidSharedMemoryId, kSharedMemoryOffset, kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kLocation,
+ kSharedMemoryId, kInvalidSharedMemoryOffset, kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kLocation,
+ kSharedMemoryId, kSharedMemoryOffset, kSharedBufferSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ memcpy(shared_memory_address_, kBadName, kBadNameSize);
+ cmd.Init(client_program_id_, kLocation,
+ kSharedMemoryId, kSharedMemoryOffset, kBadNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, BindAttribLocationImmediate) {
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ const uint32 kNameSize = strlen(kName);
+ EXPECT_CALL(
+ *gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName)))
+ .Times(1);
+ BindAttribLocationImmediate& cmd =
+ *GetImmediateAs<BindAttribLocationImmediate>();
+ cmd.Init(client_program_id_, kLocation, kName, kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+}
+
+TEST_F(GLES2DecoderTest, BindAttribLocationImmediateInvalidArgs) {
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ const uint32 kNameSize = strlen(kName);
+ EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0);
+ BindAttribLocationImmediate& cmd =
+ *GetImmediateAs<BindAttribLocationImmediate>();
+ cmd.Init(kInvalidClientId, kLocation, kName, kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, BindAttribLocationBucket) {
+ const uint32 kBucketId = 123;
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ EXPECT_CALL(
+ *gl_, BindAttribLocation(kServiceProgramId, kLocation, StrEq(kName)))
+ .Times(1);
+ SetBucketAsCString(kBucketId, kName);
+ BindAttribLocationBucket cmd;
+ cmd.Init(client_program_id_, kLocation, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, BindAttribLocationBucketInvalidArgs) {
+ const uint32 kBucketId = 123;
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ EXPECT_CALL(*gl_, BindAttribLocation(_, _, _)).Times(0);
+ BindAttribLocationBucket cmd;
+ // check bucket does not exist.
+ cmd.Init(client_program_id_, kLocation, kBucketId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ // check bucket is empty.
+ SetBucketAsCString(kBucketId, NULL);
+ cmd.Init(client_program_id_, kLocation, kBucketId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ // Check bad program id
+ SetBucketAsCString(kBucketId, kName);
+ cmd.Init(kInvalidClientId, kLocation, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttribLocation) {
+ const uint32 kNameSize = strlen(kAttrib2Name);
+ const char* kNonExistentName = "foobar";
+ const uint32 kNonExistentNameSize = strlen(kNonExistentName);
+ typedef GetAttribLocation::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
+ const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
+ memcpy(name, kAttrib2Name, kNameSize);
+ GetAttribLocation cmd;
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kAttrib2Location, *result);
+ *result = -1;
+ memcpy(name, kNonExistentName, kNonExistentNameSize);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNonExistentNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationInvalidArgs) {
+ const uint32 kNameSize = strlen(kAttrib2Name);
+ const char* kBadName = "foo\abar";
+ const uint32 kBadNameSize = strlen(kBadName);
+ typedef GetAttribLocation::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
+ const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
+ memcpy(name, kAttrib2Name, kNameSize);
+ GetAttribLocation cmd;
+ cmd.Init(kInvalidClientId,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ *result = -1;
+ cmd.Init(client_program_id_,
+ kInvalidSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kInvalidSharedMemoryOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kInvalidSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kInvalidSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kSharedBufferSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ memcpy(name, kBadName, kBadNameSize);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kBadNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationImmediate) {
+ const uint32 kNameSize = strlen(kAttrib2Name);
+ const char* kNonExistentName = "foobar";
+ const uint32 kNonExistentNameSize = strlen(kNonExistentName);
+ typedef GetAttribLocationImmediate::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ GetAttribLocationImmediate& cmd =
+ *GetImmediateAs<GetAttribLocationImmediate>();
+ cmd.Init(client_program_id_, kAttrib2Name,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(kAttrib2Location, *result);
+ *result = -1;
+ cmd.Init(client_program_id_, kNonExistentName,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNonExistentNameSize));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationImmediateInvalidArgs) {
+ const uint32 kNameSize = strlen(kAttrib2Name);
+ typedef GetAttribLocationImmediate::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ GetAttribLocationImmediate& cmd =
+ *GetImmediateAs<GetAttribLocationImmediate>();
+ cmd.Init(kInvalidClientId, kAttrib2Name,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(-1, *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ *result = -1;
+ cmd.Init(client_program_id_, kAttrib2Name,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_, kAttrib2Name,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationBucket) {
+ const uint32 kBucketId = 123;
+ const char* kNonExistentName = "foobar";
+ typedef GetAttribLocationBucket::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ SetBucketAsCString(kBucketId, kAttrib2Name);
+ *result = -1;
+ GetAttribLocationBucket cmd;
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kAttrib2Location, *result);
+ SetBucketAsCString(kBucketId, kNonExistentName);
+ *result = -1;
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetAttribLocationBucketInvalidArgs) {
+ const uint32 kBucketId = 123;
+ typedef GetAttribLocationBucket::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ GetAttribLocationBucket cmd;
+ // Check no bucket
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ // Check bad program id.
+ SetBucketAsCString(kBucketId, kAttrib2Name);
+ cmd.Init(kInvalidClientId, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ *result = -1;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // Check bad memory
+ cmd.Init(client_program_id_, kBucketId,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformLocation) {
+ const uint32 kNameSize = strlen(kUniform2Name);
+ const char* kNonExistentName = "foobar";
+ const uint32 kNonExistentNameSize = strlen(kNonExistentName);
+ typedef GetUniformLocation::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
+ const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
+ memcpy(name, kUniform2Name, kNameSize);
+ GetUniformLocation cmd;
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kUniform2FakeLocation, *result);
+ memcpy(name, kNonExistentName, kNonExistentNameSize);
+ *result = -1;
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNonExistentNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationInvalidArgs) {
+ const uint32 kNameSize = strlen(kUniform2Name);
+ const char* kBadName = "foo\abar";
+ const uint32 kBadNameSize = strlen(kBadName);
+ typedef GetUniformLocation::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ char* name = GetSharedMemoryAsWithOffset<char*>(sizeof(*result));
+ const uint32 kNameOffset = kSharedMemoryOffset + sizeof(*result);
+ memcpy(name, kUniform2Name, kNameSize);
+ GetUniformLocation cmd;
+ cmd.Init(kInvalidClientId,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ *result = -1;
+ cmd.Init(client_program_id_,
+ kInvalidSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kInvalidSharedMemoryOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kInvalidSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kInvalidSharedMemoryOffset,
+ kNameSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kSharedBufferSize);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ memcpy(name, kBadName, kBadNameSize);
+ cmd.Init(client_program_id_,
+ kSharedMemoryId, kNameOffset,
+ kSharedMemoryId, kSharedMemoryOffset,
+ kBadNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationImmediate) {
+ const uint32 kNameSize = strlen(kUniform2Name);
+ const char* kNonExistentName = "foobar";
+ const uint32 kNonExistentNameSize = strlen(kNonExistentName);
+ typedef GetUniformLocationImmediate::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ GetUniformLocationImmediate& cmd =
+ *GetImmediateAs<GetUniformLocationImmediate>();
+ cmd.Init(client_program_id_, kUniform2Name,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(kUniform2FakeLocation, *result);
+ *result = -1;
+ cmd.Init(client_program_id_, kNonExistentName,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNonExistentNameSize));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationImmediateInvalidArgs) {
+ const uint32 kNameSize = strlen(kUniform2Name);
+ typedef GetUniformLocationImmediate::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ GetUniformLocationImmediate& cmd =
+ *GetImmediateAs<GetUniformLocationImmediate>();
+ cmd.Init(kInvalidClientId, kUniform2Name,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(-1, *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ *result = -1;
+ cmd.Init(client_program_id_, kUniform2Name,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(-1, *result);
+ cmd.Init(client_program_id_, kUniform2Name,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteImmediateCmd(cmd, kNameSize));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationBucket) {
+ const uint32 kBucketId = 123;
+ const char* kNonExistentName = "foobar";
+ typedef GetUniformLocationBucket::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ SetBucketAsCString(kBucketId, kUniform2Name);
+ *result = -1;
+ GetUniformLocationBucket cmd;
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kUniform2FakeLocation, *result);
+ SetBucketAsCString(kBucketId, kNonExistentName);
+ *result = -1;
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetUniformLocationBucketInvalidArgs) {
+ const uint32 kBucketId = 123;
+ typedef GetUniformLocationBucket::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ *result = -1;
+ GetUniformLocationBucket cmd;
+ // Check no bucket
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ // Check bad program id.
+ SetBucketAsCString(kBucketId, kUniform2Name);
+ cmd.Init(kInvalidClientId, kBucketId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ *result = -1;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(-1, *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // Check bad memory
+ cmd.Init(client_program_id_, kBucketId,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, kBucketId,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetMaxValueInBufferCHROMIUM) {
+ SetupIndexBuffer();
+ GetMaxValueInBufferCHROMIUM::Result* result =
+ static_cast<GetMaxValueInBufferCHROMIUM::Result*>(shared_memory_address_);
+ *result = 0;
+
+ GetMaxValueInBufferCHROMIUM cmd;
+ cmd.Init(client_element_buffer_id_, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(7u, *result);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(100u, *result);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(kInvalidClientId, kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(client_element_buffer_id_, kOutOfRangeIndexRangeEnd,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
+ GL_UNSIGNED_SHORT,
+ kOutOfRangeIndexRangeEnd * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_buffer_id_, kValidIndexRangeCount + 1,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(client_element_buffer_id_, kValidIndexRangeCount + 1,
+ GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, SharedIds) {
+ GenSharedIdsCHROMIUM gen_cmd;
+ RegisterSharedIdsCHROMIUM reg_cmd;
+ DeleteSharedIdsCHROMIUM del_cmd;
+
+ const GLuint kNamespaceId = id_namespaces::kTextures;
+ const GLuint kExpectedId1 = 1;
+ const GLuint kExpectedId2 = 2;
+ const GLuint kExpectedId3 = 4;
+ const GLuint kRegisterId = 3;
+ GLuint* ids = GetSharedMemoryAs<GLuint*>();
+ gen_cmd.Init(kNamespaceId, 0, 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd));
+ IdAllocatorInterface* id_allocator = GetIdAllocator(kNamespaceId);
+ ASSERT_TRUE(id_allocator != NULL);
+ // This check is implementation dependant but it's kind of hard to check
+ // otherwise.
+ EXPECT_EQ(kExpectedId1, ids[0]);
+ EXPECT_EQ(kExpectedId2, ids[1]);
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId1));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
+ EXPECT_FALSE(id_allocator->InUse(kRegisterId));
+ EXPECT_FALSE(id_allocator->InUse(kExpectedId3));
+
+ ClearSharedMemory();
+ ids[0] = kRegisterId;
+ reg_cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(reg_cmd));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId1));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
+ EXPECT_TRUE(id_allocator->InUse(kRegisterId));
+ EXPECT_FALSE(id_allocator->InUse(kExpectedId3));
+
+ ClearSharedMemory();
+ gen_cmd.Init(kNamespaceId, 0, 1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd));
+ EXPECT_EQ(kExpectedId3, ids[0]);
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId1));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
+ EXPECT_TRUE(id_allocator->InUse(kRegisterId));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId3));
+
+ ClearSharedMemory();
+ ids[0] = kExpectedId1;
+ ids[1] = kRegisterId;
+ del_cmd.Init(kNamespaceId, 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(del_cmd));
+ EXPECT_FALSE(id_allocator->InUse(kExpectedId1));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId2));
+ EXPECT_FALSE(id_allocator->InUse(kRegisterId));
+ EXPECT_TRUE(id_allocator->InUse(kExpectedId3));
+
+ ClearSharedMemory();
+ ids[0] = kExpectedId3;
+ ids[1] = kExpectedId2;
+ del_cmd.Init(kNamespaceId, 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(del_cmd));
+ EXPECT_FALSE(id_allocator->InUse(kExpectedId1));
+ EXPECT_FALSE(id_allocator->InUse(kExpectedId2));
+ EXPECT_FALSE(id_allocator->InUse(kRegisterId));
+ EXPECT_FALSE(id_allocator->InUse(kExpectedId3));
+
+ // Check passing in an id_offset.
+ ClearSharedMemory();
+ const GLuint kOffset = 0xABCDEF;
+ gen_cmd.Init(kNamespaceId, kOffset, 2, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(gen_cmd));
+ EXPECT_EQ(kOffset, ids[0]);
+ EXPECT_EQ(kOffset + 1, ids[1]);
+}
+
+TEST_F(GLES2DecoderTest, GenSharedIdsCHROMIUMBadArgs) {
+ const GLuint kNamespaceId = id_namespaces::kTextures;
+ GenSharedIdsCHROMIUM cmd;
+ cmd.Init(kNamespaceId, 0, -1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 0, 1, kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 0, 1, kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, RegisterSharedIdsCHROMIUMBadArgs) {
+ const GLuint kNamespaceId = id_namespaces::kTextures;
+ RegisterSharedIdsCHROMIUM cmd;
+ cmd.Init(kNamespaceId, -1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 1, kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 1, kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, RegisterSharedIdsCHROMIUMDuplicateIds) {
+ const GLuint kNamespaceId = id_namespaces::kTextures;
+ const GLuint kRegisterId = 3;
+ RegisterSharedIdsCHROMIUM cmd;
+ GLuint* ids = GetSharedMemoryAs<GLuint*>();
+ ids[0] = kRegisterId;
+ cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, DeleteSharedIdsCHROMIUMBadArgs) {
+ const GLuint kNamespaceId = id_namespaces::kTextures;
+ DeleteSharedIdsCHROMIUM cmd;
+ cmd.Init(kNamespaceId, -1, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 1, kInvalidSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(kNamespaceId, 1, kSharedMemoryId, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, TexSubImage2DValidArgs) {
+ const int kWidth = 16;
+ const int kHeight = 8;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 1, 1, 0, kWidth - 1, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, TexSubImage2DBadArgs) {
+ const int kWidth = 16;
+ const int kHeight = 8;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ TexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE0, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_TRUE, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_INT,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, -1, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 1, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, -1, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 1, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth + 1, kHeight, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight + 1, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA,
+ GL_UNSIGNED_SHORT_4_4_4_4, kSharedMemoryId, kSharedMemoryOffset,
+ GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kInvalidSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, kWidth, kHeight, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kInvalidSharedMemoryOffset, GL_FALSE);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, CopyTexSubImage2DValidArgs) {
+ const int kWidth = 16;
+ const int kHeight = 8;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(
+ GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight))
+ .Times(1)
+ .RetiresOnSaturation();
+ CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, CopyTexSubImage2DBadArgs) {
+ const int kWidth = 16;
+ const int kHeight = 8;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 1, GL_RGBA, kWidth, kHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE0, 1, 0, 0, 0, 0, kWidth, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, -1, 0, 0, 0, kWidth, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 1, 0, 0, 0, kWidth, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, -1, 0, 0, kWidth, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 1, 0, 0, kWidth, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth + 1, kHeight);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_TEXTURE_2D, 1, 0, 0, 0, 0, kWidth, kHeight + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+// Check that if a renderbuffer is attached and GL returns
+// GL_FRAMEBUFFER_COMPLETE that the buffer is cleared and state is restored.
+TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearColor) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ ClearColor color_cmd;
+ ColorMask color_mask_cmd;
+ Enable enable_cmd;
+ FramebufferRenderbuffer cmd;
+ color_cmd.Init(0.1f, 0.2f, 0.3f, 0.4f);
+ color_mask_cmd.Init(0, 1, 0, 1);
+ enable_cmd.Init(GL_SCISSOR_TEST);
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ InSequence sequence;
+ EXPECT_CALL(*gl_, ClearColor(0.1f, 0.2f, 0.3f, 0.4f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(color_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(color_mask_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepth) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ ClearDepthf depth_cmd;
+ DepthMask depth_mask_cmd;
+ FramebufferRenderbuffer cmd;
+ depth_cmd.Init(0.5f);
+ depth_mask_cmd.Init(false);
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ InSequence sequence;
+ EXPECT_CALL(*gl_, ClearDepth(0.5f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(depth_mask_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearStencil) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ ClearStencil stencil_cmd;
+ StencilMaskSeparate stencil_mask_separate_cmd;
+ FramebufferRenderbuffer cmd;
+ stencil_cmd.Init(123);
+ stencil_mask_separate_cmd.Init(GL_BACK, 0x1234u);
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ InSequence sequence;
+ EXPECT_CALL(*gl_, ClearStencil(123))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_mask_separate_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, IsBuffer) {
+ EXPECT_FALSE(DoIsBuffer(client_buffer_id_));
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ EXPECT_TRUE(DoIsBuffer(client_buffer_id_));
+ DoDeleteBuffer(client_buffer_id_, kServiceBufferId);
+ EXPECT_FALSE(DoIsBuffer(client_buffer_id_));
+}
+
+TEST_F(GLES2DecoderTest, IsFramebuffer) {
+ EXPECT_FALSE(DoIsFramebuffer(client_framebuffer_id_));
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_TRUE(DoIsFramebuffer(client_framebuffer_id_));
+ DoDeleteFramebuffer(
+ client_framebuffer_id_, kServiceFramebufferId,
+ true, GL_FRAMEBUFFER, 0,
+ true, GL_FRAMEBUFFER, 0);
+ EXPECT_FALSE(DoIsFramebuffer(client_framebuffer_id_));
+}
+
+TEST_F(GLES2DecoderTest, IsProgram) {
+ // IsProgram is true as soon as the program is created.
+ EXPECT_TRUE(DoIsProgram(client_program_id_));
+ EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ DoDeleteProgram(client_program_id_, kServiceProgramId);
+ EXPECT_FALSE(DoIsProgram(client_program_id_));
+
+}
+
+TEST_F(GLES2DecoderTest, IsRenderbuffer) {
+ EXPECT_FALSE(DoIsRenderbuffer(client_renderbuffer_id_));
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ EXPECT_TRUE(DoIsRenderbuffer(client_renderbuffer_id_));
+ DoDeleteRenderbuffer(client_renderbuffer_id_, kServiceRenderbufferId);
+ EXPECT_FALSE(DoIsRenderbuffer(client_renderbuffer_id_));
+}
+
+TEST_F(GLES2DecoderTest, IsShader) {
+ // IsShader is true as soon as the program is created.
+ EXPECT_TRUE(DoIsShader(client_shader_id_));
+ DoDeleteShader(client_shader_id_, kServiceShaderId);
+ EXPECT_FALSE(DoIsShader(client_shader_id_));
+}
+
+TEST_F(GLES2DecoderTest, IsTexture) {
+ EXPECT_FALSE(DoIsTexture(client_texture_id_));
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ EXPECT_TRUE(DoIsTexture(client_texture_id_));
+ DoDeleteTexture(client_texture_id_, kServiceTextureId);
+ EXPECT_FALSE(DoIsTexture(client_texture_id_));
+}
+
+#if 0 // Turn this test on once we allow GL_DEPTH_STENCIL_ATTACHMENT
+TEST_F(GLES2DecoderTest, FramebufferRenderbufferClearDepthStencil) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ ClearDepthf depth_cmd;
+ ClearStencil stencil_cmd;
+ FramebufferRenderbuffer cmd;
+ depth_cmd.Init(0.5f);
+ stencil_cmd.Init(123);
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ InSequence sequence;
+ EXPECT_CALL(*gl_, ClearDepth(0.5f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearStencil(123))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(depth_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(stencil_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+#endif
+
+TEST_F(GLES2DecoderWithShaderTest, VertexAttribPointer) {
+ SetupVertexBuffer();
+ static const GLenum types[] = {
+ GL_BYTE,
+ GL_UNSIGNED_BYTE,
+ GL_SHORT,
+ GL_UNSIGNED_SHORT,
+ GL_FLOAT,
+ GL_FIXED,
+ GL_INT,
+ GL_UNSIGNED_INT,
+ };
+ static const GLsizei sizes[] = {
+ 1,
+ 1,
+ 2,
+ 2,
+ 4,
+ 4,
+ 4,
+ 4,
+ };
+ static const GLuint indices[] = {
+ 0,
+ 1,
+ kNumVertexAttribs - 1,
+ kNumVertexAttribs,
+ };
+ static const GLsizei offset_mult[] = {
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 1000,
+ };
+ static const GLsizei offset_offset[] = {
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ };
+ static const GLsizei stride_mult[] = {
+ -1,
+ 0,
+ 0,
+ 1,
+ 1,
+ 2,
+ 1000,
+ };
+ static const GLsizei stride_offset[] = {
+ 0,
+ 0,
+ 1,
+ 0,
+ 1,
+ 0,
+ 0,
+ };
+ for (size_t tt = 0; tt < arraysize(types); ++tt) {
+ GLenum type = types[tt];
+ GLsizei num_bytes = sizes[tt];
+ for (size_t ii = 0; ii < arraysize(indices); ++ii) {
+ GLuint index = indices[ii];
+ for (GLint size = 0; size < 5; ++size) {
+ for (size_t oo = 0; oo < arraysize(offset_mult); ++oo) {
+ GLuint offset = num_bytes * offset_mult[oo] + offset_offset[oo];
+ for (size_t ss = 0; ss < arraysize(stride_mult); ++ss) {
+ GLsizei stride = num_bytes * stride_mult[ss] + stride_offset[ss];
+ for (int normalize = 0; normalize < 2; ++normalize) {
+ bool index_good = index < static_cast<GLuint>(kNumVertexAttribs);
+ bool size_good = (size > 0 && size < 5);
+ bool offset_good = (offset % num_bytes == 0);
+ bool stride_good = (stride % num_bytes == 0) && stride >= 0 &&
+ stride <= 255;
+ bool type_good = (type != GL_INT && type != GL_UNSIGNED_INT &&
+ type != GL_FIXED);
+ bool good = size_good && offset_good && stride_good &&
+ type_good && index_good;
+ bool call = good && (type != GL_FIXED);
+ if (call) {
+ EXPECT_CALL(*gl_, VertexAttribPointer(
+ index, size, type, normalize, stride,
+ BufferOffset(offset)));
+ }
+ VertexAttribPointer cmd;
+ cmd.Init(index, size, type, normalize, stride, offset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ if (good) {
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ } else if (size_good &&
+ offset_good &&
+ stride_good &&
+ type_good &&
+ !index_good) {
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ } else if (size_good &&
+ offset_good &&
+ stride_good &&
+ !type_good &&
+ index_good) {
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ } else if (size_good &&
+ offset_good &&
+ !stride_good &&
+ type_good &&
+ index_good) {
+ if (stride < 0 || stride > 255) {
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ } else {
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ }
+ } else if (size_good &&
+ !offset_good &&
+ stride_good &&
+ type_good &&
+ index_good) {
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ } else if (!size_good &&
+ offset_good &&
+ stride_good &&
+ type_good &&
+ index_good) {
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ } else {
+ EXPECT_NE(GL_NO_ERROR, GetGLError());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Test that with an RGB backbuffer if we set the color mask to 1,1,1,1 it is
+// set to 1,1,1,0 at Draw time but is 1,1,1,1 at query time.
+TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMask) {
+ ColorMask cmd;
+ cmd.Init(true, true, true, true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_COLOR_WRITEMASK, result->GetData()))
+ .Times(0);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_COLOR_WRITEMASK, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_COLOR_WRITEMASK),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, result->GetData()[0]);
+ EXPECT_EQ(1, result->GetData()[1]);
+ EXPECT_EQ(1, result->GetData()[2]);
+ EXPECT_EQ(1, result->GetData()[3]);
+}
+
+// Test that with no depth if we set DepthMask true that it's set to false at
+// draw time but querying it returns true.
+TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferDepthMask) {
+ EXPECT_CALL(*gl_, DepthMask(true))
+ .Times(0)
+ .RetiresOnSaturation();
+ DepthMask cmd;
+ cmd.Init(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_WRITEMASK, result->GetData()))
+ .Times(0);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_DEPTH_WRITEMASK, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_WRITEMASK),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, result->GetData()[0]);
+}
+
+// Test that with no stencil if we set the stencil mask it's still set to 0 at
+// draw time but gets our value if we query.
+TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferStencilMask) {
+ const GLint kMask = 123;
+ EXPECT_CALL(*gl_, StencilMask(kMask))
+ .Times(0)
+ .RetiresOnSaturation();
+ StencilMask cmd;
+ cmd.Init(kMask);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_WRITEMASK, result->GetData()))
+ .Times(0);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_WRITEMASK, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_WRITEMASK),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(kMask, result->GetData()[0]);
+}
+
+// Test that if an FBO is bound we get the correct masks.
+TEST_F(GLES2DecoderRGBBackbufferTest, RGBBackbufferColorMaskFBO) {
+ ColorMask cmd;
+ cmd.Init(true, true, true, true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupTexture();
+ SetupVertexBuffer();
+ DoEnableVertexAttribArray(0);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoEnableVertexAttribArray(1);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ DoEnableVertexAttribArray(2);
+ DoVertexAttribPointer(2, 2, GL_FLOAT, 0, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Check that no extra calls are made on the next draw.
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Setup Frame buffer.
+ // needs to be 1x1 or else it's not renderable.
+ const GLsizei kWidth = 1;
+ const GLsizei kHeight = 1;
+ const GLenum kFormat = GL_RGB;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Pass some data so the texture will be marked as cleared.
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
+ kFormat, GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ client_texture_id_, kServiceTextureId, 0, GL_NO_ERROR);
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+
+ // This time state needs to be set.
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Check that no extra calls are made on the next draw.
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Unbind
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0);
+
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, ActualAlphaMatchesRequestedAlpha) {
+ InitDecoder(
+ "", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ true, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_ALPHA_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_ALPHA_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(8, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ActualAlphaDoesNotMatchRequestedAlpha) {
+ InitDecoder(
+ "", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_ALPHA_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_ALPHA_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(0, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ActualDepthMatchesRequestedDepth) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ true, // has depth
+ false, // has stencil
+ false, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(24))
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(24, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ActualDepthDoesNotMatchRequestedDepth) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ true, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(24))
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(0, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ActualStencilMatchesRequestedStencil) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ true, // has stencil
+ false, // request alpha
+ false, // request depth
+ true, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(8, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ActualStencilDoesNotMatchRequestedStencil) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ true, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(0, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, DepthEnableWithDepth) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ true, // has depth
+ false, // has stencil
+ false, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ Enable cmd;
+ cmd.Init(GL_DEPTH_TEST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupDefaultProgram();
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ true, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ true, // depth mask
+ true, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_TEST, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_DEPTH_TEST, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_TEST),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, DepthEnableWithoutRequestedDepth) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ true, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ Enable cmd;
+ cmd.Init(GL_DEPTH_TEST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupDefaultProgram();
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_TEST, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_DEPTH_TEST, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_TEST),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, StencilEnableWithStencil) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ true, // has stencil
+ false, // request alpha
+ false, // request depth
+ true, // request stencil
+ true); // bind generates resource
+
+ Enable cmd;
+ cmd.Init(GL_STENCIL_TEST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupDefaultProgram();
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ true, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ -1, // front stencil mask
+ -1, // back stencil mask
+ true, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_TEST, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_TEST, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_TEST),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, StencilEnableWithoutRequestedStencil) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ true, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ Enable cmd;
+ cmd.Init(GL_STENCIL_TEST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupDefaultProgram();
+ SetupTexture();
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ true, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1110, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays draw_cmd;
+ draw_cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(draw_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_TEST, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_TEST, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_TEST),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilReportsCorrectValues) {
+ InitDecoder(
+ "GL_OES_packed_depth_stencil", // extensions
+ false, // has alpha
+ true, // has depth
+ true, // has stencil
+ false, // request alpha
+ true, // request depth
+ true, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(8, result->GetData()[0]);
+ result->size = 0;
+ cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(24))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(24, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilNoRequestedStencil) {
+ InitDecoder(
+ "GL_OES_packed_depth_stencil", // extensions
+ false, // has alpha
+ true, // has depth
+ true, // has stencil
+ false, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(0, result->GetData()[0]);
+ result->size = 0;
+ cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(24))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(24, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferDepth) {
+ InitDecoder(
+ "GL_OES_packed_depth_stencil", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR)) // for RenderbufferStoage
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR)) // for FramebufferRenderbuffer
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(
+ GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50))
+ .Times(1)
+ .RetiresOnSaturation();
+ RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ FramebufferRenderbuffer fbrb_cmd;
+ fbrb_cmd.Init(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd));
+
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(0, result->GetData()[0]);
+ result->size = 0;
+ cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(24))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(24, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, PackedDepthStencilRenderbufferStencil) {
+ InitDecoder(
+ "GL_OES_packed_depth_stencil", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR)) // for RenderbufferStoage
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR)) // for FramebufferRenderbuffer
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR)) // for GetIntegerv
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(
+ GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50))
+ .Times(1)
+ .RetiresOnSaturation();
+ RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 100, 50);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ FramebufferRenderbuffer fbrb_cmd;
+ fbrb_cmd.Init(
+ GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(fbrb_cmd));
+
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ GetIntegerv cmd2;
+ cmd2.Init(GL_STENCIL_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(8))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_STENCIL_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(8, result->GetData()[0]);
+ result->size = 0;
+ cmd2.Init(GL_DEPTH_BITS, shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(24))
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(
+ decoder_->GetGLES2Util()->GLGetNumValuesReturned(GL_DEPTH_BITS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(0, result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderTest, GetMultipleIntegervCHROMIUMValidArgs) {
+ const GLsizei kCount = 3;
+ GLenum* pnames = GetSharedMemoryAs<GLenum*>();
+ pnames[0] = GL_DEPTH_WRITEMASK;
+ pnames[1] = GL_COLOR_WRITEMASK;
+ pnames[2] = GL_STENCIL_WRITEMASK;
+ GLint* results =
+ GetSharedMemoryAsWithOffset<GLint*>(sizeof(*pnames) * kCount);
+
+ GLsizei num_results = 0;
+ for (GLsizei ii = 0; ii < kCount; ++ii) {
+ num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]);
+ }
+ const GLsizei result_size = num_results * sizeof(*results);
+ memset(results, 0, result_size);
+
+ const GLint kSentinel = 0x12345678;
+ results[num_results] = kSentinel;
+
+ GetMultipleIntegervCHROMIUM cmd;
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset, kCount,
+ kSharedMemoryId, kSharedMemoryOffset + sizeof(*pnames) * kCount,
+ result_size);
+
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(1, results[0]); // Depth writemask
+ EXPECT_EQ(1, results[1]); // color writemask red
+ EXPECT_EQ(1, results[2]); // color writemask green
+ EXPECT_EQ(1, results[3]); // color writemask blue
+ EXPECT_EQ(1, results[4]); // color writemask alpha
+ EXPECT_EQ(-1, results[5]); // stencil writemask alpha
+ EXPECT_EQ(kSentinel, results[num_results]); // End of results
+}
+
+TEST_F(GLES2DecoderTest, GetMultipleIntegervCHROMIUMInvalidArgs) {
+ const GLsizei kCount = 3;
+ // Offset the pnames because GLGetError will use the first uint32.
+ const uint32 kPnameOffset = sizeof(uint32);
+ const uint32 kResultsOffset = kPnameOffset + sizeof(GLint) * kCount;
+ GLenum* pnames = GetSharedMemoryAsWithOffset<GLenum*>(kPnameOffset);
+ pnames[0] = GL_DEPTH_WRITEMASK;
+ pnames[1] = GL_COLOR_WRITEMASK;
+ pnames[2] = GL_STENCIL_WRITEMASK;
+ GLint* results = GetSharedMemoryAsWithOffset<GLint*>(kResultsOffset);
+
+ GLsizei num_results = 0;
+ for (GLsizei ii = 0; ii < kCount; ++ii) {
+ num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]);
+ }
+ const GLsizei result_size = num_results * sizeof(*results);
+ memset(results, 0, result_size);
+
+ const GLint kSentinel = 0x12345678;
+ results[num_results] = kSentinel;
+
+ GetMultipleIntegervCHROMIUM cmd;
+ // Check bad pnames pointer.
+ cmd.Init(
+ kInvalidSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount,
+ kSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check bad pnames pointer.
+ cmd.Init(
+ kSharedMemoryId, kInvalidSharedMemoryOffset, kCount,
+ kSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check bad count.
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, -1,
+ kSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check bad results pointer.
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount,
+ kInvalidSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check bad results pointer.
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount,
+ kSharedMemoryId, kInvalidSharedMemoryOffset,
+ result_size);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check bad size.
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount,
+ kSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // Check bad size.
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount,
+ kSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size - 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // Check bad enum.
+ cmd.Init(
+ kSharedMemoryId, kSharedMemoryOffset + kPnameOffset, kCount,
+ kSharedMemoryId, kSharedMemoryOffset + kResultsOffset,
+ result_size);
+ GLenum temp = pnames[2];
+ pnames[2] = GL_TRUE;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+ pnames[2] = temp;
+ // Check results area has not been cleared by client.
+ results[1] = 1;
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+ // Check buffer is what we expect
+ EXPECT_EQ(0, results[0]);
+ EXPECT_EQ(1, results[1]);
+ EXPECT_EQ(0, results[2]);
+ EXPECT_EQ(0, results[3]);
+ EXPECT_EQ(0, results[4]);
+ EXPECT_EQ(0, results[5]);
+ EXPECT_EQ(kSentinel, results[num_results]); // End of results
+}
+
+TEST_F(GLES2DecoderTest, TexImage2DRedefinitionSucceeds) {
+ const int kWidth = 16;
+ const int kHeight = 8;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillRepeatedly(Return(GL_NO_ERROR));
+ for (int ii = 0; ii < 2; ++ii) {
+ TexImage2D cmd;
+ if (ii == 0) {
+ EXPECT_CALL(*gl_, TexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmd.Init(
+ GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+ } else {
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, kWidth, kHeight);
+ cmd.Init(
+ GL_TEXTURE_2D, 0, GL_RGBA, kWidth, kHeight, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, 0, 0);
+ }
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ // Consider this TexSubImage2D command part of the previous TexImage2D
+ // (last GL_TRUE argument). It will be skipped if there are bugs in the
+ // redefinition case.
+ TexSubImage2D cmd2;
+ cmd2.Init(
+ GL_TEXTURE_2D, 0, 0, 0, kWidth, kHeight - 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_TRUE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ }
+}
+
+TEST_F(GLES2DecoderTest, TexImage2DGLError) {
+ GLenum target = GL_TEXTURE_2D;
+ GLint level = 0;
+ GLenum internal_format = GL_RGBA;
+ GLsizei width = 2;
+ GLsizei height = 4;
+ GLint border = 0;
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_BYTE;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ TextureManager* manager = group().texture_manager();
+ TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height));
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, TexImage2D(target, level, internal_format,
+ width, height, border, format, type, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexImage2D cmd;
+ cmd.Init(target, level, internal_format, width, height, border, format,
+ type, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height));
+}
+
+TEST_F(GLES2DecoderTest, BufferDataGLError) {
+ GLenum target = GL_ARRAY_BUFFER;
+ GLsizeiptr size = 4;
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ BufferManager* manager = group().buffer_manager();
+ Buffer* buffer = manager->GetBuffer(client_buffer_id_);
+ ASSERT_TRUE(buffer != NULL);
+ EXPECT_EQ(0, buffer->size());
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BufferData(target, size, _, GL_STREAM_DRAW))
+ .Times(1)
+ .RetiresOnSaturation();
+ BufferData cmd;
+ cmd.Init(target, size, 0, 0, GL_STREAM_DRAW);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_EQ(0, buffer->size());
+}
+
+TEST_F(GLES2DecoderTest, CopyTexImage2DGLError) {
+ GLenum target = GL_TEXTURE_2D;
+ GLint level = 0;
+ GLenum internal_format = GL_RGBA;
+ GLsizei width = 2;
+ GLsizei height = 4;
+ GLint border = 0;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ TextureManager* manager = group().texture_manager();
+ TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height));
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CopyTexImage2D(
+ target, level, internal_format, 0, 0, width, height, border))
+ .Times(1)
+ .RetiresOnSaturation();
+ CopyTexImage2D cmd;
+ cmd.Init(target, level, internal_format, 0, 0, width, height, border);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, level, &width, &height));
+}
+
+TEST_F(GLES2DecoderTest, FramebufferRenderbufferGLError) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ kServiceRenderbufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ FramebufferRenderbuffer cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, FramebufferTexture2DGLError) {
+ const GLsizei kWidth = 5;
+ const GLsizei kHeight = 3;
+ const GLenum kFormat = GL_RGB;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, kFormat, kWidth, kHeight, 0,
+ kFormat, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kServiceTextureId, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ FramebufferTexture2D fbtex_cmd;
+ fbtex_cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
+ 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(fbtex_cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, RenderbufferStorageGLError) {
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(
+ GL_RENDERBUFFER, GL_RGBA, 100, 50))
+ .Times(1)
+ .RetiresOnSaturation();
+ RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 100, 50);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, RenderbufferStorageBadArgs) {
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, TestHelper::kMaxRenderbufferSize + 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 1, TestHelper::kMaxRenderbufferSize + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, RenderbufferStorageMultisampleGLError) {
+ InitDecoder(
+ "GL_EXT_framebuffer_multisample", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, RenderbufferStorageMultisampleEXT(
+ GL_RENDERBUFFER, 1, GL_RGBA, 100, 50))
+ .Times(1)
+ .RetiresOnSaturation();
+ RenderbufferStorageMultisampleEXT cmd;
+ cmd.Init(GL_RENDERBUFFER, 1, GL_RGBA4, 100, 50);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, RenderbufferStorageMultisampleBadArgs) {
+ InitDecoder(
+ "GL_EXT_framebuffer_multisample", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ EXPECT_CALL(*gl_, RenderbufferStorageMultisampleEXT(_, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ RenderbufferStorageMultisampleEXT cmd;
+ cmd.Init(GL_RENDERBUFFER, TestHelper::kMaxSamples + 1,
+ GL_RGBA4, TestHelper::kMaxRenderbufferSize, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_RENDERBUFFER, TestHelper::kMaxSamples,
+ GL_RGBA4, TestHelper::kMaxRenderbufferSize + 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ cmd.Init(GL_RENDERBUFFER, TestHelper::kMaxSamples,
+ GL_RGBA4, 1, TestHelper::kMaxRenderbufferSize + 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, ReadPixelsGLError) {
+ GLenum kFormat = GL_RGBA;
+ GLint x = 0;
+ GLint y = 0;
+ GLsizei width = 2;
+ GLsizei height = 4;
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_OUT_OF_MEMORY))
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *gl_, ReadPixels(x, y, width, height, kFormat, GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ ReadPixels cmd;
+ cmd.Init(x, y, width, height, kFormat, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+static bool ValueInArray(GLint value, GLint* array, GLint count) {
+ for (GLint ii = 0; ii < count; ++ii) {
+ if (array[ii] == value) {
+ return true;
+ }
+ }
+ return false;
+}
+
+TEST_F(GLES2DecoderManualInitTest, GetCompressedTextureFormats) {
+ InitDecoder(
+ "GL_EXT_texture_compression_s3tc", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ GetIntegerv cmd;
+ result->size = 0;
+ EXPECT_CALL(*gl_, GetIntegerv(_, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ cmd.Init(
+ GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(1, result->GetNumResults());
+ GLint num_formats = result->GetData()[0];
+ EXPECT_EQ(4, num_formats);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ result->size = 0;
+ cmd.Init(
+ GL_COMPRESSED_TEXTURE_FORMATS,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(num_formats, result->GetNumResults());
+
+ EXPECT_TRUE(ValueInArray(
+ GL_COMPRESSED_RGB_S3TC_DXT1_EXT,
+ result->GetData(), result->GetNumResults()));
+ EXPECT_TRUE(ValueInArray(
+ GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
+ result->GetData(), result->GetNumResults()));
+ EXPECT_TRUE(ValueInArray(
+ GL_COMPRESSED_RGBA_S3TC_DXT3_EXT,
+ result->GetData(), result->GetNumResults()));
+ EXPECT_TRUE(ValueInArray(
+ GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
+ result->GetData(), result->GetNumResults()));
+
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, GetNoCompressedTextureFormats) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ GetIntegerv cmd;
+ result->size = 0;
+ EXPECT_CALL(*gl_, GetIntegerv(_, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ cmd.Init(
+ GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(1, result->GetNumResults());
+ GLint num_formats = result->GetData()[0];
+ EXPECT_EQ(0, num_formats);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ result->size = 0;
+ cmd.Init(
+ GL_COMPRESSED_TEXTURE_FORMATS,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(num_formats, result->GetNumResults());
+
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, CompressedTexImage2DBucketBadBucket) {
+ InitDecoder(
+ "GL_EXT_texture_compression_s3tc", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ const uint32 kBadBucketId = 123;
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ CompressedTexImage2DBucket cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 4, 4, 0,
+ kBadBucketId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+ CompressedTexSubImage2DBucket cmd2;
+ cmd2.Init(
+ GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT,
+ kBadBucketId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+namespace {
+
+struct S3TCTestData {
+ GLenum format;
+ size_t block_size;
+};
+
+} // anonymous namespace.
+
+TEST_F(GLES2DecoderManualInitTest, CompressedTexImage2DS3TC) {
+ InitDecoder(
+ "GL_EXT_texture_compression_s3tc", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ const uint32 kBucketId = 123;
+ CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ static const S3TCTestData test_data[] = {
+ { GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 8, },
+ { GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 8, },
+ { GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, 16, },
+ { GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, 16, },
+ };
+
+ for (size_t ii = 0; ii < arraysize(test_data); ++ii) {
+ const S3TCTestData& test = test_data[ii];
+ CompressedTexImage2DBucket cmd;
+ // test small width.
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, test.format, 2, 4, 0, test.block_size,
+ kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // test bad width.
+ cmd.Init(
+ GL_TEXTURE_2D, 0, test.format, 5, 4, 0,
+ kBucketId);
+ bucket->SetSize(test.block_size * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // test small height.
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, test.format, 4, 2, 0, test.block_size,
+ kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // test too bad height.
+ cmd.Init(
+ GL_TEXTURE_2D, 0, test.format, 4, 5, 0,
+ kBucketId);
+ bucket->SetSize(test.block_size * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // test small for level 0.
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, test.format, 1, 1, 0, test.block_size,
+ kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // test small for level 0.
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, test.format, 2, 2, 0, test.block_size,
+ kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // test size too large.
+ cmd.Init(
+ GL_TEXTURE_2D, 0, test.format, 4, 4, 0,
+ kBucketId);
+ bucket->SetSize(test.block_size * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+ // test size too small.
+ cmd.Init(
+ GL_TEXTURE_2D, 0, test.format, 4, 4, 0,
+ kBucketId);
+ bucket->SetSize(test.block_size / 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+ // test with 3 mips.
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, test.format, 4, 4, 0, test.block_size, kBucketId);
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 1, test.format, 2, 2, 0, test.block_size, kBucketId);
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 2, test.format, 1, 1, 0, test.block_size, kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Test a 16x16
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, test.format, 16, 16, 0, test.block_size * 4 * 4,
+ kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ CompressedTexSubImage2DBucket sub_cmd;
+ bucket->SetSize(test.block_size);
+ // Test sub image bad xoffset
+ sub_cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 0, 4, 4, test.format, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test sub image bad yoffset
+ sub_cmd.Init(
+ GL_TEXTURE_2D, 0, 0, 2, 4, 4, test.format, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test sub image bad width
+ bucket->SetSize(test.block_size * 2);
+ sub_cmd.Init(
+ GL_TEXTURE_2D, 0, 0, 0, 5, 4, test.format, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test sub image bad height
+ sub_cmd.Init(
+ GL_TEXTURE_2D, 0, 0, 0, 4, 5, test.format, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test sub image bad size
+ bucket->SetSize(test.block_size + 1);
+ sub_cmd.Init(
+ GL_TEXTURE_2D, 0, 0, 0, 4, 4, test.format, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+ for (GLint yoffset = 0; yoffset <= 8; yoffset += 4) {
+ for (GLint xoffset = 0; xoffset <= 8; xoffset += 4) {
+ for (GLsizei height = 4; height <= 8; height +=4 ) {
+ for (GLsizei width = 4; width <= 8; width += 4) {
+ GLsizei size = test.block_size * (width / 4) * (height / 4);
+ bucket->SetSize(size);
+ EXPECT_CALL(*gl_, CompressedTexSubImage2D(
+ GL_TEXTURE_2D, 0, xoffset, yoffset, width, height, test.format,
+ size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ sub_cmd.Init(
+ GL_TEXTURE_2D, 0, xoffset, yoffset, width, height, test.format,
+ kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ }
+ }
+ }
+ }
+ }
+}
+
+TEST_F(GLES2DecoderManualInitTest, CompressedTexImage2DETC1) {
+ InitDecoder(
+ "GL_OES_compressed_ETC1_RGB8_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ const uint32 kBucketId = 123;
+ CommonDecoder::Bucket* bucket = decoder_->CreateBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ const GLenum kFormat = GL_ETC1_RGB8_OES;
+ const size_t kBlockSize = 8;
+
+ CompressedTexImage2DBucket cmd;
+ // test small width.
+ DoCompressedTexImage2D(GL_TEXTURE_2D, 0, kFormat, 4, 8, 0, 16, kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // test small height.
+ DoCompressedTexImage2D(GL_TEXTURE_2D, 0, kFormat, 8, 4, 0, 16, kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // test size too large.
+ cmd.Init(GL_TEXTURE_2D, 0, kFormat, 4, 4, 0, kBucketId);
+ bucket->SetSize(kBlockSize * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+ // test size too small.
+ cmd.Init(GL_TEXTURE_2D, 0, kFormat, 4, 4, 0, kBucketId);
+ bucket->SetSize(kBlockSize / 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+
+ // Test a 16x16
+ DoCompressedTexImage2D(
+ GL_TEXTURE_2D, 0, kFormat, 16, 16, 0, kBlockSize * 16, kBucketId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Test CompressedTexSubImage not allowed
+ CompressedTexSubImage2DBucket sub_cmd;
+ bucket->SetSize(kBlockSize);
+ sub_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 4, 4, kFormat, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test TexSubImage not allowed for ETC1 compressed texture
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ GLenum type, internal_format;
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format));
+ EXPECT_EQ(kFormat, internal_format);
+ TexSubImage2D texsub_cmd;
+ texsub_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 4, 4, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test CopyTexSubImage not allowed for ETC1 compressed texture
+ CopyTexSubImage2D copy_cmd;
+ copy_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 4, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(copy_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, GetCompressedTextureFormatsETC1) {
+ InitDecoder(
+ "GL_OES_compressed_ETC1_RGB8_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ GetIntegerv cmd;
+ result->size = 0;
+ EXPECT_CALL(*gl_, GetIntegerv(_, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ cmd.Init(
+ GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(1, result->GetNumResults());
+ GLint num_formats = result->GetData()[0];
+ EXPECT_EQ(1, num_formats);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ result->size = 0;
+ cmd.Init(
+ GL_COMPRESSED_TEXTURE_FORMATS,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(num_formats, result->GetNumResults());
+
+ EXPECT_TRUE(ValueInArray(
+ GL_ETC1_RGB8_OES,
+ result->GetData(), result->GetNumResults()));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMValidArgs) {
+ const uint32 kBucketId = 123;
+ GetProgramInfoCHROMIUM cmd;
+ cmd.Init(client_program_id_, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ EXPECT_GT(bucket->size(), 0u);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMInvalidArgs) {
+ const uint32 kBucketId = 123;
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ EXPECT_TRUE(bucket == NULL);
+ GetProgramInfoCHROMIUM cmd;
+ cmd.Init(kInvalidClientId, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(sizeof(ProgramInfoHeader), bucket->size());
+ ProgramInfoHeader* info = bucket->GetDataAs<ProgramInfoHeader*>(
+ 0, sizeof(ProgramInfoHeader));
+ ASSERT_TRUE(info != 0);
+ EXPECT_EQ(0u, info->link_status);
+ EXPECT_EQ(0u, info->num_attribs);
+ EXPECT_EQ(0u, info->num_uniforms);
+}
+
+TEST_F(GLES2DecoderManualInitTest, EGLImageExternalBindTexture) {
+ InitDecoder(
+ "GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_EXTERNAL_OES, kNewServiceId));
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ BindTexture cmd;
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ TextureRef* texture_ref = GetTexture(kNewClientId);
+ EXPECT_TRUE(texture_ref != NULL);
+ EXPECT_TRUE(texture_ref->texture()->target() == GL_TEXTURE_EXTERNAL_OES);
+}
+
+TEST_F(GLES2DecoderManualInitTest, EGLImageExternalGetBinding) {
+ InitDecoder(
+ "GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES,
+ result->GetData()))
+ .Times(0);
+ result->size = 0;
+ GetIntegerv cmd;
+ cmd.Init(GL_TEXTURE_BINDING_EXTERNAL_OES,
+ shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_TEXTURE_BINDING_EXTERNAL_OES), result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(client_texture_id_, (uint32)result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTextureDefaults) {
+ InitDecoder(
+ "GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ EXPECT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_EXTERNAL_OES);
+ EXPECT_TRUE(texture->min_filter() == GL_LINEAR);
+ EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE);
+ EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE);
+}
+
+TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTextureParam) {
+ InitDecoder(
+ "GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST));
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR));
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE));
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE));
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ EXPECT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_EXTERNAL_OES);
+ EXPECT_TRUE(texture->min_filter() == GL_LINEAR);
+ EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE);
+ EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE);
+}
+
+TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTextureParamInvalid) {
+ InitDecoder(
+ "GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_WRAP_S,
+ GL_REPEAT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ cmd.Init(GL_TEXTURE_EXTERNAL_OES,
+ GL_TEXTURE_WRAP_T,
+ GL_REPEAT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ EXPECT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_EXTERNAL_OES);
+ EXPECT_TRUE(texture->min_filter() == GL_LINEAR);
+ EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE);
+ EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE);
+}
+
+TEST_F(GLES2DecoderManualInitTest, EGLImageExternalTexImage2DError) {
+ InitDecoder(
+ "GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ GLenum target = GL_TEXTURE_EXTERNAL_OES;
+ GLint level = 0;
+ GLenum internal_format = GL_RGBA;
+ GLsizei width = 2;
+ GLsizei height = 4;
+ GLint border = 0;
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_BYTE;
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+ ASSERT_TRUE(GetTexture(client_texture_id_) != NULL);
+ TexImage2D cmd;
+ cmd.Init(target, level, internal_format, width, height, border, format,
+ type, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+
+ // TexImage2D is not allowed with GL_TEXTURE_EXTERNAL_OES targets.
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ false); // bind generates resource
+
+ BindTexture cmd1;
+ cmd1.Init(GL_TEXTURE_2D, kInvalidClientId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd1));
+
+ BindBuffer cmd2;
+ cmd2.Init(GL_ARRAY_BUFFER, kInvalidClientId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd2));
+
+ BindFramebuffer cmd3;
+ cmd3.Init(GL_FRAMEBUFFER, kInvalidClientId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd3));
+
+ BindRenderbuffer cmd4;
+ cmd4.Init(GL_RENDERBUFFER, kInvalidClientId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd4));
+}
+
+TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUM) {
+ const GLuint kObjectId = 123;
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*stream_texture_manager(), CreateStreamTexture(
+ kServiceTextureId, client_texture_id_))
+ .WillOnce(Return(kObjectId))
+ .RetiresOnSaturation();
+
+ CreateStreamTextureCHROMIUM cmd;
+ CreateStreamTextureCHROMIUM::Result* result =
+ static_cast<CreateStreamTextureCHROMIUM::Result*>(shared_memory_address_);
+ cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(kObjectId, *result);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ EXPECT_TRUE(texture_ref != NULL);
+ EXPECT_TRUE(texture_ref->texture()->IsStreamTexture());
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUMBadId) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ CreateStreamTextureCHROMIUM cmd;
+ CreateStreamTextureCHROMIUM::Result* result =
+ static_cast<CreateStreamTextureCHROMIUM::Result*>(shared_memory_address_);
+ cmd.Init(kNewClientId, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(static_cast<GLuint>(GL_ZERO), *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUMAlreadyBound) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ CreateStreamTextureCHROMIUM cmd;
+ CreateStreamTextureCHROMIUM::Result* result =
+ static_cast<CreateStreamTextureCHROMIUM::Result*>(shared_memory_address_);
+ cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(static_cast<GLuint>(GL_ZERO), *result);
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, CreateStreamTextureCHROMIUMAlreadySet) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ CreateStreamTextureCHROMIUM cmd;
+ cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, DrawStreamTextureCHROMIUM) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture GL_OES_EGL_image_external", // extensions
+ true, // has alpha
+ true, // has depth
+ false, // has stencil
+ true, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ StrictMock<MockStreamTexture> stream_texture;
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ SetupSamplerExternalProgram();
+ SetupIndexBuffer();
+ AddExpectationsForSimulatedAttrib0(kMaxValidIndex + 1, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_TRUE(group().texture_manager()->CanRender(texture_ref));
+
+ InSequence s;
+ EXPECT_CALL(*stream_texture_manager(), LookupStreamTexture(kServiceTextureId))
+ .WillOnce(Return(&stream_texture))
+ .RetiresOnSaturation();
+ EXPECT_CALL(stream_texture, Update())
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DrawElements(_, _, _, _))
+ .Times(1);
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, BindStreamTextureCHROMIUMInvalid) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ BindTexture cmd;
+ cmd.Init(GL_TEXTURE_2D, client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ BindTexture cmd2;
+ cmd2.Init(GL_TEXTURE_CUBE_MAP, client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, DestroyStreamTextureCHROMIUM) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ DestroyStreamTextureCHROMIUM cmd;
+ cmd.Init(client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_FALSE(texture_ref->texture()->IsStreamTexture());
+ EXPECT_EQ(0U, texture_ref->texture()->target());
+}
+
+TEST_F(GLES2DecoderManualInitTest, DestroyStreamTextureCHROMIUMInvalid) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DestroyStreamTextureCHROMIUM cmd;
+ cmd.Init(client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, DestroyStreamTextureCHROMIUMBadId) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DestroyStreamTextureCHROMIUM cmd;
+ cmd.Init(GL_ZERO);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, StreamTextureCHROMIUMNullMgr) {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ CreateStreamTextureCHROMIUM cmd;
+ cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+ GetGLError(); // ignore internal error
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ DestroyStreamTextureCHROMIUM cmd2;
+ cmd2.Init(client_texture_id_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd2));
+ GetGLError(); // ignore internal error
+}
+
+TEST_F(GLES2DecoderManualInitTest, ReCreateStreamTextureCHROMIUM) {
+ const GLuint kObjectId = 123;
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*stream_texture_manager(),
+ CreateStreamTexture(kServiceTextureId, client_texture_id_))
+ .WillOnce(Return(kObjectId))
+ .RetiresOnSaturation();
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ DestroyStreamTextureCHROMIUM cmd;
+ cmd.Init(client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_FALSE(texture_ref->texture()->IsStreamTexture());
+
+ CreateStreamTextureCHROMIUM cmd2;
+ cmd2.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(texture_ref->texture()->IsStreamTexture());
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, ProduceAndConsumeStreamTextureCHROMIUM) {
+ InitDecoder(
+ "GL_CHROMIUM_stream_texture GL_OES_EGL_image_external", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ group().texture_manager()->SetStreamTexture(texture_ref, true);
+
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, client_texture_id_, kServiceTextureId);
+
+ GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
+ group().mailbox_manager()->GenerateMailboxName(
+ reinterpret_cast<MailboxName*>(mailbox));
+
+ memcpy(shared_memory_address_, mailbox, sizeof(mailbox));
+
+ EXPECT_EQ(kServiceTextureId, texture_ref->service_id());
+
+ ProduceTextureCHROMIUM produce_cmd;
+ produce_cmd.Init(
+ GL_TEXTURE_EXTERNAL_OES, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(produce_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Create new texture for consume.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId))
+ .RetiresOnSaturation();
+ DoBindTexture(GL_TEXTURE_EXTERNAL_OES, kNewClientId, kNewServiceId);
+
+ // Assigns and binds original service size texture ID.
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_EXTERNAL_OES, kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ // Shared mem got clobbered from GetError() above.
+ memcpy(shared_memory_address_, mailbox, sizeof(mailbox));
+ ConsumeTextureCHROMIUM consume_cmd;
+ consume_cmd.Init(
+ GL_TEXTURE_EXTERNAL_OES, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(consume_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Service ID is restored.
+ EXPECT_EQ(kServiceTextureId, texture_ref->service_id());
+
+ EXPECT_CALL(*stream_texture_manager(),
+ DestroyStreamTexture(kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleBindTexture) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_RECTANGLE_ARB, kNewServiceId));
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ BindTexture cmd;
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ Texture* texture = GetTexture(kNewClientId)->texture();
+ EXPECT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleGetBinding) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(
+ GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ typedef GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB,
+ result->GetData()))
+ .Times(0);
+ result->size = 0;
+ GetIntegerv cmd;
+ cmd.Init(GL_TEXTURE_BINDING_RECTANGLE_ARB,
+ shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_TEXTURE_BINDING_RECTANGLE_ARB), result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(client_texture_id_, (uint32)result->GetData()[0]);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureDefaults) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(
+ GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId);
+
+ Texture* texture = GetTexture(client_texture_id_)->texture();
+ EXPECT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB);
+ EXPECT_TRUE(texture->min_filter() == GL_LINEAR);
+ EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE);
+ EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParam) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(
+ GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId);
+
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST));
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR));
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE));
+ EXPECT_CALL(*gl_, TexParameteri(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE));
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_S,
+ GL_CLAMP_TO_EDGE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_T,
+ GL_CLAMP_TO_EDGE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ Texture* texture = GetTexture(client_texture_id_)->texture();
+ EXPECT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB);
+ EXPECT_TRUE(texture->min_filter() == GL_LINEAR);
+ EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE);
+ EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTextureParamInvalid) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(
+ GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId);
+
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_S,
+ GL_REPEAT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ cmd.Init(GL_TEXTURE_RECTANGLE_ARB,
+ GL_TEXTURE_WRAP_T,
+ GL_REPEAT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+
+ Texture* texture = GetTexture(client_texture_id_)->texture();
+ EXPECT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->target() == GL_TEXTURE_RECTANGLE_ARB);
+ EXPECT_TRUE(texture->min_filter() == GL_LINEAR);
+ EXPECT_TRUE(texture->wrap_s() == GL_CLAMP_TO_EDGE);
+ EXPECT_TRUE(texture->wrap_t() == GL_CLAMP_TO_EDGE);
+}
+
+TEST_F(GLES2DecoderManualInitTest, ARBTextureRectangleTexImage2DError) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ GLenum target = GL_TEXTURE_RECTANGLE_ARB;
+ GLint level = 0;
+ GLenum internal_format = GL_RGBA;
+ GLsizei width = 2;
+ GLsizei height = 4;
+ GLint border = 0;
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_BYTE;
+ DoBindTexture(
+ GL_TEXTURE_RECTANGLE_ARB, client_texture_id_, kServiceTextureId);
+ ASSERT_TRUE(GetTexture(client_texture_id_) != NULL);
+ TexImage2D cmd;
+ cmd.Init(target, level, internal_format, width, height, border, format,
+ type, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+
+ // TexImage2D is not allowed with GL_TEXTURE_RECTANGLE_ARB targets.
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, EnableFeatureCHROMIUMBadBucket) {
+ const uint32 kBadBucketId = 123;
+ EnableFeatureCHROMIUM cmd;
+ cmd.Init(kBadBucketId, shared_memory_id_, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, RequestExtensionCHROMIUMBadBucket) {
+ const uint32 kBadBucketId = 123;
+ RequestExtensionCHROMIUM cmd;
+ cmd.Init(kBadBucketId);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, TexSubImage2DClearsAfterTexImage2DNULL) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ // Test if we call it again it does not clear.
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, TexSubImage2DDoesNotClearAfterTexImage2DNULLThenData) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2DSameSize(
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ // Test if we call it again it does not clear.
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderANGLETest,
+ TexSubImage2DDoesNotClearAfterTexImage2DNULLThenData) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2DSameSize(
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ // Test if we call it again it does not clear.
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, TexSubImage2DClearsAfterTexImage2DWithDataThenNULL) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Put in data (so it should be marked as cleared)
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ // Put in no data.
+ TexImage2D tex_cmd;
+ tex_cmd.Init(
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ // It won't actually call TexImage2D, just mark it as uncleared.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd));
+ // Next call to TexSubImage2d should clear.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ TexSubImage2D cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, 0, 1, 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawArraysClearsAfterTexImage2DNULL) {
+ SetupAllNeededVertexBuffers();
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Create an uncleared texture with 2 levels.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ // Expect 2 levels will be cleared.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // But not again
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawElementsClearsAfterTexImage2DNULL) {
+ SetupAllNeededVertexBuffers();
+ SetupIndexBuffer();
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Create an uncleared texture with 2 levels.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ // Expect 2 levels will be cleared.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1);
+ SetupExpectationsForApplyingDefaultDirtyState();
+
+ EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2)))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawElements cmd;
+ cmd.Init(GL_TRIANGLES, kValidIndexRangeCount, GL_UNSIGNED_SHORT,
+ kValidIndexRangeStart * 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // But not again
+ EXPECT_CALL(*gl_, DrawElements(GL_TRIANGLES, kValidIndexRangeCount,
+ GL_UNSIGNED_SHORT,
+ BufferOffset(kValidIndexRangeStart * 2)))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawClearsAfterTexImage2DNULLInFBO) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ SetupAllNeededVertexBuffers();
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // But not again.
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawWitFBOThatCantClearDoesNotDraw) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_UNSUPPORTED))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DrawArrays(_, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, CopyTexImage2DMarksTextureAsCleared) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ TextureManager* manager = group().texture_manager();
+ TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ CopyTexImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 1, 1, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+}
+
+TEST_F(GLES2DecoderTest, CopyTexSubImage2DClearsUnclearedTexture) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_2D, GL_TEXTURE_2D,
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1))
+ .Times(1)
+ .RetiresOnSaturation();
+ CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderManualInitTest, CompressedImage2DMarksTextureAsCleared) {
+ InitDecoder(
+ "GL_EXT_texture_compression_s3tc", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CompressedTexImage2D(
+ GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0, 8, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ CompressedTexImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, 4, 4, 0,
+ 8, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ TextureManager* manager = group().texture_manager();
+ TextureRef* texture_ref = manager->GetTexture(client_texture_id_);
+ EXPECT_TRUE(texture_ref->texture()->SafeToRenderFrom());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnClear) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, Clear(GL_COLOR_BUFFER_BIT))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ Clear cmd;
+ cmd.Init(GL_COLOR_BUFFER_BIT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, UnClearedAttachmentsGetClearedOnReadPixels) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ typedef ReadPixels::Result Result;
+ Result* result = GetSharedMemoryAs<Result*>();
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(*result);
+ ReadPixels cmd;
+ cmd.Init(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest,
+ UnClearedAttachmentsGetClearedOnReadPixelsAndDrawBufferGetsRestored) {
+ InitDecoder(
+ "GL_EXT_framebuffer_multisample", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render from" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_READ_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ SetupExpectationsForFramebufferClearingMulti(
+ kServiceFramebufferId, // read framebuffer service id
+ 0, // backbuffer service id
+ GL_READ_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ReadPixels(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ typedef ReadPixels::Result Result;
+ uint32 result_shm_id = kSharedMemoryId;
+ uint32 result_shm_offset = kSharedMemoryOffset;
+ uint32 pixels_shm_id = kSharedMemoryId;
+ uint32 pixels_shm_offset = kSharedMemoryOffset + sizeof(Result);
+ ReadPixels cmd;
+ cmd.Init(0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE,
+ pixels_shm_id, pixels_shm_offset,
+ result_shm_id, result_shm_offset,
+ false);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, DrawClearsAfterRenderbufferStorageInFBO) {
+ SetupTexture();
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 100, 50, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, DrawArraysClearsAfterTexImage2DNULLCubemap) {
+ static const GLenum faces[] = {
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ };
+ SetupCubemapProgram();
+ DoBindTexture(GL_TEXTURE_CUBE_MAP, client_texture_id_, kServiceTextureId);
+ // Fill out all the faces for 2 levels, leave 2 uncleared.
+ for (int ii = 0; ii < 6; ++ii) {
+ GLenum face = faces[ii];
+ int32 shm_id =
+ (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryId;
+ uint32 shm_offset =
+ (face == GL_TEXTURE_CUBE_MAP_NEGATIVE_Y) ? 0 : kSharedMemoryOffset;
+ DoTexImage2D(face, 0, GL_RGBA, 2, 2, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, shm_id, shm_offset);
+ DoTexImage2D(face, 1, GL_RGBA, 1, 1, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, shm_id, shm_offset);
+ }
+ // Expect 2 levels will be cleared.
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 2, 2);
+ SetupClearTextureExpections(
+ kServiceTextureId, kServiceTextureId, GL_TEXTURE_CUBE_MAP,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1, GL_RGBA, GL_UNSIGNED_BYTE, 1, 1);
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest, TextureUsageAngleExtNotEnabledByDefault) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_2D,
+ GL_TEXTURE_USAGE_ANGLE,
+ GL_FRAMEBUFFER_ATTACHMENT_ANGLE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ DrawClearsAfterRenderbuffersWithMultipleAttachments) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
+ 1, 1, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+ SetupTexture();
+ SetupExpectationsForFramebufferClearing(
+ GL_FRAMEBUFFER, // target
+ GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, // clear bits
+ 0, 0, 0, 0, // color
+ 0, // stencil
+ 1.0f, // depth
+ false); // scissor test
+
+ AddExpectationsForSimulatedAttrib0(kNumVertices, 0);
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ true, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ true, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, CopyTexImageWithInCompleteFBOFails) {
+ GLenum target = GL_TEXTURE_2D;
+ GLint level = 0;
+ GLenum internal_format = GL_RGBA;
+ GLsizei width = 2;
+ GLsizei height = 4;
+ GLint border = 0;
+ SetupTexture();
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 0, 0, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+ EXPECT_CALL(*gl_, CopyTexImage2D(_, _, _, _, _, _, _, _))
+ .Times(0)
+ .RetiresOnSaturation();
+ CopyTexImage2D cmd;
+ cmd.Init(target, level, internal_format, 0, 0, width, height, border);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_FRAMEBUFFER_OPERATION, GetGLError());
+}
+
+void GLES2DecoderWithShaderTest::CheckRenderbufferChangesMarkFBOAsNotComplete(
+ bool bound_fbo) {
+ FramebufferManager* framebuffer_manager = group().framebuffer_manager();
+ SetupTexture();
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+
+ if (!bound_fbo) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0);
+ }
+
+ Framebuffer* framebuffer =
+ framebuffer_manager->GetFramebuffer(client_framebuffer_id_);
+ ASSERT_TRUE(framebuffer != NULL);
+ framebuffer_manager->MarkAsComplete(framebuffer);
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+
+ // Test that renderbufferStorage marks fbo as not complete.
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR);
+ EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer));
+ framebuffer_manager->MarkAsComplete(framebuffer);
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+
+ // Test deleting renderbuffer marks fbo as not complete.
+ DoDeleteRenderbuffer(client_renderbuffer_id_, kServiceRenderbufferId);
+ if (bound_fbo) {
+ EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer));
+ } else {
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+ }
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ RenderbufferChangesMarkFBOAsNotCompleteBoundFBO) {
+ CheckRenderbufferChangesMarkFBOAsNotComplete(true);
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ RenderbufferChangesMarkFBOAsNotCompleteUnboundFBO) {
+ CheckRenderbufferChangesMarkFBOAsNotComplete(false);
+}
+
+void GLES2DecoderWithShaderTest::CheckTextureChangesMarkFBOAsNotComplete(
+ bool bound_fbo) {
+ FramebufferManager* framebuffer_manager = group().framebuffer_manager();
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ SetupTexture();
+
+ // Setup "render to" texture.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT,
+ 1, 1, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+
+ if (!bound_fbo) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0);
+ }
+
+ Framebuffer* framebuffer =
+ framebuffer_manager->GetFramebuffer(client_framebuffer_id_);
+ ASSERT_TRUE(framebuffer != NULL);
+ framebuffer_manager->MarkAsComplete(framebuffer);
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+
+ // Test TexImage2D marks fbo as not complete.
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, 0, 0);
+ EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer));
+ framebuffer_manager->MarkAsComplete(framebuffer);
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+
+ // Test CopyImage2D marks fbo as not complete.
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 1, 1, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ CopyTexImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, 1, 1, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer));
+
+ // Test deleting texture marks fbo as not complete.
+ framebuffer_manager->MarkAsComplete(framebuffer);
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+ DoDeleteTexture(kFBOClientTextureId, kFBOServiceTextureId);
+
+ if (bound_fbo) {
+ EXPECT_FALSE(framebuffer_manager->IsComplete(framebuffer));
+ } else {
+ EXPECT_TRUE(framebuffer_manager->IsComplete(framebuffer));
+ }
+}
+
+TEST_F(GLES2DecoderWithShaderTest, TextureChangesMarkFBOAsNotCompleteBoundFBO) {
+ CheckTextureChangesMarkFBOAsNotComplete(true);
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ TextureChangesMarkFBOAsNotCompleteUnboundFBO) {
+ CheckTextureChangesMarkFBOAsNotComplete(false);
+}
+
+TEST_F(GLES2DecoderWithShaderTest,
+ DrawingWithFBOTwiceChecksForFBOCompleteOnce) {
+ const GLuint kFBOClientTextureId = 4100;
+ const GLuint kFBOServiceTextureId = 4101;
+
+ SetupAllNeededVertexBuffers();
+
+ // Register a texture id.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kFBOServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<GenTexturesImmediate>(kFBOClientTextureId);
+
+ // Setup "render to" texture that is cleared.
+ DoBindTexture(GL_TEXTURE_2D, kFBOClientTextureId, kFBOServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ DoBindFramebuffer(
+ GL_FRAMEBUFFER, client_framebuffer_id_, kServiceFramebufferId);
+ DoFramebufferTexture2D(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kFBOClientTextureId, kFBOServiceTextureId, 0, GL_NO_ERROR);
+
+ // Setup "render from" texture.
+ SetupTexture();
+
+ // Make sure we check for framebuffer complete.
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ false, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // But not again.
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, BeginQueryEXTDisabled) {
+ // Test something fails if off.
+}
+
+TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXT) {
+ InitDecoder(
+ "GL_EXT_occlusion_query_boolean", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ true, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ // Test end fails if no begin.
+ EndQueryEXT end_cmd;
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ BeginQueryEXT begin_cmd;
+
+ // Test id = 0 fails.
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, 0, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ GenHelper<GenQueriesEXTImmediate>(kNewClientId);
+
+ // Test valid parameters work.
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, kNewServiceId))
+ .Times(1)
+ .RetiresOnSaturation();
+ begin_cmd.Init(
+ GL_ANY_SAMPLES_PASSED_EXT, kNewClientId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ QueryManager* query_manager = decoder_->GetQueryManager();
+ ASSERT_TRUE(query_manager != NULL);
+ QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
+ ASSERT_TRUE(query != NULL);
+ EXPECT_FALSE(query->pending());
+
+ // Test trying begin again fails
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test end fails with different target
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Test end succeeds
+ EXPECT_CALL(*gl_, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT))
+ .Times(1)
+ .RetiresOnSaturation();
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(query->pending());
+
+ EXPECT_CALL(*gl_, DeleteQueriesARB(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+static void CheckBeginEndQueryBadMemoryFails(
+ GLES2DecoderTestBase* test,
+ GLuint client_id,
+ GLuint service_id,
+ int32 shm_id,
+ uint32 shm_offset) {
+ ::testing::StrictMock< ::gfx::MockGLInterface>* gl = test->GetGLMock();
+
+ BeginQueryEXT begin_cmd;
+
+ test->GenHelper<GenQueriesEXTImmediate>(client_id);
+
+ EXPECT_CALL(*gl, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(service_id))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ // Test bad shared memory fails
+ begin_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, client_id, shm_id, shm_offset);
+ error::Error error1 = test->ExecuteCmd(begin_cmd);
+
+ EXPECT_CALL(*gl, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EndQueryEXT end_cmd;
+ end_cmd.Init(GL_ANY_SAMPLES_PASSED_EXT, 1);
+ error::Error error2 = test->ExecuteCmd(end_cmd);
+
+ EXPECT_CALL(*gl,
+ GetQueryObjectuivARB(service_id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl,
+ GetQueryObjectuivARB(service_id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+
+ QueryManager* query_manager = test->GetDecoder()->GetQueryManager();
+ ASSERT_TRUE(query_manager != NULL);
+ bool process_success = query_manager->ProcessPendingQueries();
+
+ EXPECT_TRUE(error1 != error::kNoError ||
+ error2 != error::kNoError ||
+ !process_success);
+
+ EXPECT_CALL(*gl, DeleteQueriesARB(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXTBadMemoryIdFails) {
+ InitDecoder(
+ "GL_EXT_occlusion_query_boolean", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ true, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ CheckBeginEndQueryBadMemoryFails(
+ this, kNewClientId, kNewServiceId,
+ kInvalidSharedMemoryId, kSharedMemoryOffset);
+}
+
+TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXTBadMemoryOffsetFails) {
+ InitDecoder(
+ "GL_EXT_occlusion_query_boolean", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ true, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ CheckBeginEndQueryBadMemoryFails(
+ this, kNewClientId, kNewServiceId,
+ kSharedMemoryId, kInvalidSharedMemoryOffset);
+}
+
+TEST_F(GLES2DecoderTest, BeginEndQueryEXTCommandsIssuedCHROMIUM) {
+ BeginQueryEXT begin_cmd;
+
+ GenHelper<GenQueriesEXTImmediate>(kNewClientId);
+
+ // Test valid parameters work.
+ begin_cmd.Init(
+ GL_COMMANDS_ISSUED_CHROMIUM, kNewClientId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ QueryManager* query_manager = decoder_->GetQueryManager();
+ ASSERT_TRUE(query_manager != NULL);
+ QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
+ ASSERT_TRUE(query != NULL);
+ EXPECT_FALSE(query->pending());
+
+ // Test end succeeds
+ EndQueryEXT end_cmd;
+ end_cmd.Init(GL_COMMANDS_ISSUED_CHROMIUM, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_FALSE(query->pending());
+}
+
+TEST_F(GLES2DecoderTest, BeginEndQueryEXTGetErrorQueryCHROMIUM) {
+ BeginQueryEXT begin_cmd;
+
+ GenHelper<GenQueriesEXTImmediate>(kNewClientId);
+
+ // Test valid parameters work.
+ begin_cmd.Init(
+ GL_GET_ERROR_QUERY_CHROMIUM, kNewClientId,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ QueryManager* query_manager = decoder_->GetQueryManager();
+ ASSERT_TRUE(query_manager != NULL);
+ QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
+ ASSERT_TRUE(query != NULL);
+ EXPECT_FALSE(query->pending());
+
+ // Test end succeeds
+ QuerySync* sync = static_cast<QuerySync*>(shared_memory_address_);
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_INVALID_VALUE))
+ .RetiresOnSaturation();
+
+ EndQueryEXT end_cmd;
+ end_cmd.Init(GL_GET_ERROR_QUERY_CHROMIUM, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_FALSE(query->pending());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE),
+ static_cast<GLenum>(sync->result));
+}
+
+TEST_F(GLES2DecoderTest, GenMailboxCHROMIUM) {
+ const uint32 kBucketId = 123;
+
+ GenMailboxCHROMIUM gen_mailbox_cmd;
+ gen_mailbox_cmd.Init(kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(gen_mailbox_cmd));
+
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ ASSERT_EQ(static_cast<uint32>(GL_MAILBOX_SIZE_CHROMIUM), bucket->size());
+
+ static const GLbyte zero[GL_MAILBOX_SIZE_CHROMIUM] = {
+ 0
+ };
+ EXPECT_NE(0, memcmp(zero,
+ bucket->GetData(0, GL_MAILBOX_SIZE_CHROMIUM),
+ sizeof(zero)));
+}
+
+TEST_F(GLES2DecoderTest, ProduceAndConsumeTextureCHROMIUM) {
+ GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
+ group().mailbox_manager()->GenerateMailboxName(
+ reinterpret_cast<MailboxName*>(mailbox));
+
+ memcpy(shared_memory_address_, mailbox, sizeof(mailbox));
+
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ DoTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 2, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ TextureRef* texture_ref = group().texture_manager()->GetTexture(
+ client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(kServiceTextureId, texture->service_id());
+
+ ProduceTextureCHROMIUM produce_cmd;
+ produce_cmd.Init(GL_TEXTURE_2D, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(produce_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Texture didn't change.
+ GLsizei width;
+ GLsizei height;
+ GLenum type;
+ GLenum internal_format;
+
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ EXPECT_EQ(3, width);
+ EXPECT_EQ(1, height);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format);
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 1, &width, &height));
+ EXPECT_EQ(2, width);
+ EXPECT_EQ(4, height);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 1, &type, &internal_format));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format);
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+
+ // Service ID has not changed.
+ EXPECT_EQ(kServiceTextureId, texture->service_id());
+
+ // Create new texture for consume.
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId))
+ .RetiresOnSaturation();
+ DoBindTexture(GL_TEXTURE_2D, kNewClientId, kNewServiceId);
+
+ // Assigns and binds original service size texture ID.
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ memcpy(shared_memory_address_, mailbox, sizeof(mailbox));
+ ConsumeTextureCHROMIUM consume_cmd;
+ consume_cmd.Init(GL_TEXTURE_2D, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(consume_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Texture is redefined.
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ EXPECT_EQ(3, width);
+ EXPECT_EQ(1, height);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format);
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 1, &width, &height));
+ EXPECT_EQ(2, width);
+ EXPECT_EQ(4, height);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 1, &type, &internal_format));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format);
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+
+ // Service ID is restored.
+ EXPECT_EQ(kServiceTextureId, texture->service_id());
+}
+
+
+TEST_F(GLES2DecoderTest, CanChangeSurface) {
+ scoped_refptr<GLSurfaceMock> other_surface(new GLSurfaceMock);
+ EXPECT_CALL(*other_surface.get(), GetBackingFrameBufferObject()).
+ WillOnce(Return(7));
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER_EXT, 7));
+
+ decoder_->SetSurface(other_surface);
+}
+
+TEST_F(GLES2DecoderTest, IsEnabledReturnsCachedValue) {
+ // NOTE: There are no expectations because no GL functions should be
+ // called for DEPTH_TEST or STENCIL_TEST
+ static const GLenum kStates[] = {
+ GL_DEPTH_TEST,
+ GL_STENCIL_TEST,
+ };
+ for (size_t ii = 0; ii < arraysize(kStates); ++ii) {
+ Enable enable_cmd;
+ GLenum state = kStates[ii];
+ enable_cmd.Init(state);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(enable_cmd));
+ IsEnabled::Result* result =
+ static_cast<IsEnabled::Result*>(shared_memory_address_);
+ IsEnabled is_enabled_cmd;
+ is_enabled_cmd.Init(state, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(is_enabled_cmd));
+ EXPECT_NE(0u, *result);
+ Disable disable_cmd;
+ disable_cmd.Init(state);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(disable_cmd));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(is_enabled_cmd));
+ EXPECT_EQ(0u, *result);
+ }
+}
+
+TEST_F(GLES2DecoderManualInitTest, DepthTextureBadArgs) {
+ InitDecoder(
+ "GL_ANGLE_depth_texture", // extensions
+ false, // has alpha
+ true, // has depth
+ true, // has stencil
+ false, // request alpha
+ true, // request depth
+ true, // request stencil
+ true); // bind generates resource
+
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Check trying to upload data fails.
+ TexImage2D tex_cmd;
+ tex_cmd.Init(
+ GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
+ 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ // Try level > 0.
+ tex_cmd.Init(
+ GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT,
+ 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(tex_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ // Make a 1 pixel depth texture.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
+ 1, 1, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 0);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ // Check that trying to update it fails.
+ TexSubImage2D tex_sub_cmd;
+ tex_sub_cmd.Init(
+ GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
+ kSharedMemoryId, kSharedMemoryOffset, GL_FALSE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(tex_sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Check that trying to CopyTexImage2D fails
+ CopyTexImage2D copy_tex_cmd;
+ copy_tex_cmd.Init(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 0, 0, 1, 1, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(copy_tex_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ // Check that trying to CopyTexSubImage2D fails
+ CopyTexSubImage2D copy_sub_cmd;
+ copy_sub_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 0, 0, 1, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(copy_sub_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, GenerateMipmapDepthTexture) {
+ InitDecoder(
+ "GL_ANGLE_depth_texture", // extensions
+ false, // has alpha
+ true, // has depth
+ true, // has stencil
+ false, // request alpha
+ true, // request depth
+ true, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
+ 2, 2, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT,
+ 0, 0);
+ GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_2D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderANGLEManualInitTest, DrawClearsDepthTexture) {
+ InitDecoder(
+ "GL_ANGLE_depth_texture", // extensions
+ true, // has alpha
+ true, // has depth
+ false, // has stencil
+ true, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ SetupDefaultProgram();
+ SetupAllNeededVertexBuffers();
+ const GLenum attachment = GL_DEPTH_ATTACHMENT;
+ const GLenum target = GL_TEXTURE_2D;
+ const GLint level = 0;
+ DoBindTexture(target, client_texture_id_, kServiceTextureId);
+
+ // Create a depth texture.
+ DoTexImage2D(target, level, GL_DEPTH_COMPONENT, 1, 1, 0,
+ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, 0, 0);
+
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, _))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
+ GL_DRAW_FRAMEBUFFER_EXT, attachment, target, kServiceTextureId, level))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, ClearStencil(0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilMask(-1))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearDepth(1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DepthMask(true))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, Clear(GL_DEPTH_BUFFER_BIT))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ SetupExpectationsForRestoreClearState(
+ 0.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, false);
+
+ EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ SetupExpectationsForApplyingDefaultDirtyState();
+ EXPECT_CALL(*gl_, DrawArrays(GL_TRIANGLES, 0, kNumVertices))
+ .Times(1)
+ .RetiresOnSaturation();
+ DrawArrays cmd;
+ cmd.Init(GL_TRIANGLES, 0, kNumVertices);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderWithShaderTest, BindUniformLocationCHROMIUM) {
+ const GLint kLocation = 2;
+ const char* kName = "testing";
+ const uint32 kNameSize = strlen(kName);
+ const char* kBadName1 = "gl_testing";
+ const uint32 kBadName1Size = strlen(kBadName1);
+ const char* kBadName2 = "testing[1]";
+ const uint32 kBadName2Size = strlen(kBadName2);
+ memcpy(shared_memory_address_, kName, kNameSize);
+ BindUniformLocationCHROMIUM cmd;
+ cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // check negative location
+ memcpy(shared_memory_address_, kName, kNameSize);
+ cmd.Init(client_program_id_, -1, kSharedMemoryId, kSharedMemoryOffset,
+ kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // check highest location
+ memcpy(shared_memory_address_, kName, kNameSize);
+ GLint kMaxLocation =
+ (kMaxFragmentUniformVectors + kMaxVertexUniformVectors) * 4 - 1;
+ cmd.Init(client_program_id_, kMaxLocation, kSharedMemoryId,
+ kSharedMemoryOffset, kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // check too high location
+ memcpy(shared_memory_address_, kName, kNameSize);
+ cmd.Init(client_program_id_, kMaxLocation + 1, kSharedMemoryId,
+ kSharedMemoryOffset, kNameSize);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ // check bad name "gl_..."
+ memcpy(shared_memory_address_, kBadName1, kBadName1Size);
+ cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset,
+ kBadName1Size);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ // check bad name "name[1]" non zero
+ memcpy(shared_memory_address_, kBadName2, kBadName2Size);
+ cmd.Init(client_program_id_, kLocation, kSharedMemoryId, kSharedMemoryOffset,
+ kBadName2Size);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+class GLES2DecoderVertexArraysOESTest : public GLES2DecoderWithShaderTest {
+ public:
+ GLES2DecoderVertexArraysOESTest() { }
+
+ bool vertex_array_deleted_manually_;
+
+ virtual void SetUp() {
+ InitDecoder(
+ "GL_OES_vertex_array_object", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ SetupDefaultProgram();
+
+ AddExpectationsForGenVertexArraysOES();
+ GenHelper<GenVertexArraysOESImmediate>(client_vertexarray_id_);
+
+ vertex_array_deleted_manually_ = false;
+ }
+
+ virtual void TearDown() {
+ // This should only be set if the test handled deletion of the vertex array
+ // itself. Necessary because vertex_array_objects are not sharable, and thus
+ // not managed in the ContextGroup, meaning they will be destroyed during
+ // test tear down
+ if (!vertex_array_deleted_manually_) {
+ AddExpectationsForDeleteVertexArraysOES();
+ }
+
+ GLES2DecoderWithShaderTest::TearDown();
+ }
+
+ void GenVertexArraysOESValidArgs() {
+ AddExpectationsForGenVertexArraysOES();
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ GenVertexArraysOES cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetVertexArrayInfo(kNewClientId) != NULL);
+ AddExpectationsForDeleteVertexArraysOES();
+ }
+
+ void GenVertexArraysOESInvalidArgs() {
+ EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_vertexarray_id_;
+ GenVertexArraysOES cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+ }
+
+ void GenVertexArraysOESImmediateValidArgs() {
+ AddExpectationsForGenVertexArraysOES();
+ GenVertexArraysOESImmediate* cmd =
+ GetImmediateAs<GenVertexArraysOESImmediate>();
+ GLuint temp = kNewClientId;
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetVertexArrayInfo(kNewClientId) != NULL);
+ AddExpectationsForDeleteVertexArraysOES();
+ }
+
+ void GenVertexArraysOESImmediateInvalidArgs() {
+ EXPECT_CALL(*gl_, GenVertexArraysOES(_, _)).Times(0);
+ GenVertexArraysOESImmediate* cmd =
+ GetImmediateAs<GenVertexArraysOESImmediate>();
+ cmd->Init(1, &client_vertexarray_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_vertexarray_id_)));
+ }
+
+ void DeleteVertexArraysOESValidArgs() {
+ AddExpectationsForDeleteVertexArraysOES();
+ GetSharedMemoryAs<GLuint*>()[0] = client_vertexarray_id_;
+ DeleteVertexArraysOES cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetVertexArrayInfo(client_vertexarray_id_) == NULL);
+ vertex_array_deleted_manually_ = true;
+ }
+
+ void DeleteVertexArraysOESInvalidArgs() {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ DeleteVertexArraysOES cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+
+ void DeleteVertexArraysOESImmediateValidArgs() {
+ AddExpectationsForDeleteVertexArraysOES();
+ DeleteVertexArraysOESImmediate& cmd =
+ *GetImmediateAs<DeleteVertexArraysOESImmediate>();
+ cmd.Init(1, &client_vertexarray_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_vertexarray_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetVertexArrayInfo(client_vertexarray_id_) == NULL);
+ vertex_array_deleted_manually_ = true;
+ }
+
+ void DeleteVertexArraysOESImmediateInvalidArgs() {
+ DeleteVertexArraysOESImmediate& cmd =
+ *GetImmediateAs<DeleteVertexArraysOESImmediate>();
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ }
+
+ void IsVertexArrayOESValidArgs() {
+ IsVertexArrayOES cmd;
+ cmd.Init(client_vertexarray_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ }
+
+ void IsVertexArrayOESInvalidArgsBadSharedMemoryId() {
+ IsVertexArrayOES cmd;
+ cmd.Init(
+ client_vertexarray_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(
+ client_vertexarray_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ }
+
+ void BindVertexArrayOESValidArgs() {
+ AddExpectationsForBindVertexArrayOES();
+ BindVertexArrayOES cmd;
+ cmd.Init(client_vertexarray_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ }
+
+ void BindVertexArrayOESValidArgsNewId() {
+ BindVertexArrayOES cmd;
+ cmd.Init(kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ }
+};
+
+class GLES2DecoderEmulatedVertexArraysOESTest
+ : public GLES2DecoderVertexArraysOESTest {
+ public:
+ GLES2DecoderEmulatedVertexArraysOESTest() { }
+
+ virtual void SetUp() {
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ SetupDefaultProgram();
+
+ AddExpectationsForGenVertexArraysOES();
+ GenHelper<GenVertexArraysOESImmediate>(client_vertexarray_id_);
+
+ vertex_array_deleted_manually_ = false;
+ }
+};
+
+// Test vertex array objects with native support
+TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESValidArgs) {
+ GenVertexArraysOESValidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, GenVertexArraysOESValidArgs) {
+ GenVertexArraysOESValidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESInvalidArgs) {
+ GenVertexArraysOESInvalidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, ) {
+ GenVertexArraysOESInvalidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, GenVertexArraysOESImmediateValidArgs) {
+ GenVertexArraysOESImmediateValidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ GenVertexArraysOESImmediateValidArgs) {
+ GenVertexArraysOESImmediateValidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest,
+ GenVertexArraysOESImmediateInvalidArgs) {
+ GenVertexArraysOESImmediateInvalidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ GenVertexArraysOESImmediateInvalidArgs) {
+ GenVertexArraysOESImmediateInvalidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, DeleteVertexArraysOESValidArgs) {
+ DeleteVertexArraysOESValidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ DeleteVertexArraysOESValidArgs) {
+ DeleteVertexArraysOESValidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, DeleteVertexArraysOESInvalidArgs) {
+ DeleteVertexArraysOESInvalidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ DeleteVertexArraysOESInvalidArgs) {
+ DeleteVertexArraysOESInvalidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest,
+ DeleteVertexArraysOESImmediateValidArgs) {
+ DeleteVertexArraysOESImmediateValidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ DeleteVertexArraysOESImmediateValidArgs) {
+ DeleteVertexArraysOESImmediateValidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest,
+ DeleteVertexArraysOESImmediateInvalidArgs) {
+ DeleteVertexArraysOESImmediateInvalidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ DeleteVertexArraysOESImmediateInvalidArgs) {
+ DeleteVertexArraysOESImmediateInvalidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, IsVertexArrayOESValidArgs) {
+ IsVertexArrayOESValidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, IsVertexArrayOESValidArgs) {
+ IsVertexArrayOESValidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest,
+ IsVertexArrayOESInvalidArgsBadSharedMemoryId) {
+ IsVertexArrayOESInvalidArgsBadSharedMemoryId();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ IsVertexArrayOESInvalidArgsBadSharedMemoryId) {
+ IsVertexArrayOESInvalidArgsBadSharedMemoryId();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, BindVertexArrayOESValidArgs) {
+ BindVertexArrayOESValidArgs();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest, BindVertexArrayOESValidArgs) {
+ BindVertexArrayOESValidArgs();
+}
+
+TEST_F(GLES2DecoderVertexArraysOESTest, BindVertexArrayOESValidArgsNewId) {
+ BindVertexArrayOESValidArgsNewId();
+}
+TEST_F(GLES2DecoderEmulatedVertexArraysOESTest,
+ BindVertexArrayOESValidArgsNewId) {
+ BindVertexArrayOESValidArgsNewId();
+}
+
+TEST_F(GLES2DecoderTest, BindTexImage2DCHROMIUM) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ TextureRef* texture_ref = group().texture_manager()->GetTexture(
+ client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(kServiceTextureId, texture->service_id());
+
+ group().image_manager()->AddImage(gfx::GLImage::CreateGLImage(0).get(), 1);
+ EXPECT_FALSE(group().image_manager()->LookupImage(1) == NULL);
+
+ GLsizei width;
+ GLsizei height;
+ GLenum type;
+ GLenum internal_format;
+
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ EXPECT_EQ(3, width);
+ EXPECT_EQ(1, height);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format);
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
+
+ // Bind image to texture.
+ // ScopedGLErrorSuppressor calls GetError on its constructor and destructor.
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ BindTexImage2DCHROMIUM bind_tex_image_2d_cmd;
+ bind_tex_image_2d_cmd.Init(GL_TEXTURE_2D, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd));
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ // Image should now be set.
+ EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
+
+ // Define new texture image.
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ // Image should no longer be set.
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
+}
+
+TEST_F(GLES2DecoderTest, ReleaseTexImage2DCHROMIUM) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 3, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ 0, 0);
+ TextureRef* texture_ref = group().texture_manager()->GetTexture(
+ client_texture_id_);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(kServiceTextureId, texture->service_id());
+
+ group().image_manager()->AddImage(gfx::GLImage::CreateGLImage(0).get(), 1);
+ EXPECT_FALSE(group().image_manager()->LookupImage(1) == NULL);
+
+ GLsizei width;
+ GLsizei height;
+ GLenum type;
+ GLenum internal_format;
+
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ EXPECT_EQ(3, width);
+ EXPECT_EQ(1, height);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &internal_format));
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), internal_format);
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
+
+ // Bind image to texture.
+ // ScopedGLErrorSuppressor calls GetError on its constructor and destructor.
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ BindTexImage2DCHROMIUM bind_tex_image_2d_cmd;
+ bind_tex_image_2d_cmd.Init(GL_TEXTURE_2D, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(bind_tex_image_2d_cmd));
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ // Image should now be set.
+ EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
+
+ // Release image from texture.
+ // ScopedGLErrorSuppressor calls GetError on its constructor and destructor.
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ ReleaseTexImage2DCHROMIUM release_tex_image_2d_cmd;
+ release_tex_image_2d_cmd.Init(GL_TEXTURE_2D, 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(release_tex_image_2d_cmd));
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ // Image should no longer be set.
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
+}
+
+TEST_F(GLES2DecoderManualInitTest, GpuMemoryManagerCHROMIUM) {
+ InitDecoder(
+ "GL_ARB_texture_rectangle", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+
+ Texture* texture = GetTexture(client_texture_id_)->texture();
+ EXPECT_TRUE(texture != NULL);
+ EXPECT_TRUE(texture->pool() == GL_TEXTURE_POOL_UNMANAGED_CHROMIUM);
+
+ DoBindTexture(
+ GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+
+ TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_2D,
+ GL_TEXTURE_POOL_CHROMIUM,
+ GL_TEXTURE_POOL_UNMANAGED_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ cmd.Init(GL_TEXTURE_2D,
+ GL_TEXTURE_POOL_CHROMIUM,
+ GL_TEXTURE_POOL_MANAGED_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_TRUE(texture->pool() == GL_TEXTURE_POOL_MANAGED_CHROMIUM);
+
+ cmd.Init(GL_TEXTURE_2D,
+ GL_TEXTURE_POOL_CHROMIUM,
+ GL_NONE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransfers) {
+ InitDecoder(
+ "GL_CHROMIUM_async_pixel_transfers", // extensions
+ false, false, false, // has alpha/depth/stencil
+ false, false, false, // request alpha/depth/stencil
+ true); // bind generates resource
+
+ // Set up the texture.
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+ Texture* texture = texture_ref->texture();
+
+ // Set a mock Async delegate
+ StrictMock<gpu::MockAsyncPixelTransferManager>* manager =
+ new StrictMock<gpu::MockAsyncPixelTransferManager>;
+ manager->Initialize(group().texture_manager());
+ decoder_->SetAsyncPixelTransferManagerForTest(manager);
+ StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = NULL;
+
+ // Tex(Sub)Image2D upload commands.
+ AsyncTexImage2DCHROMIUM teximage_cmd;
+ teximage_cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+ AsyncTexSubImage2DCHROMIUM texsubimage_cmd;
+ texsubimage_cmd.Init(GL_TEXTURE_2D, 0, 0, 0, 8, 8, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+ WaitAsyncTexImage2DCHROMIUM wait_cmd;
+ wait_cmd.Init(GL_TEXTURE_2D);
+
+ // No transfer state exists initially.
+ EXPECT_FALSE(
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+
+ base::Closure bind_callback;
+
+ // AsyncTexImage2D
+ {
+ // Create transfer state since it doesn't exist.
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _))
+ .WillOnce(Return(
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _))
+ .WillOnce(SaveArg<2>(&bind_callback))
+ .RetiresOnSaturation();
+ // Command succeeds.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(
+ delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+ EXPECT_TRUE(texture->IsImmutable());
+ // The texture is safe but the level has not been defined yet.
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ GLsizei width, height;
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ }
+ {
+ // Async redefinitions are not allowed!
+ // Command fails.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(
+ delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+ EXPECT_TRUE(texture->IsImmutable());
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ }
+
+ // Binding/defining of the async transfer
+ {
+ // TODO(epenner): We should check that the manager gets the
+ // BindCompletedAsyncTransfers() call, which is required to
+ // guarantee the delegate calls the bind callback.
+
+ // Simulate the bind callback from the delegate.
+ bind_callback.Run();
+
+ // After the bind callback is run, the texture is safe,
+ // and has the right size etc.
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ GLsizei width, height;
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ EXPECT_EQ(width, 8);
+ EXPECT_EQ(height, 8);
+ }
+
+ // AsyncTexSubImage2D
+ decoder_->GetAsyncPixelTransferManager()
+ ->ClearPixelTransferDelegateForTest(texture_ref);
+ texture->SetImmutable(false);
+ {
+ // Create transfer state since it doesn't exist.
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _))
+ .WillOnce(Return(
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*delegate, AsyncTexSubImage2D(_, _))
+ .RetiresOnSaturation();
+ // Command succeeds.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(
+ delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+ EXPECT_TRUE(texture->IsImmutable());
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ }
+ {
+ // No transfer is in progress.
+ EXPECT_CALL(*delegate, TransferIsInProgress())
+ .WillOnce(Return(false)) // texSubImage validation
+ .WillOnce(Return(false)) // async validation
+ .RetiresOnSaturation();
+ EXPECT_CALL(*delegate, AsyncTexSubImage2D(_, _))
+ .RetiresOnSaturation();
+ // Command succeeds.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(
+ delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+ EXPECT_TRUE(texture->IsImmutable());
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ }
+ {
+ // A transfer is still in progress!
+ EXPECT_CALL(*delegate, TransferIsInProgress())
+ .WillOnce(Return(true))
+ .RetiresOnSaturation();
+ // No async call, command fails.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(texsubimage_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+ EXPECT_EQ(
+ delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+ EXPECT_TRUE(texture->IsImmutable());
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ }
+
+ // Delete delegate on DeleteTexture.
+ {
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation();
+ DoDeleteTexture(client_texture_id_, kServiceTextureId);
+ EXPECT_FALSE(
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+ delegate = NULL;
+ }
+
+ // WaitAsyncTexImage2D
+ {
+ // Get a fresh texture since the existing texture cannot be respecified
+ // asynchronously and AsyncTexSubImage2D does not involved binding.
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceTextureId));
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ texture_ref = GetTexture(client_texture_id_);
+ texture = texture_ref->texture();
+ texture->SetImmutable(false);
+ // Create transfer state since it doesn't exist.
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _))
+ .WillOnce(Return(
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _))
+ .RetiresOnSaturation();
+ // Start async transfer.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(
+ delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+
+ EXPECT_TRUE(texture->IsImmutable());
+ // Wait for completion.
+ EXPECT_CALL(*delegate, WaitForTransferCompletion());
+ EXPECT_CALL(*manager, BindCompletedAsyncTransfers());
+ EXPECT_EQ(error::kNoError, ExecuteCmd(wait_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ }
+}
+
+TEST_F(GLES2DecoderManualInitTest, AsyncPixelTransferManager) {
+ InitDecoder(
+ "GL_CHROMIUM_async_pixel_transfers", // extensions
+ false, false, false, // has alpha/depth/stencil
+ false, false, false, // request alpha/depth/stencil
+ true); // bind generates resource
+
+ // Set up the texture.
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ TextureRef* texture_ref = GetTexture(client_texture_id_);
+
+ // Set a mock Async delegate.
+ StrictMock<gpu::MockAsyncPixelTransferManager>* manager =
+ new StrictMock<gpu::MockAsyncPixelTransferManager>;
+ manager->Initialize(group().texture_manager());
+ decoder_->SetAsyncPixelTransferManagerForTest(manager);
+ StrictMock<gpu::MockAsyncPixelTransferDelegate>* delegate = NULL;
+
+ AsyncTexImage2DCHROMIUM teximage_cmd;
+ teximage_cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 8, 8, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, kSharedMemoryId, kSharedMemoryOffset);
+
+ // No transfer delegate exists initially.
+ EXPECT_FALSE(
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+
+ // Create delegate on AsyncTexImage2D.
+ {
+ EXPECT_CALL(*manager, CreatePixelTransferDelegateImpl(texture_ref, _))
+ .WillOnce(Return(
+ delegate = new StrictMock<gpu::MockAsyncPixelTransferDelegate>))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*delegate, AsyncTexImage2D(_, _, _)).RetiresOnSaturation();
+
+ // Command succeeds.
+ EXPECT_EQ(error::kNoError, ExecuteCmd(teximage_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ }
+
+ // Delegate is cached.
+ EXPECT_EQ(delegate,
+ decoder_->GetAsyncPixelTransferManager()->GetPixelTransferDelegate(
+ texture_ref));
+
+ // Delete delegate on manager teardown.
+ {
+ EXPECT_CALL(*delegate, Destroy()).RetiresOnSaturation();
+ decoder_->ResetAsyncPixelTransferManagerForTest();
+
+ // Texture ref still valid.
+ EXPECT_EQ(texture_ref, GetTexture(client_texture_id_));
+ }
+}
+
+namespace {
+
+class SizeOnlyMemoryTracker : public MemoryTracker {
+ public:
+ SizeOnlyMemoryTracker() {
+ // These are the default textures. 1 for TEXTURE_2D and 6 faces for
+ // TEXTURE_CUBE_MAP.
+ const size_t kInitialUnmanagedPoolSize = 7 * 4;
+ const size_t kInitialManagedPoolSize = 0;
+ pool_infos_[MemoryTracker::kUnmanaged].initial_size =
+ kInitialUnmanagedPoolSize;
+ pool_infos_[MemoryTracker::kManaged].initial_size =
+ kInitialManagedPoolSize;
+ }
+
+ // Ensure a certain amount of GPU memory is free. Returns true on success.
+ MOCK_METHOD1(EnsureGPUMemoryAvailable, bool(size_t size_needed));
+
+ virtual void TrackMemoryAllocatedChange(
+ size_t old_size, size_t new_size, Pool pool) {
+ PoolInfo& info = pool_infos_[pool];
+ info.size += new_size - old_size;
+ }
+
+ size_t GetPoolSize(Pool pool) {
+ const PoolInfo& info = pool_infos_[pool];
+ return info.size - info.initial_size;
+ }
+
+ private:
+ virtual ~SizeOnlyMemoryTracker() {
+ }
+ struct PoolInfo {
+ PoolInfo()
+ : initial_size(0),
+ size(0) {
+ }
+ size_t initial_size;
+ size_t size;
+ };
+ std::map<Pool, PoolInfo> pool_infos_;
+};
+
+} // anonymous namespace.
+
+TEST_F(GLES2DecoderManualInitTest, MemoryTrackerInitialSize) {
+ scoped_refptr<SizeOnlyMemoryTracker> memory_tracker =
+ new SizeOnlyMemoryTracker();
+ set_memory_tracker(memory_tracker.get());
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ // Expect that initial size - size is 0.
+ EXPECT_EQ(0u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+ EXPECT_EQ(0u, memory_tracker->GetPoolSize(MemoryTracker::kManaged));
+}
+
+TEST_F(GLES2DecoderManualInitTest, MemoryTrackerTexImage2D) {
+ scoped_refptr<SizeOnlyMemoryTracker> memory_tracker =
+ new SizeOnlyMemoryTracker();
+ set_memory_tracker(memory_tracker.get());
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(true)).RetiresOnSaturation();
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 8, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(64))
+ .WillOnce(Return(true)).RetiresOnSaturation();
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(64u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check we get out of memory and no call to glTexImage2D if Ensure fails.
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(64))
+ .WillOnce(Return(false)).RetiresOnSaturation();
+ TexImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 0, GL_RGBA, 4, 4, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_EQ(64u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+}
+
+TEST_F(GLES2DecoderManualInitTest, MemoryTrackerTexStorage2DEXT) {
+ scoped_refptr<SizeOnlyMemoryTracker> memory_tracker =
+ new SizeOnlyMemoryTracker();
+ set_memory_tracker(memory_tracker.get());
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ // Check we get out of memory and no call to glTexStorage2DEXT
+ // if Ensure fails.
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(false)).RetiresOnSaturation();
+ TexStorage2DEXT cmd;
+ cmd.Init(GL_TEXTURE_2D, 1, GL_RGBA8, 8, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+}
+
+TEST_F(GLES2DecoderManualInitTest, MemoryTrackerCopyTexImage2D) {
+ GLenum target = GL_TEXTURE_2D;
+ GLint level = 0;
+ GLenum internal_format = GL_RGBA;
+ GLsizei width = 4;
+ GLsizei height = 8;
+ GLint border = 0;
+ scoped_refptr<SizeOnlyMemoryTracker> memory_tracker =
+ new SizeOnlyMemoryTracker();
+ set_memory_tracker(memory_tracker.get());
+ InitDecoder(
+ "", // extensions
+ true, // has alpha
+ false, // has depth
+ false, // has stencil
+ true, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(true)).RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CopyTexImage2D(
+ target, level, internal_format, 0, 0, width, height, border))
+ .Times(1)
+ .RetiresOnSaturation();
+ CopyTexImage2D cmd;
+ cmd.Init(target, level, internal_format, 0, 0, width, height, border);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ // Check we get out of memory and no call to glCopyTexImage2D if Ensure fails.
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(false)).RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+}
+
+TEST_F(GLES2DecoderManualInitTest, MemoryTrackerRenderbufferStorage) {
+ scoped_refptr<SizeOnlyMemoryTracker> memory_tracker =
+ new SizeOnlyMemoryTracker();
+ set_memory_tracker(memory_tracker.get());
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(true)).RetiresOnSaturation();
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(
+ GL_RENDERBUFFER, GL_RGBA, 8, 4))
+ .Times(1)
+ .RetiresOnSaturation();
+ RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 8, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+ // Check we get out of memory and no call to glRenderbufferStorage if Ensure
+ // fails.
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(false)).RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kUnmanaged));
+}
+
+TEST_F(GLES2DecoderManualInitTest, MemoryTrackerBufferData) {
+ scoped_refptr<SizeOnlyMemoryTracker> memory_tracker =
+ new SizeOnlyMemoryTracker();
+ set_memory_tracker(memory_tracker.get());
+ InitDecoder(
+ "", // extensions
+ false, // has alpha
+ false, // has depth
+ false, // has stencil
+ false, // request alpha
+ false, // request depth
+ false, // request stencil
+ true); // bind generates resource
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_,
+ kServiceBufferId);
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(true)).RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER, 128, _, GL_STREAM_DRAW))
+ .Times(1)
+ .RetiresOnSaturation();
+ BufferData cmd;
+ cmd.Init(GL_ARRAY_BUFFER, 128, 0, 0, GL_STREAM_DRAW);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kManaged));
+ // Check we get out of memory and no call to glBufferData if Ensure
+ // fails.
+ EXPECT_CALL(*memory_tracker.get(), EnsureGPUMemoryAvailable(128))
+ .WillOnce(Return(false)).RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
+ EXPECT_EQ(128u, memory_tracker->GetPoolSize(MemoryTracker::kManaged));
+}
+
+TEST_F(GLES2DecoderTest, DrawBuffersEXTImmediateSuccceeds) {
+ const GLsizei count = 1;
+ const GLenum bufs[] = { GL_COLOR_ATTACHMENT0 };
+ DrawBuffersEXTImmediate& cmd =
+ *GetImmediateAs<DrawBuffersEXTImmediate>();
+ cmd.Init(count, bufs);
+
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_CALL(*gl_, DrawBuffersARB(count, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(bufs)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, DrawBuffersEXTImmediateFails) {
+ const GLsizei count = 1;
+ const GLenum bufs[] = { GL_COLOR_ATTACHMENT1_EXT };
+ DrawBuffersEXTImmediate& cmd =
+ *GetImmediateAs<DrawBuffersEXTImmediate>();
+ cmd.Init(count, bufs);
+
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(bufs)));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest, DrawBuffersEXTImmediateBackbuffer) {
+ const GLsizei count = 1;
+ const GLenum bufs[] = { GL_BACK };
+ DrawBuffersEXTImmediate& cmd =
+ *GetImmediateAs<DrawBuffersEXTImmediate>();
+ cmd.Init(count, bufs);
+
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(bufs)));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0); // unbind
+
+ EXPECT_CALL(*gl_, DrawBuffersARB(count, _))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(bufs)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+// TODO(gman): Complete this test.
+// TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) {
+// }
+
+// TODO(gman): BufferData
+
+// TODO(gman): BufferDataImmediate
+
+// TODO(gman): BufferSubData
+
+// TODO(gman): BufferSubDataImmediate
+
+// TODO(gman): CompressedTexImage2D
+
+// TODO(gman): CompressedTexImage2DImmediate
+
+// TODO(gman): CompressedTexSubImage2DImmediate
+
+// TODO(gman): DeleteProgram
+
+// TODO(gman): DeleteShader
+
+// TODO(gman): PixelStorei
+
+// TODO(gman): TexImage2D
+
+// TODO(gman): TexImage2DImmediate
+
+// TODO(gman): TexSubImage2DImmediate
+
+// TODO(gman): UseProgram
+
+// TODO(gman): SwapBuffers
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
new file mode 100644
index 00000000000..ac8a8f206ef
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
@@ -0,0 +1,108 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by gles2_cmd_decoder_unittest_base.cc
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_0_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_0_AUTOGEN_H_
+
+void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations() {
+ ExpectEnableDisable(GL_BLEND, false);
+ ExpectEnableDisable(GL_CULL_FACE, false);
+ ExpectEnableDisable(GL_DEPTH_TEST, false);
+ ExpectEnableDisable(GL_DITHER, true);
+ ExpectEnableDisable(GL_POLYGON_OFFSET_FILL, false);
+ ExpectEnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE, false);
+ ExpectEnableDisable(GL_SAMPLE_COVERAGE, false);
+ ExpectEnableDisable(GL_SCISSOR_TEST, false);
+ ExpectEnableDisable(GL_STENCIL_TEST, false);
+}
+
+void GLES2DecoderTestBase::SetupInitStateExpectations() {
+ EXPECT_CALL(*gl_, BlendColor(0.0f, 0.0f, 0.0f, 0.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BlendFuncSeparate(GL_ONE, GL_ZERO, GL_ONE, GL_ZERO))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0f, 0.0f, 0.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearDepth(1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearStencil(0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ColorMask(true, true, true, true))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CullFace(GL_BACK))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DepthFunc(GL_LESS))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DepthMask(true))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DepthRange(0.0f, 1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FrontFace(GL_CCW))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, Hint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, LineWidth(1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, PixelStorei(GL_PACK_ALIGNMENT, 4))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, PixelStorei(GL_UNPACK_ALIGNMENT, 4))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, PolygonOffset(0.0f, 0.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, SampleCoverage(1.0f, false))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *gl_, Scissor(kViewportX, kViewportY, kViewportWidth, kViewportHeight))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilFuncSeparate(GL_FRONT, GL_ALWAYS, 0, 0xFFFFFFFFU))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilFuncSeparate(GL_BACK, GL_ALWAYS, 0, 0xFFFFFFFFU))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, 0xFFFFFFFFU))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, 0xFFFFFFFFU))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_KEEP))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_KEEP))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(
+ *gl_, Viewport(kViewportX, kViewportY, kViewportWidth, kViewportHeight))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_0_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
new file mode 100644
index 00000000000..daa98ae66c7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+void ShaderCacheCb(const std::string& key, const std::string& shader) {
+}
+} // namespace
+
+class GLES2DecoderTest1 : public GLES2DecoderTestBase {
+ public:
+ GLES2DecoderTest1() { }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GenerateMipmap, 0>(
+ bool valid) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ if (valid) {
+ EXPECT_CALL(*gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::CheckFramebufferStatus, 0>(
+ bool /* valid */) {
+ // Give it a valid framebuffer.
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ DoRenderbufferStorage(
+ GL_RENDERBUFFER, GL_RGBA4, GL_RGBA, 1, 1, GL_NO_ERROR);
+ DoFramebufferRenderbuffer(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_, kServiceRenderbufferId, GL_NO_ERROR);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Clear, 0>(bool valid) {
+ if (valid) {
+ SetupExpectationsForApplyingDefaultDirtyState();
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::ColorMask, 0>(
+ bool /* valid */) {
+ // We bind a framebuffer color the colormask test since the framebuffer
+ // will be considered RGB.
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::CopyTexImage2D, 0>(
+ bool valid) {
+ if (valid) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::CopyTexSubImage2D, 0>(
+ bool valid) {
+ if (valid) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(
+ GL_TEXTURE_2D, 2, GL_RGBA, 16, 16, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::DetachShader, 0>(bool valid) {
+ if (valid) {
+ EXPECT_CALL(*gl_,
+ AttachShader(kServiceProgramId, kServiceShaderId))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::AttachShader attach_cmd;
+ attach_cmd.Init(client_program_id_, client_shader_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::FramebufferRenderbuffer, 0>(
+ bool valid) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ if (valid) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::FramebufferTexture2D, 0>(
+ bool valid) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+ if (valid) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<
+ cmds::GetBufferParameteriv, 0>(bool /* valid */) {
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<
+ cmds::GetFramebufferAttachmentParameteriv, 0>(bool /* valid */) {
+ DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
+ kServiceFramebufferId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<
+ cmds::GetRenderbufferParameteriv, 0>(
+ bool /* valid */) {
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GetProgramiv, 0>(
+ bool valid) {
+ if (valid) {
+ // GetProgramiv calls ClearGLError then GetError to make sure
+ // it actually got a value so it can report correctly to the client.
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+}
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GetProgramInfoLog, 0>(
+ bool /* valid */) {
+ const GLuint kClientVertexShaderId = 5001;
+ const GLuint kServiceVertexShaderId = 6001;
+ const GLuint kClientFragmentShaderId = 5002;
+ const GLuint kServiceFragmentShaderId = 6002;
+ const char* log = "hello"; // Matches auto-generated unit test.
+ DoCreateShader(
+ GL_VERTEX_SHADER, kClientVertexShaderId, kServiceVertexShaderId);
+ DoCreateShader(
+ GL_FRAGMENT_SHADER, kClientFragmentShaderId, kServiceFragmentShaderId);
+
+ GetShader(kClientVertexShaderId)->SetStatus(true, "", NULL);
+ GetShader(kClientFragmentShaderId)->SetStatus(true, "", NULL);
+
+ InSequence dummy;
+ EXPECT_CALL(*gl_,
+ AttachShader(kServiceProgramId, kServiceVertexShaderId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ AttachShader(kServiceProgramId, kServiceFragmentShaderId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, LinkProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(1));
+ EXPECT_CALL(*gl_,
+ GetProgramiv(kServiceProgramId, GL_INFO_LOG_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(strlen(log) + 1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetProgramInfoLog(kServiceProgramId, strlen(log) + 1, _, _))
+ .WillOnce(DoAll(
+ SetArgumentPointee<2>(strlen(log)),
+ SetArrayArgument<3>(log, log + strlen(log) + 1)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_ATTRIBUTES, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(
+ *gl_,
+ GetProgramiv(kServiceProgramId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(
+ *gl_,
+ GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+
+ Program* program = GetProgram(client_program_id_);
+ ASSERT_TRUE(program != NULL);
+
+ cmds::AttachShader attach_cmd;
+ attach_cmd.Init(client_program_id_, kClientVertexShaderId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+
+ attach_cmd.Init(client_program_id_, kClientFragmentShaderId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GetVertexAttribfv, 0>(
+ bool valid) {
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ DoVertexAttribPointer(1, 1, GL_FLOAT, 0, 0);
+ if (valid) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
new file mode 100644
index 00000000000..bb4b8c86b5c
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -0,0 +1,1869 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by gles2_cmd_decoder_unittest_1.cc
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
+
+// TODO(gman): ActiveTexture
+
+TEST_F(GLES2DecoderTest1, AttachShaderValidArgs) {
+ EXPECT_CALL(*gl_, AttachShader(kServiceProgramId, kServiceShaderId));
+ SpecializedSetup<cmds::AttachShader, 0>(true);
+ cmds::AttachShader cmd;
+ cmd.Init(client_program_id_, client_shader_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): BindAttribLocation
+
+// TODO(gman): BindAttribLocationImmediate
+
+// TODO(gman): BindAttribLocationBucket
+
+TEST_F(GLES2DecoderTest1, BindBufferValidArgs) {
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceBufferId));
+ SpecializedSetup<cmds::BindBuffer, 0>(true);
+ cmds::BindBuffer cmd;
+ cmd.Init(GL_ARRAY_BUFFER, client_buffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindBufferValidArgsNewId) {
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kNewServiceId));
+ EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ SpecializedSetup<cmds::BindBuffer, 0>(true);
+ cmds::BindBuffer cmd;
+ cmd.Init(GL_ARRAY_BUFFER, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetBuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, BindBufferInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, BindBuffer(_, _)).Times(0);
+ SpecializedSetup<cmds::BindBuffer, 0>(false);
+ cmds::BindBuffer cmd;
+ cmd.Init(GL_RENDERBUFFER, client_buffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindFramebufferValidArgs) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, kServiceFramebufferId));
+ SpecializedSetup<cmds::BindFramebuffer, 0>(true);
+ cmds::BindFramebuffer cmd;
+ cmd.Init(GL_FRAMEBUFFER, client_framebuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindFramebufferValidArgsNewId) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, kNewServiceId));
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ SpecializedSetup<cmds::BindFramebuffer, 0>(true);
+ cmds::BindFramebuffer cmd;
+ cmd.Init(GL_FRAMEBUFFER, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetFramebuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, BindFramebufferInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(_, _)).Times(0);
+ SpecializedSetup<cmds::BindFramebuffer, 0>(false);
+ cmds::BindFramebuffer cmd;
+ cmd.Init(GL_DRAW_FRAMEBUFFER, client_framebuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindFramebufferInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(_, _)).Times(0);
+ SpecializedSetup<cmds::BindFramebuffer, 0>(false);
+ cmds::BindFramebuffer cmd;
+ cmd.Init(GL_READ_FRAMEBUFFER, client_framebuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindRenderbufferValidArgs) {
+ EXPECT_CALL(
+ *gl_, BindRenderbufferEXT(GL_RENDERBUFFER, kServiceRenderbufferId));
+ SpecializedSetup<cmds::BindRenderbuffer, 0>(true);
+ cmds::BindRenderbuffer cmd;
+ cmd.Init(GL_RENDERBUFFER, client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindRenderbufferValidArgsNewId) {
+ EXPECT_CALL(*gl_, BindRenderbufferEXT(GL_RENDERBUFFER, kNewServiceId));
+ EXPECT_CALL(*gl_, GenRenderbuffersEXT(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ SpecializedSetup<cmds::BindRenderbuffer, 0>(true);
+ cmds::BindRenderbuffer cmd;
+ cmd.Init(GL_RENDERBUFFER, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetRenderbuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, BindRenderbufferInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, BindRenderbufferEXT(_, _)).Times(0);
+ SpecializedSetup<cmds::BindRenderbuffer, 0>(false);
+ cmds::BindRenderbuffer cmd;
+ cmd.Init(GL_FRAMEBUFFER, client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindTextureValidArgs) {
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kServiceTextureId));
+ SpecializedSetup<cmds::BindTexture, 0>(true);
+ cmds::BindTexture cmd;
+ cmd.Init(GL_TEXTURE_2D, client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindTextureValidArgsNewId) {
+ EXPECT_CALL(*gl_, BindTexture(GL_TEXTURE_2D, kNewServiceId));
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ SpecializedSetup<cmds::BindTexture, 0>(true);
+ cmds::BindTexture cmd;
+ cmd.Init(GL_TEXTURE_2D, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetTexture(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, BindTextureInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, BindTexture(_, _)).Times(0);
+ SpecializedSetup<cmds::BindTexture, 0>(false);
+ cmds::BindTexture cmd;
+ cmd.Init(GL_TEXTURE_1D, client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BindTextureInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, BindTexture(_, _)).Times(0);
+ SpecializedSetup<cmds::BindTexture, 0>(false);
+ cmds::BindTexture cmd;
+ cmd.Init(GL_TEXTURE_3D, client_texture_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendColorValidArgs) {
+ EXPECT_CALL(*gl_, BlendColor(1, 2, 3, 4));
+ SpecializedSetup<cmds::BlendColor, 0>(true);
+ cmds::BlendColor cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationValidArgs) {
+ EXPECT_CALL(*gl_, BlendEquation(GL_FUNC_SUBTRACT));
+ SpecializedSetup<cmds::BlendEquation, 0>(true);
+ cmds::BlendEquation cmd;
+ cmd.Init(GL_FUNC_SUBTRACT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, BlendEquation(_)).Times(0);
+ SpecializedSetup<cmds::BlendEquation, 0>(false);
+ cmds::BlendEquation cmd;
+ cmd.Init(GL_MIN);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, BlendEquation(_)).Times(0);
+ SpecializedSetup<cmds::BlendEquation, 0>(false);
+ cmds::BlendEquation cmd;
+ cmd.Init(GL_MAX);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationSeparateValidArgs) {
+ EXPECT_CALL(*gl_, BlendEquationSeparate(GL_FUNC_SUBTRACT, GL_FUNC_ADD));
+ SpecializedSetup<cmds::BlendEquationSeparate, 0>(true);
+ cmds::BlendEquationSeparate cmd;
+ cmd.Init(GL_FUNC_SUBTRACT, GL_FUNC_ADD);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationSeparateInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, BlendEquationSeparate(_, _)).Times(0);
+ SpecializedSetup<cmds::BlendEquationSeparate, 0>(false);
+ cmds::BlendEquationSeparate cmd;
+ cmd.Init(GL_MIN, GL_FUNC_ADD);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationSeparateInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, BlendEquationSeparate(_, _)).Times(0);
+ SpecializedSetup<cmds::BlendEquationSeparate, 0>(false);
+ cmds::BlendEquationSeparate cmd;
+ cmd.Init(GL_MAX, GL_FUNC_ADD);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationSeparateInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, BlendEquationSeparate(_, _)).Times(0);
+ SpecializedSetup<cmds::BlendEquationSeparate, 0>(false);
+ cmds::BlendEquationSeparate cmd;
+ cmd.Init(GL_FUNC_SUBTRACT, GL_MIN);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendEquationSeparateInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, BlendEquationSeparate(_, _)).Times(0);
+ SpecializedSetup<cmds::BlendEquationSeparate, 0>(false);
+ cmds::BlendEquationSeparate cmd;
+ cmd.Init(GL_FUNC_SUBTRACT, GL_MAX);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendFuncValidArgs) {
+ EXPECT_CALL(*gl_, BlendFunc(GL_ZERO, GL_ZERO));
+ SpecializedSetup<cmds::BlendFunc, 0>(true);
+ cmds::BlendFunc cmd;
+ cmd.Init(GL_ZERO, GL_ZERO);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, BlendFuncSeparateValidArgs) {
+ EXPECT_CALL(*gl_, BlendFuncSeparate(GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO));
+ SpecializedSetup<cmds::BlendFuncSeparate, 0>(true);
+ cmds::BlendFuncSeparate cmd;
+ cmd.Init(GL_ZERO, GL_ZERO, GL_ZERO, GL_ZERO);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): BufferData
+
+// TODO(gman): BufferDataImmediate
+
+// TODO(gman): BufferSubData
+
+// TODO(gman): BufferSubDataImmediate
+
+
+TEST_F(GLES2DecoderTest1, CheckFramebufferStatusValidArgs) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER));
+ SpecializedSetup<cmds::CheckFramebufferStatus, 0>(true);
+ cmds::CheckFramebufferStatus cmd;
+ cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CheckFramebufferStatusInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)).Times(0);
+ SpecializedSetup<cmds::CheckFramebufferStatus, 0>(false);
+ cmds::CheckFramebufferStatus cmd;
+ cmd.Init(GL_DRAW_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CheckFramebufferStatusInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(_)).Times(0);
+ SpecializedSetup<cmds::CheckFramebufferStatus, 0>(false);
+ cmds::CheckFramebufferStatus cmd;
+ cmd.Init(GL_READ_FRAMEBUFFER, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CheckFramebufferStatusInvalidArgsBadSharedMemoryId) {
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(GL_FRAMEBUFFER)).Times(0);
+ SpecializedSetup<cmds::CheckFramebufferStatus, 0>(false);
+ cmds::CheckFramebufferStatus cmd;
+ cmd.Init(GL_FRAMEBUFFER, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(GL_FRAMEBUFFER, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, ClearValidArgs) {
+ EXPECT_CALL(*gl_, Clear(1));
+ SpecializedSetup<cmds::Clear, 0>(true);
+ cmds::Clear cmd;
+ cmd.Init(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, ClearColorValidArgs) {
+ EXPECT_CALL(*gl_, ClearColor(1, 2, 3, 4));
+ SpecializedSetup<cmds::ClearColor, 0>(true);
+ cmds::ClearColor cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, ClearDepthfValidArgs) {
+ EXPECT_CALL(*gl_, ClearDepth(0.5f));
+ SpecializedSetup<cmds::ClearDepthf, 0>(true);
+ cmds::ClearDepthf cmd;
+ cmd.Init(0.5f);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, ClearStencilValidArgs) {
+ EXPECT_CALL(*gl_, ClearStencil(1));
+ SpecializedSetup<cmds::ClearStencil, 0>(true);
+ cmds::ClearStencil cmd;
+ cmd.Init(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, ColorMaskValidArgs) {
+ SpecializedSetup<cmds::ColorMask, 0>(true);
+ cmds::ColorMask cmd;
+ cmd.Init(true, true, true, true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): CompileShader
+// TODO(gman): CompressedTexImage2D
+
+// TODO(gman): CompressedTexImage2DImmediate
+
+// TODO(gman): CompressedTexImage2DBucket
+// TODO(gman): CompressedTexSubImage2D
+
+// TODO(gman): CompressedTexSubImage2DImmediate
+
+// TODO(gman): CompressedTexSubImage2DBucket
+// TODO(gman): CopyTexImage2D
+
+TEST_F(GLES2DecoderTest1, CopyTexSubImage2DValidArgs) {
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(GL_TEXTURE_2D, 2, 3, 4, 5, 6, 7, 8));
+ SpecializedSetup<cmds::CopyTexSubImage2D, 0>(true);
+ cmds::CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 2, 3, 4, 5, 6, 7, 8);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CopyTexSubImage2DInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(_, _, _, _, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::CopyTexSubImage2D, 0>(false);
+ cmds::CopyTexSubImage2D cmd;
+ cmd.Init(GL_PROXY_TEXTURE_CUBE_MAP, 2, 3, 4, 5, 6, 7, 8);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CopyTexSubImage2DInvalidArgs6_0) {
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(_, _, _, _, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::CopyTexSubImage2D, 0>(false);
+ cmds::CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 2, 3, 4, 5, 6, -1, 8);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CopyTexSubImage2DInvalidArgs7_0) {
+ EXPECT_CALL(*gl_, CopyTexSubImage2D(_, _, _, _, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::CopyTexSubImage2D, 0>(false);
+ cmds::CopyTexSubImage2D cmd;
+ cmd.Init(GL_TEXTURE_2D, 2, 3, 4, 5, 6, 7, -1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CreateProgramValidArgs) {
+ EXPECT_CALL(*gl_, CreateProgram())
+ .WillOnce(Return(kNewServiceId));
+ SpecializedSetup<cmds::CreateProgram, 0>(true);
+ cmds::CreateProgram cmd;
+ cmd.Init(kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetProgram(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, CreateShaderValidArgs) {
+ EXPECT_CALL(*gl_, CreateShader(GL_VERTEX_SHADER))
+ .WillOnce(Return(kNewServiceId));
+ SpecializedSetup<cmds::CreateShader, 0>(true);
+ cmds::CreateShader cmd;
+ cmd.Init(GL_VERTEX_SHADER, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetShader(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, CreateShaderInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, CreateShader(_)).Times(0);
+ SpecializedSetup<cmds::CreateShader, 0>(false);
+ cmds::CreateShader cmd;
+ cmd.Init(GL_GEOMETRY_SHADER, kNewClientId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, CullFaceValidArgs) {
+ EXPECT_CALL(*gl_, CullFace(GL_FRONT));
+ SpecializedSetup<cmds::CullFace, 0>(true);
+ cmds::CullFace cmd;
+ cmd.Init(GL_FRONT);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DeleteBuffersValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteBuffersARB(1, Pointee(kServiceBufferId)))
+ .Times(1);
+ GetSharedMemoryAs<GLuint*>()[0] = client_buffer_id_;
+ SpecializedSetup<cmds::DeleteBuffers, 0>(true);
+ cmds::DeleteBuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetBuffer(client_buffer_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteBuffersInvalidArgs) {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ SpecializedSetup<cmds::DeleteBuffers, 0>(false);
+ cmds::DeleteBuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteBuffersImmediateValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteBuffersARB(1, Pointee(kServiceBufferId)))
+ .Times(1);
+ cmds::DeleteBuffersImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteBuffersImmediate>();
+ SpecializedSetup<cmds::DeleteBuffersImmediate, 0>(true);
+ cmd.Init(1, &client_buffer_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_buffer_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetBuffer(client_buffer_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteBuffersImmediateInvalidArgs) {
+ cmds::DeleteBuffersImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteBuffersImmediate>();
+ SpecializedSetup<cmds::DeleteBuffersImmediate, 0>(false);
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteFramebuffersValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteFramebuffersEXT(1, Pointee(kServiceFramebufferId)))
+ .Times(1);
+ GetSharedMemoryAs<GLuint*>()[0] = client_framebuffer_id_;
+ SpecializedSetup<cmds::DeleteFramebuffers, 0>(true);
+ cmds::DeleteFramebuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetFramebuffer(client_framebuffer_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteFramebuffersInvalidArgs) {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ SpecializedSetup<cmds::DeleteFramebuffers, 0>(false);
+ cmds::DeleteFramebuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteFramebuffersImmediateValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteFramebuffersEXT(1, Pointee(kServiceFramebufferId)))
+ .Times(1);
+ cmds::DeleteFramebuffersImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteFramebuffersImmediate>();
+ SpecializedSetup<cmds::DeleteFramebuffersImmediate, 0>(true);
+ cmd.Init(1, &client_framebuffer_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_framebuffer_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetFramebuffer(client_framebuffer_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteFramebuffersImmediateInvalidArgs) {
+ cmds::DeleteFramebuffersImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteFramebuffersImmediate>();
+ SpecializedSetup<cmds::DeleteFramebuffersImmediate, 0>(false);
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteProgramValidArgs) {
+ EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId));
+ SpecializedSetup<cmds::DeleteProgram, 0>(true);
+ cmds::DeleteProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DeleteRenderbuffersValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteRenderbuffersEXT(1, Pointee(kServiceRenderbufferId)))
+ .Times(1);
+ GetSharedMemoryAs<GLuint*>()[0] = client_renderbuffer_id_;
+ SpecializedSetup<cmds::DeleteRenderbuffers, 0>(true);
+ cmds::DeleteRenderbuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetRenderbuffer(client_renderbuffer_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteRenderbuffersInvalidArgs) {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ SpecializedSetup<cmds::DeleteRenderbuffers, 0>(false);
+ cmds::DeleteRenderbuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteRenderbuffersImmediateValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteRenderbuffersEXT(1, Pointee(kServiceRenderbufferId)))
+ .Times(1);
+ cmds::DeleteRenderbuffersImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteRenderbuffersImmediate>();
+ SpecializedSetup<cmds::DeleteRenderbuffersImmediate, 0>(true);
+ cmd.Init(1, &client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_renderbuffer_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetRenderbuffer(client_renderbuffer_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteRenderbuffersImmediateInvalidArgs) {
+ cmds::DeleteRenderbuffersImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteRenderbuffersImmediate>();
+ SpecializedSetup<cmds::DeleteRenderbuffersImmediate, 0>(false);
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteShaderValidArgs) {
+ EXPECT_CALL(*gl_, DeleteShader(kServiceShaderId));
+ SpecializedSetup<cmds::DeleteShader, 0>(true);
+ cmds::DeleteShader cmd;
+ cmd.Init(client_shader_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DeleteTexturesValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteTextures(1, Pointee(kServiceTextureId)))
+ .Times(1);
+ GetSharedMemoryAs<GLuint*>()[0] = client_texture_id_;
+ SpecializedSetup<cmds::DeleteTextures, 0>(true);
+ cmds::DeleteTextures cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetTexture(client_texture_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteTexturesInvalidArgs) {
+ GetSharedMemoryAs<GLuint*>()[0] = kInvalidClientId;
+ SpecializedSetup<cmds::DeleteTextures, 0>(false);
+ cmds::DeleteTextures cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, DeleteTexturesImmediateValidArgs) {
+ EXPECT_CALL(
+ *gl_,
+ DeleteTextures(1, Pointee(kServiceTextureId)))
+ .Times(1);
+ cmds::DeleteTexturesImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteTexturesImmediate>();
+ SpecializedSetup<cmds::DeleteTexturesImmediate, 0>(true);
+ cmd.Init(1, &client_texture_id_);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_texture_id_)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(
+ GetTexture(client_texture_id_) == NULL);
+}
+
+TEST_F(GLES2DecoderTest1, DeleteTexturesImmediateInvalidArgs) {
+ cmds::DeleteTexturesImmediate& cmd =
+ *GetImmediateAs<cmds::DeleteTexturesImmediate>();
+ SpecializedSetup<cmds::DeleteTexturesImmediate, 0>(false);
+ GLuint temp = kInvalidClientId;
+ cmd.Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+}
+
+TEST_F(GLES2DecoderTest1, DepthFuncValidArgs) {
+ EXPECT_CALL(*gl_, DepthFunc(GL_NEVER));
+ SpecializedSetup<cmds::DepthFunc, 0>(true);
+ cmds::DepthFunc cmd;
+ cmd.Init(GL_NEVER);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DepthMaskValidArgs) {
+ SpecializedSetup<cmds::DepthMask, 0>(true);
+ cmds::DepthMask cmd;
+ cmd.Init(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DepthRangefValidArgs) {
+ EXPECT_CALL(*gl_, DepthRange(1, 2));
+ SpecializedSetup<cmds::DepthRangef, 0>(true);
+ cmds::DepthRangef cmd;
+ cmd.Init(1, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DetachShaderValidArgs) {
+ EXPECT_CALL(*gl_, DetachShader(kServiceProgramId, kServiceShaderId));
+ SpecializedSetup<cmds::DetachShader, 0>(true);
+ cmds::DetachShader cmd;
+ cmd.Init(client_program_id_, client_shader_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DisableValidArgs) {
+ EXPECT_CALL(*gl_, Disable(GL_BLEND));
+ SpecializedSetup<cmds::Disable, 0>(true);
+ cmds::Disable cmd;
+ cmd.Init(GL_BLEND);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DisableInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, Disable(_)).Times(0);
+ SpecializedSetup<cmds::Disable, 0>(false);
+ cmds::Disable cmd;
+ cmd.Init(GL_CLIP_PLANE0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DisableInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, Disable(_)).Times(0);
+ SpecializedSetup<cmds::Disable, 0>(false);
+ cmds::Disable cmd;
+ cmd.Init(GL_POINT_SPRITE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, DisableVertexAttribArrayValidArgs) {
+ EXPECT_CALL(*gl_, DisableVertexAttribArray(1));
+ SpecializedSetup<cmds::DisableVertexAttribArray, 0>(true);
+ cmds::DisableVertexAttribArray cmd;
+ cmd.Init(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): DrawArrays
+
+// TODO(gman): DrawElements
+
+
+TEST_F(GLES2DecoderTest1, EnableValidArgs) {
+ EXPECT_CALL(*gl_, Enable(GL_BLEND));
+ SpecializedSetup<cmds::Enable, 0>(true);
+ cmds::Enable cmd;
+ cmd.Init(GL_BLEND);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, EnableInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, Enable(_)).Times(0);
+ SpecializedSetup<cmds::Enable, 0>(false);
+ cmds::Enable cmd;
+ cmd.Init(GL_CLIP_PLANE0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, EnableInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, Enable(_)).Times(0);
+ SpecializedSetup<cmds::Enable, 0>(false);
+ cmds::Enable cmd;
+ cmd.Init(GL_POINT_SPRITE);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, EnableVertexAttribArrayValidArgs) {
+ EXPECT_CALL(*gl_, EnableVertexAttribArray(1));
+ SpecializedSetup<cmds::EnableVertexAttribArray, 0>(true);
+ cmds::EnableVertexAttribArray cmd;
+ cmd.Init(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FinishValidArgs) {
+ EXPECT_CALL(*gl_, Finish());
+ SpecializedSetup<cmds::Finish, 0>(true);
+ cmds::Finish cmd;
+ cmd.Init();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FlushValidArgs) {
+ EXPECT_CALL(*gl_, Flush());
+ SpecializedSetup<cmds::Flush, 0>(true);
+ cmds::Flush cmd;
+ cmd.Init();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferRenderbufferValidArgs) {
+ EXPECT_CALL(
+ *gl_, FramebufferRenderbufferEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ kServiceRenderbufferId));
+ SpecializedSetup<cmds::FramebufferRenderbuffer, 0>(true);
+ cmds::FramebufferRenderbuffer cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferRenderbufferInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferRenderbuffer, 0>(false);
+ cmds::FramebufferRenderbuffer cmd;
+ cmd.Init(
+ GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferRenderbufferInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferRenderbuffer, 0>(false);
+ cmds::FramebufferRenderbuffer cmd;
+ cmd.Init(
+ GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferRenderbufferInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferRenderbuffer, 0>(false);
+ cmds::FramebufferRenderbuffer cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_FRAMEBUFFER,
+ client_renderbuffer_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferTexture2DValidArgs) {
+ EXPECT_CALL(
+ *gl_, FramebufferTexture2DEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ kServiceTextureId, 0));
+ SpecializedSetup<cmds::FramebufferTexture2D, 0>(true);
+ cmds::FramebufferTexture2D cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
+ 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferTexture2DInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferTexture2D, 0>(false);
+ cmds::FramebufferTexture2D cmd;
+ cmd.Init(
+ GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ client_texture_id_, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferTexture2DInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferTexture2D, 0>(false);
+ cmds::FramebufferTexture2D cmd;
+ cmd.Init(
+ GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
+ client_texture_id_, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferTexture2DInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferTexture2D, 0>(false);
+ cmds::FramebufferTexture2D cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_PROXY_TEXTURE_CUBE_MAP,
+ client_texture_id_, 0);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FramebufferTexture2DInvalidArgs4_0) {
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(_, _, _, _, _)).Times(0);
+ SpecializedSetup<cmds::FramebufferTexture2D, 0>(false);
+ cmds::FramebufferTexture2D cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, client_texture_id_,
+ 1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, FrontFaceValidArgs) {
+ EXPECT_CALL(*gl_, FrontFace(GL_CW));
+ SpecializedSetup<cmds::FrontFace, 0>(true);
+ cmds::FrontFace cmd;
+ cmd.Init(GL_CW);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GenBuffersValidArgs) {
+ EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ SpecializedSetup<cmds::GenBuffers, 0>(true);
+ cmds::GenBuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetBuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenBuffersInvalidArgs) {
+ EXPECT_CALL(*gl_, GenBuffersARB(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_buffer_id_;
+ SpecializedSetup<cmds::GenBuffers, 0>(false);
+ cmds::GenBuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, GenBuffersImmediateValidArgs) {
+ EXPECT_CALL(*gl_, GenBuffersARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ cmds::GenBuffersImmediate* cmd = GetImmediateAs<cmds::GenBuffersImmediate>();
+ GLuint temp = kNewClientId;
+ SpecializedSetup<cmds::GenBuffersImmediate, 0>(true);
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetBuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenBuffersImmediateInvalidArgs) {
+ EXPECT_CALL(*gl_, GenBuffersARB(_, _)).Times(0);
+ cmds::GenBuffersImmediate* cmd = GetImmediateAs<cmds::GenBuffersImmediate>();
+ SpecializedSetup<cmds::GenBuffersImmediate, 0>(false);
+ cmd->Init(1, &client_buffer_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_buffer_id_)));
+}
+
+TEST_F(GLES2DecoderTest1, GenerateMipmapValidArgs) {
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(GL_TEXTURE_2D));
+ SpecializedSetup<cmds::GenerateMipmap, 0>(true);
+ cmds::GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_2D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GenerateMipmapInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(_)).Times(0);
+ SpecializedSetup<cmds::GenerateMipmap, 0>(false);
+ cmds::GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_1D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GenerateMipmapInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, GenerateMipmapEXT(_)).Times(0);
+ SpecializedSetup<cmds::GenerateMipmap, 0>(false);
+ cmds::GenerateMipmap cmd;
+ cmd.Init(GL_TEXTURE_3D);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GenFramebuffersValidArgs) {
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ SpecializedSetup<cmds::GenFramebuffers, 0>(true);
+ cmds::GenFramebuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetFramebuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenFramebuffersInvalidArgs) {
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_framebuffer_id_;
+ SpecializedSetup<cmds::GenFramebuffers, 0>(false);
+ cmds::GenFramebuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, GenFramebuffersImmediateValidArgs) {
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ cmds::GenFramebuffersImmediate* cmd =
+ GetImmediateAs<cmds::GenFramebuffersImmediate>();
+ GLuint temp = kNewClientId;
+ SpecializedSetup<cmds::GenFramebuffersImmediate, 0>(true);
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetFramebuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenFramebuffersImmediateInvalidArgs) {
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(_, _)).Times(0);
+ cmds::GenFramebuffersImmediate* cmd =
+ GetImmediateAs<cmds::GenFramebuffersImmediate>();
+ SpecializedSetup<cmds::GenFramebuffersImmediate, 0>(false);
+ cmd->Init(1, &client_framebuffer_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_framebuffer_id_)));
+}
+
+TEST_F(GLES2DecoderTest1, GenRenderbuffersValidArgs) {
+ EXPECT_CALL(*gl_, GenRenderbuffersEXT(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ SpecializedSetup<cmds::GenRenderbuffers, 0>(true);
+ cmds::GenRenderbuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetRenderbuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenRenderbuffersInvalidArgs) {
+ EXPECT_CALL(*gl_, GenRenderbuffersEXT(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_renderbuffer_id_;
+ SpecializedSetup<cmds::GenRenderbuffers, 0>(false);
+ cmds::GenRenderbuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, GenRenderbuffersImmediateValidArgs) {
+ EXPECT_CALL(*gl_, GenRenderbuffersEXT(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ cmds::GenRenderbuffersImmediate* cmd =
+ GetImmediateAs<cmds::GenRenderbuffersImmediate>();
+ GLuint temp = kNewClientId;
+ SpecializedSetup<cmds::GenRenderbuffersImmediate, 0>(true);
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetRenderbuffer(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenRenderbuffersImmediateInvalidArgs) {
+ EXPECT_CALL(*gl_, GenRenderbuffersEXT(_, _)).Times(0);
+ cmds::GenRenderbuffersImmediate* cmd =
+ GetImmediateAs<cmds::GenRenderbuffersImmediate>();
+ SpecializedSetup<cmds::GenRenderbuffersImmediate, 0>(false);
+ cmd->Init(1, &client_renderbuffer_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_renderbuffer_id_)));
+}
+
+TEST_F(GLES2DecoderTest1, GenTexturesValidArgs) {
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ GetSharedMemoryAs<GLuint*>()[0] = kNewClientId;
+ SpecializedSetup<cmds::GenTextures, 0>(true);
+ cmds::GenTextures cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetTexture(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenTexturesInvalidArgs) {
+ EXPECT_CALL(*gl_, GenTextures(_, _)).Times(0);
+ GetSharedMemoryAs<GLuint*>()[0] = client_texture_id_;
+ SpecializedSetup<cmds::GenTextures, 0>(false);
+ cmds::GenTextures cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, GenTexturesImmediateValidArgs) {
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgumentPointee<1>(kNewServiceId));
+ cmds::GenTexturesImmediate* cmd =
+ GetImmediateAs<cmds::GenTexturesImmediate>();
+ GLuint temp = kNewClientId;
+ SpecializedSetup<cmds::GenTexturesImmediate, 0>(true);
+ cmd->Init(1, &temp);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(*cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ EXPECT_TRUE(GetTexture(kNewClientId) != NULL);
+}
+
+TEST_F(GLES2DecoderTest1, GenTexturesImmediateInvalidArgs) {
+ EXPECT_CALL(*gl_, GenTextures(_, _)).Times(0);
+ cmds::GenTexturesImmediate* cmd =
+ GetImmediateAs<cmds::GenTexturesImmediate>();
+ SpecializedSetup<cmds::GenTexturesImmediate, 0>(false);
+ cmd->Init(1, &client_texture_id_);
+ EXPECT_EQ(error::kInvalidArguments,
+ ExecuteImmediateCmd(*cmd, sizeof(&client_texture_id_)));
+}
+// TODO(gman): GetActiveAttrib
+
+// TODO(gman): GetActiveUniform
+
+// TODO(gman): GetAttachedShaders
+
+// TODO(gman): GetAttribLocation
+
+// TODO(gman): GetAttribLocationImmediate
+
+// TODO(gman): GetAttribLocationBucket
+
+
+TEST_F(GLES2DecoderTest1, GetBooleanvValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetBooleanv, 0>(true);
+ typedef cmds::GetBooleanv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetBooleanv(GL_ACTIVE_TEXTURE, result->GetData()));
+ result->size = 0;
+ cmds::GetBooleanv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_ACTIVE_TEXTURE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetBooleanvInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetBooleanv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetBooleanv, 0>(false);
+ cmds::GetBooleanv::Result* result =
+ static_cast<cmds::GetBooleanv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBooleanv cmd;
+ cmd.Init(GL_FOG_HINT, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetBooleanvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, GetBooleanv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetBooleanv, 0>(false);
+ cmds::GetBooleanv::Result* result =
+ static_cast<cmds::GetBooleanv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBooleanv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetBooleanvInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, GetBooleanv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetBooleanv, 0>(false);
+ cmds::GetBooleanv::Result* result =
+ static_cast<cmds::GetBooleanv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBooleanv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetBufferParameterivValidArgs) {
+ SpecializedSetup<cmds::GetBufferParameteriv, 0>(true);
+ typedef cmds::GetBufferParameteriv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBufferParameteriv cmd;
+ cmd.Init(
+ GL_ARRAY_BUFFER, GL_BUFFER_SIZE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_BUFFER_SIZE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetBufferParameterivInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetBufferParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetBufferParameteriv, 0>(false);
+ cmds::GetBufferParameteriv::Result* result =
+ static_cast<cmds::GetBufferParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBufferParameteriv cmd;
+ cmd.Init(
+ GL_RENDERBUFFER, GL_BUFFER_SIZE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetBufferParameterivInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, GetBufferParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetBufferParameteriv, 0>(false);
+ cmds::GetBufferParameteriv::Result* result =
+ static_cast<cmds::GetBufferParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBufferParameteriv cmd;
+ cmd.Init(
+ GL_ARRAY_BUFFER, GL_PIXEL_PACK_BUFFER, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetBufferParameterivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetBufferParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetBufferParameteriv, 0>(false);
+ cmds::GetBufferParameteriv::Result* result =
+ static_cast<cmds::GetBufferParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBufferParameteriv cmd;
+ cmd.Init(GL_ARRAY_BUFFER, GL_BUFFER_SIZE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetBufferParameterivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetBufferParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetBufferParameteriv, 0>(false);
+ cmds::GetBufferParameteriv::Result* result =
+ static_cast<cmds::GetBufferParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetBufferParameteriv cmd;
+ cmd.Init(
+ GL_ARRAY_BUFFER, GL_BUFFER_SIZE, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetErrorValidArgs) {
+ EXPECT_CALL(*gl_, GetError());
+ SpecializedSetup<cmds::GetError, 0>(true);
+ cmds::GetError cmd;
+ cmd.Init(shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetErrorInvalidArgsBadSharedMemoryId) {
+ EXPECT_CALL(*gl_, GetError()).Times(0);
+ SpecializedSetup<cmds::GetError, 0>(false);
+ cmds::GetError cmd;
+ cmd.Init(kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest1, GetFloatvValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetFloatv, 0>(true);
+ typedef cmds::GetFloatv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetFloatv(GL_ACTIVE_TEXTURE, result->GetData()));
+ result->size = 0;
+ cmds::GetFloatv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_ACTIVE_TEXTURE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetFloatvInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetFloatv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetFloatv, 0>(false);
+ cmds::GetFloatv::Result* result =
+ static_cast<cmds::GetFloatv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetFloatv cmd;
+ cmd.Init(GL_FOG_HINT, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetFloatvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, GetFloatv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetFloatv, 0>(false);
+ cmds::GetFloatv::Result* result =
+ static_cast<cmds::GetFloatv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetFloatv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetFloatvInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, GetFloatv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetFloatv, 0>(false);
+ cmds::GetFloatv::Result* result =
+ static_cast<cmds::GetFloatv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetFloatv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetFramebufferAttachmentParameterivValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetFramebufferAttachmentParameteriv, 0>(true);
+ typedef cmds::GetFramebufferAttachmentParameteriv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(
+ *gl_, GetFramebufferAttachmentParameterivEXT(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, result->GetData()));
+ result->size = 0;
+ cmds::GetFramebufferAttachmentParameteriv cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetFramebufferAttachmentParameterivInvalidArgs0_0) {
+ EXPECT_CALL(
+ *gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::GetFramebufferAttachmentParameteriv, 0>(false);
+ cmds::GetFramebufferAttachmentParameteriv::Result* result =
+ static_cast<cmds::GetFramebufferAttachmentParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetFramebufferAttachmentParameteriv cmd;
+ cmd.Init(
+ GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetFramebufferAttachmentParameterivInvalidArgs0_1) {
+ EXPECT_CALL(
+ *gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::GetFramebufferAttachmentParameteriv, 0>(false);
+ cmds::GetFramebufferAttachmentParameteriv::Result* result =
+ static_cast<cmds::GetFramebufferAttachmentParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetFramebufferAttachmentParameteriv cmd;
+ cmd.Init(
+ GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetFramebufferAttachmentParameterivInvalidArgs3_0) {
+ EXPECT_CALL(
+ *gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::GetFramebufferAttachmentParameteriv, 0>(false);
+ cmds::GetFramebufferAttachmentParameteriv::Result* result =
+ static_cast<cmds::GetFramebufferAttachmentParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetFramebufferAttachmentParameteriv cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetFramebufferAttachmentParameterivInvalidArgs3_1) {
+ EXPECT_CALL(
+ *gl_, GetFramebufferAttachmentParameterivEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::GetFramebufferAttachmentParameteriv, 0>(false);
+ cmds::GetFramebufferAttachmentParameteriv::Result* result =
+ static_cast<cmds::GetFramebufferAttachmentParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetFramebufferAttachmentParameteriv cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetIntegervValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetIntegerv, 0>(true);
+ typedef cmds::GetIntegerv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(*gl_, GetIntegerv(GL_ACTIVE_TEXTURE, result->GetData()));
+ result->size = 0;
+ cmds::GetIntegerv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_ACTIVE_TEXTURE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetIntegervInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetIntegerv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetIntegerv, 0>(false);
+ cmds::GetIntegerv::Result* result =
+ static_cast<cmds::GetIntegerv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetIntegerv cmd;
+ cmd.Init(GL_FOG_HINT, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetIntegervInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, GetIntegerv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetIntegerv, 0>(false);
+ cmds::GetIntegerv::Result* result =
+ static_cast<cmds::GetIntegerv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetIntegerv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetIntegervInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, GetIntegerv(_, _)).Times(0);
+ SpecializedSetup<cmds::GetIntegerv, 0>(false);
+ cmds::GetIntegerv::Result* result =
+ static_cast<cmds::GetIntegerv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetIntegerv cmd;
+ cmd.Init(GL_ACTIVE_TEXTURE, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetProgramivValidArgs) {
+ SpecializedSetup<cmds::GetProgramiv, 0>(true);
+ typedef cmds::GetProgramiv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetProgramiv cmd;
+ cmd.Init(
+ client_program_id_, GL_DELETE_STATUS, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_DELETE_STATUS),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetProgramivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetProgramiv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetProgramiv, 0>(false);
+ cmds::GetProgramiv::Result* result =
+ static_cast<cmds::GetProgramiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetProgramiv cmd;
+ cmd.Init(client_program_id_, GL_DELETE_STATUS, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetProgramivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetProgramiv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetProgramiv, 0>(false);
+ cmds::GetProgramiv::Result* result =
+ static_cast<cmds::GetProgramiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetProgramiv cmd;
+ cmd.Init(
+ client_program_id_, GL_DELETE_STATUS, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetProgramInfoLogValidArgs) {
+ const char* kInfo = "hello";
+ const uint32 kBucketId = 123;
+ SpecializedSetup<cmds::GetProgramInfoLog, 0>(true);
+
+ cmds::GetProgramInfoLog cmd;
+ cmd.Init(client_program_id_, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(strlen(kInfo) + 1, bucket->size());
+ EXPECT_EQ(0, memcmp(bucket->GetData(0, bucket->size()), kInfo,
+ bucket->size()));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetProgramInfoLogInvalidArgs) {
+ const uint32 kBucketId = 123;
+ cmds::GetProgramInfoLog cmd;
+ cmd.Init(kInvalidClientId, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetRenderbufferParameterivValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetRenderbufferParameteriv, 0>(true);
+ typedef cmds::GetRenderbufferParameteriv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(
+ *gl_, GetRenderbufferParameterivEXT(
+ GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, result->GetData()));
+ result->size = 0;
+ cmds::GetRenderbufferParameteriv cmd;
+ cmd.Init(
+ GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_RENDERBUFFER_RED_SIZE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetRenderbufferParameterivInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetRenderbufferParameterivEXT(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetRenderbufferParameteriv, 0>(false);
+ cmds::GetRenderbufferParameteriv::Result* result =
+ static_cast<cmds::GetRenderbufferParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetRenderbufferParameteriv cmd;
+ cmd.Init(
+ GL_FRAMEBUFFER, GL_RENDERBUFFER_RED_SIZE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetRenderbufferParameterivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetRenderbufferParameterivEXT(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetRenderbufferParameteriv, 0>(false);
+ cmds::GetRenderbufferParameteriv::Result* result =
+ static_cast<cmds::GetRenderbufferParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetRenderbufferParameteriv cmd;
+ cmd.Init(
+ GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetRenderbufferParameterivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetRenderbufferParameterivEXT(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetRenderbufferParameteriv, 0>(false);
+ cmds::GetRenderbufferParameteriv::Result* result =
+ static_cast<cmds::GetRenderbufferParameteriv::Result*>(
+ shared_memory_address_);
+ result->size = 0;
+ cmds::GetRenderbufferParameteriv cmd;
+ cmd.Init(
+ GL_RENDERBUFFER, GL_RENDERBUFFER_RED_SIZE, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetShaderivValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetShaderiv, 0>(true);
+ typedef cmds::GetShaderiv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(
+ *gl_, GetShaderiv(kServiceShaderId, GL_SHADER_TYPE, result->GetData()));
+ result->size = 0;
+ cmds::GetShaderiv cmd;
+ cmd.Init(
+ client_shader_id_, GL_SHADER_TYPE, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_SHADER_TYPE),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetShaderivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetShaderiv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetShaderiv, 0>(false);
+ cmds::GetShaderiv::Result* result =
+ static_cast<cmds::GetShaderiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetShaderiv cmd;
+ cmd.Init(client_shader_id_, GL_SHADER_TYPE, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetShaderivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetShaderiv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetShaderiv, 0>(false);
+ cmds::GetShaderiv::Result* result =
+ static_cast<cmds::GetShaderiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetShaderiv cmd;
+ cmd.Init(
+ client_shader_id_, GL_SHADER_TYPE, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+// TODO(gman): GetShaderInfoLog
+// TODO(gman): GetShaderPrecisionFormat
+
+// TODO(gman): GetShaderSource
+// TODO(gman): GetString
+
+
+TEST_F(GLES2DecoderTest1, GetTexParameterfvValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetTexParameterfv, 0>(true);
+ typedef cmds::GetTexParameterfv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(
+ *gl_, GetTexParameterfv(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, result->GetData()));
+ result->size = 0;
+ cmds::GetTexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_TEXTURE_MAG_FILTER),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterfvInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+ cmds::GetTexParameterfv::Result* result =
+ static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameterfv cmd;
+ cmd.Init(
+ GL_PROXY_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterfvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+ cmds::GetTexParameterfv::Result* result =
+ static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterfvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+ cmds::GetTexParameterfv::Result* result =
+ static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameterfv cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterfvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetTexParameterfv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameterfv, 0>(false);
+ cmds::GetTexParameterfv::Result* result =
+ static_cast<cmds::GetTexParameterfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterivValidArgs) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ SpecializedSetup<cmds::GetTexParameteriv, 0>(true);
+ typedef cmds::GetTexParameteriv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ EXPECT_CALL(
+ *gl_, GetTexParameteriv(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, result->GetData()));
+ result->size = 0;
+ cmds::GetTexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_TEXTURE_MAG_FILTER),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterivInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+ cmds::GetTexParameteriv::Result* result =
+ static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameteriv cmd;
+ cmd.Init(
+ GL_PROXY_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterivInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+ cmds::GetTexParameteriv::Result* result =
+ static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+ cmds::GetTexParameteriv::Result* result =
+ static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameteriv cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetTexParameterivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetTexParameteriv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetTexParameteriv, 0>(false);
+ cmds::GetTexParameteriv::Result* result =
+ static_cast<cmds::GetTexParameteriv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetTexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+// TODO(gman): GetUniformfv
+
+// TODO(gman): GetUniformiv
+
+// TODO(gman): GetUniformLocation
+
+// TODO(gman): GetUniformLocationImmediate
+
+// TODO(gman): GetUniformLocationBucket
+
+
+TEST_F(GLES2DecoderTest1, GetVertexAttribfvValidArgs) {
+ SpecializedSetup<cmds::GetVertexAttribfv, 0>(true);
+ typedef cmds::GetVertexAttribfv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetVertexAttribfv cmd;
+ cmd.Init(
+ 1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_VERTEX_ATTRIB_ARRAY_NORMALIZED),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest1, GetVertexAttribfvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetVertexAttribfv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetVertexAttribfv, 0>(false);
+ cmds::GetVertexAttribfv::Result* result =
+ static_cast<cmds::GetVertexAttribfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetVertexAttribfv cmd;
+ cmd.Init(1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest1, GetVertexAttribfvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetVertexAttribfv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetVertexAttribfv, 0>(false);
+ cmds::GetVertexAttribfv::Result* result =
+ static_cast<cmds::GetVertexAttribfv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetVertexAttribfv cmd;
+ cmd.Init(
+ 1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
new file mode 100644
index 00000000000..12d96c28242
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
@@ -0,0 +1,402 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+
+namespace gpu {
+namespace gles2 {
+
+class GLES2DecoderTest2 : public GLES2DecoderTestBase {
+ public:
+ GLES2DecoderTest2() { }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GenQueriesEXT, 0>(
+ bool valid) {
+ if (!valid) {
+ // Make the client_query_id_ so that trying to make it again
+ // will fail.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ cmds::GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GenQueriesEXTImmediate, 0>(
+ bool valid) {
+ if (!valid) {
+ // Make the client_query_id_ so that trying to make it again
+ // will fail.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ cmds::GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::DeleteQueriesEXT, 0>(
+ bool valid) {
+ if (valid) {
+ // Make the client_query_id_ so that trying to delete it will succeed.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ cmds::GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::DeleteQueriesEXTImmediate, 0>(
+ bool valid) {
+ if (valid) {
+ // Make the client_query_id_ so that trying to delete it will succeed.
+ GetSharedMemoryAs<GLuint*>()[0] = client_query_id_;
+ cmds::GenQueriesEXT cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::LinkProgram, 0>(
+ bool /* valid */) {
+ const GLuint kClientVertexShaderId = 5001;
+ const GLuint kServiceVertexShaderId = 6001;
+ const GLuint kClientFragmentShaderId = 5002;
+ const GLuint kServiceFragmentShaderId = 6002;
+ DoCreateShader(
+ GL_VERTEX_SHADER, kClientVertexShaderId, kServiceVertexShaderId);
+ DoCreateShader(
+ GL_FRAGMENT_SHADER, kClientFragmentShaderId, kServiceFragmentShaderId);
+
+ GetShader(kClientVertexShaderId)->SetStatus(true, "", NULL);
+ GetShader(kClientFragmentShaderId)->SetStatus(true, "", NULL);
+
+ InSequence dummy;
+ EXPECT_CALL(*gl_,
+ AttachShader(kServiceProgramId, kServiceVertexShaderId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ AttachShader(kServiceProgramId, kServiceFragmentShaderId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_LINK_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(1));
+ EXPECT_CALL(*gl_,
+ GetProgramiv(kServiceProgramId, GL_INFO_LOG_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_ATTRIBUTES, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(
+ *gl_,
+ GetProgramiv(kServiceProgramId, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(
+ *gl_,
+ GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+
+ cmds::AttachShader attach_cmd;
+ attach_cmd.Init(client_program_id_, kClientVertexShaderId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+
+ attach_cmd.Init(client_program_id_, kClientFragmentShaderId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::ValidateProgram, 0>(
+ bool /* valid */) {
+ // Needs the same setup as LinkProgram.
+ SpecializedSetup<cmds::LinkProgram, 0>(false);
+
+ EXPECT_CALL(*gl_, LinkProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ cmds::LinkProgram link_cmd;
+ link_cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(link_cmd));
+
+ EXPECT_CALL(*gl_,
+ GetProgramiv(kServiceProgramId, GL_INFO_LOG_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform1f, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform1fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform1fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform1iv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform1ivImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform2f, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform2i, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform2fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform2iv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform2fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform2ivImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform3f, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform3i, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform3fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform3iv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform3fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform3ivImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform4f, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform4i, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform4fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform4iv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform4fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_VEC4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::Uniform4ivImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_INT_VEC4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::UniformMatrix2fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_MAT2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::UniformMatrix2fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_MAT2);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::UniformMatrix3fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_MAT3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::UniformMatrix3fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_MAT3);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::UniformMatrix4fv, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_MAT4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::UniformMatrix4fvImmediate, 0>(
+ bool /* valid */) {
+ SetupShaderForUniform(GL_FLOAT_MAT4);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::RenderbufferStorage, 0>(
+ bool valid) {
+ DoBindRenderbuffer(GL_RENDERBUFFER, client_renderbuffer_id_,
+ kServiceRenderbufferId);
+ if (valid) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ RenderbufferStorageEXT(GL_RENDERBUFFER, _, 3, 4))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::TexParameterf, 0>(
+ bool /* valid */) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::TexParameteri, 0>(
+ bool /* valid */) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::TexParameterfv, 0>(
+ bool /* valid */) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::TexParameterfvImmediate, 0>(
+ bool /* valid */) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::TexParameteriv, 0>(
+ bool /* valid */) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::TexParameterivImmediate, 0>(
+ bool /* valid */) {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+};
+
+template <>
+void GLES2DecoderTestBase::SpecializedSetup<cmds::GetVertexAttribiv, 0>(
+ bool valid) {
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ DoVertexAttribPointer(1, 1, GL_FLOAT, 0, 0);
+ if (valid) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+};
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
new file mode 100644
index 00000000000..caff2eb9807
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -0,0 +1,1767 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by gles2_cmd_decoder_unittest_2.cc
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
+
+
+TEST_F(GLES2DecoderTest2, GetVertexAttribivValidArgs) {
+ SpecializedSetup<cmds::GetVertexAttribiv, 0>(true);
+ typedef cmds::GetVertexAttribiv::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetVertexAttribiv cmd;
+ cmd.Init(
+ 1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, shared_memory_id_,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(decoder_->GetGLES2Util()->GLGetNumValuesReturned(
+ GL_VERTEX_ATTRIB_ARRAY_NORMALIZED),
+ result->GetNumResults());
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, GetVertexAttribivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, GetVertexAttribiv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetVertexAttribiv, 0>(false);
+ cmds::GetVertexAttribiv::Result* result =
+ static_cast<cmds::GetVertexAttribiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetVertexAttribiv cmd;
+ cmd.Init(1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+
+TEST_F(GLES2DecoderTest2, GetVertexAttribivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, GetVertexAttribiv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::GetVertexAttribiv, 0>(false);
+ cmds::GetVertexAttribiv::Result* result =
+ static_cast<cmds::GetVertexAttribiv::Result*>(shared_memory_address_);
+ result->size = 0;
+ cmds::GetVertexAttribiv cmd;
+ cmd.Init(
+ 1, GL_VERTEX_ATTRIB_ARRAY_NORMALIZED, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(0u, result->size);
+}
+// TODO(gman): GetVertexAttribPointerv
+
+
+TEST_F(GLES2DecoderTest2, HintValidArgs) {
+ EXPECT_CALL(*gl_, Hint(GL_GENERATE_MIPMAP_HINT, GL_FASTEST));
+ SpecializedSetup<cmds::Hint, 0>(true);
+ cmds::Hint cmd;
+ cmd.Init(GL_GENERATE_MIPMAP_HINT, GL_FASTEST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, HintInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, Hint(_, _)).Times(0);
+ SpecializedSetup<cmds::Hint, 0>(false);
+ cmds::Hint cmd;
+ cmd.Init(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsBufferValidArgs) {
+ SpecializedSetup<cmds::IsBuffer, 0>(true);
+ cmds::IsBuffer cmd;
+ cmd.Init(client_buffer_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsBufferInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsBuffer, 0>(false);
+ cmds::IsBuffer cmd;
+ cmd.Init(client_buffer_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(client_buffer_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, IsEnabledValidArgs) {
+ SpecializedSetup<cmds::IsEnabled, 0>(true);
+ cmds::IsEnabled cmd;
+ cmd.Init(GL_BLEND, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsEnabledInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, IsEnabled(_)).Times(0);
+ SpecializedSetup<cmds::IsEnabled, 0>(false);
+ cmds::IsEnabled cmd;
+ cmd.Init(GL_CLIP_PLANE0, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsEnabledInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, IsEnabled(_)).Times(0);
+ SpecializedSetup<cmds::IsEnabled, 0>(false);
+ cmds::IsEnabled cmd;
+ cmd.Init(GL_POINT_SPRITE, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsEnabledInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsEnabled, 0>(false);
+ cmds::IsEnabled cmd;
+ cmd.Init(GL_BLEND, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(GL_BLEND, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, IsFramebufferValidArgs) {
+ SpecializedSetup<cmds::IsFramebuffer, 0>(true);
+ cmds::IsFramebuffer cmd;
+ cmd.Init(client_framebuffer_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsFramebufferInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsFramebuffer, 0>(false);
+ cmds::IsFramebuffer cmd;
+ cmd.Init(
+ client_framebuffer_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(
+ client_framebuffer_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, IsProgramValidArgs) {
+ SpecializedSetup<cmds::IsProgram, 0>(true);
+ cmds::IsProgram cmd;
+ cmd.Init(client_program_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsProgramInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsProgram, 0>(false);
+ cmds::IsProgram cmd;
+ cmd.Init(client_program_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(client_program_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, IsRenderbufferValidArgs) {
+ SpecializedSetup<cmds::IsRenderbuffer, 0>(true);
+ cmds::IsRenderbuffer cmd;
+ cmd.Init(client_renderbuffer_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsRenderbufferInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsRenderbuffer, 0>(false);
+ cmds::IsRenderbuffer cmd;
+ cmd.Init(
+ client_renderbuffer_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(
+ client_renderbuffer_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, IsShaderValidArgs) {
+ SpecializedSetup<cmds::IsShader, 0>(true);
+ cmds::IsShader cmd;
+ cmd.Init(client_shader_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsShaderInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsShader, 0>(false);
+ cmds::IsShader cmd;
+ cmd.Init(client_shader_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(client_shader_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, IsTextureValidArgs) {
+ SpecializedSetup<cmds::IsTexture, 0>(true);
+ cmds::IsTexture cmd;
+ cmd.Init(client_texture_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, IsTextureInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsTexture, 0>(false);
+ cmds::IsTexture cmd;
+ cmd.Init(client_texture_id_, kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(client_texture_id_, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, LineWidthValidArgs) {
+ EXPECT_CALL(*gl_, LineWidth(0.5f));
+ SpecializedSetup<cmds::LineWidth, 0>(true);
+ cmds::LineWidth cmd;
+ cmd.Init(0.5f);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, LineWidthInvalidValue0_0) {
+ SpecializedSetup<cmds::LineWidth, 0>(false);
+ cmds::LineWidth cmd;
+ cmd.Init(0.0f);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, LinkProgramValidArgs) {
+ EXPECT_CALL(*gl_, LinkProgram(kServiceProgramId));
+ SpecializedSetup<cmds::LinkProgram, 0>(true);
+ cmds::LinkProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): PixelStorei
+
+
+TEST_F(GLES2DecoderTest2, PolygonOffsetValidArgs) {
+ EXPECT_CALL(*gl_, PolygonOffset(1, 2));
+ SpecializedSetup<cmds::PolygonOffset, 0>(true);
+ cmds::PolygonOffset cmd;
+ cmd.Init(1, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): ReadPixels
+
+// TODO(gman): ReleaseShaderCompiler
+
+TEST_F(GLES2DecoderTest2, RenderbufferStorageValidArgs) {
+ SpecializedSetup<cmds::RenderbufferStorage, 0>(true);
+ cmds::RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, RenderbufferStorageInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::RenderbufferStorage, 0>(false);
+ cmds::RenderbufferStorage cmd;
+ cmd.Init(GL_FRAMEBUFFER, GL_RGBA4, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, RenderbufferStorageInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::RenderbufferStorage, 0>(false);
+ cmds::RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, -1, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, RenderbufferStorageInvalidArgs3_0) {
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::RenderbufferStorage, 0>(false);
+ cmds::RenderbufferStorage cmd;
+ cmd.Init(GL_RENDERBUFFER, GL_RGBA4, 3, -1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, SampleCoverageValidArgs) {
+ EXPECT_CALL(*gl_, SampleCoverage(1, true));
+ SpecializedSetup<cmds::SampleCoverage, 0>(true);
+ cmds::SampleCoverage cmd;
+ cmd.Init(1, true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, ScissorValidArgs) {
+ EXPECT_CALL(*gl_, Scissor(1, 2, 3, 4));
+ SpecializedSetup<cmds::Scissor, 0>(true);
+ cmds::Scissor cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, ScissorInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Scissor(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::Scissor, 0>(false);
+ cmds::Scissor cmd;
+ cmd.Init(1, 2, -1, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, ScissorInvalidArgs3_0) {
+ EXPECT_CALL(*gl_, Scissor(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::Scissor, 0>(false);
+ cmds::Scissor cmd;
+ cmd.Init(1, 2, 3, -1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+// TODO(gman): ShaderBinary
+
+// TODO(gman): ShaderSource
+
+// TODO(gman): ShaderSourceImmediate
+
+// TODO(gman): ShaderSourceBucket
+
+TEST_F(GLES2DecoderTest2, StencilFuncValidArgs) {
+ EXPECT_CALL(*gl_, StencilFunc(GL_NEVER, 2, 3));
+ SpecializedSetup<cmds::StencilFunc, 0>(true);
+ cmds::StencilFunc cmd;
+ cmd.Init(GL_NEVER, 2, 3);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, StencilFuncSeparateValidArgs) {
+ EXPECT_CALL(*gl_, StencilFuncSeparate(GL_FRONT, GL_NEVER, 3, 4));
+ SpecializedSetup<cmds::StencilFuncSeparate, 0>(true);
+ cmds::StencilFuncSeparate cmd;
+ cmd.Init(GL_FRONT, GL_NEVER, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, StencilMaskValidArgs) {
+ SpecializedSetup<cmds::StencilMask, 0>(true);
+ cmds::StencilMask cmd;
+ cmd.Init(1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, StencilMaskSeparateValidArgs) {
+ SpecializedSetup<cmds::StencilMaskSeparate, 0>(true);
+ cmds::StencilMaskSeparate cmd;
+ cmd.Init(GL_FRONT, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, StencilOpValidArgs) {
+ EXPECT_CALL(*gl_, StencilOp(GL_KEEP, GL_INCR, GL_KEEP));
+ SpecializedSetup<cmds::StencilOp, 0>(true);
+ cmds::StencilOp cmd;
+ cmd.Init(GL_KEEP, GL_INCR, GL_KEEP);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, StencilOpSeparateValidArgs) {
+ EXPECT_CALL(*gl_, StencilOpSeparate(GL_FRONT, GL_INCR, GL_KEEP, GL_KEEP));
+ SpecializedSetup<cmds::StencilOpSeparate, 0>(true);
+ cmds::StencilOpSeparate cmd;
+ cmd.Init(GL_FRONT, GL_INCR, GL_KEEP, GL_KEEP);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): TexImage2D
+
+// TODO(gman): TexImage2DImmediate
+
+
+TEST_F(GLES2DecoderTest2, TexParameterfValidArgs) {
+ EXPECT_CALL(
+ *gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+ SpecializedSetup<cmds::TexParameterf, 0>(true);
+ cmds::TexParameterf cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterf, 0>(false);
+ cmds::TexParameterf cmd;
+ cmd.Init(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterf, 0>(false);
+ cmds::TexParameterf cmd;
+ cmd.Init(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterf, 0>(false);
+ cmds::TexParameterf cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvValidArgs) {
+ SpecializedSetup<cmds::TexParameterfv, 0>(true);
+ cmds::TexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = GL_NEAREST;
+ EXPECT_CALL(
+ *gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ *reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfv, 0>(false);
+ cmds::TexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfv, 0>(false);
+ cmds::TexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfv, 0>(false);
+ cmds::TexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfv, 0>(false);
+ cmds::TexParameterfv cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
+ GetSharedMemoryAs<GLfloat*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfv, 0>(false);
+ cmds::TexParameterfv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ GetSharedMemoryAs<GLfloat*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvImmediateValidArgs) {
+ cmds::TexParameterfvImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterfvImmediate>();
+ SpecializedSetup<cmds::TexParameterfvImmediate, 0>(true);
+ GLfloat temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, *reinterpret_cast<
+ GLfloat*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvImmediateInvalidArgs0_0) {
+ cmds::TexParameterfvImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterfvImmediate>();
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfvImmediate, 0>(false);
+ GLfloat temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvImmediateInvalidArgs0_1) {
+ cmds::TexParameterfvImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterfvImmediate>();
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfvImmediate, 0>(false);
+ GLfloat temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterfvImmediateInvalidArgs1_0) {
+ cmds::TexParameterfvImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterfvImmediate>();
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterfvImmediate, 0>(false);
+ GLfloat temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameteriValidArgs) {
+ EXPECT_CALL(
+ *gl_, TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+ SpecializedSetup<cmds::TexParameteri, 0>(true);
+ cmds::TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameteriInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteri, 0>(false);
+ cmds::TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameteriInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteri, 0>(false);
+ cmds::TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameteriInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteri, 0>(false);
+ cmds::TexParameteri cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_NEAREST);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivValidArgs) {
+ SpecializedSetup<cmds::TexParameteriv, 0>(true);
+ cmds::TexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLint*>()[0] = GL_NEAREST;
+ EXPECT_CALL(
+ *gl_, TexParameteri(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, *reinterpret_cast<const GLint*>(
+ shared_memory_address_)));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivInvalidArgs0_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteriv, 0>(false);
+ cmds::TexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLint*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivInvalidArgs0_1) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteriv, 0>(false);
+ cmds::TexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLint*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteriv, 0>(false);
+ cmds::TexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_GENERATE_MIPMAP, shared_memory_id_,
+ shared_memory_offset_);
+ GetSharedMemoryAs<GLint*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteriv, 0>(false);
+ cmds::TexParameteriv cmd;
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, kInvalidSharedMemoryId, 0);
+ GetSharedMemoryAs<GLint*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameteriv, 0>(false);
+ cmds::TexParameteriv cmd;
+ cmd.Init(
+ GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ GetSharedMemoryAs<GLint*>()[0] = GL_NEAREST;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivImmediateValidArgs) {
+ cmds::TexParameterivImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterivImmediate>();
+ SpecializedSetup<cmds::TexParameterivImmediate, 0>(true);
+ GLint temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, *reinterpret_cast<
+ GLint*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivImmediateInvalidArgs0_0) {
+ cmds::TexParameterivImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterivImmediate>();
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterivImmediate, 0>(false);
+ GLint temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivImmediateInvalidArgs0_1) {
+ cmds::TexParameterivImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterivImmediate>();
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterivImmediate, 0>(false);
+ GLint temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, TexParameterivImmediateInvalidArgs1_0) {
+ cmds::TexParameterivImmediate& cmd =
+ *GetImmediateAs<cmds::TexParameterivImmediate>();
+ EXPECT_CALL(*gl_, TexParameteri(_, _, _)).Times(0);
+ SpecializedSetup<cmds::TexParameterivImmediate, 0>(false);
+ GLint temp[1] = { GL_NEAREST, };
+ cmd.Init(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
+}
+// TODO(gman): TexSubImage2D
+
+// TODO(gman): TexSubImage2DImmediate
+
+
+TEST_F(GLES2DecoderTest2, Uniform1fValidArgs) {
+ EXPECT_CALL(*gl_, Uniform1fv(1, 1, _));
+ SpecializedSetup<cmds::Uniform1f, 0>(true);
+ cmds::Uniform1f cmd;
+ cmd.Init(1, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform1fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform1fv(
+ 1, 2, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform1fv, 0>(true);
+ cmds::Uniform1fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform1fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform1fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform1fv, 0>(false);
+ cmds::Uniform1fv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform1fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform1fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform1fv, 0>(false);
+ cmds::Uniform1fv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform1fvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform1fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform1fv, 0>(false);
+ cmds::Uniform1fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform1fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform1fv(
+ 3, 3, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform1fv, 0>(true);
+ cmds::Uniform1fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform1fvImmediateValidArgs) {
+ cmds::Uniform1fvImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform1fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform1fv(1, 2,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform1fvImmediate, 0>(true);
+ GLfloat temp[1 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): Uniform1i
+// TODO(gman): Uniform1iv
+// TODO(gman): Uniform1ivImmediate
+
+TEST_F(GLES2DecoderTest2, Uniform2fValidArgs) {
+ EXPECT_CALL(*gl_, Uniform2fv(1, 1, _));
+ SpecializedSetup<cmds::Uniform2f, 0>(true);
+ cmds::Uniform2f cmd;
+ cmd.Init(1, 2, 3);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform2fv(
+ 1, 2, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform2fv, 0>(true);
+ cmds::Uniform2fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform2fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform2fv, 0>(false);
+ cmds::Uniform2fv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform2fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform2fv, 0>(false);
+ cmds::Uniform2fv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2fvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform2fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform2fv, 0>(false);
+ cmds::Uniform2fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform2fv(
+ 3, 3, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform2fv, 0>(true);
+ cmds::Uniform2fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2fvImmediateValidArgs) {
+ cmds::Uniform2fvImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform2fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform2fv(1, 2,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform2fvImmediate, 0>(true);
+ GLfloat temp[2 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2iValidArgs) {
+ EXPECT_CALL(*gl_, Uniform2iv(1, 1, _));
+ SpecializedSetup<cmds::Uniform2i, 0>(true);
+ cmds::Uniform2i cmd;
+ cmd.Init(1, 2, 3);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2ivValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform2iv(
+ 1, 2, reinterpret_cast<const GLint*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform2iv, 0>(true);
+ cmds::Uniform2iv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2ivInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform2iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform2iv, 0>(false);
+ cmds::Uniform2iv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2ivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform2iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform2iv, 0>(false);
+ cmds::Uniform2iv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2ivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform2iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform2iv, 0>(false);
+ cmds::Uniform2iv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2ivValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform2iv(
+ 3, 3, reinterpret_cast<const GLint*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform2iv, 0>(true);
+ cmds::Uniform2iv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform2ivImmediateValidArgs) {
+ cmds::Uniform2ivImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform2ivImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform2iv(1, 2,
+ reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform2ivImmediate, 0>(true);
+ GLint temp[2 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fValidArgs) {
+ EXPECT_CALL(*gl_, Uniform3fv(1, 1, _));
+ SpecializedSetup<cmds::Uniform3f, 0>(true);
+ cmds::Uniform3f cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform3fv(
+ 1, 2, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform3fv, 0>(true);
+ cmds::Uniform3fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform3fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform3fv, 0>(false);
+ cmds::Uniform3fv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform3fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform3fv, 0>(false);
+ cmds::Uniform3fv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform3fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform3fv, 0>(false);
+ cmds::Uniform3fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform3fv(
+ 3, 3, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform3fv, 0>(true);
+ cmds::Uniform3fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3fvImmediateValidArgs) {
+ cmds::Uniform3fvImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform3fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform3fv(1, 2,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform3fvImmediate, 0>(true);
+ GLfloat temp[3 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3iValidArgs) {
+ EXPECT_CALL(*gl_, Uniform3iv(1, 1, _));
+ SpecializedSetup<cmds::Uniform3i, 0>(true);
+ cmds::Uniform3i cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3ivValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform3iv(
+ 1, 2, reinterpret_cast<const GLint*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform3iv, 0>(true);
+ cmds::Uniform3iv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3ivInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform3iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform3iv, 0>(false);
+ cmds::Uniform3iv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3ivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform3iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform3iv, 0>(false);
+ cmds::Uniform3iv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3ivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform3iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform3iv, 0>(false);
+ cmds::Uniform3iv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3ivValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform3iv(
+ 3, 3, reinterpret_cast<const GLint*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform3iv, 0>(true);
+ cmds::Uniform3iv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform3ivImmediateValidArgs) {
+ cmds::Uniform3ivImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform3ivImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform3iv(1, 2,
+ reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform3ivImmediate, 0>(true);
+ GLint temp[3 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fValidArgs) {
+ EXPECT_CALL(*gl_, Uniform4fv(1, 1, _));
+ SpecializedSetup<cmds::Uniform4f, 0>(true);
+ cmds::Uniform4f cmd;
+ cmd.Init(1, 2, 3, 4, 5);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform4fv(
+ 1, 2, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform4fv, 0>(true);
+ cmds::Uniform4fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform4fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform4fv, 0>(false);
+ cmds::Uniform4fv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform4fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform4fv, 0>(false);
+ cmds::Uniform4fv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fvInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform4fv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform4fv, 0>(false);
+ cmds::Uniform4fv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform4fv(
+ 3, 3, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform4fv, 0>(true);
+ cmds::Uniform4fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4fvImmediateValidArgs) {
+ cmds::Uniform4fvImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform4fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform4fv(1, 2,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform4fvImmediate, 0>(true);
+ GLfloat temp[4 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4iValidArgs) {
+ EXPECT_CALL(*gl_, Uniform4iv(1, 1, _));
+ SpecializedSetup<cmds::Uniform4i, 0>(true);
+ cmds::Uniform4i cmd;
+ cmd.Init(1, 2, 3, 4, 5);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4ivValidArgs) {
+ EXPECT_CALL(
+ *gl_, Uniform4iv(
+ 1, 2, reinterpret_cast<const GLint*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform4iv, 0>(true);
+ cmds::Uniform4iv cmd;
+ cmd.Init(1, 2, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4ivInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, Uniform4iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform4iv, 0>(false);
+ cmds::Uniform4iv cmd;
+ cmd.Init(1, -1, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4ivInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Uniform4iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform4iv, 0>(false);
+ cmds::Uniform4iv cmd;
+ cmd.Init(1, 2, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4ivInvalidArgs2_1) {
+ EXPECT_CALL(*gl_, Uniform4iv(_, _, _)).Times(0);
+ SpecializedSetup<cmds::Uniform4iv, 0>(false);
+ cmds::Uniform4iv cmd;
+ cmd.Init(1, 2, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4ivValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, Uniform4iv(
+ 3, 3, reinterpret_cast<const GLint*>(shared_memory_address_)));
+ SpecializedSetup<cmds::Uniform4iv, 0>(true);
+ cmds::Uniform4iv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, Uniform4ivImmediateValidArgs) {
+ cmds::Uniform4ivImmediate& cmd =
+ *GetImmediateAs<cmds::Uniform4ivImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ Uniform4iv(1, 2,
+ reinterpret_cast<GLint*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::Uniform4ivImmediate, 0>(true);
+ GLint temp[4 * 2] = { 0, };
+ cmd.Init(1, 2, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, UniformMatrix2fv(
+ 1, 2, false, reinterpret_cast<const GLfloat*>(
+ shared_memory_address_)));
+ SpecializedSetup<cmds::UniformMatrix2fv, 0>(true);
+ cmds::UniformMatrix2fv cmd;
+ cmd.Init(1, 2, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, UniformMatrix2fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix2fv, 0>(false);
+ cmds::UniformMatrix2fv cmd;
+ cmd.Init(1, -1, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, UniformMatrix2fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix2fv, 0>(false);
+ cmds::UniformMatrix2fv cmd;
+ cmd.Init(1, 2, true, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvInvalidArgs3_0) {
+ EXPECT_CALL(*gl_, UniformMatrix2fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix2fv, 0>(false);
+ cmds::UniformMatrix2fv cmd;
+ cmd.Init(1, 2, false, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvInvalidArgs3_1) {
+ EXPECT_CALL(*gl_, UniformMatrix2fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix2fv, 0>(false);
+ cmds::UniformMatrix2fv cmd;
+ cmd.Init(1, 2, false, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, UniformMatrix2fv(
+ 3, 3, false, reinterpret_cast<const GLfloat*>(
+ shared_memory_address_)));
+ SpecializedSetup<cmds::UniformMatrix2fv, 0>(true);
+ cmds::UniformMatrix2fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvImmediateValidArgs) {
+ cmds::UniformMatrix2fvImmediate& cmd =
+ *GetImmediateAs<cmds::UniformMatrix2fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ UniformMatrix2fv(1, 2, false,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::UniformMatrix2fvImmediate, 0>(true);
+ GLfloat temp[4 * 2] = { 0, };
+ cmd.Init(1, 2, false, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix2fvImmediateInvalidArgs2_0) {
+ cmds::UniformMatrix2fvImmediate& cmd =
+ *GetImmediateAs<cmds::UniformMatrix2fvImmediate>();
+ EXPECT_CALL(*gl_, UniformMatrix2fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix2fvImmediate, 0>(false);
+ GLfloat temp[4 * 2] = { 0, };
+ cmd.Init(1, 2, true, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, UniformMatrix3fv(
+ 1, 2, false, reinterpret_cast<const GLfloat*>(
+ shared_memory_address_)));
+ SpecializedSetup<cmds::UniformMatrix3fv, 0>(true);
+ cmds::UniformMatrix3fv cmd;
+ cmd.Init(1, 2, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, UniformMatrix3fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix3fv, 0>(false);
+ cmds::UniformMatrix3fv cmd;
+ cmd.Init(1, -1, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, UniformMatrix3fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix3fv, 0>(false);
+ cmds::UniformMatrix3fv cmd;
+ cmd.Init(1, 2, true, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvInvalidArgs3_0) {
+ EXPECT_CALL(*gl_, UniformMatrix3fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix3fv, 0>(false);
+ cmds::UniformMatrix3fv cmd;
+ cmd.Init(1, 2, false, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvInvalidArgs3_1) {
+ EXPECT_CALL(*gl_, UniformMatrix3fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix3fv, 0>(false);
+ cmds::UniformMatrix3fv cmd;
+ cmd.Init(1, 2, false, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, UniformMatrix3fv(
+ 3, 3, false, reinterpret_cast<const GLfloat*>(
+ shared_memory_address_)));
+ SpecializedSetup<cmds::UniformMatrix3fv, 0>(true);
+ cmds::UniformMatrix3fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvImmediateValidArgs) {
+ cmds::UniformMatrix3fvImmediate& cmd =
+ *GetImmediateAs<cmds::UniformMatrix3fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ UniformMatrix3fv(1, 2, false,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::UniformMatrix3fvImmediate, 0>(true);
+ GLfloat temp[9 * 2] = { 0, };
+ cmd.Init(1, 2, false, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix3fvImmediateInvalidArgs2_0) {
+ cmds::UniformMatrix3fvImmediate& cmd =
+ *GetImmediateAs<cmds::UniformMatrix3fvImmediate>();
+ EXPECT_CALL(*gl_, UniformMatrix3fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix3fvImmediate, 0>(false);
+ GLfloat temp[9 * 2] = { 0, };
+ cmd.Init(1, 2, true, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvValidArgs) {
+ EXPECT_CALL(
+ *gl_, UniformMatrix4fv(
+ 1, 2, false, reinterpret_cast<const GLfloat*>(
+ shared_memory_address_)));
+ SpecializedSetup<cmds::UniformMatrix4fv, 0>(true);
+ cmds::UniformMatrix4fv cmd;
+ cmd.Init(1, 2, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, UniformMatrix4fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix4fv, 0>(false);
+ cmds::UniformMatrix4fv cmd;
+ cmd.Init(1, -1, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, UniformMatrix4fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix4fv, 0>(false);
+ cmds::UniformMatrix4fv cmd;
+ cmd.Init(1, 2, true, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvInvalidArgs3_0) {
+ EXPECT_CALL(*gl_, UniformMatrix4fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix4fv, 0>(false);
+ cmds::UniformMatrix4fv cmd;
+ cmd.Init(1, 2, false, kInvalidSharedMemoryId, 0);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvInvalidArgs3_1) {
+ EXPECT_CALL(*gl_, UniformMatrix4fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix4fv, 0>(false);
+ cmds::UniformMatrix4fv cmd;
+ cmd.Init(1, 2, false, shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvValidArgsCountTooLarge) {
+ EXPECT_CALL(
+ *gl_, UniformMatrix4fv(
+ 3, 3, false, reinterpret_cast<const GLfloat*>(
+ shared_memory_address_)));
+ SpecializedSetup<cmds::UniformMatrix4fv, 0>(true);
+ cmds::UniformMatrix4fv cmd;
+ cmd.Init(
+ ProgramManager::MakeFakeLocation(
+ 1, 1), 5, false, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvImmediateValidArgs) {
+ cmds::UniformMatrix4fvImmediate& cmd =
+ *GetImmediateAs<cmds::UniformMatrix4fvImmediate>();
+ EXPECT_CALL(
+ *gl_,
+ UniformMatrix4fv(1, 2, false,
+ reinterpret_cast<GLfloat*>(ImmediateDataAddress(&cmd))));
+ SpecializedSetup<cmds::UniformMatrix4fvImmediate, 0>(true);
+ GLfloat temp[16 * 2] = { 0, };
+ cmd.Init(1, 2, false, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, UniformMatrix4fvImmediateInvalidArgs2_0) {
+ cmds::UniformMatrix4fvImmediate& cmd =
+ *GetImmediateAs<cmds::UniformMatrix4fvImmediate>();
+ EXPECT_CALL(*gl_, UniformMatrix4fv(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::UniformMatrix4fvImmediate, 0>(false);
+ GLfloat temp[16 * 2] = { 0, };
+ cmd.Init(1, 2, true, &temp[0]);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+// TODO(gman): UseProgram
+
+TEST_F(GLES2DecoderTest2, ValidateProgramValidArgs) {
+ EXPECT_CALL(*gl_, ValidateProgram(kServiceProgramId));
+ SpecializedSetup<cmds::ValidateProgram, 0>(true);
+ cmds::ValidateProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib1fValidArgs) {
+ EXPECT_CALL(*gl_, VertexAttrib1f(1, 2));
+ SpecializedSetup<cmds::VertexAttrib1f, 0>(true);
+ cmds::VertexAttrib1f cmd;
+ cmd.Init(1, 2);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib1fvValidArgs) {
+ SpecializedSetup<cmds::VertexAttrib1fv, 0>(true);
+ cmds::VertexAttrib1fv cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_CALL(
+ *gl_, VertexAttrib1fv(
+ 1, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib1fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, VertexAttrib1fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib1fv, 0>(false);
+ cmds::VertexAttrib1fv cmd;
+ cmd.Init(1, kInvalidSharedMemoryId, 0);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib1fvInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, VertexAttrib1fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib1fv, 0>(false);
+ cmds::VertexAttrib1fv cmd;
+ cmd.Init(1, shared_memory_id_, kInvalidSharedMemoryOffset);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib1fvImmediateValidArgs) {
+ cmds::VertexAttrib1fvImmediate& cmd =
+ *GetImmediateAs<cmds::VertexAttrib1fvImmediate>();
+ SpecializedSetup<cmds::VertexAttrib1fvImmediate, 0>(true);
+ GLfloat temp[1] = { 0, };
+ cmd.Init(1, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ VertexAttrib1fv(1, reinterpret_cast<
+ GLfloat*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib2fValidArgs) {
+ EXPECT_CALL(*gl_, VertexAttrib2f(1, 2, 3));
+ SpecializedSetup<cmds::VertexAttrib2f, 0>(true);
+ cmds::VertexAttrib2f cmd;
+ cmd.Init(1, 2, 3);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib2fvValidArgs) {
+ SpecializedSetup<cmds::VertexAttrib2fv, 0>(true);
+ cmds::VertexAttrib2fv cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_CALL(
+ *gl_, VertexAttrib2fv(
+ 1, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib2fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, VertexAttrib2fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib2fv, 0>(false);
+ cmds::VertexAttrib2fv cmd;
+ cmd.Init(1, kInvalidSharedMemoryId, 0);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib2fvInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, VertexAttrib2fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib2fv, 0>(false);
+ cmds::VertexAttrib2fv cmd;
+ cmd.Init(1, shared_memory_id_, kInvalidSharedMemoryOffset);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib2fvImmediateValidArgs) {
+ cmds::VertexAttrib2fvImmediate& cmd =
+ *GetImmediateAs<cmds::VertexAttrib2fvImmediate>();
+ SpecializedSetup<cmds::VertexAttrib2fvImmediate, 0>(true);
+ GLfloat temp[2] = { 0, };
+ cmd.Init(1, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ VertexAttrib2fv(1, reinterpret_cast<
+ GLfloat*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib3fValidArgs) {
+ EXPECT_CALL(*gl_, VertexAttrib3f(1, 2, 3, 4));
+ SpecializedSetup<cmds::VertexAttrib3f, 0>(true);
+ cmds::VertexAttrib3f cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib3fvValidArgs) {
+ SpecializedSetup<cmds::VertexAttrib3fv, 0>(true);
+ cmds::VertexAttrib3fv cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_CALL(
+ *gl_, VertexAttrib3fv(
+ 1, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib3fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, VertexAttrib3fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib3fv, 0>(false);
+ cmds::VertexAttrib3fv cmd;
+ cmd.Init(1, kInvalidSharedMemoryId, 0);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib3fvInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, VertexAttrib3fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib3fv, 0>(false);
+ cmds::VertexAttrib3fv cmd;
+ cmd.Init(1, shared_memory_id_, kInvalidSharedMemoryOffset);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib3fvImmediateValidArgs) {
+ cmds::VertexAttrib3fvImmediate& cmd =
+ *GetImmediateAs<cmds::VertexAttrib3fvImmediate>();
+ SpecializedSetup<cmds::VertexAttrib3fvImmediate, 0>(true);
+ GLfloat temp[3] = { 0, };
+ cmd.Init(1, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ VertexAttrib3fv(1, reinterpret_cast<
+ GLfloat*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib4fValidArgs) {
+ EXPECT_CALL(*gl_, VertexAttrib4f(1, 2, 3, 4, 5));
+ SpecializedSetup<cmds::VertexAttrib4f, 0>(true);
+ cmds::VertexAttrib4f cmd;
+ cmd.Init(1, 2, 3, 4, 5);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib4fvValidArgs) {
+ SpecializedSetup<cmds::VertexAttrib4fv, 0>(true);
+ cmds::VertexAttrib4fv cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_CALL(
+ *gl_, VertexAttrib4fv(
+ 1, reinterpret_cast<const GLfloat*>(shared_memory_address_)));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib4fvInvalidArgs1_0) {
+ EXPECT_CALL(*gl_, VertexAttrib4fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib4fv, 0>(false);
+ cmds::VertexAttrib4fv cmd;
+ cmd.Init(1, kInvalidSharedMemoryId, 0);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib4fvInvalidArgs1_1) {
+ EXPECT_CALL(*gl_, VertexAttrib4fv(_, _)).Times(0);
+ SpecializedSetup<cmds::VertexAttrib4fv, 0>(false);
+ cmds::VertexAttrib4fv cmd;
+ cmd.Init(1, shared_memory_id_, kInvalidSharedMemoryOffset);
+ GetSharedMemoryAs<GLfloat*>()[0] = 0;
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+
+TEST_F(GLES2DecoderTest2, VertexAttrib4fvImmediateValidArgs) {
+ cmds::VertexAttrib4fvImmediate& cmd =
+ *GetImmediateAs<cmds::VertexAttrib4fvImmediate>();
+ SpecializedSetup<cmds::VertexAttrib4fvImmediate, 0>(true);
+ GLfloat temp[4] = { 0, };
+ cmd.Init(1, &temp[0]);
+ EXPECT_CALL(
+ *gl_,
+ VertexAttrib4fv(1, reinterpret_cast<
+ GLfloat*>(ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+// TODO(gman): VertexAttribPointer
+
+
+TEST_F(GLES2DecoderTest2, ViewportValidArgs) {
+ EXPECT_CALL(*gl_, Viewport(1, 2, 3, 4));
+ SpecializedSetup<cmds::Viewport, 0>(true);
+ cmds::Viewport cmd;
+ cmd.Init(1, 2, 3, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, ViewportInvalidArgs2_0) {
+ EXPECT_CALL(*gl_, Viewport(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::Viewport, 0>(false);
+ cmds::Viewport cmd;
+ cmd.Init(1, 2, -1, 4);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_F(GLES2DecoderTest2, ViewportInvalidArgs3_0) {
+ EXPECT_CALL(*gl_, Viewport(_, _, _, _)).Times(0);
+ SpecializedSetup<cmds::Viewport, 0>(false);
+ cmds::Viewport cmd;
+ cmd.Init(1, 2, 3, -1);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+// TODO(gman): BlitFramebufferEXT
+// TODO(gman): RenderbufferStorageMultisampleEXT
+// TODO(gman): FramebufferTexture2DMultisampleEXT
+// TODO(gman): TexStorage2DEXT
+// TODO(gman): GenQueriesEXT
+// TODO(gman): GenQueriesEXTImmediate
+// TODO(gman): DeleteQueriesEXT
+// TODO(gman): DeleteQueriesEXTImmediate
+// TODO(gman): BeginQueryEXT
+
+// TODO(gman): EndQueryEXT
+
+// TODO(gman): InsertEventMarkerEXT
+
+// TODO(gman): PushGroupMarkerEXT
+
+
+TEST_F(GLES2DecoderTest2, PopGroupMarkerEXTValidArgs) {
+ SpecializedSetup<cmds::PopGroupMarkerEXT, 0>(true);
+ cmds::PopGroupMarkerEXT cmd;
+ cmd.Init();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc
new file mode 100644
index 00000000000..b41eed2953a
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+
+namespace gpu {
+namespace gles2 {
+
+using namespace cmds;
+
+class GLES2DecoderTest3 : public GLES2DecoderTestBase {
+ public:
+ GLES2DecoderTest3() { }
+};
+
+TEST_F(GLES2DecoderTest3, TraceBeginCHROMIUM) {
+ const uint32 kBucketId = 123;
+ const char kName[] = "test_command";
+ SetBucketAsCString(kBucketId, kName);
+
+ TraceBeginCHROMIUM begin_cmd;
+ begin_cmd.Init(kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+}
+
+TEST_F(GLES2DecoderTest3, TraceEndCHROMIUM) {
+ // Test end fails if no begin.
+ TraceEndCHROMIUM end_cmd;
+ end_cmd.Init();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+
+ const uint32 kBucketId = 123;
+ const char kName[] = "test_command";
+ SetBucketAsCString(kBucketId, kName);
+
+ TraceBeginCHROMIUM begin_cmd;
+ begin_cmd.Init(kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
+
+ end_cmd.Init();
+ EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
new file mode 100644
index 00000000000..58611bf39d0
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+// It is included by gles2_cmd_decoder_unittest_3.cc
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
+
+// TODO(gman): GenVertexArraysOES
+// TODO(gman): GenVertexArraysOESImmediate
+// TODO(gman): DeleteVertexArraysOES
+// TODO(gman): DeleteVertexArraysOESImmediate
+// TODO(gman): IsVertexArrayOES
+// TODO(gman): BindVertexArrayOES
+// TODO(gman): SwapBuffers
+// TODO(gman): GetMaxValueInBufferCHROMIUM
+// TODO(gman): GenSharedIdsCHROMIUM
+
+// TODO(gman): DeleteSharedIdsCHROMIUM
+
+// TODO(gman): RegisterSharedIdsCHROMIUM
+
+// TODO(gman): EnableFeatureCHROMIUM
+
+// TODO(gman): ResizeCHROMIUM
+// TODO(gman): GetRequestableExtensionsCHROMIUM
+
+// TODO(gman): RequestExtensionCHROMIUM
+
+// TODO(gman): GetMultipleIntegervCHROMIUM
+
+// TODO(gman): GetProgramInfoCHROMIUM
+
+// TODO(gman): CreateStreamTextureCHROMIUM
+
+// TODO(gman): DestroyStreamTextureCHROMIUM
+
+// TODO(gman): GetTranslatedShaderSourceANGLE
+// TODO(gman): PostSubBufferCHROMIUM
+// TODO(gman): TexImageIOSurface2DCHROMIUM
+// TODO(gman): CopyTextureCHROMIUM
+// TODO(gman): DrawArraysInstancedANGLE
+// TODO(gman): DrawElementsInstancedANGLE
+// TODO(gman): VertexAttribDivisorANGLE
+// TODO(gman): GenMailboxCHROMIUM
+// TODO(gman): ProduceTextureCHROMIUM
+// TODO(gman): ProduceTextureCHROMIUMImmediate
+// TODO(gman): ConsumeTextureCHROMIUM
+// TODO(gman): ConsumeTextureCHROMIUMImmediate
+// TODO(gman): BindUniformLocationCHROMIUM
+
+// TODO(gman): BindUniformLocationCHROMIUMImmediate
+
+// TODO(gman): BindUniformLocationCHROMIUMBucket
+// TODO(gman): BindTexImage2DCHROMIUM
+// TODO(gman): ReleaseTexImage2DCHROMIUM
+// TODO(gman): TraceBeginCHROMIUM
+
+// TODO(gman): TraceEndCHROMIUM
+// TODO(gman): AsyncTexSubImage2DCHROMIUM
+
+// TODO(gman): AsyncTexImage2DCHROMIUM
+
+// TODO(gman): WaitAsyncTexImage2DCHROMIUM
+
+// TODO(gman): DiscardFramebufferEXT
+// TODO(gman): DiscardFramebufferEXTImmediate
+// TODO(gman): LoseContextCHROMIUM
+
+// TODO(gman): InsertSyncPointCHROMIUM
+
+// TODO(gman): WaitSyncPointCHROMIUM
+
+// TODO(gman): DrawBuffersEXT
+// TODO(gman): DrawBuffersEXTImmediate
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
new file mode 100644
index 00000000000..e2e3551c9f2
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -0,0 +1,1434 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h"
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
+#include "gpu/command_buffer/service/logger.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgPointee;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+GLES2DecoderTestBase::GLES2DecoderTestBase()
+ : surface_(NULL),
+ context_(NULL),
+ memory_tracker_(NULL),
+ client_buffer_id_(100),
+ client_framebuffer_id_(101),
+ client_program_id_(102),
+ client_renderbuffer_id_(103),
+ client_shader_id_(104),
+ client_texture_id_(106),
+ client_element_buffer_id_(107),
+ client_vertex_shader_id_(121),
+ client_fragment_shader_id_(122),
+ client_query_id_(123),
+ client_vertexarray_id_(124) {
+ memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_));
+}
+
+GLES2DecoderTestBase::~GLES2DecoderTestBase() {}
+
+void GLES2DecoderTestBase::SetUp() {
+ InitDecoder(
+ "", // extensions
+ true, // has alpha
+ true, // has depth
+ false, // has stencil
+ true, // request alpha
+ true, // request depth
+ false, // request stencil
+ true); // bind generates resource
+}
+
+void GLES2DecoderTestBase::AddExpectationsForVertexAttribManager() {
+ for (GLint ii = 0; ii < kNumVertexAttribs; ++ii) {
+ EXPECT_CALL(*gl_, VertexAttrib4f(ii, 0.0f, 0.0f, 0.0f, 1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::InitDecoder(
+ const char* extensions,
+ bool has_alpha,
+ bool has_depth,
+ bool has_stencil,
+ bool request_alpha,
+ bool request_depth,
+ bool request_stencil,
+ bool bind_generates_resource) {
+ Framebuffer::ClearFramebufferCompleteComboMap();
+ gl_.reset(new StrictMock<MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ // Only create stream texture manager if extension is requested.
+ std::vector<std::string> list;
+ base::SplitString(std::string(extensions), ' ', &list);
+ if (std::find(list.begin(), list.end(),
+ "GL_CHROMIUM_stream_texture") != list.end())
+ stream_texture_manager_.reset(new StrictMock<MockStreamTextureManager>);
+ group_ = scoped_refptr<ContextGroup>(new ContextGroup(
+ NULL,
+ NULL,
+ memory_tracker_,
+ stream_texture_manager_.get(),
+ bind_generates_resource));
+ // These two workarounds are always turned on.
+ group_->feature_info(
+ )->workarounds_.set_texture_filter_before_generating_mipmap = true;
+ group_->feature_info()->workarounds_.clear_alpha_in_readpixels = true;
+
+ InSequence sequence;
+
+ TestHelper::SetupContextGroupInitExpectations(gl_.get(),
+ DisallowedFeatures(), extensions);
+
+ // We initialize the ContextGroup with a MockGLES2Decoder so that
+ // we can use the ContextGroup to figure out how the real GLES2Decoder
+ // will initialize itself.
+ mock_decoder_.reset(new MockGLES2Decoder());
+ EXPECT_TRUE(
+ group_->Initialize(mock_decoder_.get(), DisallowedFeatures(), NULL));
+
+ AddExpectationsForVertexAttribManager();
+
+ AddExpectationsForBindVertexArrayOES();
+
+ EXPECT_CALL(*gl_, EnableVertexAttribArray(0))
+ .Times(1)
+ .RetiresOnSaturation();
+ static GLuint attrib_0_id[] = {
+ kServiceAttrib0BufferId,
+ };
+ static GLuint fixed_attrib_buffer_id[] = {
+ kServiceFixedAttribBufferId,
+ };
+ EXPECT_CALL(*gl_, GenBuffersARB(arraysize(attrib_0_id), _))
+ .WillOnce(SetArrayArgument<1>(attrib_0_id,
+ attrib_0_id + arraysize(attrib_0_id)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, NULL))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GenBuffersARB(arraysize(fixed_attrib_buffer_id), _))
+ .WillOnce(SetArrayArgument<1>(
+ fixed_attrib_buffer_id,
+ fixed_attrib_buffer_id + arraysize(fixed_attrib_buffer_id)))
+ .RetiresOnSaturation();
+
+ for (GLint tt = 0; tt < TestHelper::kNumTextureUnits; ++tt) {
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0 + tt))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (group_->feature_info()->feature_flags().oes_egl_image_external) {
+ EXPECT_CALL(*gl_, BindTexture(
+ GL_TEXTURE_EXTERNAL_OES,
+ TestHelper::kServiceDefaultExternalTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if (group_->feature_info()->feature_flags().arb_texture_rectangle) {
+ EXPECT_CALL(*gl_, BindTexture(
+ GL_TEXTURE_RECTANGLE_ARB,
+ TestHelper::kServiceDefaultRectangleTextureId))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl_, BindTexture(
+ GL_TEXTURE_CUBE_MAP, TestHelper::kServiceDefaultTextureCubemapId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(
+ GL_TEXTURE_2D, TestHelper::kServiceDefaultTexture2dId))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetIntegerv(GL_ALPHA_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(has_alpha ? 8 : 0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetIntegerv(GL_DEPTH_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(has_depth ? 24 : 0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetIntegerv(GL_STENCIL_BITS, _))
+ .WillOnce(SetArgumentPointee<1>(has_stencil ? 8 : 0))
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, Enable(GL_VERTEX_PROGRAM_POINT_SIZE))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, Enable(GL_POINT_SPRITE))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ static GLint max_viewport_dims[] = {
+ kMaxViewportWidth,
+ kMaxViewportHeight
+ };
+ EXPECT_CALL(*gl_, GetIntegerv(GL_MAX_VIEWPORT_DIMS, _))
+ .WillOnce(SetArrayArgument<1>(
+ max_viewport_dims, max_viewport_dims + arraysize(max_viewport_dims)))
+ .RetiresOnSaturation();
+
+ SetupInitCapabilitiesExpectations();
+ SetupInitStateExpectations();
+
+ EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_FRAMEBUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindRenderbufferEXT(GL_RENDERBUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ // TODO(boliu): Remove OS_ANDROID once crbug.com/259023 is fixed and the
+ // workaround has been reverted.
+#if !defined(OS_ANDROID)
+ EXPECT_CALL(*gl_, Clear(
+ GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT))
+ .Times(1)
+ .RetiresOnSaturation();
+#endif
+
+ engine_.reset(new StrictMock<MockCommandBufferEngine>());
+ gpu::Buffer buffer = engine_->GetSharedMemoryBuffer(kSharedMemoryId);
+ shared_memory_offset_ = kSharedMemoryOffset;
+ shared_memory_address_ = reinterpret_cast<int8*>(buffer.ptr) +
+ shared_memory_offset_;
+ shared_memory_id_ = kSharedMemoryId;
+ shared_memory_base_ = buffer.ptr;
+
+ surface_ = new gfx::GLSurfaceStub;
+ surface_->SetSize(gfx::Size(kBackBufferWidth, kBackBufferHeight));
+
+ context_ = new gfx::GLContextStub;
+
+ context_->MakeCurrent(surface_.get());
+
+ int32 attributes[] = {
+ EGL_ALPHA_SIZE, request_alpha ? 8 : 0,
+ EGL_DEPTH_SIZE, request_depth ? 24 : 0,
+ EGL_STENCIL_SIZE, request_stencil ? 8 : 0,
+ };
+ std::vector<int32> attribs(attributes, attributes + arraysize(attributes));
+
+ decoder_.reset(GLES2Decoder::Create(group_.get()));
+ decoder_->GetLogger()->set_log_synthesized_gl_errors(false);
+ decoder_->Initialize(
+ surface_, context_, false, surface_->GetSize(), DisallowedFeatures(),
+ NULL, attribs);
+ decoder_->MakeCurrent();
+ decoder_->set_engine(engine_.get());
+
+ EXPECT_CALL(*gl_, GenBuffersARB(_, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceBufferId))
+ .RetiresOnSaturation();
+ GenHelper<cmds::GenBuffersImmediate>(client_buffer_id_);
+ EXPECT_CALL(*gl_, GenFramebuffersEXT(_, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceFramebufferId))
+ .RetiresOnSaturation();
+ GenHelper<cmds::GenFramebuffersImmediate>(client_framebuffer_id_);
+ EXPECT_CALL(*gl_, GenRenderbuffersEXT(_, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceRenderbufferId))
+ .RetiresOnSaturation();
+ GenHelper<cmds::GenRenderbuffersImmediate>(client_renderbuffer_id_);
+ EXPECT_CALL(*gl_, GenTextures(_, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceTextureId))
+ .RetiresOnSaturation();
+ GenHelper<cmds::GenTexturesImmediate>(client_texture_id_);
+ EXPECT_CALL(*gl_, GenBuffersARB(_, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceElementBufferId))
+ .RetiresOnSaturation();
+ GenHelper<cmds::GenBuffersImmediate>(client_element_buffer_id_);
+
+ DoCreateProgram(client_program_id_, kServiceProgramId);
+ DoCreateShader(GL_VERTEX_SHADER, client_shader_id_, kServiceShaderId);
+
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+void GLES2DecoderTestBase::TearDown() {
+ // All Tests should have read all their GLErrors before getting here.
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+
+ EXPECT_CALL(*gl_, DeleteBuffersARB(1, _))
+ .Times(2)
+ .RetiresOnSaturation();
+
+ decoder_->Destroy(true);
+ decoder_.reset();
+ group_->Destroy(mock_decoder_.get(), false);
+ engine_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+}
+
+void GLES2DecoderTestBase::ExpectEnableDisable(GLenum cap, bool enable) {
+ if (enable) {
+ EXPECT_CALL(*gl_, Enable(cap))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, Disable(cap))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+
+GLint GLES2DecoderTestBase::GetGLError() {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ cmds::GetError cmd;
+ cmd.Init(shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ return static_cast<GLint>(*GetSharedMemoryAs<GLenum*>());
+}
+
+void GLES2DecoderTestBase::DoCreateShader(
+ GLenum shader_type, GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, CreateShader(shader_type))
+ .Times(1)
+ .WillOnce(Return(service_id))
+ .RetiresOnSaturation();
+ cmds::CreateShader cmd;
+ cmd.Init(shader_type, client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+bool GLES2DecoderTestBase::DoIsShader(GLuint client_id) {
+ return IsObjectHelper<cmds::IsShader, cmds::IsShader::Result>(client_id);
+}
+
+void GLES2DecoderTestBase::DoDeleteShader(
+ GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, DeleteShader(service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::DeleteShader cmd;
+ cmd.Init(client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoCreateProgram(
+ GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, CreateProgram())
+ .Times(1)
+ .WillOnce(Return(service_id))
+ .RetiresOnSaturation();
+ cmds::CreateProgram cmd;
+ cmd.Init(client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+bool GLES2DecoderTestBase::DoIsProgram(GLuint client_id) {
+ return IsObjectHelper<cmds::IsProgram, cmds::IsProgram::Result>(client_id);
+}
+
+void GLES2DecoderTestBase::DoDeleteProgram(
+ GLuint client_id, GLuint /* service_id */) {
+ cmds::DeleteProgram cmd;
+ cmd.Init(client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::SetBucketAsCString(
+ uint32 bucket_id, const char* str) {
+ uint32 size = str ? (strlen(str) + 1) : 0;
+ cmd::SetBucketSize cmd1;
+ cmd1.Init(bucket_id, size);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+ if (str) {
+ memcpy(shared_memory_address_, str, size);
+ cmd::SetBucketData cmd2;
+ cmd2.Init(bucket_id, 0, size, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ ClearSharedMemory();
+ }
+}
+
+void GLES2DecoderTestBase::SetupClearTextureExpections(
+ GLuint service_id,
+ GLuint old_service_id,
+ GLenum bind_target,
+ GLenum target,
+ GLint level,
+ GLenum format,
+ GLenum type,
+ GLsizei width,
+ GLsizei height) {
+ EXPECT_CALL(*gl_, BindTexture(bind_target, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, TexImage2D(
+ target, level, format, width, height, 0, format, type, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindTexture(bind_target, old_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+void GLES2DecoderTestBase::SetupExpectationsForFramebufferClearing(
+ GLenum target,
+ GLuint clear_bits,
+ GLclampf restore_red,
+ GLclampf restore_green,
+ GLclampf restore_blue,
+ GLclampf restore_alpha,
+ GLuint restore_stencil,
+ GLclampf restore_depth,
+ bool restore_scissor_test) {
+ SetupExpectationsForFramebufferClearingMulti(
+ 0,
+ 0,
+ target,
+ clear_bits,
+ restore_red,
+ restore_green,
+ restore_blue,
+ restore_alpha,
+ restore_stencil,
+ restore_depth,
+ restore_scissor_test);
+}
+
+void GLES2DecoderTestBase::SetupExpectationsForRestoreClearState(
+ GLclampf restore_red,
+ GLclampf restore_green,
+ GLclampf restore_blue,
+ GLclampf restore_alpha,
+ GLuint restore_stencil,
+ GLclampf restore_depth,
+ bool restore_scissor_test) {
+ EXPECT_CALL(*gl_, ClearColor(
+ restore_red, restore_green, restore_blue, restore_alpha))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearStencil(restore_stencil))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ClearDepth(restore_depth))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (restore_scissor_test) {
+ EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::SetupExpectationsForFramebufferClearingMulti(
+ GLuint read_framebuffer_service_id,
+ GLuint draw_framebuffer_service_id,
+ GLenum target,
+ GLuint clear_bits,
+ GLclampf restore_red,
+ GLclampf restore_green,
+ GLclampf restore_blue,
+ GLclampf restore_alpha,
+ GLuint restore_stencil,
+ GLclampf restore_depth,
+ bool restore_scissor_test) {
+ // TODO(gman): Figure out why InSequence stopped working.
+ // InSequence sequence;
+ EXPECT_CALL(*gl_, CheckFramebufferStatusEXT(target))
+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE))
+ .RetiresOnSaturation();
+ if (target == GL_READ_FRAMEBUFFER_EXT) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindFramebufferEXT(
+ GL_DRAW_FRAMEBUFFER_EXT, read_framebuffer_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if ((clear_bits & GL_COLOR_BUFFER_BIT) != 0) {
+ EXPECT_CALL(*gl_, ClearColor(0.0f, 0.0f, 0.0f, 0.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, ColorMask(true, true, true, true))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if ((clear_bits & GL_STENCIL_BUFFER_BIT) != 0) {
+ EXPECT_CALL(*gl_, ClearStencil(0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilMask(static_cast<GLuint>(-1)))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if ((clear_bits & GL_DEPTH_BUFFER_BIT) != 0) {
+ EXPECT_CALL(*gl_, ClearDepth(1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DepthMask(1))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, Clear(clear_bits))
+ .Times(1)
+ .RetiresOnSaturation();
+ SetupExpectationsForRestoreClearState(
+ restore_red, restore_green, restore_blue, restore_alpha,
+ restore_stencil, restore_depth, restore_scissor_test);
+ if (target == GL_READ_FRAMEBUFFER_EXT) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(
+ GL_READ_FRAMEBUFFER_EXT, read_framebuffer_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindFramebufferEXT(
+ GL_DRAW_FRAMEBUFFER_EXT, draw_framebuffer_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::SetupShaderForUniform(GLenum uniform_type) {
+ static AttribInfo attribs[] = {
+ { "foo", 1, GL_FLOAT, 1, },
+ { "goo", 1, GL_FLOAT, 2, },
+ };
+ UniformInfo uniforms[] = {
+ { "bar", 1, uniform_type, 0, 2, -1, },
+ { "car", 4, uniform_type, 1, 1, -1, },
+ };
+ const GLuint kClientVertexShaderId = 5001;
+ const GLuint kServiceVertexShaderId = 6001;
+ const GLuint kClientFragmentShaderId = 5002;
+ const GLuint kServiceFragmentShaderId = 6002;
+ SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms),
+ client_program_id_, kServiceProgramId,
+ kClientVertexShaderId, kServiceVertexShaderId,
+ kClientFragmentShaderId, kServiceFragmentShaderId);
+
+ EXPECT_CALL(*gl_, UseProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::UseProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoBindBuffer(
+ GLenum target, GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, BindBuffer(target, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::BindBuffer cmd;
+ cmd.Init(target, client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+bool GLES2DecoderTestBase::DoIsBuffer(GLuint client_id) {
+ return IsObjectHelper<cmds::IsBuffer, cmds::IsBuffer::Result>(client_id);
+}
+
+void GLES2DecoderTestBase::DoDeleteBuffer(
+ GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, DeleteBuffersARB(1, Pointee(service_id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::DeleteBuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ memcpy(shared_memory_address_, &client_id, sizeof(client_id));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::SetupExpectationsForApplyingDirtyState(
+ bool framebuffer_is_rgb,
+ bool framebuffer_has_depth,
+ bool framebuffer_has_stencil,
+ GLuint color_bits,
+ bool depth_mask,
+ bool depth_enabled,
+ GLuint front_stencil_mask,
+ GLuint back_stencil_mask,
+ bool stencil_enabled,
+ bool cull_face_enabled,
+ bool scissor_test_enabled,
+ bool blend_enabled) {
+ EXPECT_CALL(*gl_, ColorMask(
+ (color_bits & 0x1000) != 0,
+ (color_bits & 0x0100) != 0,
+ (color_bits & 0x0010) != 0,
+ (color_bits & 0x0001) && !framebuffer_is_rgb))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, DepthMask(depth_mask))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (framebuffer_has_depth && depth_enabled) {
+ EXPECT_CALL(*gl_, Enable(GL_DEPTH_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, Disable(GL_DEPTH_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl_, StencilMaskSeparate(GL_FRONT, front_stencil_mask))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, StencilMaskSeparate(GL_BACK, back_stencil_mask))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (framebuffer_has_stencil && stencil_enabled) {
+ EXPECT_CALL(*gl_, Enable(GL_STENCIL_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, Disable(GL_STENCIL_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if (cull_face_enabled) {
+ EXPECT_CALL(*gl_, Enable(GL_CULL_FACE))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, Disable(GL_CULL_FACE))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if (scissor_test_enabled) {
+ EXPECT_CALL(*gl_, Enable(GL_SCISSOR_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, Disable(GL_SCISSOR_TEST))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if (blend_enabled) {
+ EXPECT_CALL(*gl_, Enable(GL_BLEND))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, Disable(GL_BLEND))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::SetupExpectationsForApplyingDefaultDirtyState() {
+ SetupExpectationsForApplyingDirtyState(
+ false, // Framebuffer is RGB
+ false, // Framebuffer has depth
+ false, // Framebuffer has stencil
+ 0x1111, // color bits
+ true, // depth mask
+ false, // depth enabled
+ 0, // front stencil mask
+ 0, // back stencil mask
+ false, // stencil enabled
+ false, // cull_face_enabled
+ false, // scissor_test_enabled
+ false); // blend_enabled
+}
+
+void GLES2DecoderTestBase::DoBindFramebuffer(
+ GLenum target, GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(target, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::BindFramebuffer cmd;
+ cmd.Init(target, client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+bool GLES2DecoderTestBase::DoIsFramebuffer(GLuint client_id) {
+ return IsObjectHelper<cmds::IsFramebuffer, cmds::IsFramebuffer::Result>(
+ client_id);
+}
+
+void GLES2DecoderTestBase::DoDeleteFramebuffer(
+ GLuint client_id, GLuint service_id,
+ bool reset_draw, GLenum draw_target, GLuint draw_id,
+ bool reset_read, GLenum read_target, GLuint read_id) {
+ if (reset_draw) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(draw_target, draw_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ if (reset_read) {
+ EXPECT_CALL(*gl_, BindFramebufferEXT(read_target, read_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, Pointee(service_id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::DeleteFramebuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ memcpy(shared_memory_address_, &client_id, sizeof(client_id));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoBindRenderbuffer(
+ GLenum target, GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, BindRenderbufferEXT(target, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::BindRenderbuffer cmd;
+ cmd.Init(target, client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+bool GLES2DecoderTestBase::DoIsRenderbuffer(GLuint client_id) {
+ return IsObjectHelper<cmds::IsRenderbuffer, cmds::IsRenderbuffer::Result>(
+ client_id);
+}
+
+void GLES2DecoderTestBase::DoDeleteRenderbuffer(
+ GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, Pointee(service_id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::DeleteRenderbuffers cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ memcpy(shared_memory_address_, &client_id, sizeof(client_id));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoBindTexture(
+ GLenum target, GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, BindTexture(target, service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::BindTexture cmd;
+ cmd.Init(target, client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+bool GLES2DecoderTestBase::DoIsTexture(GLuint client_id) {
+ return IsObjectHelper<cmds::IsTexture, cmds::IsTexture::Result>(client_id);
+}
+
+void GLES2DecoderTestBase::DoDeleteTexture(
+ GLuint client_id, GLuint service_id) {
+ EXPECT_CALL(*gl_, DeleteTextures(1, Pointee(service_id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::DeleteTextures cmd;
+ cmd.Init(1, shared_memory_id_, shared_memory_offset_);
+ memcpy(shared_memory_address_, &client_id, sizeof(client_id));
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoTexImage2D(
+ GLenum target, GLint level, GLenum internal_format,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, TexImage2D(target, level, internal_format,
+ width, height, border, format, type, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ cmds::TexImage2D cmd;
+ cmd.Init(target, level, internal_format, width, height, border, format,
+ type, shared_memory_id, shared_memory_offset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoCompressedTexImage2D(
+ GLenum target, GLint level, GLenum format,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei size, uint32 bucket_id) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, CompressedTexImage2D(
+ target, level, format, width, height, border, size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ CommonDecoder::Bucket* bucket = decoder_->CreateBucket(bucket_id);
+ bucket->SetSize(size);
+ cmds::CompressedTexImage2DBucket cmd;
+ cmd.Init(
+ target, level, format, width, height, border,
+ bucket_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoTexImage2DSameSize(
+ GLenum target, GLint level, GLenum internal_format,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type,
+ uint32 shared_memory_id, uint32 shared_memory_offset) {
+ if (GLES2Decoder::IsAngle()) {
+ EXPECT_CALL(*gl_, TexSubImage2D(
+ target, level, 0, 0, width, height, format, type, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, TexImage2D(target, level, internal_format,
+ width, height, border, format, type, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ }
+ cmds::TexImage2D cmd;
+ cmd.Init(target, level, internal_format, width, height, border, format,
+ type, shared_memory_id, shared_memory_offset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoRenderbufferStorage(
+ GLenum target, GLenum internal_format, GLenum actual_format,
+ GLsizei width, GLsizei height, GLenum error) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, RenderbufferStorageEXT(
+ target, actual_format, width, height))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ cmds::RenderbufferStorage cmd;
+ cmd.Init(target, internal_format, width, height);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoFramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture_client_id, GLuint texture_service_id, GLint level,
+ GLenum error) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferTexture2DEXT(
+ target, attachment, textarget, texture_service_id, level))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ cmds::FramebufferTexture2D cmd;
+ cmd.Init(target, attachment, textarget, texture_client_id, level);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoFramebufferRenderbuffer(
+ GLenum target,
+ GLenum attachment,
+ GLenum renderbuffer_target,
+ GLuint renderbuffer_client_id,
+ GLuint renderbuffer_service_id,
+ GLenum error) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, FramebufferRenderbufferEXT(
+ target, attachment, renderbuffer_target, renderbuffer_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ cmds::FramebufferRenderbuffer cmd;
+ cmd.Init(target, attachment, renderbuffer_target, renderbuffer_client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoVertexAttribPointer(
+ GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset) {
+ EXPECT_CALL(*gl_,
+ VertexAttribPointer(index, size, type, GL_FALSE, stride,
+ BufferOffset(offset)))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::VertexAttribPointer cmd;
+ cmd.Init(index, size, GL_FLOAT, GL_FALSE, stride, offset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoVertexAttribDivisorANGLE(
+ GLuint index, GLuint divisor) {
+ EXPECT_CALL(*gl_,
+ VertexAttribDivisorANGLE(index, divisor))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::VertexAttribDivisorANGLE cmd;
+ cmd.Init(index, divisor);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::AddExpectationsForGenVertexArraysOES(){
+ if (group_->feature_info()->feature_flags().native_vertex_array_object) {
+ EXPECT_CALL(*gl_, GenVertexArraysOES(1, _))
+ .WillOnce(SetArgumentPointee<1>(kServiceVertexArrayId))
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::AddExpectationsForDeleteVertexArraysOES(){
+ if (group_->feature_info()->feature_flags().native_vertex_array_object) {
+ EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::AddExpectationsForBindVertexArrayOES() {
+ if (group_->feature_info()->feature_flags().native_vertex_array_object) {
+ EXPECT_CALL(*gl_, BindVertexArrayOES(_))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ for (uint32 vv = 0; vv < group_->max_vertex_attribs(); ++vv) {
+ AddExpectationsForRestoreAttribState(vv);
+ }
+
+ EXPECT_CALL(*gl_, BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::AddExpectationsForRestoreAttribState(GLuint attrib) {
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, _))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, VertexAttribPointer(attrib, _, _, _, _, _))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, VertexAttribDivisorANGLE(attrib, _))
+ .Times(testing::AtMost(1))
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, _))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ if (attrib != 0 ||
+ gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+
+ // TODO(bajones): Not sure if I can tell which of these will be called
+ EXPECT_CALL(*gl_, EnableVertexAttribArray(attrib))
+ .Times(testing::AtMost(1))
+ .RetiresOnSaturation();
+
+ EXPECT_CALL(*gl_, DisableVertexAttribArray(attrib))
+ .Times(testing::AtMost(1))
+ .RetiresOnSaturation();
+ }
+}
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const int GLES2DecoderTestBase::kBackBufferWidth;
+const int GLES2DecoderTestBase::kBackBufferHeight;
+
+const GLint GLES2DecoderTestBase::kMaxTextureSize;
+const GLint GLES2DecoderTestBase::kMaxCubeMapTextureSize;
+const GLint GLES2DecoderTestBase::kNumVertexAttribs;
+const GLint GLES2DecoderTestBase::kNumTextureUnits;
+const GLint GLES2DecoderTestBase::kMaxTextureImageUnits;
+const GLint GLES2DecoderTestBase::kMaxVertexTextureImageUnits;
+const GLint GLES2DecoderTestBase::kMaxFragmentUniformVectors;
+const GLint GLES2DecoderTestBase::kMaxVaryingVectors;
+const GLint GLES2DecoderTestBase::kMaxVertexUniformVectors;
+const GLint GLES2DecoderTestBase::kMaxViewportWidth;
+const GLint GLES2DecoderTestBase::kMaxViewportHeight;
+
+const GLint GLES2DecoderTestBase::kViewportX;
+const GLint GLES2DecoderTestBase::kViewportY;
+const GLint GLES2DecoderTestBase::kViewportWidth;
+const GLint GLES2DecoderTestBase::kViewportHeight;
+
+const GLuint GLES2DecoderTestBase::kServiceAttrib0BufferId;
+const GLuint GLES2DecoderTestBase::kServiceFixedAttribBufferId;
+
+const GLuint GLES2DecoderTestBase::kServiceBufferId;
+const GLuint GLES2DecoderTestBase::kServiceFramebufferId;
+const GLuint GLES2DecoderTestBase::kServiceRenderbufferId;
+const GLuint GLES2DecoderTestBase::kServiceTextureId;
+const GLuint GLES2DecoderTestBase::kServiceProgramId;
+const GLuint GLES2DecoderTestBase::kServiceShaderId;
+const GLuint GLES2DecoderTestBase::kServiceElementBufferId;
+const GLuint GLES2DecoderTestBase::kServiceQueryId;
+const GLuint GLES2DecoderTestBase::kServiceVertexArrayId;
+
+const int32 GLES2DecoderTestBase::kSharedMemoryId;
+const size_t GLES2DecoderTestBase::kSharedBufferSize;
+const uint32 GLES2DecoderTestBase::kSharedMemoryOffset;
+const int32 GLES2DecoderTestBase::kInvalidSharedMemoryId;
+const uint32 GLES2DecoderTestBase::kInvalidSharedMemoryOffset;
+const uint32 GLES2DecoderTestBase::kInitialResult;
+const uint8 GLES2DecoderTestBase::kInitialMemoryValue;
+
+const uint32 GLES2DecoderTestBase::kNewClientId;
+const uint32 GLES2DecoderTestBase::kNewServiceId;
+const uint32 GLES2DecoderTestBase::kInvalidClientId;
+
+const GLuint GLES2DecoderTestBase::kServiceVertexShaderId;
+const GLuint GLES2DecoderTestBase::kServiceFragmentShaderId;
+
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumShaderId;
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumProgramId;
+
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumTextureBufferId;
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumVertexBufferId;
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumFBOId;
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumPositionAttrib;
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumTexAttrib;
+const GLuint GLES2DecoderTestBase::kServiceCopyTextureChromiumSamplerLocation;
+
+const GLsizei GLES2DecoderTestBase::kNumVertices;
+const GLsizei GLES2DecoderTestBase::kNumIndices;
+const int GLES2DecoderTestBase::kValidIndexRangeStart;
+const int GLES2DecoderTestBase::kValidIndexRangeCount;
+const int GLES2DecoderTestBase::kInvalidIndexRangeStart;
+const int GLES2DecoderTestBase::kInvalidIndexRangeCount;
+const int GLES2DecoderTestBase::kOutOfRangeIndexRangeEnd;
+const GLuint GLES2DecoderTestBase::kMaxValidIndex;
+
+const GLint GLES2DecoderTestBase::kMaxAttribLength;
+const GLint GLES2DecoderTestBase::kAttrib1Size;
+const GLint GLES2DecoderTestBase::kAttrib2Size;
+const GLint GLES2DecoderTestBase::kAttrib3Size;
+const GLint GLES2DecoderTestBase::kAttrib1Location;
+const GLint GLES2DecoderTestBase::kAttrib2Location;
+const GLint GLES2DecoderTestBase::kAttrib3Location;
+const GLenum GLES2DecoderTestBase::kAttrib1Type;
+const GLenum GLES2DecoderTestBase::kAttrib2Type;
+const GLenum GLES2DecoderTestBase::kAttrib3Type;
+const GLint GLES2DecoderTestBase::kInvalidAttribLocation;
+const GLint GLES2DecoderTestBase::kBadAttribIndex;
+
+const GLint GLES2DecoderTestBase::kMaxUniformLength;
+const GLint GLES2DecoderTestBase::kUniform1Size;
+const GLint GLES2DecoderTestBase::kUniform2Size;
+const GLint GLES2DecoderTestBase::kUniform3Size;
+const GLint GLES2DecoderTestBase::kUniform1RealLocation;
+const GLint GLES2DecoderTestBase::kUniform2RealLocation;
+const GLint GLES2DecoderTestBase::kUniform2ElementRealLocation;
+const GLint GLES2DecoderTestBase::kUniform3RealLocation;
+const GLint GLES2DecoderTestBase::kUniform1FakeLocation;
+const GLint GLES2DecoderTestBase::kUniform2FakeLocation;
+const GLint GLES2DecoderTestBase::kUniform2ElementFakeLocation;
+const GLint GLES2DecoderTestBase::kUniform3FakeLocation;
+const GLint GLES2DecoderTestBase::kUniform1DesiredLocation;
+const GLint GLES2DecoderTestBase::kUniform2DesiredLocation;
+const GLint GLES2DecoderTestBase::kUniform3DesiredLocation;
+const GLenum GLES2DecoderTestBase::kUniform1Type;
+const GLenum GLES2DecoderTestBase::kUniform2Type;
+const GLenum GLES2DecoderTestBase::kUniform3Type;
+const GLenum GLES2DecoderTestBase::kUniformCubemapType;
+const GLint GLES2DecoderTestBase::kInvalidUniformLocation;
+const GLint GLES2DecoderTestBase::kBadUniformIndex;
+
+#endif
+
+const char* GLES2DecoderTestBase::kAttrib1Name = "attrib1";
+const char* GLES2DecoderTestBase::kAttrib2Name = "attrib2";
+const char* GLES2DecoderTestBase::kAttrib3Name = "attrib3";
+const char* GLES2DecoderTestBase::kUniform1Name = "uniform1";
+const char* GLES2DecoderTestBase::kUniform2Name = "uniform2[0]";
+const char* GLES2DecoderTestBase::kUniform3Name = "uniform3[0]";
+
+void GLES2DecoderTestBase::SetupDefaultProgram() {
+ {
+ static AttribInfo attribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ static UniformInfo uniforms[] = {
+ { kUniform1Name, kUniform1Size, kUniform1Type,
+ kUniform1FakeLocation, kUniform1RealLocation,
+ kUniform1DesiredLocation },
+ { kUniform2Name, kUniform2Size, kUniform2Type,
+ kUniform2FakeLocation, kUniform2RealLocation,
+ kUniform2DesiredLocation },
+ { kUniform3Name, kUniform3Size, kUniform3Type,
+ kUniform3FakeLocation, kUniform3RealLocation,
+ kUniform3DesiredLocation },
+ };
+ SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms),
+ client_program_id_, kServiceProgramId,
+ client_vertex_shader_id_, kServiceVertexShaderId,
+ client_fragment_shader_id_, kServiceFragmentShaderId);
+ }
+
+ {
+ EXPECT_CALL(*gl_, UseProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::UseProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+}
+
+void GLES2DecoderTestBase::SetupCubemapProgram() {
+ {
+ static AttribInfo attribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ static UniformInfo uniforms[] = {
+ { kUniform1Name, kUniform1Size, kUniformCubemapType,
+ kUniform1FakeLocation, kUniform1RealLocation,
+ kUniform1DesiredLocation, },
+ { kUniform2Name, kUniform2Size, kUniform2Type,
+ kUniform2FakeLocation, kUniform2RealLocation,
+ kUniform2DesiredLocation, },
+ { kUniform3Name, kUniform3Size, kUniform3Type,
+ kUniform3FakeLocation, kUniform3RealLocation,
+ kUniform3DesiredLocation, },
+ };
+ SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms),
+ client_program_id_, kServiceProgramId,
+ client_vertex_shader_id_, kServiceVertexShaderId,
+ client_fragment_shader_id_, kServiceFragmentShaderId);
+ }
+
+ {
+ EXPECT_CALL(*gl_, UseProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::UseProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+}
+
+void GLES2DecoderTestBase::SetupSamplerExternalProgram() {
+ {
+ static AttribInfo attribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ static UniformInfo uniforms[] = {
+ { kUniform1Name, kUniform1Size, kUniformSamplerExternalType,
+ kUniform1FakeLocation, kUniform1RealLocation,
+ kUniform1DesiredLocation, },
+ { kUniform2Name, kUniform2Size, kUniform2Type,
+ kUniform2FakeLocation, kUniform2RealLocation,
+ kUniform2DesiredLocation, },
+ { kUniform3Name, kUniform3Size, kUniform3Type,
+ kUniform3FakeLocation, kUniform3RealLocation,
+ kUniform3DesiredLocation, },
+ };
+ SetupShader(attribs, arraysize(attribs), uniforms, arraysize(uniforms),
+ client_program_id_, kServiceProgramId,
+ client_vertex_shader_id_, kServiceVertexShaderId,
+ client_fragment_shader_id_, kServiceFragmentShaderId);
+ }
+
+ {
+ EXPECT_CALL(*gl_, UseProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::UseProgram cmd;
+ cmd.Init(client_program_id_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ }
+}
+
+void GLES2DecoderWithShaderTestBase::TearDown() {
+ GLES2DecoderTestBase::TearDown();
+}
+
+void GLES2DecoderTestBase::SetupShader(
+ GLES2DecoderTestBase::AttribInfo* attribs, size_t num_attribs,
+ GLES2DecoderTestBase::UniformInfo* uniforms, size_t num_uniforms,
+ GLuint program_client_id, GLuint program_service_id,
+ GLuint vertex_shader_client_id, GLuint vertex_shader_service_id,
+ GLuint fragment_shader_client_id, GLuint fragment_shader_service_id) {
+ {
+ InSequence s;
+
+ EXPECT_CALL(*gl_,
+ AttachShader(program_service_id, vertex_shader_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ AttachShader(program_service_id, fragment_shader_service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ TestHelper::SetupShader(
+ gl_.get(), attribs, num_attribs, uniforms, num_uniforms,
+ program_service_id);
+ }
+
+ DoCreateShader(
+ GL_VERTEX_SHADER, vertex_shader_client_id, vertex_shader_service_id);
+ DoCreateShader(
+ GL_FRAGMENT_SHADER, fragment_shader_client_id,
+ fragment_shader_service_id);
+
+ GetShader(vertex_shader_client_id)->SetStatus(true, "", NULL);
+ GetShader(fragment_shader_client_id)->SetStatus(true, "", NULL);
+
+ cmds::AttachShader attach_cmd;
+ attach_cmd.Init(program_client_id, vertex_shader_client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+
+ attach_cmd.Init(program_client_id, fragment_shader_client_id);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(attach_cmd));
+
+ cmds::LinkProgram link_cmd;
+ link_cmd.Init(program_client_id);
+
+ EXPECT_EQ(error::kNoError, ExecuteCmd(link_cmd));
+
+ // Assume the next command will be UseProgram.
+ SetupExpectationsForClearingUniforms(uniforms, num_uniforms);
+}
+
+void GLES2DecoderTestBase::DoEnableVertexAttribArray(GLint index) {
+ EXPECT_CALL(*gl_, EnableVertexAttribArray(index))
+ .Times(1)
+ .RetiresOnSaturation();
+ cmds::EnableVertexAttribArray cmd;
+ cmd.Init(index);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoBufferData(GLenum target, GLsizei size) {
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BufferData(target, size, _, GL_STREAM_DRAW))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .RetiresOnSaturation();
+ cmds::BufferData cmd;
+ cmd.Init(target, size, 0, 0, GL_STREAM_DRAW);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::DoBufferSubData(
+ GLenum target, GLint offset, GLsizei size, const void* data) {
+ EXPECT_CALL(*gl_, BufferSubData(target, offset, size,
+ shared_memory_address_))
+ .Times(1)
+ .RetiresOnSaturation();
+ memcpy(shared_memory_address_, data, size);
+ cmds::BufferSubData cmd;
+ cmd.Init(target, offset, size, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+}
+
+void GLES2DecoderTestBase::SetupVertexBuffer() {
+ DoEnableVertexAttribArray(1);
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ GLfloat f = 0;
+ DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 2 * sizeof(f));
+}
+
+void GLES2DecoderTestBase::SetupAllNeededVertexBuffers() {
+ DoBindBuffer(GL_ARRAY_BUFFER, client_buffer_id_, kServiceBufferId);
+ DoBufferData(GL_ARRAY_BUFFER, kNumVertices * 16 * sizeof(float));
+ DoEnableVertexAttribArray(0);
+ DoEnableVertexAttribArray(1);
+ DoEnableVertexAttribArray(2);
+ DoVertexAttribPointer(0, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribPointer(1, 2, GL_FLOAT, 0, 0);
+ DoVertexAttribPointer(2, 2, GL_FLOAT, 0, 0);
+}
+
+void GLES2DecoderTestBase::SetupIndexBuffer() {
+ DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
+ client_element_buffer_id_,
+ kServiceElementBufferId);
+ static const GLshort indices[] = {100, 1, 2, 3, 4, 5, 6, 7, 100, 9};
+ COMPILE_ASSERT(arraysize(indices) == kNumIndices, Indices_is_not_10);
+ DoBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices));
+ DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, 2, indices);
+ DoBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 2, sizeof(indices) - 2, &indices[1]);
+}
+
+void GLES2DecoderTestBase::SetupTexture() {
+ DoBindTexture(GL_TEXTURE_2D, client_texture_id_, kServiceTextureId);
+ DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ kSharedMemoryId, kSharedMemoryOffset);
+};
+
+void GLES2DecoderTestBase::DeleteVertexBuffer() {
+ DoDeleteBuffer(client_buffer_id_, kServiceBufferId);
+}
+
+void GLES2DecoderTestBase::DeleteIndexBuffer() {
+ DoDeleteBuffer(client_element_buffer_id_, kServiceElementBufferId);
+}
+
+void GLES2DecoderTestBase::AddExpectationsForSimulatedAttrib0WithError(
+ GLsizei num_vertices, GLuint buffer_id, GLenum error) {
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2) {
+ return;
+ }
+
+ EXPECT_CALL(*gl_, GetError())
+ .WillOnce(Return(GL_NO_ERROR))
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, kServiceAttrib0BufferId))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BufferData(GL_ARRAY_BUFFER,
+ num_vertices * sizeof(GLfloat) * 4,
+ _, GL_DYNAMIC_DRAW))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (error == GL_NO_ERROR) {
+ EXPECT_CALL(*gl_, BufferSubData(
+ GL_ARRAY_BUFFER, 0, num_vertices * sizeof(GLfloat) * 4, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, VertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, NULL))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, BindBuffer(GL_ARRAY_BUFFER, buffer_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+}
+
+void GLES2DecoderTestBase::AddExpectationsForSimulatedAttrib0(
+ GLsizei num_vertices, GLuint buffer_id) {
+ AddExpectationsForSimulatedAttrib0WithError(
+ num_vertices, buffer_id, GL_NO_ERROR);
+}
+
+GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::
+MockCommandBufferEngine() {
+ data_.reset(new int8[kSharedBufferSize]);
+ ClearSharedMemory();
+ valid_buffer_.ptr = data_.get();
+ valid_buffer_.size = kSharedBufferSize;
+}
+
+GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::
+~MockCommandBufferEngine() {}
+
+gpu::Buffer
+GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::GetSharedMemoryBuffer(
+ int32 shm_id) {
+ return shm_id == kSharedMemoryId ? valid_buffer_ : invalid_buffer_;
+}
+
+void GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::set_token(
+ int32 token) {
+ DCHECK(false);
+}
+
+bool GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::SetGetBuffer(
+ int32 /* transfer_buffer_id */) {
+ DCHECK(false);
+ return false;
+}
+
+bool GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::SetGetOffset(
+ int32 offset) {
+ DCHECK(false);
+ return false;
+}
+
+int32 GLES2DecoderWithShaderTestBase::MockCommandBufferEngine::GetGetOffset() {
+ DCHECK(false);
+ return 0;
+}
+
+void GLES2DecoderWithShaderTestBase::SetUp() {
+ GLES2DecoderTestBase::SetUp();
+ SetupDefaultProgram();
+}
+
+// Include the auto-generated part of this file. We split this because it means
+// we can easily edit the non-auto generated parts right here in this file
+// instead of having to edit some template or the code generator.
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
new file mode 100644
index 00000000000..c8505c10493
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -0,0 +1,558 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_BASE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_BASE_H_
+
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/stream_texture_manager_mock.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/vertex_array_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_context_stub.h"
+#include "ui/gl/gl_surface_stub.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class MemoryTracker;
+
+class GLES2DecoderTestBase : public testing::Test {
+ public:
+ GLES2DecoderTestBase();
+ virtual ~GLES2DecoderTestBase();
+
+ // Template to call glGenXXX functions.
+ template <typename T>
+ void GenHelper(GLuint client_id) {
+ int8 buffer[sizeof(T) + sizeof(client_id)];
+ T& cmd = *reinterpret_cast<T*>(&buffer);
+ cmd.Init(1, &client_id);
+ EXPECT_EQ(error::kNoError,
+ ExecuteImmediateCmd(cmd, sizeof(client_id)));
+ }
+
+ // This template exists solely so we can specialize it for
+ // certain commands.
+ template <typename T, int id>
+ void SpecializedSetup(bool valid) {
+ }
+
+ template <typename T>
+ T* GetImmediateAs() {
+ return reinterpret_cast<T*>(immediate_buffer_);
+ }
+
+ template <typename T, typename Command>
+ T GetImmediateDataAs(Command* cmd) {
+ return reinterpret_cast<T>(ImmediateDataAddress(cmd));
+ }
+
+ void ClearSharedMemory() {
+ engine_->ClearSharedMemory();
+ }
+
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+ template <typename T>
+ error::Error ExecuteCmd(const T& cmd) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kFixed, Cmd_kArgFlags_not_kFixed);
+ return decoder_->DoCommand(cmd.kCmdId,
+ ComputeNumEntries(sizeof(cmd)) - 1,
+ &cmd);
+ }
+
+ template <typename T>
+ error::Error ExecuteImmediateCmd(const T& cmd, size_t data_size) {
+ COMPILE_ASSERT(T::kArgFlags == cmd::kAtLeastN, Cmd_kArgFlags_not_kAtLeastN);
+ return decoder_->DoCommand(cmd.kCmdId,
+ ComputeNumEntries(sizeof(cmd) + data_size) - 1,
+ &cmd);
+ }
+
+ template <typename T>
+ T GetSharedMemoryAs() {
+ return reinterpret_cast<T>(shared_memory_address_);
+ }
+
+ template <typename T>
+ T GetSharedMemoryAsWithOffset(uint32 offset) {
+ void* ptr = reinterpret_cast<int8*>(shared_memory_address_) + offset;
+ return reinterpret_cast<T>(ptr);
+ }
+
+ IdAllocatorInterface* GetIdAllocator(GLuint namespace_id) {
+ return group_->GetIdAllocator(namespace_id);
+ }
+
+ Buffer* GetBuffer(GLuint service_id) {
+ return group_->buffer_manager()->GetBuffer(service_id);
+ }
+
+ Framebuffer* GetFramebuffer(GLuint service_id) {
+ return group_->framebuffer_manager()->GetFramebuffer(service_id);
+ }
+
+ Renderbuffer* GetRenderbuffer(
+ GLuint service_id) {
+ return group_->renderbuffer_manager()->GetRenderbuffer(service_id);
+ }
+
+ TextureRef* GetTexture(GLuint client_id) {
+ return group_->texture_manager()->GetTexture(client_id);
+ }
+
+ Shader* GetShader(GLuint client_id) {
+ return group_->shader_manager()->GetShader(client_id);
+ }
+
+ Program* GetProgram(GLuint client_id) {
+ return group_->program_manager()->GetProgram(client_id);
+ }
+
+ QueryManager::Query* GetQueryInfo(GLuint client_id) {
+ return decoder_->GetQueryManager()->GetQuery(client_id);
+ }
+
+ // This name doesn't match the underlying function, but doing it this way
+ // prevents the need to special-case the unit test generation
+ VertexAttribManager* GetVertexArrayInfo(GLuint client_id) {
+ return decoder_->GetVertexArrayManager()->GetVertexAttribManager(client_id);
+ }
+
+ ProgramManager* program_manager() {
+ return group_->program_manager();
+ }
+
+ ::testing::StrictMock<MockStreamTextureManager>*
+ stream_texture_manager() const {
+ return stream_texture_manager_.get();
+ }
+
+ void DoCreateProgram(GLuint client_id, GLuint service_id);
+ void DoCreateShader(GLenum shader_type, GLuint client_id, GLuint service_id);
+
+ void SetBucketAsCString(uint32 bucket_id, const char* str);
+
+ void set_memory_tracker(MemoryTracker* memory_tracker) {
+ memory_tracker_ = memory_tracker;
+ }
+
+ void InitDecoder(
+ const char* extensions,
+ bool has_alpha,
+ bool has_depth,
+ bool has_stencil,
+ bool request_alpha,
+ bool request_depth,
+ bool request_stencil,
+ bool bind_generates_resource);
+
+ const ContextGroup& group() const {
+ return *group_.get();
+ }
+
+ ::testing::StrictMock< ::gfx::MockGLInterface>* GetGLMock() const {
+ return gl_.get();
+ }
+
+ GLES2Decoder* GetDecoder() const {
+ return decoder_.get();
+ }
+
+ typedef TestHelper::AttribInfo AttribInfo;
+ typedef TestHelper::UniformInfo UniformInfo;
+
+ void SetupShader(
+ AttribInfo* attribs, size_t num_attribs,
+ UniformInfo* uniforms, size_t num_uniforms,
+ GLuint client_id, GLuint service_id,
+ GLuint vertex_shader_client_id, GLuint vertex_shader_service_id,
+ GLuint fragment_shader_client_id, GLuint fragment_shader_service_id);
+
+ void SetupExpectationsForClearingUniforms(
+ UniformInfo* uniforms, size_t num_uniforms) {
+ TestHelper::SetupExpectationsForClearingUniforms(
+ gl_.get(), uniforms, num_uniforms);
+ }
+
+ void SetupInitCapabilitiesExpectations();
+ void SetupInitStateExpectations();
+ void ExpectEnableDisable(GLenum cap, bool enable);
+
+ // Setups up a shader for testing glUniform.
+ void SetupShaderForUniform(GLenum uniform_type);
+ void SetupDefaultProgram();
+ void SetupCubemapProgram();
+ void SetupSamplerExternalProgram();
+ void SetupTexture();
+
+ // Note that the error is returned as GLint instead of GLenum.
+ // This is because there is a mismatch in the types of GLenum and
+ // the error values GL_NO_ERROR, GL_INVALID_ENUM, etc. GLenum is
+ // typedef'd as unsigned int while the error values are defined as
+ // integers. This is problematic for template functions such as
+ // EXPECT_EQ that expect both types to be the same.
+ GLint GetGLError();
+
+ void DoBindBuffer(GLenum target, GLuint client_id, GLuint service_id);
+ void DoBindFramebuffer(GLenum target, GLuint client_id, GLuint service_id);
+ void DoBindRenderbuffer(GLenum target, GLuint client_id, GLuint service_id);
+ void DoBindTexture(GLenum target, GLuint client_id, GLuint service_id);
+ void DoBindVertexArrayOES(GLuint client_id, GLuint service_id);
+
+ bool DoIsBuffer(GLuint client_id);
+ bool DoIsFramebuffer(GLuint client_id);
+ bool DoIsProgram(GLuint client_id);
+ bool DoIsRenderbuffer(GLuint client_id);
+ bool DoIsShader(GLuint client_id);
+ bool DoIsTexture(GLuint client_id);
+
+ void DoDeleteBuffer(GLuint client_id, GLuint service_id);
+ void DoDeleteFramebuffer(
+ GLuint client_id, GLuint service_id,
+ bool reset_draw, GLenum draw_target, GLuint draw_id,
+ bool reset_read, GLenum read_target, GLuint read_id);
+ void DoDeleteProgram(GLuint client_id, GLuint service_id);
+ void DoDeleteRenderbuffer(GLuint client_id, GLuint service_id);
+ void DoDeleteShader(GLuint client_id, GLuint service_id);
+ void DoDeleteTexture(GLuint client_id, GLuint service_id);
+
+ void DoCompressedTexImage2D(
+ GLenum target, GLint level, GLenum format,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei size, uint32 bucket_id);
+ void DoTexImage2D(
+ GLenum target, GLint level, GLenum internal_format,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type,
+ uint32 shared_memory_id, uint32 shared_memory_offset);
+ void DoTexImage2DSameSize(
+ GLenum target, GLint level, GLenum internal_format,
+ GLsizei width, GLsizei height, GLint border,
+ GLenum format, GLenum type,
+ uint32 shared_memory_id, uint32 shared_memory_offset);
+ void DoRenderbufferStorage(
+ GLenum target, GLenum internal_format, GLenum actual_format,
+ GLsizei width, GLsizei height, GLenum error);
+ void DoFramebufferRenderbuffer(
+ GLenum target,
+ GLenum attachment,
+ GLenum renderbuffer_target,
+ GLuint renderbuffer_client_id,
+ GLuint renderbuffer_service_id,
+ GLenum error);
+ void DoFramebufferTexture2D(
+ GLenum target, GLenum attachment, GLenum tex_target,
+ GLuint texture_client_id, GLuint texture_service_id,
+ GLint level, GLenum error);
+ void DoVertexAttribPointer(
+ GLuint index, GLint size, GLenum type, GLsizei stride, GLuint offset);
+ void DoVertexAttribDivisorANGLE(GLuint index, GLuint divisor);
+
+ void DoEnableVertexAttribArray(GLint index);
+
+ void DoBufferData(GLenum target, GLsizei size);
+
+ void DoBufferSubData(
+ GLenum target, GLint offset, GLsizei size, const void* data);
+
+ void SetupVertexBuffer();
+ void SetupAllNeededVertexBuffers();
+
+ void SetupIndexBuffer();
+
+ void DeleteVertexBuffer();
+
+ void DeleteIndexBuffer();
+
+ void SetupClearTextureExpections(
+ GLuint service_id,
+ GLuint old_service_id,
+ GLenum bind_target,
+ GLenum target,
+ GLint level,
+ GLenum format,
+ GLenum type,
+ GLsizei width,
+ GLsizei height);
+
+ void SetupExpectationsForRestoreClearState(
+ GLclampf restore_red,
+ GLclampf restore_green,
+ GLclampf restore_blue,
+ GLclampf restore_alpha,
+ GLuint restore_stencil,
+ GLclampf restore_depth,
+ bool restore_scissor_test);
+
+ void SetupExpectationsForFramebufferClearing(
+ GLenum target,
+ GLuint clear_bits,
+ GLclampf restore_red,
+ GLclampf restore_green,
+ GLclampf restore_blue,
+ GLclampf restore_alpha,
+ GLuint restore_stencil,
+ GLclampf restore_depth,
+ bool restore_scissor_test);
+
+ void SetupExpectationsForFramebufferClearingMulti(
+ GLuint read_framebuffer_service_id,
+ GLuint draw_framebuffer_service_id,
+ GLenum target,
+ GLuint clear_bits,
+ GLclampf restore_red,
+ GLclampf restore_green,
+ GLclampf restore_blue,
+ GLclampf restore_alpha,
+ GLuint restore_stencil,
+ GLclampf restore_depth,
+ bool restore_scissor_test);
+
+ void SetupExpectationsForApplyingDirtyState(
+ bool framebuffer_is_rgb,
+ bool framebuffer_has_depth,
+ bool framebuffer_has_stencil,
+ GLuint color_bits, // NOTE! bits are 0x1000, 0x0100, 0x0010, and 0x0001
+ bool depth_mask,
+ bool depth_enabled,
+ GLuint front_stencil_mask,
+ GLuint back_stencil_mask,
+ bool stencil_enabled,
+ bool cull_face_enabled,
+ bool scissor_test_enabled,
+ bool blend_enabled);
+
+ void SetupExpectationsForApplyingDefaultDirtyState();
+
+ void AddExpectationsForSimulatedAttrib0WithError(
+ GLsizei num_vertices, GLuint buffer_id, GLenum error);
+
+ void AddExpectationsForSimulatedAttrib0(
+ GLsizei num_vertices, GLuint buffer_id);
+
+ void AddExpectationsForGenVertexArraysOES();
+ void AddExpectationsForDeleteVertexArraysOES();
+ void AddExpectationsForBindVertexArrayOES();
+ void AddExpectationsForRestoreAttribState(GLuint attrib);
+
+ GLvoid* BufferOffset(unsigned i) {
+ return static_cast<int8 *>(NULL)+(i);
+ }
+
+ template <typename Command, typename Result>
+ bool IsObjectHelper(GLuint client_id) {
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ Command cmd;
+ cmd.Init(client_id, kSharedMemoryId, kSharedMemoryOffset);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ bool isObject = static_cast<bool>(*result);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ return isObject;
+ }
+
+ protected:
+ static const int kBackBufferWidth = 128;
+ static const int kBackBufferHeight = 64;
+
+ static const GLint kMaxTextureSize = 2048;
+ static const GLint kMaxCubeMapTextureSize = 256;
+ static const GLint kNumVertexAttribs = 16;
+ static const GLint kNumTextureUnits = 8;
+ static const GLint kMaxTextureImageUnits = 8;
+ static const GLint kMaxVertexTextureImageUnits = 2;
+ static const GLint kMaxFragmentUniformVectors = 16;
+ static const GLint kMaxVaryingVectors = 8;
+ static const GLint kMaxVertexUniformVectors = 128;
+ static const GLint kMaxViewportWidth = 8192;
+ static const GLint kMaxViewportHeight = 8192;
+
+ static const GLint kViewportX = 0;
+ static const GLint kViewportY = 0;
+ static const GLint kViewportWidth = kBackBufferWidth;
+ static const GLint kViewportHeight = kBackBufferHeight;
+
+ static const GLuint kServiceAttrib0BufferId = 801;
+ static const GLuint kServiceFixedAttribBufferId = 802;
+
+ static const GLuint kServiceBufferId = 301;
+ static const GLuint kServiceFramebufferId = 302;
+ static const GLuint kServiceRenderbufferId = 303;
+ static const GLuint kServiceTextureId = 304;
+ static const GLuint kServiceProgramId = 305;
+ static const GLuint kServiceShaderId = 306;
+ static const GLuint kServiceElementBufferId = 308;
+ static const GLuint kServiceQueryId = 309;
+ static const GLuint kServiceVertexArrayId = 310;
+
+ static const int32 kSharedMemoryId = 401;
+ static const size_t kSharedBufferSize = 2048;
+ static const uint32 kSharedMemoryOffset = 132;
+ static const int32 kInvalidSharedMemoryId = 402;
+ static const uint32 kInvalidSharedMemoryOffset = kSharedBufferSize + 1;
+ static const uint32 kInitialResult = 0xBDBDBDBDu;
+ static const uint8 kInitialMemoryValue = 0xBDu;
+
+ static const uint32 kNewClientId = 501;
+ static const uint32 kNewServiceId = 502;
+ static const uint32 kInvalidClientId = 601;
+
+ static const GLuint kServiceVertexShaderId = 321;
+ static const GLuint kServiceFragmentShaderId = 322;
+
+ static const GLuint kServiceCopyTextureChromiumShaderId = 701;
+ static const GLuint kServiceCopyTextureChromiumProgramId = 721;
+
+ static const GLuint kServiceCopyTextureChromiumTextureBufferId = 751;
+ static const GLuint kServiceCopyTextureChromiumVertexBufferId = 752;
+ static const GLuint kServiceCopyTextureChromiumFBOId = 753;
+ static const GLuint kServiceCopyTextureChromiumPositionAttrib = 761;
+ static const GLuint kServiceCopyTextureChromiumTexAttrib = 762;
+ static const GLuint kServiceCopyTextureChromiumSamplerLocation = 763;
+
+ static const GLsizei kNumVertices = 100;
+ static const GLsizei kNumIndices = 10;
+ static const int kValidIndexRangeStart = 1;
+ static const int kValidIndexRangeCount = 7;
+ static const int kInvalidIndexRangeStart = 0;
+ static const int kInvalidIndexRangeCount = 7;
+ static const int kOutOfRangeIndexRangeEnd = 10;
+ static const GLuint kMaxValidIndex = 7;
+
+ static const GLint kMaxAttribLength = 10;
+ static const char* kAttrib1Name;
+ static const char* kAttrib2Name;
+ static const char* kAttrib3Name;
+ static const GLint kAttrib1Size = 1;
+ static const GLint kAttrib2Size = 1;
+ static const GLint kAttrib3Size = 1;
+ static const GLint kAttrib1Location = 0;
+ static const GLint kAttrib2Location = 1;
+ static const GLint kAttrib3Location = 2;
+ static const GLenum kAttrib1Type = GL_FLOAT_VEC4;
+ static const GLenum kAttrib2Type = GL_FLOAT_VEC2;
+ static const GLenum kAttrib3Type = GL_FLOAT_VEC3;
+ static const GLint kInvalidAttribLocation = 30;
+ static const GLint kBadAttribIndex = kNumVertexAttribs;
+
+ static const GLint kMaxUniformLength = 12;
+ static const char* kUniform1Name;
+ static const char* kUniform2Name;
+ static const char* kUniform3Name;
+ static const GLint kUniform1Size = 1;
+ static const GLint kUniform2Size = 3;
+ static const GLint kUniform3Size = 2;
+ static const GLint kUniform1RealLocation = 3;
+ static const GLint kUniform2RealLocation = 10;
+ static const GLint kUniform2ElementRealLocation = 12;
+ static const GLint kUniform3RealLocation = 20;
+ static const GLint kUniform1FakeLocation = 0; // These are
+ static const GLint kUniform2FakeLocation = 1; // hardcoded
+ static const GLint kUniform2ElementFakeLocation = 0x10001; // to match
+ static const GLint kUniform3FakeLocation = 2; // ProgramManager.
+ static const GLint kUniform1DesiredLocation = -1;
+ static const GLint kUniform2DesiredLocation = -1;
+ static const GLint kUniform3DesiredLocation = -1;
+ static const GLenum kUniform1Type = GL_SAMPLER_2D;
+ static const GLenum kUniform2Type = GL_INT_VEC2;
+ static const GLenum kUniform3Type = GL_FLOAT_VEC3;
+ static const GLenum kUniformSamplerExternalType = GL_SAMPLER_EXTERNAL_OES;
+ static const GLenum kUniformCubemapType = GL_SAMPLER_CUBE;
+ static const GLint kInvalidUniformLocation = 30;
+ static const GLint kBadUniformIndex = 1000;
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_refptr<gfx::GLSurfaceStub> surface_;
+ scoped_refptr<gfx::GLContextStub> context_;
+ scoped_ptr<GLES2Decoder> mock_decoder_;
+ scoped_ptr<GLES2Decoder> decoder_;
+ MemoryTracker* memory_tracker_;
+
+ GLuint client_buffer_id_;
+ GLuint client_framebuffer_id_;
+ GLuint client_program_id_;
+ GLuint client_renderbuffer_id_;
+ GLuint client_shader_id_;
+ GLuint client_texture_id_;
+ GLuint client_element_buffer_id_;
+ GLuint client_vertex_shader_id_;
+ GLuint client_fragment_shader_id_;
+ GLuint client_query_id_;
+ GLuint client_vertexarray_id_;
+
+ uint32 shared_memory_id_;
+ uint32 shared_memory_offset_;
+ void* shared_memory_address_;
+ void* shared_memory_base_;
+
+ int8 immediate_buffer_[256];
+
+ private:
+ class MockCommandBufferEngine : public CommandBufferEngine {
+ public:
+ MockCommandBufferEngine();
+
+ virtual ~MockCommandBufferEngine();
+
+ virtual gpu::Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE;
+
+ void ClearSharedMemory() {
+ memset(data_.get(), kInitialMemoryValue, kSharedBufferSize);
+ }
+
+ virtual void set_token(int32 token) OVERRIDE;
+
+ virtual bool SetGetBuffer(int32 /* transfer_buffer_id */) OVERRIDE;
+
+ // Overridden from CommandBufferEngine.
+ virtual bool SetGetOffset(int32 offset) OVERRIDE;
+
+ // Overridden from CommandBufferEngine.
+ virtual int32 GetGetOffset() OVERRIDE;
+
+ private:
+ scoped_ptr<int8[]> data_;
+ gpu::Buffer valid_buffer_;
+ gpu::Buffer invalid_buffer_;
+ };
+
+ void AddExpectationsForVertexAttribManager();
+
+ scoped_ptr< ::testing::StrictMock<MockCommandBufferEngine> > engine_;
+ scoped_ptr< ::testing::StrictMock<MockStreamTextureManager> >
+ stream_texture_manager_;
+ scoped_refptr<ContextGroup> group_;
+};
+
+class GLES2DecoderWithShaderTestBase : public GLES2DecoderTestBase {
+ public:
+ GLES2DecoderWithShaderTestBase()
+ : GLES2DecoderTestBase() {
+ }
+
+ protected:
+ virtual void SetUp() OVERRIDE;
+ virtual void TearDown() OVERRIDE;
+
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_BASE_H_
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_validation.cc b/chromium/gpu/command_buffer/service/gles2_cmd_validation.cc
new file mode 100644
index 00000000000..8d4fd71abb7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_validation.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Contains various validation functions for the GLES2 service.
+
+#include "base/basictypes.h"
+#define GLES2_GPU_SERVICE 1
+#include "gpu/command_buffer/service/gles2_cmd_validation.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+
+namespace gpu {
+namespace gles2 {
+
+#include "gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h"
+
+} // namespace gles2
+} // namespace gpu
+
+
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_validation.h b/chromium/gpu/command_buffer/service/gles2_cmd_validation.h
new file mode 100644
index 00000000000..22ee2da0d0d
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_validation.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Contains various validation functions for the GLES2 service.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_H_
+
+#include <algorithm>
+#include <vector>
+#define GLES2_GPU_SERVICE 1
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+
+namespace gpu {
+namespace gles2 {
+
+// ValueValidator returns true if a value is valid.
+template <typename T>
+class ValueValidator {
+ public:
+ ValueValidator() {}
+
+ ValueValidator(const T* valid_values, int num_values) {
+ for (int ii = 0; ii < num_values; ++ii) {
+ AddValue(valid_values[ii]);
+ }
+ }
+
+ void AddValue(const T value) {
+ if (!IsValid(value)) {
+ valid_values_.push_back(value);
+ }
+ }
+
+ bool IsValid(const T value) const {
+ return std::find(valid_values_.begin(), valid_values_.end(), value) !=
+ valid_values_.end();
+ }
+
+ const std::vector<T>& GetValues() const {
+ return valid_values_;
+ }
+
+ private:
+ std::vector<T> valid_values_;
+};
+
+struct Validators {
+ Validators();
+#include "gpu/command_buffer/service/gles2_cmd_validation_autogen.h"
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
new file mode 100644
index 00000000000..7e417882471
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_AUTOGEN_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_AUTOGEN_H_
+
+ValueValidator<GLenum> attachment;
+ValueValidator<GLenum> backbuffer_attachment;
+ValueValidator<GLenum> blit_filter;
+ValueValidator<GLenum> buffer_parameter;
+ValueValidator<GLenum> buffer_target;
+ValueValidator<GLenum> buffer_usage;
+ValueValidator<GLenum> capability;
+ValueValidator<GLenum> cmp_function;
+ValueValidator<GLenum> compressed_texture_format;
+ValueValidator<GLenum> draw_mode;
+ValueValidator<GLenum> dst_blend_factor;
+ValueValidator<GLenum> equation;
+ValueValidator<GLenum> face_mode;
+ValueValidator<GLenum> face_type;
+ValueValidator<GLboolean> false_only;
+ValueValidator<GLenum> frame_buffer_parameter;
+ValueValidator<GLenum> frame_buffer_target;
+ValueValidator<GLenum> g_l_state;
+ValueValidator<GLenum> get_max_index_type;
+ValueValidator<GLenum> get_tex_param_target;
+ValueValidator<GLenum> hint_mode;
+ValueValidator<GLenum> hint_target;
+ValueValidator<GLenum> index_type;
+ValueValidator<GLenum> pixel_store;
+ValueValidator<GLint> pixel_store_alignment;
+ValueValidator<GLenum> pixel_type;
+ValueValidator<GLenum> program_parameter;
+ValueValidator<GLenum> query_object_parameter;
+ValueValidator<GLenum> query_parameter;
+ValueValidator<GLenum> query_target;
+ValueValidator<GLenum> read_pixel_format;
+ValueValidator<GLenum> read_pixel_type;
+ValueValidator<GLenum> render_buffer_format;
+ValueValidator<GLenum> render_buffer_parameter;
+ValueValidator<GLenum> render_buffer_target;
+ValueValidator<GLenum> reset_status;
+ValueValidator<GLenum> shader_binary_format;
+ValueValidator<GLenum> shader_parameter;
+ValueValidator<GLenum> shader_precision;
+ValueValidator<GLenum> shader_type;
+ValueValidator<GLenum> src_blend_factor;
+ValueValidator<GLenum> stencil_op;
+ValueValidator<GLenum> string_type;
+ValueValidator<GLenum> texture_bind_target;
+ValueValidator<GLint> texture_border;
+ValueValidator<GLenum> texture_format;
+ValueValidator<GLenum> texture_internal_format;
+ValueValidator<GLenum> texture_internal_format_storage;
+ValueValidator<GLenum> texture_mag_filter_mode;
+ValueValidator<GLenum> texture_min_filter_mode;
+ValueValidator<GLenum> texture_parameter;
+ValueValidator<GLenum> texture_pool;
+ValueValidator<GLenum> texture_target;
+ValueValidator<GLenum> texture_usage;
+ValueValidator<GLenum> texture_wrap_mode;
+ValueValidator<GLint> vertex_attrib_size;
+ValueValidator<GLenum> vertex_attrib_type;
+ValueValidator<GLenum> vertex_attribute;
+ValueValidator<GLenum> vertex_pointer;
+ValueValidator<GLint> zero_only;
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_AUTOGEN_H_
+
diff --git a/chromium/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/chromium/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
new file mode 100644
index 00000000000..b8194d9589e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -0,0 +1,675 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is auto-generated from
+// gpu/command_buffer/build_gles2_cmd_buffer.py
+// DO NOT EDIT!
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_IMPLEMENTATION_AUTOGEN_H_ // NOLINT
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_IMPLEMENTATION_AUTOGEN_H_ // NOLINT
+
+static const GLenum valid_attachment_table[] = {
+ GL_COLOR_ATTACHMENT0,
+ GL_DEPTH_ATTACHMENT,
+ GL_STENCIL_ATTACHMENT,
+};
+
+static const GLenum valid_backbuffer_attachment_table[] = {
+ GL_COLOR_EXT,
+ GL_DEPTH_EXT,
+ GL_STENCIL_EXT,
+};
+
+static const GLenum valid_blit_filter_table[] = {
+ GL_NEAREST,
+ GL_LINEAR,
+};
+
+static const GLenum valid_buffer_parameter_table[] = {
+ GL_BUFFER_SIZE,
+ GL_BUFFER_USAGE,
+};
+
+static const GLenum valid_buffer_target_table[] = {
+ GL_ARRAY_BUFFER,
+ GL_ELEMENT_ARRAY_BUFFER,
+};
+
+static const GLenum valid_buffer_usage_table[] = {
+ GL_STREAM_DRAW,
+ GL_STATIC_DRAW,
+ GL_DYNAMIC_DRAW,
+};
+
+static const GLenum valid_capability_table[] = {
+ GL_BLEND,
+ GL_CULL_FACE,
+ GL_DEPTH_TEST,
+ GL_DITHER,
+ GL_POLYGON_OFFSET_FILL,
+ GL_SAMPLE_ALPHA_TO_COVERAGE,
+ GL_SAMPLE_COVERAGE,
+ GL_SCISSOR_TEST,
+ GL_STENCIL_TEST,
+};
+
+static const GLenum valid_cmp_function_table[] = {
+ GL_NEVER,
+ GL_LESS,
+ GL_EQUAL,
+ GL_LEQUAL,
+ GL_GREATER,
+ GL_NOTEQUAL,
+ GL_GEQUAL,
+ GL_ALWAYS,
+};
+
+static const GLenum valid_draw_mode_table[] = {
+ GL_POINTS,
+ GL_LINE_STRIP,
+ GL_LINE_LOOP,
+ GL_LINES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN,
+ GL_TRIANGLES,
+};
+
+static const GLenum valid_dst_blend_factor_table[] = {
+ GL_ZERO,
+ GL_ONE,
+ GL_SRC_COLOR,
+ GL_ONE_MINUS_SRC_COLOR,
+ GL_DST_COLOR,
+ GL_ONE_MINUS_DST_COLOR,
+ GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA,
+ GL_CONSTANT_COLOR,
+ GL_ONE_MINUS_CONSTANT_COLOR,
+ GL_CONSTANT_ALPHA,
+ GL_ONE_MINUS_CONSTANT_ALPHA,
+};
+
+static const GLenum valid_equation_table[] = {
+ GL_FUNC_ADD,
+ GL_FUNC_SUBTRACT,
+ GL_FUNC_REVERSE_SUBTRACT,
+};
+
+static const GLenum valid_face_mode_table[] = {
+ GL_CW,
+ GL_CCW,
+};
+
+static const GLenum valid_face_type_table[] = {
+ GL_FRONT,
+ GL_BACK,
+ GL_FRONT_AND_BACK,
+};
+
+static const GLboolean valid_false_only_table[] = {
+ false,
+};
+
+static const GLenum valid_frame_buffer_parameter_table[] = {
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE,
+ GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME,
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL,
+ GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE,
+};
+
+static const GLenum valid_frame_buffer_target_table[] = {
+ GL_FRAMEBUFFER,
+};
+
+static const GLenum valid_g_l_state_table[] = {
+ GL_ACTIVE_TEXTURE,
+ GL_ALIASED_LINE_WIDTH_RANGE,
+ GL_ALIASED_POINT_SIZE_RANGE,
+ GL_ALPHA_BITS,
+ GL_ARRAY_BUFFER_BINDING,
+ GL_BLUE_BITS,
+ GL_COMPRESSED_TEXTURE_FORMATS,
+ GL_CURRENT_PROGRAM,
+ GL_DEPTH_BITS,
+ GL_DEPTH_RANGE,
+ GL_ELEMENT_ARRAY_BUFFER_BINDING,
+ GL_FRAMEBUFFER_BINDING,
+ GL_GENERATE_MIPMAP_HINT,
+ GL_GREEN_BITS,
+ GL_IMPLEMENTATION_COLOR_READ_FORMAT,
+ GL_IMPLEMENTATION_COLOR_READ_TYPE,
+ GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
+ GL_MAX_CUBE_MAP_TEXTURE_SIZE,
+ GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+ GL_MAX_RENDERBUFFER_SIZE,
+ GL_MAX_TEXTURE_IMAGE_UNITS,
+ GL_MAX_TEXTURE_SIZE,
+ GL_MAX_VARYING_VECTORS,
+ GL_MAX_VERTEX_ATTRIBS,
+ GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+ GL_MAX_VERTEX_UNIFORM_VECTORS,
+ GL_MAX_VIEWPORT_DIMS,
+ GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+ GL_NUM_SHADER_BINARY_FORMATS,
+ GL_PACK_ALIGNMENT,
+ GL_RED_BITS,
+ GL_RENDERBUFFER_BINDING,
+ GL_SAMPLE_BUFFERS,
+ GL_SAMPLE_COVERAGE_INVERT,
+ GL_SAMPLE_COVERAGE_VALUE,
+ GL_SAMPLES,
+ GL_SCISSOR_BOX,
+ GL_SHADER_BINARY_FORMATS,
+ GL_SHADER_COMPILER,
+ GL_SUBPIXEL_BITS,
+ GL_STENCIL_BITS,
+ GL_TEXTURE_BINDING_2D,
+ GL_TEXTURE_BINDING_CUBE_MAP,
+ GL_UNPACK_ALIGNMENT,
+ GL_UNPACK_FLIP_Y_CHROMIUM,
+ GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
+ GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM,
+ GL_VERTEX_ARRAY_BINDING_OES,
+ GL_VIEWPORT,
+ GL_BLEND_COLOR,
+ GL_BLEND_EQUATION_RGB,
+ GL_BLEND_EQUATION_ALPHA,
+ GL_BLEND_SRC_RGB,
+ GL_BLEND_DST_RGB,
+ GL_BLEND_SRC_ALPHA,
+ GL_BLEND_DST_ALPHA,
+ GL_COLOR_CLEAR_VALUE,
+ GL_DEPTH_CLEAR_VALUE,
+ GL_STENCIL_CLEAR_VALUE,
+ GL_COLOR_WRITEMASK,
+ GL_CULL_FACE_MODE,
+ GL_DEPTH_FUNC,
+ GL_DEPTH_WRITEMASK,
+ GL_DEPTH_RANGE,
+ GL_FRONT_FACE,
+ GL_GENERATE_MIPMAP_HINT,
+ GL_LINE_WIDTH,
+ GL_PACK_ALIGNMENT,
+ GL_UNPACK_ALIGNMENT,
+ GL_POLYGON_OFFSET_FACTOR,
+ GL_POLYGON_OFFSET_UNITS,
+ GL_SAMPLE_COVERAGE_VALUE,
+ GL_SAMPLE_COVERAGE_INVERT,
+ GL_SCISSOR_BOX,
+ GL_STENCIL_FUNC,
+ GL_STENCIL_REF,
+ GL_STENCIL_VALUE_MASK,
+ GL_STENCIL_BACK_FUNC,
+ GL_STENCIL_BACK_REF,
+ GL_STENCIL_BACK_VALUE_MASK,
+ GL_STENCIL_WRITEMASK,
+ GL_STENCIL_BACK_WRITEMASK,
+ GL_STENCIL_FAIL,
+ GL_STENCIL_PASS_DEPTH_FAIL,
+ GL_STENCIL_PASS_DEPTH_PASS,
+ GL_STENCIL_BACK_FAIL,
+ GL_STENCIL_BACK_PASS_DEPTH_FAIL,
+ GL_STENCIL_BACK_PASS_DEPTH_PASS,
+ GL_VIEWPORT,
+ GL_BLEND,
+ GL_CULL_FACE,
+ GL_DEPTH_TEST,
+ GL_DITHER,
+ GL_POLYGON_OFFSET_FILL,
+ GL_SAMPLE_ALPHA_TO_COVERAGE,
+ GL_SAMPLE_COVERAGE,
+ GL_SCISSOR_TEST,
+ GL_STENCIL_TEST,
+};
+
+static const GLenum valid_get_max_index_type_table[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT,
+ GL_UNSIGNED_INT,
+};
+
+static const GLenum valid_get_tex_param_target_table[] = {
+ GL_TEXTURE_2D,
+ GL_TEXTURE_CUBE_MAP,
+};
+
+static const GLenum valid_hint_mode_table[] = {
+ GL_FASTEST,
+ GL_NICEST,
+ GL_DONT_CARE,
+};
+
+static const GLenum valid_hint_target_table[] = {
+ GL_GENERATE_MIPMAP_HINT,
+};
+
+static const GLenum valid_index_type_table[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT,
+};
+
+static const GLenum valid_pixel_store_table[] = {
+ GL_PACK_ALIGNMENT,
+ GL_UNPACK_ALIGNMENT,
+ GL_UNPACK_FLIP_Y_CHROMIUM,
+ GL_UNPACK_PREMULTIPLY_ALPHA_CHROMIUM,
+ GL_UNPACK_UNPREMULTIPLY_ALPHA_CHROMIUM,
+};
+
+static const GLint valid_pixel_store_alignment_table[] = {
+ 1,
+ 2,
+ 4,
+ 8,
+};
+
+static const GLenum valid_pixel_type_table[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_5_6_5,
+ GL_UNSIGNED_SHORT_4_4_4_4,
+ GL_UNSIGNED_SHORT_5_5_5_1,
+};
+
+static const GLenum valid_program_parameter_table[] = {
+ GL_DELETE_STATUS,
+ GL_LINK_STATUS,
+ GL_VALIDATE_STATUS,
+ GL_INFO_LOG_LENGTH,
+ GL_ATTACHED_SHADERS,
+ GL_ACTIVE_ATTRIBUTES,
+ GL_ACTIVE_ATTRIBUTE_MAX_LENGTH,
+ GL_ACTIVE_UNIFORMS,
+ GL_ACTIVE_UNIFORM_MAX_LENGTH,
+};
+
+static const GLenum valid_query_object_parameter_table[] = {
+ GL_QUERY_RESULT_EXT,
+ GL_QUERY_RESULT_AVAILABLE_EXT,
+};
+
+static const GLenum valid_query_parameter_table[] = {
+ GL_CURRENT_QUERY_EXT,
+};
+
+static const GLenum valid_query_target_table[] = {
+ GL_ANY_SAMPLES_PASSED_EXT,
+ GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT,
+ GL_COMMANDS_ISSUED_CHROMIUM,
+ GL_LATENCY_QUERY_CHROMIUM,
+ GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM,
+ GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM,
+};
+
+static const GLenum valid_read_pixel_format_table[] = {
+ GL_ALPHA,
+ GL_RGB,
+ GL_RGBA,
+};
+
+static const GLenum valid_read_pixel_type_table[] = {
+ GL_UNSIGNED_BYTE,
+ GL_UNSIGNED_SHORT_5_6_5,
+ GL_UNSIGNED_SHORT_4_4_4_4,
+ GL_UNSIGNED_SHORT_5_5_5_1,
+};
+
+static const GLenum valid_render_buffer_format_table[] = {
+ GL_RGBA4,
+ GL_RGB565,
+ GL_RGB5_A1,
+ GL_DEPTH_COMPONENT16,
+ GL_STENCIL_INDEX8,
+};
+
+static const GLenum valid_render_buffer_parameter_table[] = {
+ GL_RENDERBUFFER_RED_SIZE,
+ GL_RENDERBUFFER_GREEN_SIZE,
+ GL_RENDERBUFFER_BLUE_SIZE,
+ GL_RENDERBUFFER_ALPHA_SIZE,
+ GL_RENDERBUFFER_DEPTH_SIZE,
+ GL_RENDERBUFFER_STENCIL_SIZE,
+ GL_RENDERBUFFER_WIDTH,
+ GL_RENDERBUFFER_HEIGHT,
+ GL_RENDERBUFFER_INTERNAL_FORMAT,
+};
+
+static const GLenum valid_render_buffer_target_table[] = {
+ GL_RENDERBUFFER,
+};
+
+static const GLenum valid_reset_status_table[] = {
+ GL_GUILTY_CONTEXT_RESET_ARB,
+ GL_INNOCENT_CONTEXT_RESET_ARB,
+ GL_UNKNOWN_CONTEXT_RESET_ARB,
+};
+
+static const GLenum valid_shader_parameter_table[] = {
+ GL_SHADER_TYPE,
+ GL_DELETE_STATUS,
+ GL_COMPILE_STATUS,
+ GL_INFO_LOG_LENGTH,
+ GL_SHADER_SOURCE_LENGTH,
+ GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
+};
+
+static const GLenum valid_shader_precision_table[] = {
+ GL_LOW_FLOAT,
+ GL_MEDIUM_FLOAT,
+ GL_HIGH_FLOAT,
+ GL_LOW_INT,
+ GL_MEDIUM_INT,
+ GL_HIGH_INT,
+};
+
+static const GLenum valid_shader_type_table[] = {
+ GL_VERTEX_SHADER,
+ GL_FRAGMENT_SHADER,
+};
+
+static const GLenum valid_src_blend_factor_table[] = {
+ GL_ZERO,
+ GL_ONE,
+ GL_SRC_COLOR,
+ GL_ONE_MINUS_SRC_COLOR,
+ GL_DST_COLOR,
+ GL_ONE_MINUS_DST_COLOR,
+ GL_SRC_ALPHA,
+ GL_ONE_MINUS_SRC_ALPHA,
+ GL_DST_ALPHA,
+ GL_ONE_MINUS_DST_ALPHA,
+ GL_CONSTANT_COLOR,
+ GL_ONE_MINUS_CONSTANT_COLOR,
+ GL_CONSTANT_ALPHA,
+ GL_ONE_MINUS_CONSTANT_ALPHA,
+ GL_SRC_ALPHA_SATURATE,
+};
+
+static const GLenum valid_stencil_op_table[] = {
+ GL_KEEP,
+ GL_ZERO,
+ GL_REPLACE,
+ GL_INCR,
+ GL_INCR_WRAP,
+ GL_DECR,
+ GL_DECR_WRAP,
+ GL_INVERT,
+};
+
+static const GLenum valid_string_type_table[] = {
+ GL_VENDOR,
+ GL_RENDERER,
+ GL_VERSION,
+ GL_SHADING_LANGUAGE_VERSION,
+ GL_EXTENSIONS,
+};
+
+static const GLenum valid_texture_bind_target_table[] = {
+ GL_TEXTURE_2D,
+ GL_TEXTURE_CUBE_MAP,
+};
+
+static const GLint valid_texture_border_table[] = {
+ 0,
+};
+
+static const GLenum valid_texture_format_table[] = {
+ GL_ALPHA,
+ GL_LUMINANCE,
+ GL_LUMINANCE_ALPHA,
+ GL_RGB,
+ GL_RGBA,
+};
+
+static const GLenum valid_texture_internal_format_table[] = {
+ GL_ALPHA,
+ GL_LUMINANCE,
+ GL_LUMINANCE_ALPHA,
+ GL_RGB,
+ GL_RGBA,
+};
+
+static const GLenum valid_texture_internal_format_storage_table[] = {
+ GL_RGB565,
+ GL_RGBA4,
+ GL_RGB5_A1,
+ GL_ALPHA8_EXT,
+ GL_LUMINANCE8_EXT,
+ GL_LUMINANCE8_ALPHA8_EXT,
+ GL_RGB8_OES,
+ GL_RGBA8_OES,
+};
+
+static const GLenum valid_texture_mag_filter_mode_table[] = {
+ GL_NEAREST,
+ GL_LINEAR,
+};
+
+static const GLenum valid_texture_min_filter_mode_table[] = {
+ GL_NEAREST,
+ GL_LINEAR,
+ GL_NEAREST_MIPMAP_NEAREST,
+ GL_LINEAR_MIPMAP_NEAREST,
+ GL_NEAREST_MIPMAP_LINEAR,
+ GL_LINEAR_MIPMAP_LINEAR,
+};
+
+static const GLenum valid_texture_parameter_table[] = {
+ GL_TEXTURE_MAG_FILTER,
+ GL_TEXTURE_MIN_FILTER,
+ GL_TEXTURE_POOL_CHROMIUM,
+ GL_TEXTURE_WRAP_S,
+ GL_TEXTURE_WRAP_T,
+};
+
+static const GLenum valid_texture_pool_table[] = {
+ GL_TEXTURE_POOL_MANAGED_CHROMIUM,
+ GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
+};
+
+static const GLenum valid_texture_target_table[] = {
+ GL_TEXTURE_2D,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+};
+
+static const GLenum valid_texture_usage_table[] = {
+ GL_NONE,
+ GL_FRAMEBUFFER_ATTACHMENT_ANGLE,
+};
+
+static const GLenum valid_texture_wrap_mode_table[] = {
+ GL_CLAMP_TO_EDGE,
+ GL_MIRRORED_REPEAT,
+ GL_REPEAT,
+};
+
+static const GLint valid_vertex_attrib_size_table[] = {
+ 1,
+ 2,
+ 3,
+ 4,
+};
+
+static const GLenum valid_vertex_attrib_type_table[] = {
+ GL_BYTE,
+ GL_UNSIGNED_BYTE,
+ GL_SHORT,
+ GL_UNSIGNED_SHORT,
+ GL_FLOAT,
+};
+
+static const GLenum valid_vertex_attribute_table[] = {
+ GL_VERTEX_ATTRIB_ARRAY_NORMALIZED,
+ GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING,
+ GL_VERTEX_ATTRIB_ARRAY_ENABLED,
+ GL_VERTEX_ATTRIB_ARRAY_SIZE,
+ GL_VERTEX_ATTRIB_ARRAY_STRIDE,
+ GL_VERTEX_ATTRIB_ARRAY_TYPE,
+ GL_CURRENT_VERTEX_ATTRIB,
+};
+
+static const GLenum valid_vertex_pointer_table[] = {
+ GL_VERTEX_ATTRIB_ARRAY_POINTER,
+};
+
+static const GLint valid_zero_only_table[] = {
+ 0,
+};
+
+Validators::Validators()
+ : attachment(
+ valid_attachment_table, arraysize(valid_attachment_table)),
+ backbuffer_attachment(
+ valid_backbuffer_attachment_table, arraysize(
+ valid_backbuffer_attachment_table)),
+ blit_filter(
+ valid_blit_filter_table, arraysize(valid_blit_filter_table)),
+ buffer_parameter(
+ valid_buffer_parameter_table, arraysize(
+ valid_buffer_parameter_table)),
+ buffer_target(
+ valid_buffer_target_table, arraysize(valid_buffer_target_table)),
+ buffer_usage(
+ valid_buffer_usage_table, arraysize(valid_buffer_usage_table)),
+ capability(
+ valid_capability_table, arraysize(valid_capability_table)),
+ cmp_function(
+ valid_cmp_function_table, arraysize(valid_cmp_function_table)),
+ compressed_texture_format(),
+ draw_mode(
+ valid_draw_mode_table, arraysize(valid_draw_mode_table)),
+ dst_blend_factor(
+ valid_dst_blend_factor_table, arraysize(
+ valid_dst_blend_factor_table)),
+ equation(
+ valid_equation_table, arraysize(valid_equation_table)),
+ face_mode(
+ valid_face_mode_table, arraysize(valid_face_mode_table)),
+ face_type(
+ valid_face_type_table, arraysize(valid_face_type_table)),
+ false_only(
+ valid_false_only_table, arraysize(valid_false_only_table)),
+ frame_buffer_parameter(
+ valid_frame_buffer_parameter_table, arraysize(
+ valid_frame_buffer_parameter_table)),
+ frame_buffer_target(
+ valid_frame_buffer_target_table, arraysize(
+ valid_frame_buffer_target_table)),
+ g_l_state(
+ valid_g_l_state_table, arraysize(valid_g_l_state_table)),
+ get_max_index_type(
+ valid_get_max_index_type_table, arraysize(
+ valid_get_max_index_type_table)),
+ get_tex_param_target(
+ valid_get_tex_param_target_table, arraysize(
+ valid_get_tex_param_target_table)),
+ hint_mode(
+ valid_hint_mode_table, arraysize(valid_hint_mode_table)),
+ hint_target(
+ valid_hint_target_table, arraysize(valid_hint_target_table)),
+ index_type(
+ valid_index_type_table, arraysize(valid_index_type_table)),
+ pixel_store(
+ valid_pixel_store_table, arraysize(valid_pixel_store_table)),
+ pixel_store_alignment(
+ valid_pixel_store_alignment_table, arraysize(
+ valid_pixel_store_alignment_table)),
+ pixel_type(
+ valid_pixel_type_table, arraysize(valid_pixel_type_table)),
+ program_parameter(
+ valid_program_parameter_table, arraysize(
+ valid_program_parameter_table)),
+ query_object_parameter(
+ valid_query_object_parameter_table, arraysize(
+ valid_query_object_parameter_table)),
+ query_parameter(
+ valid_query_parameter_table, arraysize(valid_query_parameter_table)),
+ query_target(
+ valid_query_target_table, arraysize(valid_query_target_table)),
+ read_pixel_format(
+ valid_read_pixel_format_table, arraysize(
+ valid_read_pixel_format_table)),
+ read_pixel_type(
+ valid_read_pixel_type_table, arraysize(valid_read_pixel_type_table)),
+ render_buffer_format(
+ valid_render_buffer_format_table, arraysize(
+ valid_render_buffer_format_table)),
+ render_buffer_parameter(
+ valid_render_buffer_parameter_table, arraysize(
+ valid_render_buffer_parameter_table)),
+ render_buffer_target(
+ valid_render_buffer_target_table, arraysize(
+ valid_render_buffer_target_table)),
+ reset_status(
+ valid_reset_status_table, arraysize(valid_reset_status_table)),
+ shader_binary_format(),
+ shader_parameter(
+ valid_shader_parameter_table, arraysize(
+ valid_shader_parameter_table)),
+ shader_precision(
+ valid_shader_precision_table, arraysize(
+ valid_shader_precision_table)),
+ shader_type(
+ valid_shader_type_table, arraysize(valid_shader_type_table)),
+ src_blend_factor(
+ valid_src_blend_factor_table, arraysize(
+ valid_src_blend_factor_table)),
+ stencil_op(
+ valid_stencil_op_table, arraysize(valid_stencil_op_table)),
+ string_type(
+ valid_string_type_table, arraysize(valid_string_type_table)),
+ texture_bind_target(
+ valid_texture_bind_target_table, arraysize(
+ valid_texture_bind_target_table)),
+ texture_border(
+ valid_texture_border_table, arraysize(valid_texture_border_table)),
+ texture_format(
+ valid_texture_format_table, arraysize(valid_texture_format_table)),
+ texture_internal_format(
+ valid_texture_internal_format_table, arraysize(
+ valid_texture_internal_format_table)),
+ texture_internal_format_storage(
+ valid_texture_internal_format_storage_table, arraysize(
+ valid_texture_internal_format_storage_table)),
+ texture_mag_filter_mode(
+ valid_texture_mag_filter_mode_table, arraysize(
+ valid_texture_mag_filter_mode_table)),
+ texture_min_filter_mode(
+ valid_texture_min_filter_mode_table, arraysize(
+ valid_texture_min_filter_mode_table)),
+ texture_parameter(
+ valid_texture_parameter_table, arraysize(
+ valid_texture_parameter_table)),
+ texture_pool(
+ valid_texture_pool_table, arraysize(valid_texture_pool_table)),
+ texture_target(
+ valid_texture_target_table, arraysize(valid_texture_target_table)),
+ texture_usage(
+ valid_texture_usage_table, arraysize(valid_texture_usage_table)),
+ texture_wrap_mode(
+ valid_texture_wrap_mode_table, arraysize(
+ valid_texture_wrap_mode_table)),
+ vertex_attrib_size(
+ valid_vertex_attrib_size_table, arraysize(
+ valid_vertex_attrib_size_table)),
+ vertex_attrib_type(
+ valid_vertex_attrib_type_table, arraysize(
+ valid_vertex_attrib_type_table)),
+ vertex_attribute(
+ valid_vertex_attribute_table, arraysize(
+ valid_vertex_attribute_table)),
+ vertex_pointer(
+ valid_vertex_pointer_table, arraysize(valid_vertex_pointer_table)),
+ zero_only(
+ valid_zero_only_table, arraysize(valid_zero_only_table)) {
+}
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_VALIDATION_IMPLEMENTATION_AUTOGEN_H_ // NOLINT
+
diff --git a/chromium/gpu/command_buffer/service/gpu_scheduler.cc b/chromium/gpu/command_buffer/service/gpu_scheduler.cc
new file mode 100644
index 00000000000..cc86390846e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_scheduler.cc
@@ -0,0 +1,310 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/compiler_specific.h"
+#include "base/debug/trace_event.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_fence.h"
+#include "ui/gl/gl_switches.h"
+
+#if defined(OS_WIN)
+#include "base/win/windows_version.h"
+#endif
+
+using ::base::SharedMemory;
+
+namespace gpu {
+
+namespace {
+const int64 kRescheduleTimeOutDelay = 1000;
+const int64 kUnscheduleFenceTimeOutDelay = 10000;
+}
+
+GpuScheduler::GpuScheduler(CommandBuffer* command_buffer,
+ AsyncAPIInterface* handler,
+ gles2::GLES2Decoder* decoder)
+ : command_buffer_(command_buffer),
+ handler_(handler),
+ decoder_(decoder),
+ unscheduled_count_(0),
+ rescheduled_count_(0),
+ reschedule_task_factory_(this),
+ was_preempted_(false) {}
+
+GpuScheduler::~GpuScheduler() {
+}
+
+void GpuScheduler::PutChanged() {
+ TRACE_EVENT1(
+ "gpu", "GpuScheduler:PutChanged",
+ "decoder", decoder_ ? decoder_->GetLogger()->GetLogPrefix() : "None");
+
+ CommandBuffer::State state = command_buffer_->GetState();
+
+ // If there is no parser, exit.
+ if (!parser_.get()) {
+ DCHECK_EQ(state.get_offset, state.put_offset);
+ return;
+ }
+
+ parser_->set_put(state.put_offset);
+ if (state.error != error::kNoError)
+ return;
+
+ // Check that the GPU has passed all fences.
+ if (!PollUnscheduleFences())
+ return;
+
+ // One of the unschedule fence tasks might have unscheduled us.
+ if (!IsScheduled())
+ return;
+
+ base::TimeTicks begin_time(base::TimeTicks::HighResNow());
+ error::Error error = error::kNoError;
+ while (!parser_->IsEmpty()) {
+ if (IsPreempted())
+ break;
+
+ DCHECK(IsScheduled());
+ DCHECK(unschedule_fences_.empty());
+
+ error = parser_->ProcessCommand();
+
+ if (error == error::kDeferCommandUntilLater) {
+ DCHECK_GT(unscheduled_count_, 0);
+ break;
+ }
+
+ // TODO(piman): various classes duplicate various pieces of state, leading
+ // to needlessly complex update logic. It should be possible to simply
+ // share the state across all of them.
+ command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
+
+ if (error::IsError(error)) {
+ LOG(ERROR) << "[" << decoder_ << "] "
+ << "GPU PARSE ERROR: " << error;
+ command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
+ command_buffer_->SetParseError(error);
+ break;
+ }
+
+ if (!command_processed_callback_.is_null())
+ command_processed_callback_.Run();
+
+ if (unscheduled_count_ > 0)
+ break;
+ }
+
+ if (decoder_) {
+ if (!error::IsError(error) && decoder_->WasContextLost()) {
+ command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
+ command_buffer_->SetParseError(error::kLostContext);
+ }
+ decoder_->AddProcessingCommandsTime(
+ base::TimeTicks::HighResNow() - begin_time);
+ }
+}
+
+void GpuScheduler::SetScheduled(bool scheduled) {
+ TRACE_EVENT2("gpu", "GpuScheduler:SetScheduled", "this", this,
+ "new unscheduled_count_",
+ unscheduled_count_ + (scheduled? -1 : 1));
+ if (scheduled) {
+ // If the scheduler was rescheduled after a timeout, ignore the subsequent
+ // calls to SetScheduled when they eventually arrive until they are all
+ // accounted for.
+ if (rescheduled_count_ > 0) {
+ --rescheduled_count_;
+ return;
+ } else {
+ --unscheduled_count_;
+ }
+
+ DCHECK_GE(unscheduled_count_, 0);
+
+ if (unscheduled_count_ == 0) {
+ TRACE_EVENT_ASYNC_END1("gpu", "ProcessingSwap", this,
+ "GpuScheduler", this);
+ // When the scheduler transitions from the unscheduled to the scheduled
+ // state, cancel the task that would reschedule it after a timeout.
+ reschedule_task_factory_.InvalidateWeakPtrs();
+
+ if (!scheduling_changed_callback_.is_null())
+ scheduling_changed_callback_.Run(true);
+ }
+ } else {
+ ++unscheduled_count_;
+ if (unscheduled_count_ == 1) {
+ TRACE_EVENT_ASYNC_BEGIN1("gpu", "ProcessingSwap", this,
+ "GpuScheduler", this);
+#if defined(OS_WIN)
+ if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+ // When the scheduler transitions from scheduled to unscheduled, post a
+ // delayed task that it will force it back into a scheduled state after
+ // a timeout. This should only be necessary on pre-Vista.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&GpuScheduler::RescheduleTimeOut,
+ reschedule_task_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(kRescheduleTimeOutDelay));
+ }
+#endif
+ if (!scheduling_changed_callback_.is_null())
+ scheduling_changed_callback_.Run(false);
+ }
+ }
+}
+
+bool GpuScheduler::IsScheduled() {
+ return unscheduled_count_ == 0;
+}
+
+bool GpuScheduler::HasMoreWork() {
+ return !unschedule_fences_.empty() ||
+ (decoder_ && decoder_->ProcessPendingQueries()) ||
+ HasMoreIdleWork();
+}
+
+void GpuScheduler::SetSchedulingChangedCallback(
+ const SchedulingChangedCallback& callback) {
+ scheduling_changed_callback_ = callback;
+}
+
+Buffer GpuScheduler::GetSharedMemoryBuffer(int32 shm_id) {
+ return command_buffer_->GetTransferBuffer(shm_id);
+}
+
+void GpuScheduler::set_token(int32 token) {
+ command_buffer_->SetToken(token);
+}
+
+bool GpuScheduler::SetGetBuffer(int32 transfer_buffer_id) {
+ Buffer ring_buffer = command_buffer_->GetTransferBuffer(transfer_buffer_id);
+ if (!ring_buffer.ptr) {
+ return false;
+ }
+
+ if (!parser_.get()) {
+ parser_.reset(new CommandParser(handler_));
+ }
+
+ parser_->SetBuffer(
+ ring_buffer.ptr,
+ ring_buffer.size,
+ 0,
+ ring_buffer.size);
+
+ SetGetOffset(0);
+ return true;
+}
+
+bool GpuScheduler::SetGetOffset(int32 offset) {
+ if (parser_->set_get(offset)) {
+ command_buffer_->SetGetOffset(static_cast<int32>(parser_->get()));
+ return true;
+ }
+ return false;
+}
+
+int32 GpuScheduler::GetGetOffset() {
+ return parser_->get();
+}
+
+void GpuScheduler::SetCommandProcessedCallback(
+ const base::Closure& callback) {
+ command_processed_callback_ = callback;
+}
+
+void GpuScheduler::DeferToFence(base::Closure task) {
+ unschedule_fences_.push(make_linked_ptr(
+ new UnscheduleFence(gfx::GLFence::Create(), task)));
+ SetScheduled(false);
+}
+
+bool GpuScheduler::PollUnscheduleFences() {
+ if (unschedule_fences_.empty())
+ return true;
+
+ if (unschedule_fences_.front()->fence.get()) {
+ base::Time now = base::Time::Now();
+ base::TimeDelta timeout =
+ base::TimeDelta::FromMilliseconds(kUnscheduleFenceTimeOutDelay);
+
+ while (!unschedule_fences_.empty()) {
+ const UnscheduleFence& fence = *unschedule_fences_.front();
+ if (fence.fence->HasCompleted() ||
+ now - fence.issue_time > timeout) {
+ unschedule_fences_.front()->task.Run();
+ unschedule_fences_.pop();
+ SetScheduled(true);
+ } else {
+ return false;
+ }
+ }
+ } else {
+ glFinish();
+
+ while (!unschedule_fences_.empty()) {
+ unschedule_fences_.front()->task.Run();
+ unschedule_fences_.pop();
+ SetScheduled(true);
+ }
+ }
+
+ return true;
+}
+
+bool GpuScheduler::IsPreempted() {
+ if (!preemption_flag_.get())
+ return false;
+
+ if (!was_preempted_ && preemption_flag_->IsSet()) {
+ TRACE_COUNTER_ID1("gpu", "GpuScheduler::Preempted", this, 1);
+ was_preempted_ = true;
+ } else if (was_preempted_ && !preemption_flag_->IsSet()) {
+ TRACE_COUNTER_ID1("gpu", "GpuScheduler::Preempted", this, 0);
+ was_preempted_ = false;
+ }
+
+ return preemption_flag_->IsSet();
+}
+
+bool GpuScheduler::HasMoreIdleWork() {
+ return (decoder_ && decoder_->HasMoreIdleWork());
+}
+
+void GpuScheduler::PerformIdleWork() {
+ if (!decoder_)
+ return;
+ decoder_->PerformIdleWork();
+}
+
+void GpuScheduler::RescheduleTimeOut() {
+ int new_count = unscheduled_count_ + rescheduled_count_;
+
+ rescheduled_count_ = 0;
+
+ while (unscheduled_count_)
+ SetScheduled(true);
+
+ rescheduled_count_ = new_count;
+}
+
+GpuScheduler::UnscheduleFence::UnscheduleFence(gfx::GLFence* fence_,
+ base::Closure task_)
+ : fence(fence_),
+ issue_time(base::Time::Now()),
+ task(task_) {
+}
+
+GpuScheduler::UnscheduleFence::~UnscheduleFence() {
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gpu_scheduler.h b/chromium/gpu/command_buffer/service/gpu_scheduler.h
new file mode 100644
index 00000000000..8fb791cd3fd
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_scheduler.h
@@ -0,0 +1,168 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_
+
+#include <queue>
+
+#include "base/atomic_ref_count.h"
+#include "base/atomicops.h"
+#include "base/callback.h"
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/shared_memory.h"
+#include "base/memory/weak_ptr.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class GLFence;
+}
+
+namespace gpu {
+
+class PreemptionFlag
+ : public base::RefCountedThreadSafe<PreemptionFlag> {
+ public:
+ PreemptionFlag() : flag_(0) {}
+
+ bool IsSet() { return !base::AtomicRefCountIsZero(&flag_); }
+ void Set() { base::AtomicRefCountInc(&flag_); }
+ void Reset() { base::subtle::NoBarrier_Store(&flag_, 0); }
+
+ private:
+ base::AtomicRefCount flag_;
+
+ ~PreemptionFlag() {}
+
+ friend class base::RefCountedThreadSafe<PreemptionFlag>;
+};
+
+// This class schedules commands that have been flushed. They are received via
+// a command buffer and forwarded to a command parser. TODO(apatrick): This
+// class should not know about the decoder. Do not add additional dependencies
+// on it.
+class GPU_EXPORT GpuScheduler
+ : NON_EXPORTED_BASE(public CommandBufferEngine),
+ public base::SupportsWeakPtr<GpuScheduler> {
+ public:
+ GpuScheduler(CommandBuffer* command_buffer,
+ AsyncAPIInterface* handler,
+ gles2::GLES2Decoder* decoder);
+
+ virtual ~GpuScheduler();
+
+ void PutChanged();
+
+ void SetPreemptByFlag(scoped_refptr<PreemptionFlag> flag) {
+ preemption_flag_ = flag;
+ }
+
+ // Sets whether commands should be processed by this scheduler. Setting to
+ // false unschedules. Setting to true reschedules. Whether or not the
+ // scheduler is currently scheduled is "reference counted". Every call with
+ // false must eventually be paired by a call with true.
+ void SetScheduled(bool is_scheduled);
+
+ // Returns whether the scheduler is currently able to process more commands.
+ bool IsScheduled();
+
+ // Returns whether the scheduler needs to be polled again in the future.
+ bool HasMoreWork();
+
+ typedef base::Callback<void(bool /* scheduled */)> SchedulingChangedCallback;
+
+ // Sets a callback that is invoked just before scheduler is rescheduled
+ // or descheduled. Takes ownership of callback object.
+ void SetSchedulingChangedCallback(const SchedulingChangedCallback& callback);
+
+ // Implementation of CommandBufferEngine.
+ virtual Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE;
+ virtual void set_token(int32 token) OVERRIDE;
+ virtual bool SetGetBuffer(int32 transfer_buffer_id) OVERRIDE;
+ virtual bool SetGetOffset(int32 offset) OVERRIDE;
+ virtual int32 GetGetOffset() OVERRIDE;
+
+ void SetCommandProcessedCallback(const base::Closure& callback);
+
+ void DeferToFence(base::Closure task);
+
+ // Polls the fences, invoking callbacks that were waiting to be triggered
+ // by them and returns whether all fences were complete.
+ bool PollUnscheduleFences();
+
+ bool HasMoreIdleWork();
+ void PerformIdleWork();
+
+ CommandParser* parser() const {
+ return parser_.get();
+ }
+
+ bool IsPreempted();
+
+ private:
+ // Artificially reschedule if the scheduler is still unscheduled after a
+ // timeout.
+ void RescheduleTimeOut();
+
+ // The GpuScheduler holds a weak reference to the CommandBuffer. The
+ // CommandBuffer owns the GpuScheduler and holds a strong reference to it
+ // through the ProcessCommands callback.
+ CommandBuffer* command_buffer_;
+
+ // The parser uses this to execute commands.
+ AsyncAPIInterface* handler_;
+
+ // Does not own decoder. TODO(apatrick): The GpuScheduler shouldn't need a
+ // pointer to the decoder, it is only used to initialize the CommandParser,
+ // which could be an argument to the constructor, and to determine the
+ // reason for context lost.
+ gles2::GLES2Decoder* decoder_;
+
+ // TODO(apatrick): The GpuScheduler currently creates and owns the parser.
+ // This should be an argument to the constructor.
+ scoped_ptr<CommandParser> parser_;
+
+ // Greater than zero if this is waiting to be rescheduled before continuing.
+ int unscheduled_count_;
+
+ // The number of times this scheduler has been artificially rescheduled on
+ // account of a timeout.
+ int rescheduled_count_;
+
+ // A factory for outstanding rescheduling tasks that is invalidated whenever
+ // the scheduler is rescheduled.
+ base::WeakPtrFactory<GpuScheduler> reschedule_task_factory_;
+
+ // The GpuScheduler will unschedule itself in the event that further GL calls
+ // are issued to it before all these fences have been crossed by the GPU.
+ struct UnscheduleFence {
+ UnscheduleFence(gfx::GLFence* fence, base::Closure task);
+ ~UnscheduleFence();
+
+ scoped_ptr<gfx::GLFence> fence;
+ base::Time issue_time;
+ base::Closure task;
+ };
+ std::queue<linked_ptr<UnscheduleFence> > unschedule_fences_;
+
+ SchedulingChangedCallback scheduling_changed_callback_;
+ base::Closure descheduled_callback_;
+ base::Closure command_processed_callback_;
+
+ // If non-NULL and |preemption_flag_->IsSet()|, exit PutChanged early.
+ scoped_refptr<PreemptionFlag> preemption_flag_;
+ bool was_preempted_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuScheduler);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_H_
diff --git a/chromium/gpu/command_buffer/service/gpu_scheduler_mock.h b/chromium/gpu/command_buffer/service/gpu_scheduler_mock.h
new file mode 100644
index 00000000000..ed308e09582
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_scheduler_mock.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_MOCK_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_MOCK_H_
+
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+class MockGpuScheduler : public GpuScheduler {
+ public:
+ explicit MockGpuScheduler(CommandBuffer* command_buffer)
+ : GpuScheduler(command_buffer) {
+ }
+
+ MOCK_METHOD1(GetSharedMemoryBuffer, Buffer(int32 shm_id));
+ MOCK_METHOD1(set_token, void(int32 token));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockGpuScheduler);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_SCHEDULER_MOCK_H_
diff --git a/chromium/gpu/command_buffer/service/gpu_scheduler_unittest.cc b/chromium/gpu/command_buffer/service/gpu_scheduler_unittest.cc
new file mode 100644
index 00000000000..84e40c7c658
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_scheduler_unittest.cc
@@ -0,0 +1,218 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/message_loop/message_loop.h"
+#include "gpu/command_buffer/common/command_buffer_mock.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+
+using testing::_;
+using testing::DoAll;
+using testing::Invoke;
+using testing::NiceMock;
+using testing::Return;
+using testing::SetArgumentPointee;
+using testing::StrictMock;
+
+namespace gpu {
+
+const size_t kRingBufferSize = 1024;
+const size_t kRingBufferEntries = kRingBufferSize / sizeof(CommandBufferEntry);
+
+class GpuSchedulerTest : public testing::Test {
+ protected:
+ static const int32 kTransferBufferId = 123;
+
+ virtual void SetUp() {
+ shared_memory_.reset(new ::base::SharedMemory);
+ shared_memory_->CreateAndMapAnonymous(kRingBufferSize);
+ buffer_ = static_cast<int32*>(shared_memory_->memory());
+ shared_memory_buffer_.ptr = buffer_;
+ shared_memory_buffer_.size = kRingBufferSize;
+ memset(buffer_, 0, kRingBufferSize);
+
+ command_buffer_.reset(new MockCommandBuffer);
+
+ CommandBuffer::State default_state;
+ default_state.num_entries = kRingBufferEntries;
+ ON_CALL(*command_buffer_.get(), GetState())
+ .WillByDefault(Return(default_state));
+
+ decoder_.reset(new gles2::MockGLES2Decoder());
+ scheduler_.reset(new gpu::GpuScheduler(command_buffer_.get(),
+ decoder_.get(),
+ decoder_.get()));
+ EXPECT_CALL(*command_buffer_, GetTransferBuffer(kTransferBufferId))
+ .WillOnce(Return(shared_memory_buffer_));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(0));
+ EXPECT_TRUE(scheduler_->SetGetBuffer(kTransferBufferId));
+ }
+
+ virtual void TearDown() {
+ // Ensure that any unexpected tasks posted by the GPU scheduler are executed
+ // in order to fail the test.
+ base::MessageLoop::current()->RunUntilIdle();
+ }
+
+ error::Error GetError() {
+ return command_buffer_->GetState().error;
+ }
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool autorelease_pool_;
+#endif
+ base::MessageLoop message_loop;
+ scoped_ptr<MockCommandBuffer> command_buffer_;
+ scoped_ptr<base::SharedMemory> shared_memory_;
+ Buffer shared_memory_buffer_;
+ int32* buffer_;
+ scoped_ptr<gles2::MockGLES2Decoder> decoder_;
+ scoped_ptr<GpuScheduler> scheduler_;
+};
+
+TEST_F(GpuSchedulerTest, SchedulerDoesNothingIfRingBufferIsEmpty) {
+ CommandBuffer::State state;
+
+ state.put_offset = 0;
+ EXPECT_CALL(*command_buffer_, GetState())
+ .WillRepeatedly(Return(state));
+
+ EXPECT_CALL(*command_buffer_, SetParseError(_))
+ .Times(0);
+
+ scheduler_->PutChanged();
+}
+
+TEST_F(GpuSchedulerTest, GetSetBuffer) {
+ CommandBuffer::State state;
+
+ // Set the get offset to something not 0.
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+ scheduler_->SetGetOffset(2);
+ EXPECT_EQ(2, scheduler_->GetGetOffset());
+
+ // Set the buffer.
+ EXPECT_CALL(*command_buffer_, GetTransferBuffer(kTransferBufferId))
+ .WillOnce(Return(shared_memory_buffer_));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(0));
+ EXPECT_TRUE(scheduler_->SetGetBuffer(kTransferBufferId));
+
+ // Check the get offset was reset.
+ EXPECT_EQ(0, scheduler_->GetGetOffset());
+}
+
+TEST_F(GpuSchedulerTest, ProcessesOneCommand) {
+ CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+
+ CommandBuffer::State state;
+
+ state.put_offset = 2;
+ EXPECT_CALL(*command_buffer_, GetState())
+ .WillRepeatedly(Return(state));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+
+ EXPECT_CALL(*decoder_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(error::kNoError));
+
+ EXPECT_CALL(*command_buffer_, SetParseError(_))
+ .Times(0);
+
+ scheduler_->PutChanged();
+}
+
+TEST_F(GpuSchedulerTest, ProcessesTwoCommands) {
+ CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 2;
+ buffer_[1] = 123;
+ header[2].command = 8;
+ header[2].size = 1;
+
+ CommandBuffer::State state;
+
+ state.put_offset = 3;
+ EXPECT_CALL(*command_buffer_, GetState())
+ .WillRepeatedly(Return(state));
+
+ EXPECT_CALL(*decoder_, DoCommand(7, 1, &buffer_[0]))
+ .WillOnce(Return(error::kNoError));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(2));
+
+ EXPECT_CALL(*decoder_, DoCommand(8, 0, &buffer_[2]))
+ .WillOnce(Return(error::kNoError));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(3));
+
+ scheduler_->PutChanged();
+}
+
+TEST_F(GpuSchedulerTest, SetsErrorCodeOnCommandBuffer) {
+ CommandHeader* header = reinterpret_cast<CommandHeader*>(&buffer_[0]);
+ header[0].command = 7;
+ header[0].size = 1;
+
+ CommandBuffer::State state;
+
+ state.put_offset = 1;
+ EXPECT_CALL(*command_buffer_, GetState())
+ .WillRepeatedly(Return(state));
+
+ EXPECT_CALL(*decoder_, DoCommand(7, 0, &buffer_[0]))
+ .WillOnce(Return(
+ error::kUnknownCommand));
+ EXPECT_CALL(*command_buffer_, SetGetOffset(1));
+
+ EXPECT_CALL(*command_buffer_, SetContextLostReason(_));
+ EXPECT_CALL(*decoder_, GetContextLostReason())
+ .WillOnce(Return(error::kUnknown));
+ EXPECT_CALL(*command_buffer_,
+ SetParseError(error::kUnknownCommand));
+
+ scheduler_->PutChanged();
+}
+
+TEST_F(GpuSchedulerTest, ProcessCommandsDoesNothingAfterError) {
+ CommandBuffer::State state;
+ state.error = error::kGenericError;
+
+ EXPECT_CALL(*command_buffer_, GetState())
+ .WillRepeatedly(Return(state));
+
+ scheduler_->PutChanged();
+}
+
+TEST_F(GpuSchedulerTest, CanGetAddressOfSharedMemory) {
+ EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7))
+ .WillOnce(Return(shared_memory_buffer_));
+
+ EXPECT_EQ(&buffer_[0], scheduler_->GetSharedMemoryBuffer(7).ptr);
+}
+
+ACTION_P2(SetPointee, address, value) {
+ *address = value;
+}
+
+TEST_F(GpuSchedulerTest, CanGetSizeOfSharedMemory) {
+ EXPECT_CALL(*command_buffer_.get(), GetTransferBuffer(7))
+ .WillOnce(Return(shared_memory_buffer_));
+
+ EXPECT_EQ(kRingBufferSize, scheduler_->GetSharedMemoryBuffer(7).size);
+}
+
+TEST_F(GpuSchedulerTest, SetTokenForwardsToCommandBuffer) {
+ EXPECT_CALL(*command_buffer_, SetToken(7));
+ scheduler_->set_token(7);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gpu_switches.cc b/chromium/gpu/command_buffer/service/gpu_switches.cc
new file mode 100644
index 00000000000..221dd609756
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_switches.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "base/basictypes.h"
+
+namespace switches {
+
+// Always return success when compiling a shader. Linking will still fail.
+const char kCompileShaderAlwaysSucceeds[] = "compile-shader-always-succeeds";
+
+// Disable the GL error log limit.
+const char kDisableGLErrorLimit[] = "disable-gl-error-limit";
+
+// Disable the GLSL translator.
+const char kDisableGLSLTranslator[] = "disable-glsl-translator";
+
+// Disable workarounds for various GPU driver bugs.
+const char kDisableGpuDriverBugWorkarounds[] =
+ "disable-gpu-driver-bug-workarounds";
+
+// Turn off user-defined name hashing in shaders.
+const char kDisableShaderNameHashing[] = "disable-shader-name-hashing";
+
+// Turn on Logging GPU commands.
+const char kEnableGPUCommandLogging[] = "enable-gpu-command-logging";
+
+// Turn on Calling GL Error after every command.
+const char kEnableGPUDebugging[] = "enable-gpu-debugging";
+
+// Enable GPU service logging. Note: This is the same switch as the one in
+// gl_switches.cc. It's defined here again to avoid dependencies between
+// dlls.
+const char kEnableGPUServiceLoggingGPU[] = "enable-gpu-service-logging";
+
+// Turn off gpu program caching
+const char kDisableGpuProgramCache[] = "disable-gpu-program-cache";
+
+// Enforce GL minimums.
+const char kEnforceGLMinimums[] = "enforce-gl-minimums";
+
+// Force the use of a workaround for graphics hangs seen on certain
+// Mac OS systems. Enabled by default (and can't be disabled) on known
+// affected systems.
+const char kForceGLFinishWorkaround[] = "force-glfinish-workaround";
+
+// Sets the total amount of memory that may be allocated for GPU resources
+const char kForceGpuMemAvailableMb[] = "force-gpu-mem-available-mb";
+
+// Force the synchronous copy path in compositing_iosurface_mac.
+const char kForceSynchronousGLReadPixels[] = "force-synchronous-glreadpixels";
+
+// Pass a set of GpuDriverBugWorkaroundType ids, seperated by ','.
+const char kGpuDriverBugWorkarounds[] = "gpu-driver-bug-workarounds";
+
+// Sets the maximum size of the in-memory gpu program cache, in kb
+const char kGpuProgramCacheSizeKb[] = "gpu-program-cache-size-kb";
+
+const char kTraceGL[] = "trace-gl";
+
+// Disables the GPU shader on disk cache.
+const char kDisableGpuShaderDiskCache[] = "disable-gpu-shader-disk-cache";
+
+// Allows async texture uploads (off main thread) via GL context sharing.
+const char kEnableShareGroupAsyncTextureUpload[] =
+ "enable-share-group-async-texture-upload";
+
+const char* kGpuSwitches[] = {
+ kCompileShaderAlwaysSucceeds,
+ kDisableGLErrorLimit,
+ kDisableGLSLTranslator,
+ kDisableGpuDriverBugWorkarounds,
+ kDisableShaderNameHashing,
+ kEnableGPUCommandLogging,
+ kEnableGPUDebugging,
+ kEnableGPUServiceLoggingGPU,
+ kDisableGpuProgramCache,
+ kEnforceGLMinimums,
+ kForceGLFinishWorkaround,
+ kForceGpuMemAvailableMb,
+ kForceSynchronousGLReadPixels,
+ kGpuDriverBugWorkarounds,
+ kGpuProgramCacheSizeKb,
+ kTraceGL,
+ kDisableGpuShaderDiskCache,
+ kEnableShareGroupAsyncTextureUpload,
+};
+
+const int kNumGpuSwitches = arraysize(kGpuSwitches);
+
+} // namespace switches
diff --git a/chromium/gpu/command_buffer/service/gpu_switches.h b/chromium/gpu/command_buffer/service/gpu_switches.h
new file mode 100644
index 00000000000..7634c571174
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_switches.h
@@ -0,0 +1,39 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Defines all the command-line switches used by gpu/command_buffer/service/.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_SWITCHES_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_SWITCHES_H_
+
+#include "gpu/gpu_export.h"
+
+namespace switches {
+
+GPU_EXPORT extern const char kCompileShaderAlwaysSucceeds[];
+GPU_EXPORT extern const char kDisableGLErrorLimit[];
+GPU_EXPORT extern const char kDisableGLSLTranslator[];
+GPU_EXPORT extern const char kDisableGpuDriverBugWorkarounds[];
+GPU_EXPORT extern const char kDisableShaderNameHashing[];
+GPU_EXPORT extern const char kEnableGPUCommandLogging[];
+GPU_EXPORT extern const char kEnableGPUDebugging[];
+GPU_EXPORT extern const char kEnableGPUServiceLoggingGPU[];
+GPU_EXPORT extern const char kDisableGpuProgramCache[];
+GPU_EXPORT extern const char kEnforceGLMinimums[];
+GPU_EXPORT extern const char kForceGLFinishWorkaround[];
+GPU_EXPORT extern const char kForceGpuMemAvailableMb[];
+GPU_EXPORT extern const char kForceSynchronousGLReadPixels[];
+GPU_EXPORT extern const char kGpuDriverBugWorkarounds[];
+GPU_EXPORT extern const char kGpuProgramCacheSizeKb[];
+GPU_EXPORT extern const char kTraceGL[];
+GPU_EXPORT extern const char kDisableGpuShaderDiskCache[];
+GPU_EXPORT extern const char kEnableShareGroupAsyncTextureUpload[];
+
+GPU_EXPORT extern const char* kGpuSwitches[];
+GPU_EXPORT extern const int kNumGpuSwitches;
+
+} // namespace switches
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_SWITCHES_H_
+
diff --git a/chromium/gpu/command_buffer/service/gpu_tracer.cc b/chromium/gpu/command_buffer/service/gpu_tracer.cc
new file mode 100644
index 00000000000..6bb2dfb672f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_tracer.cc
@@ -0,0 +1,347 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/gpu_tracer.h"
+
+#include <deque>
+
+#include "base/bind.h"
+#include "base/debug/trace_event.h"
+#include "base/memory/weak_ptr.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace gpu {
+namespace gles2 {
+namespace {
+
+class Outputter;
+
+static const unsigned int kProcessInterval = 16;
+static Outputter* g_outputter_thread = NULL;
+
+class Outputter
+ : private base::Thread,
+ public base::RefCounted<Outputter> {
+ public:
+ static scoped_refptr<Outputter> Create(const std::string& name) {
+ if (!g_outputter_thread) {
+ g_outputter_thread = new Outputter(name);
+ g_outputter_thread->Start();
+ g_outputter_thread->Stop();
+ }
+ return g_outputter_thread;
+ }
+
+ uint64 Id() { return thread_id(); }
+
+ private:
+ friend class base::RefCounted<Outputter>;
+
+ explicit Outputter(const std::string& name) : base::Thread(name.c_str()) {}
+
+ virtual ~Outputter() {
+ g_outputter_thread = NULL;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(Outputter);
+};
+
+class Trace : public base::RefCounted<Trace> {
+ public:
+ explicit Trace(const std::string& name) : name_(name) {}
+
+ virtual void Start() = 0;
+ virtual void End() = 0;
+
+ // True if the the results of this query are available.
+ virtual bool IsAvailable() = 0;
+
+ virtual bool IsProcessable() { return true; }
+ virtual void Process() = 0;
+
+ virtual const std::string& name() {
+ return name_;
+ }
+
+ protected:
+ virtual ~Trace() {}
+
+ private:
+ friend class base::RefCounted<Trace>;
+
+ std::string name_;
+
+ DISALLOW_COPY_AND_ASSIGN(Trace);
+};
+
+class GLARBTimerTrace : public Trace {
+ public:
+ GLARBTimerTrace(scoped_refptr<Outputter> outputter, const std::string& name,
+ int64 offset);
+
+ // Implementation of Tracer
+ virtual void Start() OVERRIDE;
+ virtual void End() OVERRIDE;
+ virtual bool IsAvailable() OVERRIDE;
+ virtual void Process() OVERRIDE;
+
+ private:
+ virtual ~GLARBTimerTrace();
+
+ void Output();
+
+ scoped_refptr<Outputter> outputter_;
+
+ int64 offset_;
+ int64 start_time_;
+ int64 end_time_;
+ bool end_requested_;
+
+ GLuint queries_[2];
+
+ DISALLOW_COPY_AND_ASSIGN(GLARBTimerTrace);
+};
+
+class NoopTrace : public Trace {
+ public:
+ explicit NoopTrace(const std::string& name) : Trace(name) {}
+
+ // Implementation of Tracer
+ virtual void Start() OVERRIDE {}
+ virtual void End() OVERRIDE {}
+ virtual bool IsAvailable() OVERRIDE { return true; }
+ virtual bool IsProcessable() OVERRIDE { return false; }
+ virtual void Process() OVERRIDE {}
+
+ private:
+ virtual ~NoopTrace() {}
+
+ DISALLOW_COPY_AND_ASSIGN(NoopTrace);
+};
+
+class GPUTracerImpl
+ : public GPUTracer,
+ public base::SupportsWeakPtr<GPUTracerImpl> {
+ public:
+ GPUTracerImpl()
+ : gpu_category_enabled_(
+ TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("gpu")),
+ process_posted_(false) {
+ }
+ virtual ~GPUTracerImpl() {}
+
+ // Implementation of gpu::gles2::GPUTracer
+ virtual bool Begin(const std::string& name) OVERRIDE;
+ virtual bool End() OVERRIDE;
+ virtual const std::string& CurrentName() const OVERRIDE;
+
+ // Process any completed traces.
+ virtual void Process();
+
+ protected:
+ // Create a new trace.
+ virtual scoped_refptr<Trace> CreateTrace(const std::string& name);
+
+ const unsigned char* gpu_category_enabled_;
+
+ private:
+ void IssueProcessTask();
+
+ scoped_refptr<Trace> current_trace_;
+ std::deque<scoped_refptr<Trace> > traces_;
+
+ bool process_posted_;
+
+ DISALLOW_COPY_AND_ASSIGN(GPUTracerImpl);
+};
+
+class GPUTracerARBTimerQuery : public GPUTracerImpl {
+ public:
+ GPUTracerARBTimerQuery();
+ virtual ~GPUTracerARBTimerQuery();
+
+ // Implementation of GPUTracerImpl
+ virtual void Process() OVERRIDE;
+
+ private:
+ // Implementation of GPUTracerImpl.
+ virtual scoped_refptr<Trace> CreateTrace(const std::string& name) OVERRIDE;
+
+ void CalculateTimerOffset();
+
+ scoped_refptr<Outputter> outputter_;
+
+ int64 timer_offset_;
+ int64 last_offset_check_;
+
+ DISALLOW_COPY_AND_ASSIGN(GPUTracerARBTimerQuery);
+};
+
+GLARBTimerTrace::GLARBTimerTrace(scoped_refptr<Outputter> outputter,
+ const std::string& name, int64 offset)
+ : Trace(name),
+ outputter_(outputter),
+ offset_(offset),
+ start_time_(0),
+ end_time_(0),
+ end_requested_(false) {
+ glGenQueries(2, queries_);
+}
+
+GLARBTimerTrace::~GLARBTimerTrace() {
+}
+
+void GLARBTimerTrace::Start() {
+ glQueryCounter(queries_[0], GL_TIMESTAMP);
+}
+
+void GLARBTimerTrace::End() {
+ glQueryCounter(queries_[1], GL_TIMESTAMP);
+ end_requested_ = true;
+}
+
+bool GLARBTimerTrace::IsAvailable() {
+ if (!end_requested_)
+ return false;
+
+ GLint done = 0;
+ glGetQueryObjectiv(queries_[1], GL_QUERY_RESULT_AVAILABLE, &done);
+ return !!done;
+}
+
+void GLARBTimerTrace::Process() {
+ DCHECK(IsAvailable());
+
+ GLint64 timestamp;
+
+ // TODO(dsinclair): It's possible for the timer to wrap during the start/end.
+ // We need to detect if the end is less then the start and correct for the
+ // wrapping.
+ glGetQueryObjecti64v(queries_[0], GL_QUERY_RESULT, &timestamp);
+ start_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
+
+ glGetQueryObjecti64v(queries_[1], GL_QUERY_RESULT, &timestamp);
+ end_time_ = (timestamp / base::Time::kNanosecondsPerMicrosecond) + offset_;
+
+ glDeleteQueries(2, queries_);
+
+ TRACE_EVENT_COPY_BEGIN_WITH_ID_TID_AND_TIMESTAMP0("gpu", name().c_str(),
+ this, outputter_->Id(), start_time_);
+ TRACE_EVENT_COPY_END_WITH_ID_TID_AND_TIMESTAMP0("gpu", name().c_str(),
+ this, outputter_->Id(), end_time_);
+}
+
+bool GPUTracerImpl::Begin(const std::string& name) {
+ // Make sure we are not nesting trace commands.
+ if (current_trace_.get())
+ return false;
+
+ current_trace_ = CreateTrace(name);
+ current_trace_->Start();
+ return true;
+}
+
+bool GPUTracerImpl::End() {
+ if (!current_trace_.get())
+ return false;
+
+ current_trace_->End();
+ if (current_trace_->IsProcessable())
+ traces_.push_back(current_trace_);
+ current_trace_ = NULL;
+
+ IssueProcessTask();
+ return true;
+}
+
+void GPUTracerImpl::Process() {
+ process_posted_ = false;
+
+ while (!traces_.empty() && traces_.front()->IsAvailable()) {
+ traces_.front()->Process();
+ traces_.pop_front();
+ }
+
+ IssueProcessTask();
+}
+
+const std::string& GPUTracerImpl::CurrentName() const {
+ if (!current_trace_.get())
+ return EmptyString();
+ return current_trace_->name();
+}
+
+scoped_refptr<Trace> GPUTracerImpl::CreateTrace(const std::string& name) {
+ return new NoopTrace(name);
+}
+
+void GPUTracerImpl::IssueProcessTask() {
+ if (traces_.empty() || process_posted_)
+ return;
+
+ process_posted_ = true;
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&GPUTracerImpl::Process, base::AsWeakPtr(this)),
+ base::TimeDelta::FromMilliseconds(kProcessInterval));
+}
+
+GPUTracerARBTimerQuery::GPUTracerARBTimerQuery()
+ : GPUTracerImpl(),
+ timer_offset_(0),
+ last_offset_check_(0) {
+ CalculateTimerOffset();
+ outputter_ = Outputter::Create("GL_ARB_timer_query");
+}
+
+GPUTracerARBTimerQuery::~GPUTracerARBTimerQuery() {
+}
+
+scoped_refptr<Trace> GPUTracerARBTimerQuery::CreateTrace(
+ const std::string& name) {
+ if (*gpu_category_enabled_)
+ return new GLARBTimerTrace(outputter_, name, timer_offset_);
+ return GPUTracerImpl::CreateTrace(name);
+}
+
+void GPUTracerARBTimerQuery::Process() {
+ GPUTracerImpl::Process();
+
+ if (*gpu_category_enabled_ &&
+ (last_offset_check_ + base::Time::kMicrosecondsPerSecond) <
+ base::TimeTicks::NowFromSystemTraceTime().ToInternalValue())
+ CalculateTimerOffset();
+}
+
+void GPUTracerARBTimerQuery::CalculateTimerOffset() {
+ TRACE_EVENT0("gpu", "CalculateTimerOffset");
+ // TODO(dsinclair): Change to glGetInteger64v.
+ GLuint64 gl_now = 0;
+ GLuint query;
+ glGenQueries(1, &query);
+
+ glQueryCounter(query, GL_TIMESTAMP);
+ glGetQueryObjectui64v(query, GL_QUERY_RESULT, &gl_now);
+ base::TimeTicks system_now = base::TimeTicks::NowFromSystemTraceTime();
+
+ gl_now /= base::Time::kNanosecondsPerMicrosecond;
+ timer_offset_ = system_now.ToInternalValue() - gl_now;
+ glDeleteQueries(1, &query);
+
+ last_offset_check_ = system_now.ToInternalValue();
+}
+
+} // namespace
+
+scoped_ptr<GPUTracer> GPUTracer::Create() {
+ if (gfx::g_driver_gl.ext.b_GL_ARB_timer_query)
+ return scoped_ptr<GPUTracer>(new GPUTracerARBTimerQuery());
+ return scoped_ptr<GPUTracer>(new GPUTracerImpl());
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/gpu_tracer.h b/chromium/gpu/command_buffer/service/gpu_tracer.h
new file mode 100644
index 00000000000..f64455c0671
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/gpu_tracer.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the GPUTrace class.
+#ifndef GPU_COMMAND_BUFFER_SERVICE_GPU_TRACER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GPU_TRACER_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace gpu {
+namespace gles2 {
+
+// Traces GPU Commands.
+class GPUTracer {
+ public:
+ static scoped_ptr<GPUTracer> Create();
+
+ GPUTracer() {}
+ virtual ~GPUTracer() {}
+
+ // Begin a trace.
+ virtual bool Begin(const std::string& name) = 0;
+
+ // End the last started trace.
+ virtual bool End() = 0;
+
+ // Retrieve the name of the current open trace.
+ // Returns empty string if no current open trace.
+ virtual const std::string& CurrentName() const = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GPUTracer);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GPU_TRACER_H_
diff --git a/chromium/gpu/command_buffer/service/id_manager.cc b/chromium/gpu/command_buffer/service/id_manager.cc
new file mode 100644
index 00000000000..be60d7b2cb7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/id_manager.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/id_manager.h"
+#include "base/logging.h"
+
+namespace gpu {
+namespace gles2 {
+
+IdManager::IdManager() {}
+
+IdManager::~IdManager() {}
+
+bool IdManager::AddMapping(GLuint client_id, GLuint service_id) {
+ std::pair<MapType::iterator, bool> result = id_map_.insert(
+ std::make_pair(client_id, service_id));
+ return result.second;
+}
+
+bool IdManager::RemoveMapping(GLuint client_id, GLuint service_id) {
+ MapType::iterator iter = id_map_.find(client_id);
+ if (iter != id_map_.end() && iter->second == service_id) {
+ id_map_.erase(iter);
+ return true;
+ }
+ return false;
+}
+
+bool IdManager::GetServiceId(GLuint client_id, GLuint* service_id) {
+ DCHECK(service_id);
+ MapType::iterator iter = id_map_.find(client_id);
+ if (iter != id_map_.end()) {
+ *service_id = iter->second;
+ return true;
+ }
+ return false;
+}
+
+bool IdManager::GetClientId(GLuint service_id, GLuint* client_id) {
+ DCHECK(client_id);
+ MapType::iterator end(id_map_.end());
+ for (MapType::iterator iter(id_map_.begin());
+ iter != end;
+ ++iter) {
+ if (iter->second == service_id) {
+ *client_id = iter->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/id_manager.h b/chromium/gpu/command_buffer/service/id_manager.h
new file mode 100644
index 00000000000..0bc06741904
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/id_manager.h
@@ -0,0 +1,51 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_ID_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_ID_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+// This class maps one set of ids to another.
+//
+// NOTE: To support shared resources an instance of this class will
+// need to be shared by multiple GLES2Decoders.
+class GPU_EXPORT IdManager {
+ public:
+ IdManager();
+ ~IdManager();
+
+ // Maps a client_id to a service_id. Return false if the client_id or
+ // service_id are already mapped to something else.
+ bool AddMapping(GLuint client_id, GLuint service_id);
+
+ // Unmaps a pair of ids. Returns false if the pair were not previously mapped.
+ bool RemoveMapping(GLuint client_id, GLuint service_id);
+
+ // Gets the corresponding service_id for the given client_id.
+ // Returns false if there is no corresponding service_id.
+ bool GetServiceId(GLuint client_id, GLuint* service_id);
+
+ // Gets the corresponding client_id for the given service_id.
+ // Returns false if there is no corresponding client_id.
+ bool GetClientId(GLuint service_id, GLuint* client_id);
+
+ private:
+ typedef base::hash_map<GLuint, GLuint> MapType;
+ MapType id_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(IdManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_ID_MANAGER_H_
+
diff --git a/chromium/gpu/command_buffer/service/id_manager_unittest.cc b/chromium/gpu/command_buffer/service/id_manager_unittest.cc
new file mode 100644
index 00000000000..015a44252ee
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/id_manager_unittest.cc
@@ -0,0 +1,76 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/id_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+class IdManagerTest : public testing::Test {
+ public:
+ IdManagerTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ }
+
+ virtual void TearDown() {
+ }
+
+ IdManager manager_;
+};
+
+TEST_F(IdManagerTest, Basic) {
+ const GLuint kClientId1 = 1;
+ const GLuint kClientId2 = 2;
+ const GLuint kServiceId1 = 201;
+ const GLuint kServiceId2 = 202;
+ // Check we can add an id
+ EXPECT_TRUE(manager_.AddMapping(kClientId1, kServiceId1));
+ // Check we can get that mapping
+ GLuint service_id = 0;
+ EXPECT_TRUE(manager_.GetServiceId(kClientId1, &service_id));
+ EXPECT_EQ(kServiceId1, service_id);
+ GLuint client_id = 0;
+ EXPECT_TRUE(manager_.GetClientId(kServiceId1, &client_id));
+ EXPECT_EQ(kClientId1, client_id);
+ // Check that it fails if we get a non-existent id.
+ service_id = 0;
+ client_id = 0;
+ EXPECT_FALSE(manager_.GetServiceId(kClientId2, &service_id));
+ EXPECT_FALSE(manager_.GetClientId(kServiceId2, &client_id));
+ EXPECT_EQ(0u, service_id);
+ EXPECT_EQ(0u, client_id);
+ // Check we can add a second id.
+ EXPECT_TRUE(manager_.AddMapping(kClientId2, kServiceId2));
+ // Check we can get that mapping
+ service_id = 0;
+ EXPECT_TRUE(manager_.GetServiceId(kClientId1, &service_id));
+ EXPECT_EQ(kServiceId1, service_id);
+ EXPECT_TRUE(manager_.GetServiceId(kClientId2, &service_id));
+ EXPECT_EQ(kServiceId2, service_id);
+ client_id = 0;
+ EXPECT_TRUE(manager_.GetClientId(kServiceId1, &client_id));
+ EXPECT_EQ(kClientId1, client_id);
+ EXPECT_TRUE(manager_.GetClientId(kServiceId2, &client_id));
+ EXPECT_EQ(kClientId2, client_id);
+ // Check if we remove an id we can no longer get it.
+ EXPECT_TRUE(manager_.RemoveMapping(kClientId1, kServiceId1));
+ EXPECT_FALSE(manager_.GetServiceId(kClientId1, &service_id));
+ EXPECT_FALSE(manager_.GetClientId(kServiceId1, &client_id));
+ // Check we get an error if we try to remove a non-existent id.
+ EXPECT_FALSE(manager_.RemoveMapping(kClientId1, kServiceId1));
+ EXPECT_FALSE(manager_.RemoveMapping(kClientId2, kServiceId1));
+ EXPECT_FALSE(manager_.RemoveMapping(kClientId1, kServiceId2));
+ // Check we get an error if we try to map an existing id.
+ EXPECT_FALSE(manager_.AddMapping(kClientId2, kServiceId2));
+ EXPECT_FALSE(manager_.AddMapping(kClientId2, kServiceId1));
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/image_manager.cc b/chromium/gpu/command_buffer/service/image_manager.cc
new file mode 100644
index 00000000000..6be4e667721
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/image_manager.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/image_manager.h"
+
+#include "ui/gl/gl_image.h"
+
+namespace gpu {
+namespace gles2 {
+
+ImageManager::ImageManager() {
+}
+
+ImageManager::~ImageManager() {
+}
+
+void ImageManager::AddImage(gfx::GLImage* image, int32 service_id) {
+ gl_images_[service_id] = image;
+}
+
+void ImageManager::RemoveImage(int32 service_id) {
+ gl_images_.erase(service_id);
+}
+
+gfx::GLImage* ImageManager::LookupImage(int32 service_id) {
+ GLImageMap::const_iterator iter = gl_images_.find(service_id);
+ if (iter != gl_images_.end())
+ return iter->second.get();
+
+ return NULL;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/image_manager.h b/chromium/gpu/command_buffer/service/image_manager.h
new file mode 100644
index 00000000000..1b421469443
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/image_manager.h
@@ -0,0 +1,43 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_IMAGE_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_IMAGE_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class GLImage;
+}
+
+namespace gpu {
+namespace gles2 {
+
+// Interface used by the cmd decoder to lookup images.
+class GPU_EXPORT ImageManager : public base::RefCounted<ImageManager> {
+ public:
+ ImageManager();
+
+ void AddImage(gfx::GLImage* gl_image, int32 service_id);
+ void RemoveImage(int32 service_id);
+ gfx::GLImage* LookupImage(int32 service_id);
+
+ private:
+ friend class base::RefCounted<ImageManager>;
+
+ ~ImageManager();
+
+ typedef base::hash_map<uint32, scoped_refptr<gfx::GLImage> > GLImageMap;
+ GLImageMap gl_images_;
+
+ DISALLOW_COPY_AND_ASSIGN(ImageManager);
+};
+
+} // namespage gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_IMAGE_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/in_process_command_buffer.cc b/chromium/gpu/command_buffer/service/in_process_command_buffer.cc
new file mode 100644
index 00000000000..ccbfb32a504
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -0,0 +1,756 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/in_process_command_buffer.h"
+
+#include <queue>
+#include <utility>
+
+#include <GLES2/gl2.h>
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES 1
+#endif
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/memory/weak_ptr.h"
+#include "base/message_loop/message_loop_proxy.h"
+#include "base/sequence_checker.h"
+#include "base/threading/thread.h"
+#include "gpu/command_buffer/common/id_allocator.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/gl_context_virtual.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/image_manager.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "ui/gfx/size.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_image.h"
+#include "ui/gl/gl_share_group.h"
+
+namespace gpu {
+
+namespace {
+
+static base::LazyInstance<std::set<InProcessCommandBuffer*> >
+ g_all_shared_contexts = LAZY_INSTANCE_INITIALIZER;
+
+static bool g_use_virtualized_gl_context = false;
+static bool g_uses_explicit_scheduling = false;
+
+template <typename T>
+static void RunTaskWithResult(base::Callback<T(void)> task,
+ T* result,
+ base::WaitableEvent* completion) {
+ *result = task.Run();
+ completion->Signal();
+}
+
+class GpuInProcessThread
+ : public base::Thread,
+ public base::RefCountedThreadSafe<GpuInProcessThread> {
+ public:
+ GpuInProcessThread();
+
+ private:
+ friend class base::RefCountedThreadSafe<GpuInProcessThread>;
+ virtual ~GpuInProcessThread();
+
+ DISALLOW_COPY_AND_ASSIGN(GpuInProcessThread);
+};
+
+GpuInProcessThread::GpuInProcessThread() : base::Thread("GpuThread") {
+ Start();
+}
+
+GpuInProcessThread::~GpuInProcessThread() {
+ Stop();
+}
+
+// Used with explicit scheduling when there is no dedicated GPU thread.
+class GpuCommandQueue {
+ public:
+ GpuCommandQueue();
+ ~GpuCommandQueue();
+
+ void QueueTask(const base::Closure& task);
+ void RunTasks();
+ void SetScheduleCallback(const base::Closure& callback);
+
+ private:
+ base::Lock tasks_lock_;
+ std::queue<base::Closure> tasks_;
+ base::Closure schedule_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(GpuCommandQueue);
+};
+
+GpuCommandQueue::GpuCommandQueue() {}
+
+GpuCommandQueue::~GpuCommandQueue() {
+ base::AutoLock lock(tasks_lock_);
+ DCHECK(tasks_.empty());
+}
+
+void GpuCommandQueue::QueueTask(const base::Closure& task) {
+ {
+ base::AutoLock lock(tasks_lock_);
+ tasks_.push(task);
+ }
+
+ DCHECK(!schedule_callback_.is_null());
+ schedule_callback_.Run();
+}
+
+void GpuCommandQueue::RunTasks() {
+ size_t num_tasks;
+ {
+ base::AutoLock lock(tasks_lock_);
+ num_tasks = tasks_.size();
+ }
+
+ while (num_tasks) {
+ base::Closure task;
+ {
+ base::AutoLock lock(tasks_lock_);
+ task = tasks_.front();
+ tasks_.pop();
+ num_tasks = tasks_.size();
+ }
+
+ task.Run();
+ }
+}
+
+void GpuCommandQueue::SetScheduleCallback(const base::Closure& callback) {
+ DCHECK(schedule_callback_.is_null());
+ schedule_callback_ = callback;
+}
+
+static base::LazyInstance<GpuCommandQueue> g_gpu_queue =
+ LAZY_INSTANCE_INITIALIZER;
+
+class SchedulerClientBase : public InProcessCommandBuffer::SchedulerClient {
+ public:
+ explicit SchedulerClientBase(bool need_thread);
+ virtual ~SchedulerClientBase();
+
+ static bool HasClients();
+
+ protected:
+ scoped_refptr<GpuInProcessThread> thread_;
+
+ private:
+ static base::LazyInstance<std::set<SchedulerClientBase*> > all_clients_;
+ static base::LazyInstance<base::Lock> all_clients_lock_;
+};
+
+base::LazyInstance<std::set<SchedulerClientBase*> >
+ SchedulerClientBase::all_clients_ = LAZY_INSTANCE_INITIALIZER;
+base::LazyInstance<base::Lock> SchedulerClientBase::all_clients_lock_ =
+ LAZY_INSTANCE_INITIALIZER;
+
+SchedulerClientBase::SchedulerClientBase(bool need_thread) {
+ base::AutoLock(all_clients_lock_.Get());
+ if (need_thread) {
+ if (!all_clients_.Get().empty()) {
+ SchedulerClientBase* other = *all_clients_.Get().begin();
+ thread_ = other->thread_;
+ DCHECK(thread_.get());
+ } else {
+ thread_ = new GpuInProcessThread;
+ }
+ }
+ all_clients_.Get().insert(this);
+}
+
+SchedulerClientBase::~SchedulerClientBase() {
+ base::AutoLock(all_clients_lock_.Get());
+ all_clients_.Get().erase(this);
+}
+
+bool SchedulerClientBase::HasClients() {
+ base::AutoLock(all_clients_lock_.Get());
+ return !all_clients_.Get().empty();
+}
+
+// A client that talks to the GPU thread
+class ThreadClient : public SchedulerClientBase {
+ public:
+ ThreadClient();
+ virtual void QueueTask(const base::Closure& task) OVERRIDE;
+};
+
+ThreadClient::ThreadClient() : SchedulerClientBase(true) {
+ DCHECK(thread_.get());
+}
+
+void ThreadClient::QueueTask(const base::Closure& task) {
+ thread_->message_loop()->PostTask(FROM_HERE, task);
+}
+
+// A client that talks to the GpuCommandQueue
+class QueueClient : public SchedulerClientBase {
+ public:
+ QueueClient();
+ virtual void QueueTask(const base::Closure& task) OVERRIDE;
+};
+
+QueueClient::QueueClient() : SchedulerClientBase(false) {
+ DCHECK(!thread_.get());
+}
+
+void QueueClient::QueueTask(const base::Closure& task) {
+ g_gpu_queue.Get().QueueTask(task);
+}
+
+static scoped_ptr<InProcessCommandBuffer::SchedulerClient>
+CreateSchedulerClient() {
+ scoped_ptr<InProcessCommandBuffer::SchedulerClient> client;
+ if (g_uses_explicit_scheduling)
+ client.reset(new QueueClient);
+ else
+ client.reset(new ThreadClient);
+
+ return client.Pass();
+}
+
+class ScopedEvent {
+ public:
+ ScopedEvent(base::WaitableEvent* event) : event_(event) {}
+ ~ScopedEvent() { event_->Signal(); }
+
+ private:
+ base::WaitableEvent* event_;
+};
+
+} // anonyous namespace
+
+InProcessCommandBuffer::InProcessCommandBuffer()
+ : context_lost_(false),
+ share_group_id_(0),
+ last_put_offset_(-1),
+ flush_event_(false, false),
+ queue_(CreateSchedulerClient()) {}
+
+InProcessCommandBuffer::~InProcessCommandBuffer() {
+ Destroy();
+}
+
+bool InProcessCommandBuffer::IsContextLost() {
+ CheckSequencedThread();
+ if (context_lost_ || !command_buffer_) {
+ return true;
+ }
+ CommandBuffer::State state = GetState();
+ return error::IsError(state.error);
+}
+
+void InProcessCommandBuffer::OnResizeView(gfx::Size size, float scale_factor) {
+ CheckSequencedThread();
+ DCHECK(!surface_->IsOffscreen());
+ surface_->Resize(size);
+}
+
+bool InProcessCommandBuffer::MakeCurrent() {
+ CheckSequencedThread();
+ command_buffer_lock_.AssertAcquired();
+
+ if (!context_lost_ && decoder_->MakeCurrent())
+ return true;
+ DLOG(ERROR) << "Context lost because MakeCurrent failed.";
+ command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
+ command_buffer_->SetParseError(gpu::error::kLostContext);
+ return false;
+}
+
+void InProcessCommandBuffer::PumpCommands() {
+ CheckSequencedThread();
+ command_buffer_lock_.AssertAcquired();
+
+ if (!MakeCurrent())
+ return;
+
+ gpu_scheduler_->PutChanged();
+}
+
+bool InProcessCommandBuffer::GetBufferChanged(int32 transfer_buffer_id) {
+ CheckSequencedThread();
+ command_buffer_lock_.AssertAcquired();
+ command_buffer_->SetGetBuffer(transfer_buffer_id);
+ return true;
+}
+
+bool InProcessCommandBuffer::Initialize(
+ scoped_refptr<gfx::GLSurface> surface,
+ bool is_offscreen,
+ bool share_resources,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs,
+ gfx::GpuPreference gpu_preference,
+ const base::Closure& context_lost_callback,
+ unsigned int share_group_id) {
+
+ share_resources_ = share_resources;
+ context_lost_callback_ = WrapCallback(context_lost_callback);
+ share_group_id_ = share_group_id;
+
+ if (surface) {
+ // GPU thread must be the same as client thread due to GLSurface not being
+ // thread safe.
+ sequence_checker_.reset(new base::SequenceChecker);
+ surface_ = surface;
+ }
+
+ base::Callback<bool(void)> init_task =
+ base::Bind(&InProcessCommandBuffer::InitializeOnGpuThread,
+ base::Unretained(this),
+ is_offscreen,
+ window,
+ size,
+ allowed_extensions,
+ attribs,
+ gpu_preference);
+
+ base::WaitableEvent completion(true, false);
+ bool result = false;
+ QueueTask(
+ base::Bind(&RunTaskWithResult<bool>, init_task, &result, &completion));
+ completion.Wait();
+ return result;
+}
+
+bool InProcessCommandBuffer::InitializeOnGpuThread(
+ bool is_offscreen,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs,
+ gfx::GpuPreference gpu_preference) {
+ CheckSequencedThread();
+ // Use one share group for all contexts.
+ CR_DEFINE_STATIC_LOCAL(scoped_refptr<gfx::GLShareGroup>, share_group,
+ (new gfx::GLShareGroup));
+
+ DCHECK(size.width() >= 0 && size.height() >= 0);
+
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ manager->Initialize();
+
+ scoped_ptr<CommandBufferService> command_buffer(
+ new CommandBufferService(transfer_buffer_manager_.get()));
+ command_buffer->SetPutOffsetChangeCallback(base::Bind(
+ &InProcessCommandBuffer::PumpCommands, base::Unretained(this)));
+ command_buffer->SetParseErrorCallback(base::Bind(
+ &InProcessCommandBuffer::OnContextLost, base::Unretained(this)));
+
+ if (!command_buffer->Initialize()) {
+ LOG(ERROR) << "Could not initialize command buffer.";
+ DestroyOnGpuThread();
+ return false;
+ }
+
+ InProcessCommandBuffer* context_group = NULL;
+
+ if (share_resources_ && !g_all_shared_contexts.Get().empty()) {
+ DCHECK(share_group_id_);
+ for (std::set<InProcessCommandBuffer*>::iterator it =
+ g_all_shared_contexts.Get().begin();
+ it != g_all_shared_contexts.Get().end();
+ ++it) {
+ if ((*it)->share_group_id_ == share_group_id_) {
+ context_group = *it;
+ DCHECK(context_group->share_resources_);
+ context_lost_ = context_group->IsContextLost();
+ break;
+ }
+ }
+ if (!context_group)
+ share_group = new gfx::GLShareGroup;
+ }
+
+ bool bind_generates_resource = false;
+ decoder_.reset(gles2::GLES2Decoder::Create(
+ context_group ? context_group->decoder_->GetContextGroup()
+ : new gles2::ContextGroup(
+ NULL, NULL, NULL, NULL, bind_generates_resource)));
+
+ gpu_scheduler_.reset(
+ new GpuScheduler(command_buffer.get(), decoder_.get(), decoder_.get()));
+ command_buffer->SetGetBufferChangeCallback(base::Bind(
+ &GpuScheduler::SetGetBuffer, base::Unretained(gpu_scheduler_.get())));
+ command_buffer_ = command_buffer.Pass();
+
+ decoder_->set_engine(gpu_scheduler_.get());
+
+ if (!surface_) {
+ if (is_offscreen)
+ surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
+ else
+ surface_ = gfx::GLSurface::CreateViewGLSurface(window);
+ }
+
+ if (!surface_.get()) {
+ LOG(ERROR) << "Could not create GLSurface.";
+ DestroyOnGpuThread();
+ return false;
+ }
+
+ if (g_use_virtualized_gl_context) {
+ context_ = share_group->GetSharedContext();
+ if (!context_.get()) {
+ context_ = gfx::GLContext::CreateGLContext(
+ share_group.get(), surface_.get(), gpu_preference);
+ share_group->SetSharedContext(context_.get());
+ }
+
+ context_ = new GLContextVirtual(
+ share_group.get(), context_.get(), decoder_->AsWeakPtr());
+ if (context_->Initialize(surface_.get(), gpu_preference)) {
+ VLOG(1) << "Created virtual GL context.";
+ } else {
+ context_ = NULL;
+ }
+ } else {
+ context_ = gfx::GLContext::CreateGLContext(
+ share_group.get(), surface_.get(), gpu_preference);
+ }
+
+ if (!context_.get()) {
+ LOG(ERROR) << "Could not create GLContext.";
+ DestroyOnGpuThread();
+ return false;
+ }
+
+ if (!context_->MakeCurrent(surface_.get())) {
+ LOG(ERROR) << "Could not make context current.";
+ DestroyOnGpuThread();
+ return false;
+ }
+
+ gles2::DisallowedFeatures disallowed_features;
+ disallowed_features.swap_buffer_complete_callback = true;
+ disallowed_features.gpu_memory_manager = true;
+ if (!decoder_->Initialize(surface_,
+ context_,
+ is_offscreen,
+ size,
+ disallowed_features,
+ allowed_extensions,
+ attribs)) {
+ LOG(ERROR) << "Could not initialize decoder.";
+ DestroyOnGpuThread();
+ return false;
+ }
+
+ if (!is_offscreen) {
+ decoder_->SetResizeCallback(base::Bind(
+ &InProcessCommandBuffer::OnResizeView, base::Unretained(this)));
+ }
+
+ if (share_resources_) {
+ g_all_shared_contexts.Pointer()->insert(this);
+ }
+
+ return true;
+}
+
+void InProcessCommandBuffer::Destroy() {
+ CheckSequencedThread();
+ base::WaitableEvent completion(true, false);
+ bool result = false;
+ base::Callback<bool(void)> destroy_task = base::Bind(
+ &InProcessCommandBuffer::DestroyOnGpuThread, base::Unretained(this));
+ QueueTask(
+ base::Bind(&RunTaskWithResult<bool>, destroy_task, &result, &completion));
+ completion.Wait();
+}
+
+bool InProcessCommandBuffer::DestroyOnGpuThread() {
+ CheckSequencedThread();
+ command_buffer_.reset();
+ // Clean up GL resources if possible.
+ bool have_context = context_ && context_->MakeCurrent(surface_);
+ if (decoder_) {
+ decoder_->Destroy(have_context);
+ decoder_.reset();
+ }
+ context_ = NULL;
+ surface_ = NULL;
+
+ g_all_shared_contexts.Pointer()->erase(this);
+ return true;
+}
+
+void InProcessCommandBuffer::CheckSequencedThread() {
+ DCHECK(!sequence_checker_ ||
+ sequence_checker_->CalledOnValidSequencedThread());
+}
+
+unsigned int InProcessCommandBuffer::CreateImageForGpuMemoryBuffer(
+ gfx::GpuMemoryBufferHandle buffer,
+ gfx::Size size) {
+ CheckSequencedThread();
+ unsigned int image_id;
+ {
+ // TODO: ID allocation should go through CommandBuffer
+ base::AutoLock lock(command_buffer_lock_);
+ gles2::ContextGroup* group = decoder_->GetContextGroup();
+ image_id =
+ group->GetIdAllocator(gles2::id_namespaces::kImages)->AllocateID();
+ }
+ base::Closure image_task =
+ base::Bind(&InProcessCommandBuffer::CreateImageOnGpuThread,
+ base::Unretained(this), buffer, size, image_id);
+ QueueTask(image_task);
+ return image_id;
+}
+
+void InProcessCommandBuffer::CreateImageOnGpuThread(
+ gfx::GpuMemoryBufferHandle buffer,
+ gfx::Size size,
+ unsigned int image_id) {
+ CheckSequencedThread();
+ scoped_refptr<gfx::GLImage> gl_image =
+ gfx::GLImage::CreateGLImageForGpuMemoryBuffer(buffer, size);
+ decoder_->GetContextGroup()->image_manager()->AddImage(gl_image, image_id);
+}
+
+void InProcessCommandBuffer::RemoveImage(unsigned int image_id) {
+ CheckSequencedThread();
+ {
+ // TODO: ID allocation should go through CommandBuffer
+ base::AutoLock lock(command_buffer_lock_);
+ gles2::ContextGroup* group = decoder_->GetContextGroup();
+ group->GetIdAllocator(gles2::id_namespaces::kImages)->FreeID(image_id);
+ }
+ base::Closure image_manager_task =
+ base::Bind(&InProcessCommandBuffer::RemoveImageOnGpuThread,
+ base::Unretained(this),
+ image_id);
+ QueueTask(image_manager_task);
+}
+
+void InProcessCommandBuffer::RemoveImageOnGpuThread(unsigned int image_id) {
+ CheckSequencedThread();
+ decoder_->GetContextGroup()->image_manager()->RemoveImage(image_id);
+}
+
+void InProcessCommandBuffer::OnContextLost() {
+ CheckSequencedThread();
+ if (!context_lost_callback_.is_null()) {
+ context_lost_callback_.Run();
+ context_lost_callback_.Reset();
+ }
+
+ context_lost_ = true;
+ if (share_resources_) {
+ for (std::set<InProcessCommandBuffer*>::iterator it =
+ g_all_shared_contexts.Get().begin();
+ it != g_all_shared_contexts.Get().end();
+ ++it) {
+ (*it)->context_lost_ = true;
+ }
+ }
+}
+
+CommandBuffer::State InProcessCommandBuffer::GetStateFast() {
+ CheckSequencedThread();
+ base::AutoLock lock(state_after_last_flush_lock_);
+ if (state_after_last_flush_.generation - last_state_.generation < 0x80000000U)
+ last_state_ = state_after_last_flush_;
+ return last_state_;
+}
+
+CommandBuffer::State InProcessCommandBuffer::GetState() {
+ CheckSequencedThread();
+ return GetStateFast();
+}
+
+CommandBuffer::State InProcessCommandBuffer::GetLastState() {
+ CheckSequencedThread();
+ return last_state_;
+}
+
+int32 InProcessCommandBuffer::GetLastToken() {
+ CheckSequencedThread();
+ GetStateFast();
+ return last_state_.token;
+}
+
+void InProcessCommandBuffer::FlushOnGpuThread(int32 put_offset) {
+ CheckSequencedThread();
+ ScopedEvent handle_flush(&flush_event_);
+ base::AutoLock lock(command_buffer_lock_);
+ command_buffer_->Flush(put_offset);
+ {
+ // Update state before signaling the flush event.
+ base::AutoLock lock(state_after_last_flush_lock_);
+ state_after_last_flush_ = command_buffer_->GetState();
+ }
+ DCHECK((!error::IsError(state_after_last_flush_.error) && !context_lost_) ||
+ (error::IsError(state_after_last_flush_.error) && context_lost_));
+}
+
+void InProcessCommandBuffer::Flush(int32 put_offset) {
+ CheckSequencedThread();
+ if (last_state_.error != gpu::error::kNoError)
+ return;
+
+ if (last_put_offset_ == put_offset)
+ return;
+
+ last_put_offset_ = put_offset;
+ base::Closure task = base::Bind(&InProcessCommandBuffer::FlushOnGpuThread,
+ base::Unretained(this),
+ put_offset);
+ QueueTask(task);
+}
+
+CommandBuffer::State InProcessCommandBuffer::FlushSync(int32 put_offset,
+ int32 last_known_get) {
+ CheckSequencedThread();
+ if (put_offset == last_known_get || last_state_.error != gpu::error::kNoError)
+ return last_state_;
+
+ Flush(put_offset);
+ GetStateFast();
+ while (last_known_get == last_state_.get_offset &&
+ last_state_.error == gpu::error::kNoError) {
+ flush_event_.Wait();
+ GetStateFast();
+ }
+
+ return last_state_;
+}
+
+void InProcessCommandBuffer::SetGetBuffer(int32 shm_id) {
+ CheckSequencedThread();
+ if (last_state_.error != gpu::error::kNoError)
+ return;
+
+ {
+ base::AutoLock lock(command_buffer_lock_);
+ command_buffer_->SetGetBuffer(shm_id);
+ last_put_offset_ = 0;
+ }
+ {
+ base::AutoLock lock(state_after_last_flush_lock_);
+ state_after_last_flush_ = command_buffer_->GetState();
+ }
+}
+
+gpu::Buffer InProcessCommandBuffer::CreateTransferBuffer(size_t size,
+ int32* id) {
+ CheckSequencedThread();
+ base::AutoLock lock(command_buffer_lock_);
+ return command_buffer_->CreateTransferBuffer(size, id);
+}
+
+void InProcessCommandBuffer::DestroyTransferBuffer(int32 id) {
+ CheckSequencedThread();
+ base::Closure task = base::Bind(&CommandBuffer::DestroyTransferBuffer,
+ base::Unretained(command_buffer_.get()),
+ id);
+
+ QueueTask(task);
+}
+
+gpu::Buffer InProcessCommandBuffer::GetTransferBuffer(int32 id) {
+ NOTREACHED();
+ return gpu::Buffer();
+}
+
+uint32 InProcessCommandBuffer::InsertSyncPoint() {
+ NOTREACHED();
+ return 0;
+}
+void InProcessCommandBuffer::SignalSyncPoint(unsigned sync_point,
+ const base::Closure& callback) {
+ CheckSequencedThread();
+ QueueTask(WrapCallback(callback));
+}
+
+gpu::error::Error InProcessCommandBuffer::GetLastError() {
+ CheckSequencedThread();
+ return last_state_.error;
+}
+
+bool InProcessCommandBuffer::Initialize() {
+ NOTREACHED();
+ return false;
+}
+
+void InProcessCommandBuffer::SetGetOffset(int32 get_offset) { NOTREACHED(); }
+
+void InProcessCommandBuffer::SetToken(int32 token) { NOTREACHED(); }
+
+void InProcessCommandBuffer::SetParseError(gpu::error::Error error) {
+ NOTREACHED();
+}
+
+void InProcessCommandBuffer::SetContextLostReason(
+ gpu::error::ContextLostReason reason) {
+ NOTREACHED();
+}
+
+namespace {
+
+void PostCallback(const scoped_refptr<base::MessageLoopProxy>& loop,
+ const base::Closure& callback) {
+ if (!loop->BelongsToCurrentThread()) {
+ loop->PostTask(FROM_HERE, callback);
+ } else {
+ callback.Run();
+ }
+}
+
+void RunOnTargetThread(scoped_ptr<base::Closure> callback) {
+ DCHECK(callback.get());
+ callback->Run();
+}
+
+} // anonymous namespace
+
+base::Closure InProcessCommandBuffer::WrapCallback(
+ const base::Closure& callback) {
+ // Make sure the callback gets deleted on the target thread by passing
+ // ownership.
+ scoped_ptr<base::Closure> scoped_callback(new base::Closure(callback));
+ base::Closure callback_on_client_thread =
+ base::Bind(&RunOnTargetThread, base::Passed(&scoped_callback));
+ base::Closure wrapped_callback =
+ base::Bind(&PostCallback, base::MessageLoopProxy::current(),
+ callback_on_client_thread);
+ return wrapped_callback;
+}
+
+// static
+void InProcessCommandBuffer::EnableVirtualizedContext() {
+ g_use_virtualized_gl_context = true;
+}
+
+// static
+void InProcessCommandBuffer::SetScheduleCallback(
+ const base::Closure& callback) {
+ DCHECK(!g_uses_explicit_scheduling);
+ DCHECK(!SchedulerClientBase::HasClients());
+ g_uses_explicit_scheduling = true;
+ g_gpu_queue.Get().SetScheduleCallback(callback);
+}
+
+// static
+void InProcessCommandBuffer::ProcessGpuWorkOnCurrentThread() {
+ g_gpu_queue.Get().RunTasks();
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/in_process_command_buffer.h b/chromium/gpu/command_buffer/service/in_process_command_buffer.h
new file mode 100644
index 00000000000..9bdbd49616d
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/in_process_command_buffer.h
@@ -0,0 +1,171 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/gpu_export.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gpu_preference.h"
+
+namespace base {
+class SequenceChecker;
+}
+
+namespace gfx {
+class GLContext;
+class GLImage;
+class GLSurface;
+class Size;
+}
+
+namespace gpu {
+
+namespace gles2 {
+class GLES2Decoder;
+}
+
+class GpuScheduler;
+class TransferBufferManagerInterface;
+
+// This class provides a thread-safe interface to the global GPU service (for
+// example GPU thread) when being run in single process mode.
+// However, the behavior for accessing one context (i.e. one instance of this
+// class) from different client threads is undefined.
+class GPU_EXPORT InProcessCommandBuffer : public CommandBuffer {
+ public:
+ InProcessCommandBuffer();
+ virtual ~InProcessCommandBuffer();
+
+ // Used to override the GPU thread with explicit scheduling.
+ // (By default an internal GPU thread will be spawned to handle all GL work
+ // and the two functions are unused.)
+ // The callback will be called from different client threads. After the
+ // callback is issued, the client is expected to eventually call
+ // ProcessGpuWorkOnCurrentThread(). The latter cannot be called from different
+ // threads.
+ // The callback needs to be set before any context is created.
+ static void SetScheduleCallback(const base::Closure& callback);
+ static void ProcessGpuWorkOnCurrentThread();
+
+ static void EnableVirtualizedContext();
+
+ // If |surface| is not NULL, use it directly; in this case, the command
+ // buffer gpu thread must be the same as the client thread. Otherwise create
+ // a new GLSurface.
+ bool Initialize(scoped_refptr<gfx::GLSurface> surface,
+ bool is_offscreen,
+ bool share_resources,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs,
+ gfx::GpuPreference gpu_preference,
+ const base::Closure& context_lost_callback,
+ unsigned int share_group_id);
+ void Destroy();
+ void SignalSyncPoint(unsigned sync_point,
+ const base::Closure& callback);
+ unsigned int CreateImageForGpuMemoryBuffer(
+ gfx::GpuMemoryBufferHandle buffer,
+ gfx::Size size);
+ void RemoveImage(unsigned int image_id);
+
+ // CommandBuffer implementation:
+ virtual bool Initialize() OVERRIDE;
+ virtual State GetState() OVERRIDE;
+ virtual State GetLastState() OVERRIDE;
+ virtual int32 GetLastToken() OVERRIDE;
+ virtual void Flush(int32 put_offset) OVERRIDE;
+ virtual State FlushSync(int32 put_offset, int32 last_known_get) OVERRIDE;
+ virtual void SetGetBuffer(int32 shm_id) OVERRIDE;
+ virtual void SetGetOffset(int32 get_offset) OVERRIDE;
+ virtual gpu::Buffer CreateTransferBuffer(size_t size, int32* id) OVERRIDE;
+ virtual void DestroyTransferBuffer(int32 id) OVERRIDE;
+ virtual gpu::Buffer GetTransferBuffer(int32 id) OVERRIDE;
+ virtual void SetToken(int32 token) OVERRIDE;
+ virtual void SetParseError(gpu::error::Error error) OVERRIDE;
+ virtual void SetContextLostReason(
+ gpu::error::ContextLostReason reason) OVERRIDE;
+ virtual uint32 InsertSyncPoint() OVERRIDE;
+ virtual gpu::error::Error GetLastError() OVERRIDE;
+
+ // The serializer interface to the GPU service (i.e. thread).
+ class SchedulerClient {
+ public:
+ virtual ~SchedulerClient() {}
+ virtual void QueueTask(const base::Closure& task) = 0;
+ };
+
+ private:
+ bool InitializeOnGpuThread(bool is_offscreen,
+ gfx::AcceleratedWidget window,
+ const gfx::Size& size,
+ const char* allowed_extensions,
+ const std::vector<int32>& attribs,
+ gfx::GpuPreference gpu_preference);
+ bool DestroyOnGpuThread();
+ void FlushOnGpuThread(int32 put_offset);
+ void CreateImageOnGpuThread(gfx::GpuMemoryBufferHandle buffer,
+ gfx::Size size,
+ unsigned int image_id);
+ void RemoveImageOnGpuThread(unsigned int image_id);
+ bool MakeCurrent();
+ bool IsContextLost();
+ base::Closure WrapCallback(const base::Closure& callback);
+ State GetStateFast();
+ void QueueTask(const base::Closure& task) { queue_->QueueTask(task); }
+ void CheckSequencedThread();
+
+ // Callbacks:
+ void OnContextLost();
+ void OnResizeView(gfx::Size size, float scale_factor);
+ bool GetBufferChanged(int32 transfer_buffer_id);
+ void PumpCommands();
+
+ // Members accessed on the gpu thread (possibly with the exception of
+ // creation):
+ bool context_lost_;
+ bool share_resources_;
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<GpuScheduler> gpu_scheduler_;
+ scoped_ptr<gles2::GLES2Decoder> decoder_;
+ scoped_refptr<gfx::GLContext> context_;
+ scoped_refptr<gfx::GLSurface> surface_;
+ base::Closure context_lost_callback_;
+ unsigned int share_group_id_;
+
+ // Members accessed on the client thread:
+ State last_state_;
+ int32 last_put_offset_;
+
+ // Accessed on both threads:
+ scoped_ptr<CommandBuffer> command_buffer_;
+ base::Lock command_buffer_lock_;
+ base::WaitableEvent flush_event_;
+ scoped_ptr<SchedulerClient> queue_;
+ State state_after_last_flush_;
+ base::Lock state_after_last_flush_lock_;
+
+ // Only used with explicit scheduling and the gpu thread is the same as
+ // the client thread.
+ scoped_ptr<base::SequenceChecker> sequence_checker_;
+
+ DISALLOW_COPY_AND_ASSIGN(InProcessCommandBuffer);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_IN_PROCESS_COMMAND_BUFFER_H_
diff --git a/chromium/gpu/command_buffer/service/logger.cc b/chromium/gpu/command_buffer/service/logger.cc
new file mode 100644
index 00000000000..1fd29336d7b
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/logger.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/logger.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/common/debug_marker_manager.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+
+namespace gpu {
+namespace gles2 {
+
+Logger::Logger(const DebugMarkerManager* debug_marker_manager)
+ : debug_marker_manager_(debug_marker_manager),
+ log_message_count_(0),
+ log_synthesized_gl_errors_(true) {
+ Logger* this_temp = this;
+ this_in_hex_ = std::string("GroupMarkerNotSet(crbug.com/242999)!:") +
+ base::HexEncode(&this_temp, sizeof(this_temp));
+}
+
+Logger::~Logger() {}
+
+void Logger::LogMessage(
+ const char* filename, int line, const std::string& msg) {
+ if (log_message_count_ < kMaxLogMessages ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGLErrorLimit)) {
+ std::string prefixed_msg(std::string("[") + GetLogPrefix() + "]" + msg);
+ ++log_message_count_;
+ // LOG this unless logging is turned off as any chromium code that
+ // generates these errors probably has a bug.
+ if (log_synthesized_gl_errors_) {
+ ::logging::LogMessage(
+ filename, line, ::logging::LOG_ERROR).stream() << prefixed_msg;
+ }
+ if (!msg_callback_.is_null()) {
+ msg_callback_.Run(0, prefixed_msg);
+ }
+ } else {
+ if (log_message_count_ == kMaxLogMessages) {
+ ++log_message_count_;
+ LOG(ERROR)
+ << "Too many GL errors, not reporting any more for this context."
+ << " use --disable-gl-error-limit to see all errors.";
+ }
+ }
+}
+
+const std::string& Logger::GetLogPrefix() const {
+ const std::string& prefix(debug_marker_manager_->GetMarker());
+ return prefix.empty() ? this_in_hex_ : prefix;
+}
+
+void Logger::SetMsgCallback(const MsgCallback& callback) {
+ msg_callback_ = callback;
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/logger.h b/chromium/gpu/command_buffer/service/logger.h
new file mode 100644
index 00000000000..46914435461
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/logger.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains the Logger class.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_LOGGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_LOGGER_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+typedef base::Callback<void(int32 id, const std::string& msg)> MsgCallback;
+
+class DebugMarkerManager;
+
+class GPU_EXPORT Logger {
+ public:
+ static const int kMaxLogMessages = 256;
+
+ explicit Logger(const DebugMarkerManager* debug_marker_manager);
+ ~Logger();
+
+ void LogMessage(const char* filename, int line, const std::string& msg);
+ const std::string& GetLogPrefix() const;
+
+ // Defaults to true. Set to false for the gpu_unittests as they
+ // are explicitly checking errors are generated and so don't need the numerous
+ // messages. Otherwise, chromium code that generates these errors likely has a
+ // bug.
+ void set_log_synthesized_gl_errors(bool enabled) {
+ log_synthesized_gl_errors_ = enabled;
+ }
+
+ void SetMsgCallback(const MsgCallback& callback);
+
+ private:
+ // Uses the current marker to add information to logs.
+ const DebugMarkerManager* debug_marker_manager_;
+ std::string this_in_hex_;
+
+ int log_message_count_;
+ bool log_synthesized_gl_errors_;
+
+ MsgCallback msg_callback_;
+ DISALLOW_COPY_AND_ASSIGN(Logger);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_LOGGER_H_
+
diff --git a/chromium/gpu/command_buffer/service/mailbox_manager.cc b/chromium/gpu/command_buffer/service/mailbox_manager.cc
new file mode 100644
index 00000000000..a569bb5ead7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/mailbox_manager.cc
@@ -0,0 +1,116 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/mailbox_manager.h"
+
+#include <algorithm>
+
+#include "base/rand_util.h"
+#include "crypto/hmac.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+MailboxName::MailboxName() {
+ std::fill(key, key + sizeof(key), 0);
+ std::fill(signature, signature + sizeof(signature), 0);
+}
+
+MailboxManager::MailboxManager()
+ : hmac_(crypto::HMAC::SHA256),
+ mailbox_to_textures_(std::ptr_fun(&MailboxManager::TargetNameLess)) {
+ base::RandBytes(private_key_, sizeof(private_key_));
+ bool success = hmac_.Init(
+ base::StringPiece(private_key_, sizeof(private_key_)));
+ DCHECK(success);
+ DCHECK(!IsMailboxNameValid(MailboxName()));
+}
+
+MailboxManager::~MailboxManager() {
+ DCHECK(mailbox_to_textures_.empty());
+ DCHECK(textures_to_mailboxes_.empty());
+}
+
+void MailboxManager::GenerateMailboxName(MailboxName* name) {
+ base::RandBytes(name->key, sizeof(name->key));
+ SignMailboxName(name);
+}
+
+Texture* MailboxManager::ConsumeTexture(unsigned target,
+ const MailboxName& name) {
+ if (!IsMailboxNameValid(name))
+ return NULL;
+
+ MailboxToTextureMap::iterator it =
+ mailbox_to_textures_.find(TargetName(target, name));
+ if (it == mailbox_to_textures_.end())
+ return NULL;
+
+ return it->second->first;
+}
+
+bool MailboxManager::ProduceTexture(unsigned target,
+ const MailboxName& name,
+ Texture* texture) {
+ if (!IsMailboxNameValid(name))
+ return false;
+
+ texture->SetMailboxManager(this);
+ TargetName target_name(target, name);
+ MailboxToTextureMap::iterator it = mailbox_to_textures_.find(target_name);
+ if (it != mailbox_to_textures_.end()) {
+ TextureToMailboxMap::iterator texture_it = it->second;
+ mailbox_to_textures_.erase(it);
+ textures_to_mailboxes_.erase(texture_it);
+ }
+ TextureToMailboxMap::iterator texture_it =
+ textures_to_mailboxes_.insert(std::make_pair(texture, target_name));
+ mailbox_to_textures_.insert(std::make_pair(target_name, texture_it));
+ DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
+
+ return true;
+}
+
+void MailboxManager::TextureDeleted(Texture* texture) {
+ std::pair<TextureToMailboxMap::iterator,
+ TextureToMailboxMap::iterator> range =
+ textures_to_mailboxes_.equal_range(texture);
+ for (TextureToMailboxMap::iterator it = range.first;
+ it != range.second; ++it) {
+ size_t count = mailbox_to_textures_.erase(it->second);
+ DCHECK(count == 1);
+ }
+ textures_to_mailboxes_.erase(range.first, range.second);
+ DCHECK_EQ(mailbox_to_textures_.size(), textures_to_mailboxes_.size());
+}
+
+void MailboxManager::SignMailboxName(MailboxName* name) {
+ bool success = hmac_.Sign(
+ base::StringPiece(reinterpret_cast<char*>(name->key), sizeof(name->key)),
+ reinterpret_cast<unsigned char*>(name->signature),
+ sizeof(name->signature));
+ DCHECK(success);
+}
+
+bool MailboxManager::IsMailboxNameValid(const MailboxName& name) {
+ return hmac_.Verify(
+ base::StringPiece(reinterpret_cast<const char*>(name.key),
+ sizeof(name.key)),
+ base::StringPiece(reinterpret_cast<const char*>(name.signature),
+ sizeof(name.signature)));
+}
+
+MailboxManager::TargetName::TargetName(unsigned target, const MailboxName& name)
+ : target(target),
+ name(name) {
+}
+
+bool MailboxManager::TargetNameLess(const MailboxManager::TargetName& lhs,
+ const MailboxManager::TargetName& rhs) {
+ return memcmp(&lhs, &rhs, sizeof(lhs)) < 0;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/mailbox_manager.h b/chromium/gpu/command_buffer/service/mailbox_manager.h
new file mode 100644
index 00000000000..c97302813a0
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/mailbox_manager.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_MAILBOX_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_MAILBOX_MANAGER_H_
+
+#include <functional>
+#include <map>
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/ref_counted.h"
+#include "crypto/hmac.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/gpu_export.h"
+
+// From gl2/gl2ext.h.
+#ifndef GL_MAILBOX_SIZE_CHROMIUM
+#define GL_MAILBOX_SIZE_CHROMIUM 64
+#endif
+
+typedef signed char GLbyte;
+
+namespace gpu {
+namespace gles2 {
+
+class Texture;
+class TextureManager;
+
+// Identifies a mailbox where a texture definition can be stored for
+// transferring textures between contexts that are not in the same context
+// group. It is a random key signed with a hash of a private key.
+struct GPU_EXPORT MailboxName {
+ MailboxName();
+ GLbyte key[GL_MAILBOX_SIZE_CHROMIUM / 2];
+ GLbyte signature[GL_MAILBOX_SIZE_CHROMIUM / 2];
+};
+
+// Manages resources scoped beyond the context or context group level.
+class GPU_EXPORT MailboxManager : public base::RefCounted<MailboxManager> {
+ public:
+ MailboxManager();
+
+ // Generate a unique mailbox name signed with the manager's private key.
+ void GenerateMailboxName(MailboxName* name);
+
+ // Look up the texture definition from the named mailbox.
+ Texture* ConsumeTexture(unsigned target, const MailboxName& name);
+
+ // Put the texture into the named mailbox.
+ bool ProduceTexture(unsigned target,
+ const MailboxName& name,
+ Texture* texture);
+
+ // Destroy any mailbox that reference the given texture.
+ void TextureDeleted(Texture* texture);
+
+ std::string private_key() {
+ return std::string(private_key_, sizeof(private_key_));
+ }
+
+ private:
+ friend class base::RefCounted<MailboxManager>;
+
+ ~MailboxManager();
+
+ void SignMailboxName(MailboxName* name);
+ bool IsMailboxNameValid(const MailboxName& name);
+
+ struct TargetName {
+ TargetName(unsigned target, const MailboxName& name);
+ unsigned target;
+ MailboxName name;
+ };
+
+ static bool TargetNameLess(const TargetName& lhs, const TargetName& rhs);
+
+ // This is a bidirectional map between mailbox and textures. We can have
+ // multiple mailboxes per texture, but one texture per mailbox. We keep an
+ // iterator in the MailboxToTextureMap to be able to manage changes to
+ // the TextureToMailboxMap efficiently.
+ typedef std::multimap<Texture*, TargetName> TextureToMailboxMap;
+ typedef std::map<
+ TargetName,
+ TextureToMailboxMap::iterator,
+ std::pointer_to_binary_function<
+ const TargetName&, const TargetName&, bool> > MailboxToTextureMap;
+
+ char private_key_[GL_MAILBOX_SIZE_CHROMIUM / 2];
+ crypto::HMAC hmac_;
+ MailboxToTextureMap mailbox_to_textures_;
+ TextureToMailboxMap textures_to_mailboxes_;
+
+ DISALLOW_COPY_AND_ASSIGN(MailboxManager);
+};
+} // namespage gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_MAILBOX_MANAGER_H_
+
+
diff --git a/chromium/gpu/command_buffer/service/mailbox_manager_unittest.cc b/chromium/gpu/command_buffer/service/mailbox_manager_unittest.cc
new file mode 100644
index 00000000000..8864843571d
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -0,0 +1,146 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/mailbox_manager.h"
+
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+class MailboxManagerTest : public testing::Test {
+ public:
+ MailboxManagerTest() : manager_(new MailboxManager()) {}
+ virtual ~MailboxManagerTest() {}
+
+ protected:
+ Texture* CreateTexture() {
+ return new Texture(0);
+ }
+
+ void DestroyTexture(Texture* texture) {
+ delete texture;
+ }
+
+ scoped_refptr<MailboxManager> manager_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MailboxManagerTest);
+};
+
+// Tests basic produce/consume behavior.
+TEST_F(MailboxManagerTest, Basic) {
+ Texture* texture = CreateTexture();
+
+ MailboxName name;
+ manager_->GenerateMailboxName(&name);
+ EXPECT_TRUE(manager_->ProduceTexture(0, name, texture));
+ EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
+
+ // We can consume multiple times.
+ EXPECT_EQ(texture, manager_->ConsumeTexture(0, name));
+
+ // Wrong target should fail the consume.
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(1, name));
+
+ // Destroy should cleanup the mailbox.
+ DestroyTexture(texture);
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
+}
+
+// Should fail to produce or consume with an invalid mailbox.
+TEST_F(MailboxManagerTest, InvalidName) {
+ Texture* texture = CreateTexture();
+ MailboxName name;
+ memset(&name, 0, sizeof(name));
+ EXPECT_FALSE(manager_->ProduceTexture(0, name, texture));
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
+ DestroyTexture(texture);
+}
+
+// Tests behavior with multiple produce on the same texture.
+TEST_F(MailboxManagerTest, ProduceMultipleMailbox) {
+ Texture* texture = CreateTexture();
+
+ MailboxName name1;
+ manager_->GenerateMailboxName(&name1);
+
+ EXPECT_TRUE(manager_->ProduceTexture(0, name1, texture));
+ EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
+
+ // Can produce a second time with the same mailbox.
+ EXPECT_TRUE(manager_->ProduceTexture(0, name1, texture));
+ EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
+
+ // Can produce again, with a different mailbox.
+ MailboxName name2;
+ manager_->GenerateMailboxName(&name2);
+ EXPECT_TRUE(manager_->ProduceTexture(0, name2, texture));
+
+ // Still available under all mailboxes.
+ EXPECT_EQ(texture, manager_->ConsumeTexture(0, name1));
+ EXPECT_EQ(texture, manager_->ConsumeTexture(0, name2));
+
+ // Destroy should cleanup all mailboxes.
+ DestroyTexture(texture);
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name1));
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
+}
+
+// Tests behavior with multiple produce on the same mailbox with different
+// textures.
+TEST_F(MailboxManagerTest, ProduceMultipleTexture) {
+ Texture* texture1 = CreateTexture();
+ Texture* texture2 = CreateTexture();
+
+ MailboxName name;
+ manager_->GenerateMailboxName(&name);
+
+ EXPECT_TRUE(manager_->ProduceTexture(0, name, texture1));
+ EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name));
+
+ // Can produce a second time with the same mailbox, but different texture.
+ EXPECT_TRUE(manager_->ProduceTexture(0, name, texture2));
+ EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name));
+
+ // Destroying the texture that's under no mailbox shouldn't have an effect.
+ DestroyTexture(texture1);
+ EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name));
+
+ // Destroying the texture that's bound should clean up.
+ DestroyTexture(texture2);
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name));
+}
+
+TEST_F(MailboxManagerTest, ProduceMultipleTextureMailbox) {
+ Texture* texture1 = CreateTexture();
+ Texture* texture2 = CreateTexture();
+ MailboxName name1;
+ manager_->GenerateMailboxName(&name1);
+ MailboxName name2;
+ manager_->GenerateMailboxName(&name2);
+
+ // Put texture1 on name1 and name2.
+ EXPECT_TRUE(manager_->ProduceTexture(0, name1, texture1));
+ EXPECT_TRUE(manager_->ProduceTexture(0, name2, texture1));
+ EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name1));
+ EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name2));
+
+ // Put texture2 on name2.
+ EXPECT_TRUE(manager_->ProduceTexture(0, name2, texture2));
+ EXPECT_EQ(texture1, manager_->ConsumeTexture(0, name1));
+ EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name2));
+
+ // Destroy texture1, shouldn't affect name2.
+ DestroyTexture(texture1);
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name1));
+ EXPECT_EQ(texture2, manager_->ConsumeTexture(0, name2));
+
+ DestroyTexture(texture2);
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(0, name2));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/memory_program_cache.cc b/chromium/gpu/command_buffer/service/memory_program_cache.cc
new file mode 100644
index 00000000000..e09d132f6a0
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/memory_program_cache.cc
@@ -0,0 +1,336 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/memory_program_cache.h"
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/metrics/histogram.h"
+#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/common/constants.h"
+#include "gpu/command_buffer/service/disk_cache_proto.pb.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "ui/gl/gl_bindings.h"
+
+namespace {
+
+size_t GetCacheSizeBytes() {
+ size_t size;
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kGpuProgramCacheSizeKb) &&
+ base::StringToSizeT(command_line->GetSwitchValueNative(
+ switches::kGpuProgramCacheSizeKb),
+ &size)) {
+ return size * 1024;
+ }
+ return gpu::kDefaultMaxProgramCacheMemoryBytes;
+}
+
+} // anonymous namespace
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+enum ShaderMapType {
+ ATTRIB_MAP = 0,
+ UNIFORM_MAP
+};
+
+void StoreShaderInfo(ShaderMapType type, ShaderProto *proto,
+ const ShaderTranslator::VariableMap& map) {
+ ShaderTranslator::VariableMap::const_iterator iter;
+ for (iter = map.begin(); iter != map.end(); iter++) {
+ ShaderInfoProto* info;
+ if (type == UNIFORM_MAP) {
+ info = proto->add_uniforms();
+ } else {
+ info = proto->add_attribs();
+ }
+
+ info->set_key(iter->first);
+ info->set_type(iter->second.type);
+ info->set_size(iter->second.size);
+ info->set_name(iter->second.name);
+ }
+}
+
+void RetrieveShaderInfo(const ShaderInfoProto& proto,
+ ShaderTranslator::VariableMap* map) {
+ ShaderTranslator::VariableInfo info(proto.type(), proto.size(),
+ proto.name());
+ (*map)[proto.key()] = info;
+}
+
+void FillShaderProto(ShaderProto* proto, const char* sha,
+ const Shader* shader) {
+ proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength);
+ StoreShaderInfo(ATTRIB_MAP, proto, shader->attrib_map());
+ StoreShaderInfo(UNIFORM_MAP, proto, shader->uniform_map());
+}
+
+void RunShaderCallback(const ShaderCacheCallback& callback,
+ GpuProgramProto* proto,
+ std::string sha_string) {
+ std::string shader;
+ proto->SerializeToString(&shader);
+
+ std::string key;
+ base::Base64Encode(sha_string, &key);
+ callback.Run(key, shader);
+}
+
+} // namespace
+
+MemoryProgramCache::MemoryProgramCache()
+ : max_size_bytes_(GetCacheSizeBytes()),
+ curr_size_bytes_(0),
+ store_(ProgramMRUCache::NO_AUTO_EVICT) {
+}
+
+MemoryProgramCache::MemoryProgramCache(const size_t max_cache_size_bytes)
+ : max_size_bytes_(max_cache_size_bytes),
+ curr_size_bytes_(0),
+ store_(ProgramMRUCache::NO_AUTO_EVICT) {
+}
+
+MemoryProgramCache::~MemoryProgramCache() {}
+
+void MemoryProgramCache::ClearBackend() {
+ store_.Clear();
+ DCHECK_EQ(0U, curr_size_bytes_);
+}
+
+ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram(
+ GLuint program,
+ Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& shader_callback) {
+ char a_sha[kHashLength];
+ char b_sha[kHashLength];
+ DCHECK(shader_a && shader_a->signature_source() &&
+ shader_b && shader_b->signature_source());
+ ComputeShaderHash(
+ *shader_a->signature_source(), translator_a, a_sha);
+ ComputeShaderHash(
+ *shader_b->signature_source(), translator_b, b_sha);
+
+ char sha[kHashLength];
+ ComputeProgramHash(a_sha,
+ b_sha,
+ bind_attrib_location_map,
+ sha);
+ const std::string sha_string(sha, kHashLength);
+
+ ProgramMRUCache::iterator found = store_.Get(sha_string);
+ if (found == store_.end()) {
+ return PROGRAM_LOAD_FAILURE;
+ }
+ const scoped_refptr<ProgramCacheValue> value = found->second;
+ glProgramBinary(program,
+ value->format(),
+ static_cast<const GLvoid*>(value->data()),
+ value->length());
+ GLint success = 0;
+ glGetProgramiv(program, GL_LINK_STATUS, &success);
+ if (success == GL_FALSE) {
+ return PROGRAM_LOAD_FAILURE;
+ }
+ shader_a->set_attrib_map(value->attrib_map_0());
+ shader_a->set_uniform_map(value->uniform_map_0());
+ shader_b->set_attrib_map(value->attrib_map_1());
+ shader_b->set_uniform_map(value->uniform_map_1());
+
+ if (!shader_callback.is_null() &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuShaderDiskCache)) {
+ scoped_ptr<GpuProgramProto> proto(
+ GpuProgramProto::default_instance().New());
+ proto->set_sha(sha, kHashLength);
+ proto->set_format(value->format());
+ proto->set_program(value->data(), value->length());
+
+ FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
+ FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
+ RunShaderCallback(shader_callback, proto.get(), sha_string);
+ }
+
+ return PROGRAM_LOAD_SUCCESS;
+}
+
+void MemoryProgramCache::SaveLinkedProgram(
+ GLuint program,
+ const Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& shader_callback) {
+ GLenum format;
+ GLsizei length = 0;
+ glGetProgramiv(program, GL_PROGRAM_BINARY_LENGTH_OES, &length);
+ if (length == 0 || static_cast<unsigned int>(length) > max_size_bytes_) {
+ return;
+ }
+ scoped_ptr<char[]> binary(new char[length]);
+ glGetProgramBinary(program,
+ length,
+ NULL,
+ &format,
+ binary.get());
+ UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.ProgramBinarySizeBytes", length);
+
+ char a_sha[kHashLength];
+ char b_sha[kHashLength];
+ DCHECK(shader_a && shader_a->signature_source() &&
+ shader_b && shader_b->signature_source());
+ ComputeShaderHash(
+ *shader_a->signature_source(), translator_a, a_sha);
+ ComputeShaderHash(
+ *shader_b->signature_source(), translator_b, b_sha);
+
+ char sha[kHashLength];
+ ComputeProgramHash(a_sha,
+ b_sha,
+ bind_attrib_location_map,
+ sha);
+ const std::string sha_string(sha, sizeof(sha));
+
+ UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeBeforeKb",
+ curr_size_bytes_ / 1024);
+
+ // Evict any cached program with the same key in favor of the least recently
+ // accessed.
+ ProgramMRUCache::iterator existing = store_.Peek(sha_string);
+ if(existing != store_.end())
+ store_.Erase(existing);
+
+ while (curr_size_bytes_ + length > max_size_bytes_) {
+ DCHECK(!store_.empty());
+ store_.Erase(store_.rbegin());
+ }
+
+ if (!shader_callback.is_null() &&
+ !CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuShaderDiskCache)) {
+ scoped_ptr<GpuProgramProto> proto(
+ GpuProgramProto::default_instance().New());
+ proto->set_sha(sha, kHashLength);
+ proto->set_format(format);
+ proto->set_program(binary.get(), length);
+
+ FillShaderProto(proto->mutable_vertex_shader(), a_sha, shader_a);
+ FillShaderProto(proto->mutable_fragment_shader(), b_sha, shader_b);
+ RunShaderCallback(shader_callback, proto.get(), sha_string);
+ }
+
+ store_.Put(sha_string,
+ new ProgramCacheValue(length,
+ format,
+ binary.release(),
+ sha_string,
+ a_sha,
+ shader_a->attrib_map(),
+ shader_a->uniform_map(),
+ b_sha,
+ shader_b->attrib_map(),
+ shader_b->uniform_map(),
+ this));
+
+ UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
+ curr_size_bytes_ / 1024);
+}
+
+void MemoryProgramCache::LoadProgram(const std::string& program) {
+ scoped_ptr<GpuProgramProto> proto(GpuProgramProto::default_instance().New());
+ if (proto->ParseFromString(program)) {
+ ShaderTranslator::VariableMap vertex_attribs;
+ ShaderTranslator::VariableMap vertex_uniforms;
+
+ for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) {
+ RetrieveShaderInfo(proto->vertex_shader().attribs(i), &vertex_attribs);
+ }
+
+ for (int i = 0; i < proto->vertex_shader().uniforms_size(); i++) {
+ RetrieveShaderInfo(proto->vertex_shader().uniforms(i), &vertex_uniforms);
+ }
+
+ ShaderTranslator::VariableMap fragment_attribs;
+ ShaderTranslator::VariableMap fragment_uniforms;
+
+ for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) {
+ RetrieveShaderInfo(proto->fragment_shader().attribs(i),
+ &fragment_attribs);
+ }
+
+ for (int i = 0; i < proto->fragment_shader().uniforms_size(); i++) {
+ RetrieveShaderInfo(proto->fragment_shader().uniforms(i),
+ &fragment_uniforms);
+ }
+
+ scoped_ptr<char[]> binary(new char[proto->program().length()]);
+ memcpy(binary.get(), proto->program().c_str(), proto->program().length());
+
+ store_.Put(proto->sha(),
+ new ProgramCacheValue(proto->program().length(),
+ proto->format(),
+ binary.release(),
+ proto->sha(),
+ proto->vertex_shader().sha().c_str(),
+ vertex_attribs,
+ vertex_uniforms,
+ proto->fragment_shader().sha().c_str(),
+ fragment_attribs,
+ fragment_uniforms,
+ this));
+
+ UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb",
+ curr_size_bytes_ / 1024);
+ } else {
+ LOG(ERROR) << "Failed to parse proto file.";
+ }
+}
+
+MemoryProgramCache::ProgramCacheValue::ProgramCacheValue(
+ GLsizei length,
+ GLenum format,
+ const char* data,
+ const std::string& program_hash,
+ const char* shader_0_hash,
+ const ShaderTranslator::VariableMap& attrib_map_0,
+ const ShaderTranslator::VariableMap& uniform_map_0,
+ const char* shader_1_hash,
+ const ShaderTranslator::VariableMap& attrib_map_1,
+ const ShaderTranslator::VariableMap& uniform_map_1,
+ MemoryProgramCache* program_cache)
+ : length_(length),
+ format_(format),
+ data_(data),
+ program_hash_(program_hash),
+ shader_0_hash_(shader_0_hash, kHashLength),
+ attrib_map_0_(attrib_map_0),
+ uniform_map_0_(uniform_map_0),
+ shader_1_hash_(shader_1_hash, kHashLength),
+ attrib_map_1_(attrib_map_1),
+ uniform_map_1_(uniform_map_1),
+ program_cache_(program_cache) {
+ program_cache_->curr_size_bytes_ += length_;
+ program_cache_->LinkedProgramCacheSuccess(program_hash);
+}
+
+MemoryProgramCache::ProgramCacheValue::~ProgramCacheValue() {
+ program_cache_->curr_size_bytes_ -= length_;
+ program_cache_->Evict(program_hash_);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/memory_program_cache.h b/chromium/gpu/command_buffer/service/memory_program_cache.h
new file mode 100644
index 00000000000..b2f23e6d8c9
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/memory_program_cache.h
@@ -0,0 +1,136 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_MEMORY_PROGRAM_CACHE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_MEMORY_PROGRAM_CACHE_H_
+
+#include <map>
+#include <string>
+
+#include "base/containers/hash_tables.h"
+#include "base/containers/mru_cache.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/program_cache.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+
+namespace gpu {
+namespace gles2 {
+
+// Program cache that stores binaries completely in-memory
+class GPU_EXPORT MemoryProgramCache : public ProgramCache {
+ public:
+ MemoryProgramCache();
+ explicit MemoryProgramCache(const size_t max_cache_size_bytes);
+ virtual ~MemoryProgramCache();
+
+ virtual ProgramLoadResult LoadLinkedProgram(
+ GLuint program,
+ Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& shader_callback) OVERRIDE;
+ virtual void SaveLinkedProgram(
+ GLuint program,
+ const Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& shader_callback) OVERRIDE;
+
+ virtual void LoadProgram(const std::string& program) OVERRIDE;
+
+ private:
+ virtual void ClearBackend() OVERRIDE;
+
+ class ProgramCacheValue : public base::RefCounted<ProgramCacheValue> {
+ public:
+ ProgramCacheValue(GLsizei length,
+ GLenum format,
+ const char* data,
+ const std::string& program_hash,
+ const char* shader_0_hash,
+ const ShaderTranslator::VariableMap& attrib_map_0,
+ const ShaderTranslator::VariableMap& uniform_map_0,
+ const char* shader_1_hash,
+ const ShaderTranslator::VariableMap& attrib_map_1,
+ const ShaderTranslator::VariableMap& uniform_map_1,
+ MemoryProgramCache* program_cache);
+
+ GLsizei length() const {
+ return length_;
+ }
+
+ GLenum format() const {
+ return format_;
+ }
+
+ const char* data() const {
+ return data_.get();
+ }
+
+ const std::string& shader_0_hash() const {
+ return shader_0_hash_;
+ }
+
+ const ShaderTranslator::VariableMap& attrib_map_0() const {
+ return attrib_map_0_;
+ }
+
+ const ShaderTranslator::VariableMap& uniform_map_0() const {
+ return uniform_map_0_;
+ }
+
+ const std::string& shader_1_hash() const {
+ return shader_1_hash_;
+ }
+
+ const ShaderTranslator::VariableMap& attrib_map_1() const {
+ return attrib_map_1_;
+ }
+
+ const ShaderTranslator::VariableMap& uniform_map_1() const {
+ return uniform_map_1_;
+ }
+
+ private:
+ friend class base::RefCounted<ProgramCacheValue>;
+
+ ~ProgramCacheValue();
+
+ const GLsizei length_;
+ const GLenum format_;
+ const scoped_ptr<const char[]> data_;
+ const std::string program_hash_;
+ const std::string shader_0_hash_;
+ const ShaderTranslator::VariableMap attrib_map_0_;
+ const ShaderTranslator::VariableMap uniform_map_0_;
+ const std::string shader_1_hash_;
+ const ShaderTranslator::VariableMap attrib_map_1_;
+ const ShaderTranslator::VariableMap uniform_map_1_;
+ MemoryProgramCache* const program_cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProgramCacheValue);
+ };
+
+ friend class ProgramCacheValue;
+
+ typedef base::MRUCache<std::string,
+ scoped_refptr<ProgramCacheValue> > ProgramMRUCache;
+
+ const size_t max_size_bytes_;
+ size_t curr_size_bytes_;
+ ProgramMRUCache store_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryProgramCache);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_MEMORY_PROGRAM_CACHE_H_
diff --git a/chromium/gpu/command_buffer/service/memory_program_cache_unittest.cc b/chromium/gpu/command_buffer/service/memory_program_cache_unittest.cc
new file mode 100644
index 00000000000..83fc12a386e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -0,0 +1,626 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/memory_program_cache.h"
+
+#include "base/bind.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Invoke;
+using ::testing::SetArgPointee;
+using ::testing::SetArrayArgument;
+
+namespace {
+typedef gpu::gles2::ShaderTranslator::VariableMap VariableMap;
+} // anonymous namespace
+
+namespace gpu {
+namespace gles2 {
+
+class ProgramBinaryEmulator {
+ public:
+ ProgramBinaryEmulator(GLsizei length,
+ GLenum format,
+ const char* binary)
+ : length_(length),
+ format_(format),
+ binary_(binary) { }
+
+ void GetProgramBinary(GLuint program,
+ GLsizei buffer_size,
+ GLsizei* length,
+ GLenum* format,
+ GLvoid* binary) {
+ if (length) {
+ *length = length_;
+ }
+ *format = format_;
+ memcpy(binary, binary_, length_);
+ }
+
+ void ProgramBinary(GLuint program,
+ GLenum format,
+ const GLvoid* binary,
+ GLsizei length) {
+ // format and length are verified by matcher
+ EXPECT_EQ(0, memcmp(binary_, binary, length));
+ }
+
+ GLsizei length() const { return length_; }
+ GLenum format() const { return format_; }
+ const char* binary() const { return binary_; }
+
+ private:
+ GLsizei length_;
+ GLenum format_;
+ const char* binary_;
+};
+
+class MemoryProgramCacheTest : public testing::Test {
+ public:
+ static const size_t kCacheSizeBytes = 1024;
+ static const GLuint kVertexShaderClientId = 90;
+ static const GLuint kVertexShaderServiceId = 100;
+ static const GLuint kFragmentShaderClientId = 91;
+ static const GLuint kFragmentShaderServiceId = 100;
+
+ MemoryProgramCacheTest()
+ : cache_(new MemoryProgramCache(kCacheSizeBytes)),
+ vertex_shader_(NULL),
+ fragment_shader_(NULL),
+ shader_cache_count_(0) { }
+ virtual ~MemoryProgramCacheTest() {
+ shader_manager_.Destroy(false);
+ }
+
+ void ShaderCacheCb(const std::string& key, const std::string& shader) {
+ shader_cache_count_++;
+ shader_cache_shader_ = shader;
+ }
+
+ int32 shader_cache_count() { return shader_cache_count_; }
+ const std::string& shader_cache_shader() { return shader_cache_shader_; }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock<gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ vertex_shader_ = shader_manager_.CreateShader(kVertexShaderClientId,
+ kVertexShaderServiceId,
+ GL_VERTEX_SHADER);
+ fragment_shader_ = shader_manager_.CreateShader(
+ kFragmentShaderClientId,
+ kFragmentShaderServiceId,
+ GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(vertex_shader_ != NULL);
+ ASSERT_TRUE(fragment_shader_ != NULL);
+ typedef ShaderTranslatorInterface::VariableInfo VariableInfo;
+ typedef ShaderTranslator::VariableMap VariableMap;
+ VariableMap vertex_attrib_map;
+ VariableMap vertex_uniform_map;
+ VariableMap fragment_attrib_map;
+ VariableMap fragment_uniform_map;
+
+ vertex_attrib_map["a"] = VariableInfo(1, 34, "a");
+ vertex_uniform_map["a"] = VariableInfo(0, 10, "a");
+ vertex_uniform_map["b"] = VariableInfo(2, 3114, "b");
+ fragment_attrib_map["jjjbb"] = VariableInfo(463, 1114, "jjjbb");
+ fragment_uniform_map["k"] = VariableInfo(10, 34413, "k");
+
+ vertex_shader_->set_attrib_map(vertex_attrib_map);
+ vertex_shader_->set_uniform_map(vertex_uniform_map);
+ fragment_shader_->set_attrib_map(vertex_attrib_map);
+ fragment_shader_->set_uniform_map(vertex_uniform_map);
+
+ vertex_shader_->UpdateSource("bbbalsldkdkdkd");
+ fragment_shader_->UpdateSource("bbbal sldkdkdkas 134 ad");
+
+ vertex_shader_->SetStatus(true, NULL, NULL);
+ fragment_shader_->SetStatus(true, NULL, NULL);
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ void SetExpectationsForSaveLinkedProgram(
+ const GLint program_id,
+ ProgramBinaryEmulator* emulator) const {
+ EXPECT_CALL(*gl_.get(),
+ GetProgramiv(program_id, GL_PROGRAM_BINARY_LENGTH_OES, _))
+ .WillOnce(SetArgPointee<2>(emulator->length()));
+ EXPECT_CALL(*gl_.get(),
+ GetProgramBinary(program_id, emulator->length(), _, _, _))
+ .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::GetProgramBinary));
+ }
+
+ void SetExpectationsForLoadLinkedProgram(
+ const GLint program_id,
+ ProgramBinaryEmulator* emulator) const {
+ EXPECT_CALL(*gl_.get(),
+ ProgramBinary(program_id,
+ emulator->format(),
+ _,
+ emulator->length()))
+ .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::ProgramBinary));
+ EXPECT_CALL(*gl_.get(),
+ GetProgramiv(program_id, GL_LINK_STATUS, _))
+ .WillOnce(SetArgPointee<2>(GL_TRUE));
+ }
+
+ void SetExpectationsForLoadLinkedProgramFailure(
+ const GLint program_id,
+ ProgramBinaryEmulator* emulator) const {
+ EXPECT_CALL(*gl_.get(),
+ ProgramBinary(program_id,
+ emulator->format(),
+ _,
+ emulator->length()))
+ .WillOnce(Invoke(emulator, &ProgramBinaryEmulator::ProgramBinary));
+ EXPECT_CALL(*gl_.get(),
+ GetProgramiv(program_id, GL_LINK_STATUS, _))
+ .WillOnce(SetArgPointee<2>(GL_FALSE));
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock<gfx::MockGLInterface> > gl_;
+ scoped_ptr<MemoryProgramCache> cache_;
+ ShaderManager shader_manager_;
+ Shader* vertex_shader_;
+ Shader* fragment_shader_;
+ int32 shader_cache_count_;
+ std::string shader_cache_shader_;
+};
+
+TEST_F(MemoryProgramCacheTest, CacheSave) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
+ *vertex_shader_->signature_source(),
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+ EXPECT_EQ(1, shader_cache_count());
+}
+
+TEST_F(MemoryProgramCacheTest, LoadProgram) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
+ *vertex_shader_->signature_source(),
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+ EXPECT_EQ(1, shader_cache_count());
+
+ cache_->Clear();
+
+ cache_->LoadProgram(shader_cache_shader());
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
+ *vertex_shader_->signature_source(),
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+}
+
+TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+ EXPECT_EQ(1, shader_cache_count());
+
+ VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
+ VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
+ VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
+ VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
+
+ vertex_shader_->set_attrib_map(VariableMap());
+ vertex_shader_->set_uniform_map(VariableMap());
+ fragment_shader_->set_attrib_map(VariableMap());
+ fragment_shader_->set_uniform_map(VariableMap());
+
+ SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
+
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+
+ // apparently the hash_map implementation on android doesn't have the
+ // equality operator
+#if !defined(OS_ANDROID)
+ EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
+ EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map());
+ EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map());
+ EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map());
+#endif
+}
+
+TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+ EXPECT_EQ(1, shader_cache_count());
+
+ VariableMap vertex_attrib_map = vertex_shader_->attrib_map();
+ VariableMap vertex_uniform_map = vertex_shader_->uniform_map();
+ VariableMap fragment_attrib_map = fragment_shader_->attrib_map();
+ VariableMap fragment_uniform_map = fragment_shader_->uniform_map();
+
+ vertex_shader_->set_attrib_map(VariableMap());
+ vertex_shader_->set_uniform_map(VariableMap());
+ fragment_shader_->set_attrib_map(VariableMap());
+ fragment_shader_->set_uniform_map(VariableMap());
+
+ SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
+
+ cache_->Clear();
+ cache_->LoadProgram(shader_cache_shader());
+
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+
+ // apparently the hash_map implementation on android doesn't have the
+ // equality operator
+#if !defined(OS_ANDROID)
+ EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map());
+ EXPECT_EQ(vertex_attrib_map, vertex_shader_->uniform_map());
+ EXPECT_EQ(vertex_attrib_map, fragment_shader_->attrib_map());
+ EXPECT_EQ(vertex_attrib_map, fragment_shader_->uniform_map());
+#endif
+}
+
+TEST_F(MemoryProgramCacheTest, LoadFailOnLinkFalse) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ SetExpectationsForLoadLinkedProgramFailure(kProgramId, &emulator);
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+}
+
+TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentSource) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ const std::string vertex_orig_source =
+ *vertex_shader_->signature_source();
+ vertex_shader_->UpdateSource("different!");
+ vertex_shader_->SetStatus(true, NULL, NULL);
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+
+ vertex_shader_->UpdateSource(vertex_orig_source.c_str());
+ vertex_shader_->SetStatus(true, NULL, NULL);
+ fragment_shader_->UpdateSource("different!");
+ fragment_shader_->SetStatus(true, NULL, NULL);
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+}
+
+TEST_F(MemoryProgramCacheTest, LoadFailOnDifferentMap) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ ProgramCache::LocationMap binding_map;
+ binding_map["test"] = 512;
+ cache_->SaveLinkedProgram(kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ &binding_map,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ binding_map["different!"] = 59;
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ &binding_map,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_FAILURE, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+}
+
+TEST_F(MemoryProgramCacheTest, MemoryProgramCacheEviction) {
+ typedef ShaderTranslator::VariableMap VariableMap;
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
+
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ const int kEvictingProgramId = 11;
+ const GLuint kEvictingBinaryLength = kCacheSizeBytes - kBinaryLength + 1;
+
+ // save old source and modify for new program
+ const std::string old_source =
+ *fragment_shader_->signature_source();
+ fragment_shader_->UpdateSource("al sdfkjdk");
+ fragment_shader_->SetStatus(true, NULL, NULL);
+
+ scoped_ptr<char[]> bigTestBinary =
+ scoped_ptr<char[]>(new char[kEvictingBinaryLength]);
+ for (size_t i = 0; i < kEvictingBinaryLength; ++i) {
+ bigTestBinary[i] = i % 250;
+ }
+ ProgramBinaryEmulator emulator2(kEvictingBinaryLength,
+ kFormat,
+ bigTestBinary.get());
+
+ SetExpectationsForSaveLinkedProgram(kEvictingProgramId, &emulator2);
+ cache_->SaveLinkedProgram(kEvictingProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
+ *vertex_shader_->signature_source(),
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN, cache_->GetLinkedProgramStatus(
+ old_source,
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+}
+
+TEST_F(MemoryProgramCacheTest, SaveCorrectProgram) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator1(kBinaryLength, kFormat, test_binary);
+
+ vertex_shader_->UpdateSource("different!");
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator1);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
+ *vertex_shader_->signature_source(),
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+}
+
+TEST_F(MemoryProgramCacheTest, LoadCorrectProgram) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED, cache_->GetLinkedProgramStatus(
+ *vertex_shader_->signature_source(),
+ NULL,
+ *fragment_shader_->signature_source(),
+ NULL,
+ NULL));
+
+ SetExpectationsForLoadLinkedProgram(kProgramId, &emulator);
+
+ fragment_shader_->UpdateSource("different!");
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+}
+
+TEST_F(MemoryProgramCacheTest, OverwriteOnNewSave) {
+ const GLenum kFormat = 1;
+ const int kProgramId = 10;
+ const int kBinaryLength = 20;
+ char test_binary[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary[i] = i;
+ }
+ ProgramBinaryEmulator emulator(kBinaryLength, kFormat, test_binary);
+
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+
+ char test_binary2[kBinaryLength];
+ for (int i = 0; i < kBinaryLength; ++i) {
+ test_binary2[i] = (i*2) % 250;
+ }
+ ProgramBinaryEmulator emulator2(kBinaryLength, kFormat, test_binary2);
+ SetExpectationsForSaveLinkedProgram(kProgramId, &emulator2);
+ cache_->SaveLinkedProgram(kProgramId, vertex_shader_, NULL,
+ fragment_shader_, NULL, NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this)));
+
+ SetExpectationsForLoadLinkedProgram(kProgramId, &emulator2);
+ EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram(
+ kProgramId,
+ vertex_shader_,
+ NULL,
+ fragment_shader_,
+ NULL,
+ NULL,
+ base::Bind(&MemoryProgramCacheTest::ShaderCacheCb,
+ base::Unretained(this))));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/memory_tracking.h b/chromium/gpu/command_buffer/service/memory_tracking.h
new file mode 100644
index 00000000000..151432523ff
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/memory_tracking.h
@@ -0,0 +1,112 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_MEMORY_TRACKING_H_
+#define GPU_COMMAND_BUFFER_SERVICE_MEMORY_TRACKING_H_
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+
+namespace gpu {
+namespace gles2 {
+
+// A MemoryTracker is used to propagate per-ContextGroup memory usage
+// statistics to the global GpuMemoryManager.
+class MemoryTracker : public base::RefCounted<MemoryTracker> {
+ public:
+ enum Pool {
+ kUnmanaged,
+ kManaged
+ };
+
+ virtual void TrackMemoryAllocatedChange(size_t old_size,
+ size_t new_size,
+ Pool pool) = 0;
+
+ // Ensure a certain amount of GPU memory is free. Returns true on success.
+ virtual bool EnsureGPUMemoryAvailable(size_t size_needed) = 0;
+
+ protected:
+ friend class base::RefCounted<MemoryTracker>;
+ MemoryTracker() {}
+ virtual ~MemoryTracker() {};
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MemoryTracker);
+};
+
+// A MemoryTypeTracker tracks the use of a particular type of memory (buffer,
+// texture, or renderbuffer) and forward the result to a specified
+// MemoryTracker.
+class MemoryTypeTracker {
+ public:
+ MemoryTypeTracker(MemoryTracker* memory_tracker, MemoryTracker::Pool pool)
+ : memory_tracker_(memory_tracker),
+ pool_(pool),
+ has_done_update_(false),
+ mem_represented_(0),
+ mem_represented_at_last_update_(0) {
+ UpdateMemRepresented();
+ }
+
+ ~MemoryTypeTracker() {
+ UpdateMemRepresented();
+ }
+
+ void TrackMemAlloc(size_t bytes) {
+ mem_represented_ += bytes;
+ UpdateMemRepresented();
+ }
+
+ void TrackMemFree(size_t bytes) {
+ DCHECK(bytes <= mem_represented_);
+ mem_represented_ -= bytes;
+ UpdateMemRepresented();
+ }
+
+ size_t GetMemRepresented() const {
+ return mem_represented_at_last_update_;
+ }
+
+ // Ensure a certain amount of GPU memory is free. Returns true on success.
+ bool EnsureGPUMemoryAvailable(size_t size_needed) {
+ if (memory_tracker_) {
+ return memory_tracker_->EnsureGPUMemoryAvailable(size_needed);
+ }
+ return true;
+ }
+
+ private:
+ void UpdateMemRepresented() {
+ // Skip redundant updates only if we have already done an update.
+ if (!has_done_update_ &&
+ mem_represented_ == mem_represented_at_last_update_) {
+ return;
+ }
+ if (memory_tracker_) {
+ memory_tracker_->TrackMemoryAllocatedChange(
+ mem_represented_at_last_update_,
+ mem_represented_,
+ pool_);
+ }
+ has_done_update_ = true;
+ mem_represented_at_last_update_ = mem_represented_;
+ }
+
+ MemoryTracker* memory_tracker_;
+ MemoryTracker::Pool pool_;
+ bool has_done_update_;
+ size_t mem_represented_;
+ size_t mem_represented_at_last_update_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryTypeTracker);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_MEMORY_TRACKING_H_
diff --git a/chromium/gpu/command_buffer/service/mocks.cc b/chromium/gpu/command_buffer/service/mocks.cc
new file mode 100644
index 00000000000..25598478bf8
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/mocks.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/thread.h"
+#include "base/time/time.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "gpu/command_buffer/service/mocks.h"
+
+namespace gpu {
+
+AsyncAPIMock::AsyncAPIMock() {
+ testing::DefaultValue<error::Error>::Set(
+ error::kNoError);
+}
+
+AsyncAPIMock::~AsyncAPIMock() {}
+
+void AsyncAPIMock::SetToken(unsigned int command,
+ unsigned int arg_count,
+ const void* _args) {
+ DCHECK(engine_);
+ DCHECK_EQ(1u, command);
+ DCHECK_EQ(1u, arg_count);
+ const cmd::SetToken* args =
+ static_cast<const cmd::SetToken*>(_args);
+ engine_->set_token(args->token);
+}
+
+namespace gles2 {
+
+MockShaderTranslator::MockShaderTranslator() {}
+
+MockShaderTranslator::~MockShaderTranslator() {}
+
+MockProgramCache::MockProgramCache() {}
+MockProgramCache::~MockProgramCache() {}
+
+MockMemoryTracker::MockMemoryTracker() {}
+MockMemoryTracker::~MockMemoryTracker() {}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/mocks.h b/chromium/gpu/command_buffer/service/mocks.h
new file mode 100644
index 00000000000..fda872245c9
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/mocks.h
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file contains definitions for mock objects, used for testing.
+
+// TODO(apatrick): This file "manually" defines some mock objects. Using gMock
+// would be definitely preferable, unfortunately it doesn't work on Windows yet.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_
+#define GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_
+
+#include <string>
+#include <vector>
+
+#include "base/logging.h"
+#include "gpu/command_buffer/service/cmd_parser.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/program_cache.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+// Mocks an AsyncAPIInterface, using GMock.
+class AsyncAPIMock : public AsyncAPIInterface {
+ public:
+ AsyncAPIMock();
+ virtual ~AsyncAPIMock();
+
+ // Predicate that matches args passed to DoCommand, by looking at the values.
+ class IsArgs {
+ public:
+ IsArgs(unsigned int arg_count, const void* args)
+ : arg_count_(arg_count),
+ args_(static_cast<CommandBufferEntry*>(const_cast<void*>(args))) {
+ }
+
+ bool operator() (const void* _args) const {
+ const CommandBufferEntry* args =
+ static_cast<const CommandBufferEntry*>(_args) + 1;
+ for (unsigned int i = 0; i < arg_count_; ++i) {
+ if (args[i].value_uint32 != args_[i].value_uint32) return false;
+ }
+ return true;
+ }
+
+ private:
+ unsigned int arg_count_;
+ CommandBufferEntry *args_;
+ };
+
+ MOCK_METHOD3(DoCommand, error::Error(
+ unsigned int command,
+ unsigned int arg_count,
+ const void* cmd_data));
+
+ const char* GetCommandName(unsigned int command_id) const {
+ return "";
+ };
+
+ // Sets the engine, to forward SetToken commands to it.
+ void set_engine(CommandBufferEngine *engine) { engine_ = engine; }
+
+ // Forwards the SetToken commands to the engine.
+ void SetToken(unsigned int command,
+ unsigned int arg_count,
+ const void* _args);
+
+ private:
+ CommandBufferEngine *engine_;
+};
+
+namespace gles2 {
+
+class MockShaderTranslator : public ShaderTranslatorInterface {
+ public:
+ MockShaderTranslator();
+ virtual ~MockShaderTranslator();
+
+ MOCK_METHOD5(Init, bool(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources* resources,
+ GlslImplementationType glsl_implementation_type,
+ GlslBuiltInFunctionBehavior glsl_built_in_function_behavior));
+ MOCK_METHOD1(Translate, bool(const char* shader));
+ MOCK_CONST_METHOD0(translated_shader, const char*());
+ MOCK_CONST_METHOD0(info_log, const char*());
+ MOCK_CONST_METHOD0(attrib_map, const VariableMap&());
+ MOCK_CONST_METHOD0(uniform_map, const VariableMap&());
+ MOCK_CONST_METHOD0(name_map, const NameMap&());
+ MOCK_CONST_METHOD0(
+ GetStringForOptionsThatWouldEffectCompilation, std::string());
+};
+
+class MockProgramCache : public ProgramCache {
+ public:
+ MockProgramCache();
+ virtual ~MockProgramCache();
+
+ MOCK_METHOD7(LoadLinkedProgram, ProgramLoadResult(
+ GLuint program,
+ Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& callback));
+
+ MOCK_METHOD7(SaveLinkedProgram, void(
+ GLuint program,
+ const Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& callback));
+ MOCK_METHOD1(LoadProgram, void(const std::string&));
+
+ private:
+ MOCK_METHOD0(ClearBackend, void());
+};
+
+class MockMemoryTracker : public MemoryTracker {
+ public:
+ MockMemoryTracker();
+
+ MOCK_METHOD3(TrackMemoryAllocatedChange, void(
+ size_t old_size, size_t new_size, Pool pool));
+ MOCK_METHOD1(EnsureGPUMemoryAvailable, bool(size_t size_needed));
+
+ private:
+ friend class ::testing::StrictMock<MockMemoryTracker>;
+ friend class base::RefCounted< ::testing::StrictMock<MockMemoryTracker> >;
+ virtual ~MockMemoryTracker();
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_MOCKS_H_
diff --git a/chromium/gpu/command_buffer/service/program_cache.cc b/chromium/gpu/command_buffer/service/program_cache.cc
new file mode 100644
index 00000000000..6599d4ad3d9
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/program_cache.cc
@@ -0,0 +1,136 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/program_cache.h"
+
+#include <string>
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+ProgramCache::ProgramCache() {}
+ProgramCache::~ProgramCache() {}
+
+void ProgramCache::Clear() {
+ ClearBackend();
+ link_status_.clear();
+}
+
+ProgramCache::LinkedProgramStatus ProgramCache::GetLinkedProgramStatus(
+ const std::string& untranslated_a,
+ const ShaderTranslatorInterface* translator_a,
+ const std::string& untranslated_b,
+ const ShaderTranslatorInterface* translator_b,
+ const std::map<std::string, GLint>* bind_attrib_location_map) const {
+ char a_sha[kHashLength];
+ char b_sha[kHashLength];
+ ComputeShaderHash(untranslated_a, translator_a, a_sha);
+ ComputeShaderHash(untranslated_b, translator_b, b_sha);
+
+ char sha[kHashLength];
+ ComputeProgramHash(a_sha,
+ b_sha,
+ bind_attrib_location_map,
+ sha);
+ const std::string sha_string(sha, kHashLength);
+
+ LinkStatusMap::const_iterator found = link_status_.find(sha_string);
+ if (found == link_status_.end()) {
+ return ProgramCache::LINK_UNKNOWN;
+ } else {
+ return found->second;
+ }
+}
+
+void ProgramCache::LinkedProgramCacheSuccess(
+ const std::string& shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const std::string& shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map) {
+ char a_sha[kHashLength];
+ char b_sha[kHashLength];
+ ComputeShaderHash(shader_a, translator_a, a_sha);
+ ComputeShaderHash(shader_b, translator_b, b_sha);
+ char sha[kHashLength];
+ ComputeProgramHash(a_sha,
+ b_sha,
+ bind_attrib_location_map,
+ sha);
+ const std::string sha_string(sha, kHashLength);
+
+ LinkedProgramCacheSuccess(sha_string);
+}
+
+void ProgramCache::LinkedProgramCacheSuccess(const std::string& program_hash) {
+ link_status_[program_hash] = LINK_SUCCEEDED;
+}
+
+void ProgramCache::ComputeShaderHash(
+ const std::string& str,
+ const ShaderTranslatorInterface* translator,
+ char* result) const {
+ std::string s((
+ translator ? translator->GetStringForOptionsThatWouldEffectCompilation() :
+ std::string()) + str);
+ base::SHA1HashBytes(reinterpret_cast<const unsigned char*>(s.c_str()),
+ s.length(), reinterpret_cast<unsigned char*>(result));
+}
+
+void ProgramCache::Evict(const std::string& program_hash) {
+ link_status_.erase(program_hash);
+}
+
+namespace {
+size_t CalculateMapSize(const std::map<std::string, GLint>* map) {
+ if (!map) {
+ return 0;
+ }
+ std::map<std::string, GLint>::const_iterator it;
+ size_t total = 0;
+ for (it = map->begin(); it != map->end(); ++it) {
+ total += 4 + it->first.length();
+ }
+ return total;
+}
+} // anonymous namespace
+
+void ProgramCache::ComputeProgramHash(
+ const char* hashed_shader_0,
+ const char* hashed_shader_1,
+ const std::map<std::string, GLint>* bind_attrib_location_map,
+ char* result) const {
+ const size_t shader0_size = kHashLength;
+ const size_t shader1_size = kHashLength;
+ const size_t map_size = CalculateMapSize(bind_attrib_location_map);
+ const size_t total_size = shader0_size + shader1_size + map_size;
+
+ scoped_ptr<unsigned char[]> buffer(new unsigned char[total_size]);
+ memcpy(buffer.get(), hashed_shader_0, shader0_size);
+ memcpy(&buffer[shader0_size], hashed_shader_1, shader1_size);
+ if (map_size != 0) {
+ // copy our map
+ size_t current_pos = shader0_size + shader1_size;
+ std::map<std::string, GLint>::const_iterator it;
+ for (it = bind_attrib_location_map->begin();
+ it != bind_attrib_location_map->end();
+ ++it) {
+ const size_t name_size = it->first.length();
+ memcpy(&buffer.get()[current_pos], it->first.c_str(), name_size);
+ current_pos += name_size;
+ const GLint value = it->second;
+ buffer[current_pos++] = value >> 24;
+ buffer[current_pos++] = value >> 16;
+ buffer[current_pos++] = value >> 8;
+ buffer[current_pos++] = value;
+ }
+ }
+ base::SHA1HashBytes(buffer.get(),
+ total_size, reinterpret_cast<unsigned char*>(result));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/program_cache.h b/chromium/gpu/command_buffer/service/program_cache.h
new file mode 100644
index 00000000000..3fb5687e8b1
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/program_cache.h
@@ -0,0 +1,118 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_PROGRAM_CACHE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_PROGRAM_CACHE_H_
+
+#include <map>
+#include <string>
+
+#include "base/containers/hash_tables.h"
+#include "base/sha1.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+class Shader;
+class ShaderTranslator;
+
+// Program cache base class for caching linked gpu programs
+class GPU_EXPORT ProgramCache {
+ public:
+ static const size_t kHashLength = base::kSHA1Length;
+
+ typedef std::map<std::string, GLint> LocationMap;
+
+ enum LinkedProgramStatus {
+ LINK_UNKNOWN,
+ LINK_SUCCEEDED
+ };
+
+ enum ProgramLoadResult {
+ PROGRAM_LOAD_FAILURE,
+ PROGRAM_LOAD_SUCCESS
+ };
+
+ ProgramCache();
+ virtual ~ProgramCache();
+
+ LinkedProgramStatus GetLinkedProgramStatus(
+ const std::string& untranslated_shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const std::string& untranslated_shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map) const;
+
+ // Loads the linked program from the cache. If the program is not found or
+ // there was an error, PROGRAM_LOAD_FAILURE should be returned.
+ virtual ProgramLoadResult LoadLinkedProgram(
+ GLuint program,
+ Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& shader_callback) = 0;
+
+ // Saves the program into the cache. If successful, the implementation should
+ // call LinkedProgramCacheSuccess.
+ virtual void SaveLinkedProgram(
+ GLuint program,
+ const Shader* shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const Shader* shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map,
+ const ShaderCacheCallback& shader_callback) = 0;
+
+ virtual void LoadProgram(const std::string& program) = 0;
+
+ // clears the cache
+ void Clear();
+
+ // Only for testing
+ void LinkedProgramCacheSuccess(const std::string& shader_a,
+ const ShaderTranslatorInterface* translator_a,
+ const std::string& shader_b,
+ const ShaderTranslatorInterface* translator_b,
+ const LocationMap* bind_attrib_location_map);
+
+ protected:
+ // called by implementing class after a shader was successfully cached
+ void LinkedProgramCacheSuccess(const std::string& program_hash);
+
+ // result is not null terminated
+ void ComputeShaderHash(const std::string& shader,
+ const ShaderTranslatorInterface* translator,
+ char* result) const;
+
+ // result is not null terminated. hashed shaders are expected to be
+ // kHashLength in length
+ void ComputeProgramHash(
+ const char* hashed_shader_0,
+ const char* hashed_shader_1,
+ const LocationMap* bind_attrib_location_map,
+ char* result) const;
+
+ void Evict(const std::string& program_hash);
+
+ private:
+ typedef base::hash_map<std::string,
+ LinkedProgramStatus> LinkStatusMap;
+
+ // called to clear the backend cache
+ virtual void ClearBackend() = 0;
+
+ LinkStatusMap link_status_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProgramCache);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_PROGRAM_CACHE_H_
diff --git a/chromium/gpu/command_buffer/service/program_cache_unittest.cc b/chromium/gpu/command_buffer/service/program_cache_unittest.cc
new file mode 100644
index 00000000000..4e2abc317d4
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/program_cache_unittest.cc
@@ -0,0 +1,201 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/program_cache.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Return;
+
+namespace gpu {
+namespace gles2 {
+
+class NoBackendProgramCache : public ProgramCache {
+ public:
+ virtual ProgramLoadResult LoadLinkedProgram(
+ GLuint /* program */,
+ Shader* /* shader_a */,
+ const ShaderTranslatorInterface* /* translator_a */,
+ Shader* /* shader_b */,
+ const ShaderTranslatorInterface* /* translator_b */,
+ const LocationMap* /* bind_attrib_location_map */,
+ const ShaderCacheCallback& /* callback */) OVERRIDE {
+ return PROGRAM_LOAD_SUCCESS;
+ }
+ virtual void SaveLinkedProgram(
+ GLuint /* program */,
+ const Shader* /* shader_a */,
+ const ShaderTranslatorInterface* /* translator_b */,
+ const Shader* /* shader_b */,
+ const ShaderTranslatorInterface* /* translator_b */,
+ const LocationMap* /* bind_attrib_location_map */,
+ const ShaderCacheCallback& /* callback */) OVERRIDE { }
+
+ virtual void LoadProgram(const std::string& /* program */) OVERRIDE {}
+
+ virtual void ClearBackend() OVERRIDE {}
+
+ void SaySuccessfullyCached(const std::string& shader1,
+ const ShaderTranslatorInterface* translator_1,
+ const std::string& shader2,
+ const ShaderTranslatorInterface* translator_2,
+ std::map<std::string, GLint>* attrib_map) {
+ char a_sha[kHashLength];
+ char b_sha[kHashLength];
+ ComputeShaderHash(shader1, translator_1, a_sha);
+ ComputeShaderHash(shader2, translator_2, b_sha);
+
+ char sha[kHashLength];
+ ComputeProgramHash(a_sha,
+ b_sha,
+ attrib_map,
+ sha);
+ const std::string shaString(sha, kHashLength);
+
+ LinkedProgramCacheSuccess(shaString);
+ }
+
+ void ComputeShaderHash(const std::string& shader,
+ const ShaderTranslatorInterface* translator,
+ char* result) const {
+ ProgramCache::ComputeShaderHash(shader, translator, result);
+ }
+
+ void ComputeProgramHash(const char* hashed_shader_0,
+ const char* hashed_shader_1,
+ const LocationMap* bind_attrib_location_map,
+ char* result) const {
+ ProgramCache::ComputeProgramHash(hashed_shader_0,
+ hashed_shader_1,
+ bind_attrib_location_map,
+ result);
+ }
+
+ void Evict(const std::string& program_hash) {
+ ProgramCache::Evict(program_hash);
+ }
+};
+
+class ProgramCacheTest : public testing::Test {
+ public:
+ ProgramCacheTest() :
+ cache_(new NoBackendProgramCache()) { }
+
+ protected:
+ scoped_ptr<NoBackendProgramCache> cache_;
+};
+
+TEST_F(ProgramCacheTest, LinkStatusSave) {
+ const std::string shader1 = "abcd1234";
+ const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
+ {
+ std::string shader_a = shader1;
+ std::string shader_b = shader2;
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(
+ shader_a, NULL, shader_b, NULL, NULL));
+ cache_->SaySuccessfullyCached(shader_a, NULL, shader_b, NULL, NULL);
+
+ shader_a.clear();
+ shader_b.clear();
+ }
+ // make sure it was copied
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
+ cache_->GetLinkedProgramStatus(
+ shader1, NULL, shader2, NULL, NULL));
+}
+
+TEST_F(ProgramCacheTest, LinkUnknownOnFragmentSourceChange) {
+ const std::string shader1 = "abcd1234";
+ std::string shader2 = "abcda sda b1~#4 bbbbb1234";
+ cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+
+ shader2 = "different!";
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+}
+
+TEST_F(ProgramCacheTest, LinkUnknownOnVertexSourceChange) {
+ std::string shader1 = "abcd1234";
+ const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
+ cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+
+ shader1 = "different!";
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+}
+
+TEST_F(ProgramCacheTest, StatusEviction) {
+ const std::string shader1 = "abcd1234";
+ const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
+ cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+ char a_sha[ProgramCache::kHashLength];
+ char b_sha[ProgramCache::kHashLength];
+ cache_->ComputeShaderHash(shader1, NULL, a_sha);
+ cache_->ComputeShaderHash(shader2, NULL, b_sha);
+
+ char sha[ProgramCache::kHashLength];
+ cache_->ComputeProgramHash(a_sha,
+ b_sha,
+ NULL,
+ sha);
+ cache_->Evict(std::string(sha, ProgramCache::kHashLength));
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+}
+
+TEST_F(ProgramCacheTest, EvictionWithReusedShader) {
+ const std::string shader1 = "abcd1234";
+ const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
+ const std::string shader3 = "asbjbbjj239a";
+ cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+ cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
+
+ char a_sha[ProgramCache::kHashLength];
+ char b_sha[ProgramCache::kHashLength];
+ char c_sha[ProgramCache::kHashLength];
+ cache_->ComputeShaderHash(shader1, NULL, a_sha);
+ cache_->ComputeShaderHash(shader2, NULL, b_sha);
+ cache_->ComputeShaderHash(shader3, NULL, c_sha);
+
+ char sha[ProgramCache::kHashLength];
+ cache_->ComputeProgramHash(a_sha,
+ b_sha,
+ NULL,
+ sha);
+ cache_->Evict(std::string(sha, ProgramCache::kHashLength));
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+ EXPECT_EQ(ProgramCache::LINK_SUCCEEDED,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
+
+
+ cache_->ComputeProgramHash(a_sha,
+ c_sha,
+ NULL,
+ sha);
+ cache_->Evict(std::string(sha, ProgramCache::kHashLength));
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
+}
+
+TEST_F(ProgramCacheTest, StatusClear) {
+ const std::string shader1 = "abcd1234";
+ const std::string shader2 = "abcda sda b1~#4 bbbbb1234";
+ const std::string shader3 = "asbjbbjj239a";
+ cache_->SaySuccessfullyCached(shader1, NULL, shader2, NULL, NULL);
+ cache_->SaySuccessfullyCached(shader1, NULL, shader3, NULL, NULL);
+ cache_->Clear();
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader2, NULL, NULL));
+ EXPECT_EQ(ProgramCache::LINK_UNKNOWN,
+ cache_->GetLinkedProgramStatus(shader1, NULL, shader3, NULL, NULL));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/program_manager.cc b/chromium/gpu/command_buffer/service/program_manager.cc
new file mode 100644
index 00000000000..8b1eedea35e
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/program_manager.cc
@@ -0,0 +1,1187 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/program_manager.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/metrics/histogram.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/program_cache.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "third_party/re2/re2/re2.h"
+
+using base::TimeDelta;
+using base::TimeTicks;
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+int ShaderTypeToIndex(GLenum shader_type) {
+ switch (shader_type) {
+ case GL_VERTEX_SHADER:
+ return 0;
+ case GL_FRAGMENT_SHADER:
+ return 1;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+ShaderTranslator* ShaderIndexToTranslator(
+ int index,
+ ShaderTranslator* vertex_translator,
+ ShaderTranslator* fragment_translator) {
+ switch (index) {
+ case 0:
+ return vertex_translator;
+ case 1:
+ return fragment_translator;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+}
+
+// Given a name like "foo.bar[123].moo[456]" sets new_name to "foo.bar[123].moo"
+// and sets element_index to 456. returns false if element expression was not a
+// whole decimal number. For example: "foo[1b2]"
+bool GetUniformNameSansElement(
+ const std::string& name, int* element_index, std::string* new_name) {
+ DCHECK(element_index);
+ DCHECK(new_name);
+ if (name.size() < 3 || name[name.size() - 1] != ']') {
+ *element_index = 0;
+ *new_name = name;
+ return true;
+ }
+
+ // Look for an array specification.
+ size_t open_pos = name.find_last_of('[');
+ if (open_pos == std::string::npos ||
+ open_pos >= name.size() - 2) {
+ return false;
+ }
+
+ GLint index = 0;
+ size_t last = name.size() - 1;
+ for (size_t pos = open_pos + 1; pos < last; ++pos) {
+ int8 digit = name[pos] - '0';
+ if (digit < 0 || digit > 9) {
+ return false;
+ }
+ index = index * 10 + digit;
+ }
+
+ *element_index = index;
+ *new_name = name.substr(0, open_pos);
+ return true;
+}
+
+} // anonymous namespace.
+
+Program::UniformInfo::UniformInfo()
+ : size(0),
+ type(GL_NONE),
+ fake_location_base(0),
+ is_array(false) {
+}
+
+Program::UniformInfo::UniformInfo(
+ GLsizei _size,
+ GLenum _type,
+ int _fake_location_base,
+ const std::string& _name)
+ : size(_size),
+ type(_type),
+ fake_location_base(_fake_location_base),
+ is_array(false),
+ name(_name) {
+}
+
+Program::UniformInfo::~UniformInfo() {}
+
+bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
+ static const char kInvalidPrefix[] = { 'g', 'l', '_' };
+ return (length >= sizeof(kInvalidPrefix) &&
+ memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
+}
+
+Program::Program(
+ ProgramManager* manager, GLuint service_id)
+ : manager_(manager),
+ use_count_(0),
+ max_attrib_name_length_(0),
+ max_uniform_name_length_(0),
+ service_id_(service_id),
+ deleted_(false),
+ valid_(false),
+ link_status_(false),
+ uniforms_cleared_(false),
+ num_uniforms_(0) {
+ manager_->StartTracking(this);
+}
+
+void Program::Reset() {
+ valid_ = false;
+ link_status_ = false;
+ num_uniforms_ = 0;
+ max_uniform_name_length_ = 0;
+ max_attrib_name_length_ = 0;
+ attrib_infos_.clear();
+ uniform_infos_.clear();
+ sampler_indices_.clear();
+ attrib_location_to_index_map_.clear();
+}
+
+std::string Program::ProcessLogInfo(
+ const std::string& log) {
+ std::string output;
+ re2::StringPiece input(log);
+ std::string prior_log;
+ std::string hashed_name;
+ while (RE2::Consume(&input,
+ "(.*)(webgl_[0123456789abcdefABCDEF]+)",
+ &prior_log,
+ &hashed_name)) {
+ output += prior_log;
+
+ const std::string* original_name =
+ GetOriginalNameFromHashedName(hashed_name);
+ if (original_name)
+ output += *original_name;
+ else
+ output += hashed_name;
+ }
+
+ return output + input.as_string();
+}
+
+void Program::UpdateLogInfo() {
+ GLint max_len = 0;
+ glGetProgramiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
+ if (max_len == 0) {
+ set_log_info(NULL);
+ return;
+ }
+ scoped_ptr<char[]> temp(new char[max_len]);
+ GLint len = 0;
+ glGetProgramInfoLog(service_id_, max_len, &len, temp.get());
+ DCHECK(max_len == 0 || len < max_len);
+ DCHECK(len == 0 || temp[len] == '\0');
+ std::string log(temp.get(), len);
+ set_log_info(ProcessLogInfo(log).c_str());
+}
+
+void Program::ClearUniforms(
+ std::vector<uint8>* zero_buffer) {
+ DCHECK(zero_buffer);
+ if (uniforms_cleared_) {
+ return;
+ }
+ uniforms_cleared_ = true;
+ for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& uniform_info = uniform_infos_[ii];
+ if (!uniform_info.IsValid()) {
+ continue;
+ }
+ GLint location = uniform_info.element_locations[0];
+ GLsizei size = uniform_info.size;
+ uint32 unit_size = GLES2Util::GetGLDataTypeSizeForUniforms(
+ uniform_info.type);
+ uint32 size_needed = size * unit_size;
+ if (size_needed > zero_buffer->size()) {
+ zero_buffer->resize(size_needed, 0u);
+ }
+ const void* zero = &(*zero_buffer)[0];
+ switch (uniform_info.type) {
+ case GL_FLOAT:
+ glUniform1fv(location, size, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ case GL_FLOAT_VEC2:
+ glUniform2fv(location, size, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ case GL_FLOAT_VEC3:
+ glUniform3fv(location, size, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ case GL_FLOAT_VEC4:
+ glUniform4fv(location, size, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ case GL_INT:
+ case GL_BOOL:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_3D_OES:
+ case GL_SAMPLER_2D_RECT_ARB:
+ glUniform1iv(location, size, reinterpret_cast<const GLint*>(zero));
+ break;
+ case GL_INT_VEC2:
+ case GL_BOOL_VEC2:
+ glUniform2iv(location, size, reinterpret_cast<const GLint*>(zero));
+ break;
+ case GL_INT_VEC3:
+ case GL_BOOL_VEC3:
+ glUniform3iv(location, size, reinterpret_cast<const GLint*>(zero));
+ break;
+ case GL_INT_VEC4:
+ case GL_BOOL_VEC4:
+ glUniform4iv(location, size, reinterpret_cast<const GLint*>(zero));
+ break;
+ case GL_FLOAT_MAT2:
+ glUniformMatrix2fv(
+ location, size, false, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ case GL_FLOAT_MAT3:
+ glUniformMatrix3fv(
+ location, size, false, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ case GL_FLOAT_MAT4:
+ glUniformMatrix4fv(
+ location, size, false, reinterpret_cast<const GLfloat*>(zero));
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+namespace {
+
+struct UniformData {
+ UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
+ }
+ std::string queried_name;
+ std::string corrected_name;
+ std::string original_name;
+ GLsizei size;
+ GLenum type;
+ GLint location;
+ bool added;
+};
+
+struct UniformDataComparer {
+ bool operator()(const UniformData& lhs, const UniformData& rhs) const {
+ return lhs.queried_name < rhs.queried_name;
+ }
+};
+
+} // anonymous namespace
+
+void Program::Update() {
+ Reset();
+ UpdateLogInfo();
+ link_status_ = true;
+ uniforms_cleared_ = false;
+ GLint num_attribs = 0;
+ GLint max_len = 0;
+ GLint max_location = -1;
+ glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTES, &num_attribs);
+ glGetProgramiv(service_id_, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_len);
+ // TODO(gman): Should we check for error?
+ scoped_ptr<char[]> name_buffer(new char[max_len]);
+ for (GLint ii = 0; ii < num_attribs; ++ii) {
+ GLsizei length = 0;
+ GLsizei size = 0;
+ GLenum type = 0;
+ glGetActiveAttrib(
+ service_id_, ii, max_len, &length, &size, &type, name_buffer.get());
+ DCHECK(max_len == 0 || length < max_len);
+ DCHECK(length == 0 || name_buffer[length] == '\0');
+ if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
+ std::string name;
+ std::string original_name;
+ GetCorrectedVariableInfo(
+ false, name_buffer.get(), &name, &original_name, &size, &type);
+ // TODO(gman): Should we check for error?
+ GLint location = glGetAttribLocation(service_id_, name_buffer.get());
+ if (location > max_location) {
+ max_location = location;
+ }
+ attrib_infos_.push_back(
+ VertexAttrib(size, type, original_name, location));
+ max_attrib_name_length_ = std::max(
+ max_attrib_name_length_, static_cast<GLsizei>(original_name.size()));
+ }
+ }
+
+ // Create attrib location to index map.
+ attrib_location_to_index_map_.resize(max_location + 1);
+ for (GLint ii = 0; ii <= max_location; ++ii) {
+ attrib_location_to_index_map_[ii] = -1;
+ }
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttrib& info = attrib_infos_[ii];
+ attrib_location_to_index_map_[info.location] = ii;
+ }
+
+#if !defined(NDEBUG)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUServiceLoggingGPU)) {
+ DLOG(INFO) << "----: attribs for service_id: " << service_id();
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttrib& info = attrib_infos_[ii];
+ DLOG(INFO) << ii << ": loc = " << info.location
+ << ", size = " << info.size
+ << ", type = " << GLES2Util::GetStringEnum(info.type)
+ << ", name = " << info.name;
+ }
+ }
+#endif
+
+ max_len = 0;
+ GLint num_uniforms = 0;
+ glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
+ glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
+ name_buffer.reset(new char[max_len]);
+
+ // Reads all the names.
+ std::vector<UniformData> uniform_data_;
+ for (GLint ii = 0; ii < num_uniforms; ++ii) {
+ GLsizei length = 0;
+ UniformData data;
+ glGetActiveUniform(
+ service_id_, ii, max_len, &length,
+ &data.size, &data.type, name_buffer.get());
+ DCHECK(max_len == 0 || length < max_len);
+ DCHECK(length == 0 || name_buffer[length] == '\0');
+ if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
+ data.queried_name = std::string(name_buffer.get());
+ GetCorrectedVariableInfo(
+ true, name_buffer.get(), &data.corrected_name, &data.original_name,
+ &data.size, &data.type);
+ uniform_data_.push_back(data);
+ }
+ }
+
+ // NOTE: We don't care if 2 uniforms are bound to the same location.
+ // One of them will take preference. The spec allows this, same as
+ // BindAttribLocation.
+ //
+ // The reason we don't check is if we were to fail we'd have to
+ // restore the previous program but since we've already linked successfully
+ // at this point the previous program is gone.
+
+ // Assigns the uniforms with bindings.
+ size_t next_available_index = 0;
+ for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
+ UniformData& data = uniform_data_[ii];
+ data.location = glGetUniformLocation(
+ service_id_, data.queried_name.c_str());
+ // remove "[0]"
+ std::string short_name;
+ int element_index = 0;
+ bool good ALLOW_UNUSED = GetUniformNameSansElement(
+ data.queried_name, &element_index, &short_name);\
+ DCHECK(good);
+ LocationMap::const_iterator it = bind_uniform_location_map_.find(
+ short_name);
+ if (it != bind_uniform_location_map_.end()) {
+ data.added = AddUniformInfo(
+ data.size, data.type, data.location, it->second, data.corrected_name,
+ data.original_name, &next_available_index);
+ }
+ }
+
+ // Assigns the uniforms that were not bound.
+ for (size_t ii = 0; ii < uniform_data_.size(); ++ii) {
+ const UniformData& data = uniform_data_[ii];
+ if (!data.added) {
+ AddUniformInfo(
+ data.size, data.type, data.location, -1, data.corrected_name,
+ data.original_name, &next_available_index);
+ }
+ }
+
+#if !defined(NDEBUG)
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableGPUServiceLoggingGPU)) {
+ DLOG(INFO) << "----: uniforms for service_id: " << service_id();
+ for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ if (info.IsValid()) {
+ DLOG(INFO) << ii << ": loc = " << info.element_locations[0]
+ << ", size = " << info.size
+ << ", type = " << GLES2Util::GetStringEnum(info.type)
+ << ", name = " << info.name;
+ }
+ }
+ }
+#endif
+
+ valid_ = true;
+}
+
+void Program::ExecuteBindAttribLocationCalls() {
+ for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
+ it != bind_attrib_location_map_.end(); ++it) {
+ const std::string* mapped_name = GetAttribMappedName(it->first);
+ if (mapped_name && *mapped_name != it->first)
+ glBindAttribLocation(service_id_, it->second, mapped_name->c_str());
+ }
+}
+
+void ProgramManager::DoCompileShader(Shader* shader,
+ ShaderTranslator* translator,
+ FeatureInfo* feature_info) {
+ // Translate GL ES 2.0 shader to Desktop GL shader and pass that to
+ // glShaderSource and then glCompileShader.
+ const std::string* source = shader->source();
+ const char* shader_src = source ? source->c_str() : "";
+ if (translator) {
+ if (!translator->Translate(shader_src)) {
+ shader->SetStatus(false, translator->info_log(), NULL);
+ return;
+ }
+ shader_src = translator->translated_shader();
+ if (!feature_info->feature_flags().angle_translated_shader_source)
+ shader->UpdateTranslatedSource(shader_src);
+ }
+
+ glShaderSource(shader->service_id(), 1, &shader_src, NULL);
+ glCompileShader(shader->service_id());
+ if (feature_info->feature_flags().angle_translated_shader_source) {
+ GLint max_len = 0;
+ glGetShaderiv(shader->service_id(),
+ GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
+ &max_len);
+ scoped_ptr<char[]> temp(new char[max_len]);
+ GLint len = 0;
+ glGetTranslatedShaderSourceANGLE(
+ shader->service_id(), max_len, &len, temp.get());
+ DCHECK(max_len == 0 || len < max_len);
+ DCHECK(len == 0 || temp[len] == '\0');
+ shader->UpdateTranslatedSource(max_len ? temp.get() : NULL);
+ }
+
+ GLint status = GL_FALSE;
+ glGetShaderiv(shader->service_id(), GL_COMPILE_STATUS, &status);
+ if (status) {
+ shader->SetStatus(true, "", translator);
+ } else {
+ // We cannot reach here if we are using the shader translator.
+ // All invalid shaders must be rejected by the translator.
+ // All translated shaders must compile.
+ GLint max_len = 0;
+ glGetShaderiv(shader->service_id(), GL_INFO_LOG_LENGTH, &max_len);
+ scoped_ptr<char[]> temp(new char[max_len]);
+ GLint len = 0;
+ glGetShaderInfoLog(shader->service_id(), max_len, &len, temp.get());
+ DCHECK(max_len == 0 || len < max_len);
+ DCHECK(len == 0 || temp[len] == '\0');
+ shader->SetStatus(false, std::string(temp.get(), len).c_str(), NULL);
+ LOG_IF(ERROR, translator)
+ << "Shader translator allowed/produced an invalid shader "
+ << "unless the driver is buggy:"
+ << "\n--original-shader--\n" << (source ? *source : std::string())
+ << "\n--translated-shader--\n" << shader_src << "\n--info-log--\n"
+ << *shader->log_info();
+ }
+}
+
+bool Program::Link(ShaderManager* manager,
+ ShaderTranslator* vertex_translator,
+ ShaderTranslator* fragment_translator,
+ FeatureInfo* feature_info,
+ const ShaderCacheCallback& shader_callback) {
+ ClearLinkStatus();
+ if (!CanLink()) {
+ set_log_info("missing shaders");
+ return false;
+ }
+ if (DetectAttribLocationBindingConflicts()) {
+ set_log_info("glBindAttribLocation() conflicts");
+ return false;
+ }
+
+ TimeTicks before_time = TimeTicks::HighResNow();
+ bool link = true;
+ ProgramCache* cache = manager_->program_cache_;
+ if (cache) {
+ DCHECK(attached_shaders_[0]->signature_source() &&
+ attached_shaders_[1]->signature_source());
+ ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus(
+ *attached_shaders_[0]->signature_source(),
+ vertex_translator,
+ *attached_shaders_[1]->signature_source(),
+ fragment_translator,
+ &bind_attrib_location_map_);
+
+ if (status == ProgramCache::LINK_SUCCEEDED) {
+ ProgramCache::ProgramLoadResult success =
+ cache->LoadLinkedProgram(service_id(),
+ attached_shaders_[0].get(),
+ vertex_translator,
+ attached_shaders_[1].get(),
+ fragment_translator,
+ &bind_attrib_location_map_,
+ shader_callback);
+ link = success != ProgramCache::PROGRAM_LOAD_SUCCESS;
+ UMA_HISTOGRAM_BOOLEAN("GPU.ProgramCache.LoadBinarySuccess", !link);
+ }
+ }
+
+ if (link) {
+ ExecuteBindAttribLocationCalls();
+ before_time = TimeTicks::HighResNow();
+ if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
+ glProgramParameteri(service_id(),
+ PROGRAM_BINARY_RETRIEVABLE_HINT,
+ GL_TRUE);
+ }
+ glLinkProgram(service_id());
+ }
+
+ GLint success = 0;
+ glGetProgramiv(service_id(), GL_LINK_STATUS, &success);
+ if (success == GL_TRUE) {
+ Update();
+ if (link) {
+ if (cache) {
+ cache->SaveLinkedProgram(service_id(),
+ attached_shaders_[0].get(),
+ vertex_translator,
+ attached_shaders_[1].get(),
+ fragment_translator,
+ &bind_attrib_location_map_,
+ shader_callback);
+ }
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "GPU.ProgramCache.BinaryCacheMissTime",
+ (TimeTicks::HighResNow() - before_time).InMicroseconds(),
+ 0,
+ TimeDelta::FromSeconds(10).InMicroseconds(),
+ 50);
+ } else {
+ UMA_HISTOGRAM_CUSTOM_COUNTS(
+ "GPU.ProgramCache.BinaryCacheHitTime",
+ (TimeTicks::HighResNow() - before_time).InMicroseconds(),
+ 0,
+ TimeDelta::FromSeconds(1).InMicroseconds(),
+ 50);
+ }
+ } else {
+ UpdateLogInfo();
+ }
+ return success == GL_TRUE;
+}
+
+void Program::Validate() {
+ if (!IsValid()) {
+ set_log_info("program not linked");
+ return;
+ }
+ glValidateProgram(service_id());
+ UpdateLogInfo();
+}
+
+GLint Program::GetUniformFakeLocation(
+ const std::string& name) const {
+ bool getting_array_location = false;
+ size_t open_pos = std::string::npos;
+ int index = 0;
+ if (!GLES2Util::ParseUniformName(
+ name, &open_pos, &index, &getting_array_location)) {
+ return -1;
+ }
+ for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ if (!info.IsValid()) {
+ continue;
+ }
+ if (info.name == name ||
+ (info.is_array &&
+ info.name.compare(0, info.name.size() - 3, name) == 0)) {
+ return info.fake_location_base;
+ } else if (getting_array_location && info.is_array) {
+ // Look for an array specification.
+ size_t open_pos_2 = info.name.find_last_of('[');
+ if (open_pos_2 == open_pos &&
+ name.compare(0, open_pos, info.name, 0, open_pos) == 0) {
+ if (index >= 0 && index < info.size) {
+ return ProgramManager::MakeFakeLocation(
+ info.fake_location_base, index);
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+GLint Program::GetAttribLocation(
+ const std::string& name) const {
+ for (GLuint ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttrib& info = attrib_infos_[ii];
+ if (info.name == name) {
+ return info.location;
+ }
+ }
+ return -1;
+}
+
+const Program::UniformInfo*
+ Program::GetUniformInfoByFakeLocation(
+ GLint fake_location, GLint* real_location, GLint* array_index) const {
+ DCHECK(real_location);
+ DCHECK(array_index);
+ if (fake_location < 0) {
+ return NULL;
+ }
+
+ GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
+ if (uniform_index >= 0 &&
+ static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
+ const UniformInfo& uniform_info = uniform_infos_[uniform_index];
+ if (!uniform_info.IsValid()) {
+ return NULL;
+ }
+ GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
+ if (element_index < uniform_info.size) {
+ *real_location = uniform_info.element_locations[element_index];
+ *array_index = element_index;
+ return &uniform_info;
+ }
+ }
+ return NULL;
+}
+
+const std::string* Program::GetAttribMappedName(
+ const std::string& original_name) const {
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ Shader* shader = attached_shaders_[ii].get();
+ if (shader) {
+ const std::string* mapped_name =
+ shader->GetAttribMappedName(original_name);
+ if (mapped_name)
+ return mapped_name;
+ }
+ }
+ return NULL;
+}
+
+const std::string* Program::GetOriginalNameFromHashedName(
+ const std::string& hashed_name) const {
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ Shader* shader = attached_shaders_[ii].get();
+ if (shader) {
+ const std::string* original_name =
+ shader->GetOriginalNameFromHashedName(hashed_name);
+ if (original_name)
+ return original_name;
+ }
+ }
+ return NULL;
+}
+
+bool Program::SetUniformLocationBinding(
+ const std::string& name, GLint location) {
+ std::string short_name;
+ int element_index = 0;
+ if (!GetUniformNameSansElement(name, &element_index, &short_name) ||
+ element_index != 0) {
+ return false;
+ }
+
+ bind_uniform_location_map_[short_name] = location;
+ return true;
+}
+
+// Note: This is only valid to call right after a program has been linked
+// successfully.
+void Program::GetCorrectedVariableInfo(
+ bool use_uniforms,
+ const std::string& name, std::string* corrected_name,
+ std::string* original_name,
+ GLsizei* size, GLenum* type) const {
+ DCHECK(corrected_name);
+ DCHECK(original_name);
+ DCHECK(size);
+ DCHECK(type);
+ const char* kArraySpec = "[0]";
+ for (int jj = 0; jj < 2; ++jj) {
+ std::string test_name(name + ((jj == 1) ? kArraySpec : ""));
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ Shader* shader = attached_shaders_[ii].get();
+ if (shader) {
+ const Shader::VariableInfo* variable_info =
+ use_uniforms ? shader->GetUniformInfo(test_name) :
+ shader->GetAttribInfo(test_name);
+ // Note: There is an assuption here that if an attrib is defined in more
+ // than 1 attached shader their types and sizes match. Should we check
+ // for that case?
+ if (variable_info) {
+ *corrected_name = test_name;
+ *original_name = variable_info->name;
+ *type = variable_info->type;
+ *size = variable_info->size;
+ return;
+ }
+ }
+ }
+ }
+ *corrected_name = name;
+ *original_name = name;
+}
+
+bool Program::AddUniformInfo(
+ GLsizei size, GLenum type, GLint location, GLint fake_base_location,
+ const std::string& name, const std::string& original_name,
+ size_t* next_available_index) {
+ DCHECK(next_available_index);
+ const char* kArraySpec = "[0]";
+ size_t uniform_index =
+ fake_base_location >= 0 ? fake_base_location : *next_available_index;
+ if (uniform_infos_.size() < uniform_index + 1) {
+ uniform_infos_.resize(uniform_index + 1);
+ }
+
+ // return if this location is already in use.
+ if (uniform_infos_[uniform_index].IsValid()) {
+ DCHECK_GE(fake_base_location, 0);
+ return false;
+ }
+
+ uniform_infos_[uniform_index] = UniformInfo(
+ size, type, uniform_index, original_name);
+ ++num_uniforms_;
+
+ UniformInfo& info = uniform_infos_[uniform_index];
+ info.element_locations.resize(size);
+ info.element_locations[0] = location;
+ DCHECK_GE(size, 0);
+ size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
+ info.texture_units.clear();
+ info.texture_units.resize(num_texture_units, 0);
+
+ if (size > 1) {
+ // Go through the array element locations looking for a match.
+ // We can skip the first element because it's the same as the
+ // the location without the array operators.
+ size_t array_pos = name.rfind(kArraySpec);
+ std::string base_name = name;
+ if (name.size() > 3) {
+ if (array_pos != name.size() - 3) {
+ info.name = name + kArraySpec;
+ } else {
+ base_name = name.substr(0, name.size() - 3);
+ }
+ }
+ for (GLsizei ii = 1; ii < info.size; ++ii) {
+ std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
+ info.element_locations[ii] =
+ glGetUniformLocation(service_id_, element_name.c_str());
+ }
+ }
+
+ info.is_array =
+ (size > 1 ||
+ (info.name.size() > 3 &&
+ info.name.rfind(kArraySpec) == info.name.size() - 3));
+
+ if (info.IsSampler()) {
+ sampler_indices_.push_back(info.fake_location_base);
+ }
+ max_uniform_name_length_ =
+ std::max(max_uniform_name_length_,
+ static_cast<GLsizei>(info.name.size()));
+
+ while (*next_available_index < uniform_infos_.size() &&
+ uniform_infos_[*next_available_index].IsValid()) {
+ *next_available_index = *next_available_index + 1;
+ }
+
+ return true;
+}
+
+const Program::UniformInfo*
+ Program::GetUniformInfo(
+ GLint index) const {
+ if (static_cast<size_t>(index) >= uniform_infos_.size()) {
+ return NULL;
+ }
+
+ const UniformInfo& info = uniform_infos_[index];
+ return info.IsValid() ? &info : NULL;
+}
+
+bool Program::SetSamplers(
+ GLint num_texture_units, GLint fake_location,
+ GLsizei count, const GLint* value) {
+ if (fake_location < 0) {
+ return true;
+ }
+ GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
+ if (uniform_index >= 0 &&
+ static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
+ UniformInfo& info = uniform_infos_[uniform_index];
+ if (!info.IsValid()) {
+ return false;
+ }
+ GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
+ if (element_index < info.size) {
+ count = std::min(info.size - element_index, count);
+ if (info.IsSampler() && count > 0) {
+ for (GLsizei ii = 0; ii < count; ++ii) {
+ if (value[ii] < 0 || value[ii] >= num_texture_units) {
+ return false;
+ }
+ }
+ std::copy(value, value + count,
+ info.texture_units.begin() + element_index);
+ return true;
+ }
+ }
+ }
+ return true;
+}
+
+void Program::GetProgramiv(GLenum pname, GLint* params) {
+ switch (pname) {
+ case GL_ACTIVE_ATTRIBUTES:
+ *params = attrib_infos_.size();
+ break;
+ case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
+ // Notice +1 to accomodate NULL terminator.
+ *params = max_attrib_name_length_ + 1;
+ break;
+ case GL_ACTIVE_UNIFORMS:
+ *params = num_uniforms_;
+ break;
+ case GL_ACTIVE_UNIFORM_MAX_LENGTH:
+ // Notice +1 to accomodate NULL terminator.
+ *params = max_uniform_name_length_ + 1;
+ break;
+ case GL_LINK_STATUS:
+ *params = link_status_;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ // Notice +1 to accomodate NULL terminator.
+ *params = log_info_.get() ? (log_info_->size() + 1) : 0;
+ break;
+ case GL_DELETE_STATUS:
+ *params = deleted_;
+ break;
+ case GL_VALIDATE_STATUS:
+ if (!IsValid()) {
+ *params = GL_FALSE;
+ } else {
+ glGetProgramiv(service_id_, pname, params);
+ }
+ break;
+ default:
+ glGetProgramiv(service_id_, pname, params);
+ break;
+ }
+}
+
+bool Program::AttachShader(
+ ShaderManager* shader_manager,
+ Shader* shader) {
+ DCHECK(shader_manager);
+ DCHECK(shader);
+ int index = ShaderTypeToIndex(shader->shader_type());
+ if (attached_shaders_[index].get() != NULL) {
+ return false;
+ }
+ attached_shaders_[index] = scoped_refptr<Shader>(shader);
+ shader_manager->UseShader(shader);
+ return true;
+}
+
+bool Program::DetachShader(
+ ShaderManager* shader_manager,
+ Shader* shader) {
+ DCHECK(shader_manager);
+ DCHECK(shader);
+ if (attached_shaders_[ShaderTypeToIndex(shader->shader_type())].get() !=
+ shader) {
+ return false;
+ }
+ attached_shaders_[ShaderTypeToIndex(shader->shader_type())] = NULL;
+ shader_manager->UnuseShader(shader);
+ return true;
+}
+
+void Program::DetachShaders(ShaderManager* shader_manager) {
+ DCHECK(shader_manager);
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ if (attached_shaders_[ii].get()) {
+ DetachShader(shader_manager, attached_shaders_[ii].get());
+ }
+ }
+}
+
+bool Program::CanLink() const {
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool Program::DetectAttribLocationBindingConflicts() const {
+ std::set<GLint> location_binding_used;
+ for (LocationMap::const_iterator it = bind_attrib_location_map_.begin();
+ it != bind_attrib_location_map_.end(); ++it) {
+ // Find out if an attribute is declared in this program's shaders.
+ bool active = false;
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) {
+ if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->IsValid())
+ continue;
+ if (attached_shaders_[ii]->GetAttribInfo(it->first)) {
+ active = true;
+ break;
+ }
+ }
+ if (active) {
+ std::pair<std::set<GLint>::iterator, bool> result =
+ location_binding_used.insert(it->second);
+ if (!result.second)
+ return true;
+ }
+ }
+ return false;
+}
+
+static uint32 ComputeOffset(const void* start, const void* position) {
+ return static_cast<const uint8*>(position) -
+ static_cast<const uint8*>(start);
+}
+
+void Program::GetProgramInfo(
+ ProgramManager* manager, CommonDecoder::Bucket* bucket) const {
+ // NOTE: It seems to me the math in here does not need check for overflow
+ // because the data being calucated from has various small limits. The max
+ // number of attribs + uniforms is somewhere well under 1024. The maximum size
+ // of an identifier is 256 characters.
+ uint32 num_locations = 0;
+ uint32 total_string_size = 0;
+
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttrib& info = attrib_infos_[ii];
+ num_locations += 1;
+ total_string_size += info.name.size();
+ }
+
+ for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ if (info.IsValid()) {
+ num_locations += info.element_locations.size();
+ total_string_size += info.name.size();
+ }
+ }
+
+ uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
+ uint32 input_size = num_inputs * sizeof(ProgramInput);
+ uint32 location_size = num_locations * sizeof(int32);
+ uint32 size = sizeof(ProgramInfoHeader) +
+ input_size + location_size + total_string_size;
+
+ bucket->SetSize(size);
+ ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
+ ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
+ sizeof(ProgramInfoHeader), input_size);
+ int32* locations = bucket->GetDataAs<int32*>(
+ sizeof(ProgramInfoHeader) + input_size, location_size);
+ char* strings = bucket->GetDataAs<char*>(
+ sizeof(ProgramInfoHeader) + input_size + location_size,
+ total_string_size);
+ DCHECK(header);
+ DCHECK(inputs);
+ DCHECK(locations);
+ DCHECK(strings);
+
+ header->link_status = link_status_;
+ header->num_attribs = attrib_infos_.size();
+ header->num_uniforms = num_uniforms_;
+
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttrib& info = attrib_infos_[ii];
+ inputs->size = info.size;
+ inputs->type = info.type;
+ inputs->location_offset = ComputeOffset(header, locations);
+ inputs->name_offset = ComputeOffset(header, strings);
+ inputs->name_length = info.name.size();
+ *locations++ = info.location;
+ memcpy(strings, info.name.c_str(), info.name.size());
+ strings += info.name.size();
+ ++inputs;
+ }
+
+ for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ if (info.IsValid()) {
+ inputs->size = info.size;
+ inputs->type = info.type;
+ inputs->location_offset = ComputeOffset(header, locations);
+ inputs->name_offset = ComputeOffset(header, strings);
+ inputs->name_length = info.name.size();
+ DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
+ for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
+ *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
+ }
+ memcpy(strings, info.name.c_str(), info.name.size());
+ strings += info.name.size();
+ ++inputs;
+ }
+ }
+
+ DCHECK_EQ(ComputeOffset(header, strings), size);
+}
+
+Program::~Program() {
+ if (manager_) {
+ if (manager_->have_context_) {
+ glDeleteProgram(service_id());
+ }
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+
+ProgramManager::ProgramManager(ProgramCache* program_cache)
+ : program_count_(0),
+ have_context_(true),
+ disable_workarounds_(
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuDriverBugWorkarounds)),
+ program_cache_(program_cache) { }
+
+ProgramManager::~ProgramManager() {
+ DCHECK(programs_.empty());
+}
+
+void ProgramManager::Destroy(bool have_context) {
+ have_context_ = have_context;
+ programs_.clear();
+}
+
+void ProgramManager::StartTracking(Program* /* program */) {
+ ++program_count_;
+}
+
+void ProgramManager::StopTracking(Program* /* program */) {
+ --program_count_;
+}
+
+Program* ProgramManager::CreateProgram(
+ GLuint client_id, GLuint service_id) {
+ std::pair<ProgramMap::iterator, bool> result =
+ programs_.insert(
+ std::make_pair(client_id,
+ scoped_refptr<Program>(
+ new Program(this, service_id))));
+ DCHECK(result.second);
+ return result.first->second.get();
+}
+
+Program* ProgramManager::GetProgram(GLuint client_id) {
+ ProgramMap::iterator it = programs_.find(client_id);
+ return it != programs_.end() ? it->second.get() : NULL;
+}
+
+bool ProgramManager::GetClientId(GLuint service_id, GLuint* client_id) const {
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (ProgramMap::const_iterator it = programs_.begin();
+ it != programs_.end(); ++it) {
+ if (it->second->service_id() == service_id) {
+ *client_id = it->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+ProgramCache* ProgramManager::program_cache() const {
+ return program_cache_;
+}
+
+bool ProgramManager::IsOwned(Program* program) {
+ for (ProgramMap::iterator it = programs_.begin();
+ it != programs_.end(); ++it) {
+ if (it->second.get() == program) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ProgramManager::RemoveProgramInfoIfUnused(
+ ShaderManager* shader_manager, Program* program) {
+ DCHECK(shader_manager);
+ DCHECK(program);
+ DCHECK(IsOwned(program));
+ if (program->IsDeleted() && !program->InUse()) {
+ program->DetachShaders(shader_manager);
+ for (ProgramMap::iterator it = programs_.begin();
+ it != programs_.end(); ++it) {
+ if (it->second.get() == program) {
+ programs_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+ }
+}
+
+void ProgramManager::MarkAsDeleted(
+ ShaderManager* shader_manager,
+ Program* program) {
+ DCHECK(shader_manager);
+ DCHECK(program);
+ DCHECK(IsOwned(program));
+ program->MarkAsDeleted();
+ RemoveProgramInfoIfUnused(shader_manager, program);
+}
+
+void ProgramManager::UseProgram(Program* program) {
+ DCHECK(program);
+ DCHECK(IsOwned(program));
+ program->IncUseCount();
+ ClearUniforms(program);
+}
+
+void ProgramManager::UnuseProgram(
+ ShaderManager* shader_manager,
+ Program* program) {
+ DCHECK(shader_manager);
+ DCHECK(program);
+ DCHECK(IsOwned(program));
+ program->DecUseCount();
+ RemoveProgramInfoIfUnused(shader_manager, program);
+}
+
+void ProgramManager::ClearUniforms(Program* program) {
+ DCHECK(program);
+ if (!disable_workarounds_) {
+ program->ClearUniforms(&zero_);
+ }
+}
+
+int32 ProgramManager::MakeFakeLocation(int32 index, int32 element) {
+ return index + element * 0x10000;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/program_manager.h b/chromium/gpu/command_buffer/service/program_manager.h
new file mode 100644
index 00000000000..dca232bf242
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/program_manager.h
@@ -0,0 +1,398 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_PROGRAM_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_PROGRAM_MANAGER_H_
+
+#include <map>
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class FeatureInfo;
+class ProgramCache;
+class ProgramManager;
+class Shader;
+class ShaderManager;
+class ShaderTranslator;
+
+// This is used to track which attributes a particular program needs
+// so we can verify at glDrawXXX time that every attribute is either disabled
+// or if enabled that it points to a valid source.
+class GPU_EXPORT Program : public base::RefCounted<Program> {
+ public:
+ static const int kMaxAttachedShaders = 2;
+
+ struct UniformInfo {
+ UniformInfo();
+ UniformInfo(
+ GLsizei _size, GLenum _type, GLint _fake_location_base,
+ const std::string& _name);
+ ~UniformInfo();
+
+ bool IsValid() const {
+ return size != 0;
+ }
+
+ bool IsSampler() const {
+ return type == GL_SAMPLER_2D || type == GL_SAMPLER_2D_RECT_ARB ||
+ type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
+ }
+
+ GLsizei size;
+ GLenum type;
+ GLint fake_location_base;
+ bool is_array;
+ std::string name;
+ std::vector<GLint> element_locations;
+ std::vector<GLuint> texture_units;
+ };
+ struct VertexAttrib {
+ VertexAttrib(GLsizei _size, GLenum _type, const std::string& _name,
+ GLint _location)
+ : size(_size),
+ type(_type),
+ location(_location),
+ name(_name) {
+ }
+ GLsizei size;
+ GLenum type;
+ GLint location;
+ std::string name;
+ };
+
+ typedef std::vector<UniformInfo> UniformInfoVector;
+ typedef std::vector<VertexAttrib> AttribInfoVector;
+ typedef std::vector<int> SamplerIndices;
+ typedef std::map<std::string, GLint> LocationMap;
+
+ Program(ProgramManager* manager, GLuint service_id);
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ const SamplerIndices& sampler_indices() {
+ return sampler_indices_;
+ }
+
+ const AttribInfoVector& GetAttribInfos() const {
+ return attrib_infos_;
+ }
+
+ const VertexAttrib* GetAttribInfo(GLint index) const {
+ return (static_cast<size_t>(index) < attrib_infos_.size()) ?
+ &attrib_infos_[index] : NULL;
+ }
+
+ GLint GetAttribLocation(const std::string& name) const;
+
+ const VertexAttrib* GetAttribInfoByLocation(GLuint location) const {
+ if (location < attrib_location_to_index_map_.size()) {
+ GLint index = attrib_location_to_index_map_[location];
+ if (index >= 0) {
+ return &attrib_infos_[index];
+ }
+ }
+ return NULL;
+ }
+
+ const UniformInfo* GetUniformInfo(GLint index) const;
+
+ // If the original name is not found, return NULL.
+ const std::string* GetAttribMappedName(
+ const std::string& original_name) const;
+
+ // If the hashed name is not found, return NULL.
+ const std::string* GetOriginalNameFromHashedName(
+ const std::string& hashed_name) const;
+
+ // Gets the fake location of a uniform by name.
+ GLint GetUniformFakeLocation(const std::string& name) const;
+
+ // Gets the UniformInfo of a uniform by location.
+ const UniformInfo* GetUniformInfoByFakeLocation(
+ GLint fake_location, GLint* real_location, GLint* array_index) const;
+
+ // Gets all the program info.
+ void GetProgramInfo(
+ ProgramManager* manager, CommonDecoder::Bucket* bucket) const;
+
+ // Sets the sampler values for a uniform.
+ // This is safe to call for any location. If the location is not
+ // a sampler uniform nothing will happen.
+ // Returns false if fake_location is a sampler and any value
+ // is >= num_texture_units. Returns true otherwise.
+ bool SetSamplers(
+ GLint num_texture_units, GLint fake_location,
+ GLsizei count, const GLint* value);
+
+ bool IsDeleted() const {
+ return deleted_;
+ }
+
+ void GetProgramiv(GLenum pname, GLint* params);
+
+ bool IsValid() const {
+ return valid_;
+ }
+
+ bool AttachShader(ShaderManager* manager, Shader* shader);
+ bool DetachShader(ShaderManager* manager, Shader* shader);
+
+ bool CanLink() const;
+
+ // Performs glLinkProgram and related activities.
+ bool Link(ShaderManager* manager,
+ ShaderTranslator* vertex_translator,
+ ShaderTranslator* fragment_shader,
+ FeatureInfo* feature_info,
+ const ShaderCacheCallback& shader_callback);
+
+ // Performs glValidateProgram and related activities.
+ void Validate();
+
+ const std::string* log_info() const {
+ return log_info_.get();
+ }
+
+ bool InUse() const {
+ DCHECK_GE(use_count_, 0);
+ return use_count_ != 0;
+ }
+
+ // Sets attribute-location binding from a glBindAttribLocation() call.
+ void SetAttribLocationBinding(const std::string& attrib, GLint location) {
+ bind_attrib_location_map_[attrib] = location;
+ }
+
+ // Sets uniform-location binding from a glBindUniformLocationCHROMIUM call.
+ // returns false if error.
+ bool SetUniformLocationBinding(const std::string& name, GLint location);
+
+ // Detects if there are attribute location conflicts from
+ // glBindAttribLocation() calls.
+ // We only consider the declared attributes in the program.
+ bool DetectAttribLocationBindingConflicts() const;
+
+ // Visible for testing
+ const LocationMap& bind_attrib_location_map() const {
+ return bind_attrib_location_map_;
+ }
+
+ private:
+ friend class base::RefCounted<Program>;
+ friend class ProgramManager;
+
+ ~Program();
+
+ void set_log_info(const char* str) {
+ log_info_.reset(str ? new std::string(str) : NULL);
+ }
+
+ void ClearLinkStatus() {
+ link_status_ = false;
+ }
+
+ void IncUseCount() {
+ ++use_count_;
+ }
+
+ void DecUseCount() {
+ --use_count_;
+ DCHECK_GE(use_count_, 0);
+ }
+
+ void MarkAsDeleted() {
+ DCHECK(!deleted_);
+ deleted_ = true;
+ }
+
+ // Resets the program.
+ void Reset();
+
+ // Updates the program info after a successful link.
+ void Update();
+
+ // Process the program log, replacing the hashed names with original names.
+ std::string ProcessLogInfo(const std::string& log);
+
+ // Updates the program log info from GL
+ void UpdateLogInfo();
+
+ // Clears all the uniforms.
+ void ClearUniforms(std::vector<uint8>* zero_buffer);
+
+ // If long attribate names are mapped during shader translation, call
+ // glBindAttribLocation() again with the mapped names.
+ // This is called right before the glLink() call, but after shaders are
+ // translated.
+ void ExecuteBindAttribLocationCalls();
+
+ bool AddUniformInfo(
+ GLsizei size, GLenum type, GLint location, GLint fake_base_location,
+ const std::string& name, const std::string& original_name,
+ size_t* next_available_index);
+
+ void GetCorrectedVariableInfo(
+ bool use_uniforms, const std::string& name, std::string* corrected_name,
+ std::string* original_name, GLsizei* size, GLenum* type) const;
+
+ void DetachShaders(ShaderManager* manager);
+
+ static inline GLint GetUniformInfoIndexFromFakeLocation(
+ GLint fake_location) {
+ return fake_location & 0xFFFF;
+ }
+
+ static inline GLint GetArrayElementIndexFromFakeLocation(
+ GLint fake_location) {
+ return (fake_location >> 16) & 0xFFFF;
+ }
+
+ ProgramManager* manager_;
+
+ int use_count_;
+
+ GLsizei max_attrib_name_length_;
+
+ // Attrib by index.
+ AttribInfoVector attrib_infos_;
+
+ // Attrib by location to index.
+ std::vector<GLint> attrib_location_to_index_map_;
+
+ GLsizei max_uniform_name_length_;
+
+ // Uniform info by index.
+ UniformInfoVector uniform_infos_;
+
+ // The indices of the uniforms that are samplers.
+ SamplerIndices sampler_indices_;
+
+ // The program this Program is tracking.
+ GLuint service_id_;
+
+ // Shaders by type of shader.
+ scoped_refptr<Shader>
+ attached_shaders_[kMaxAttachedShaders];
+
+ // True if this program is marked as deleted.
+ bool deleted_;
+
+ // This is true if glLinkProgram was successful at least once.
+ bool valid_;
+
+ // This is true if glLinkProgram was successful last time it was called.
+ bool link_status_;
+
+ // True if the uniforms have been cleared.
+ bool uniforms_cleared_;
+
+ // This is different than uniform_infos_.size() because
+ // that is a sparce array.
+ GLint num_uniforms_;
+
+ // Log info
+ scoped_ptr<std::string> log_info_;
+
+ // attribute-location binding map from glBindAttribLocation() calls.
+ LocationMap bind_attrib_location_map_;
+
+ // uniform-location binding map from glBindUniformLocationCHROMIUM() calls.
+ LocationMap bind_uniform_location_map_;
+};
+
+// Tracks the Programs.
+//
+// NOTE: To support shared resources an instance of this class will
+// need to be shared by multiple GLES2Decoders.
+class GPU_EXPORT ProgramManager {
+ public:
+ explicit ProgramManager(ProgramCache* program_cache);
+ ~ProgramManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a new program.
+ Program* CreateProgram(GLuint client_id, GLuint service_id);
+
+ // Gets a program.
+ Program* GetProgram(GLuint client_id);
+
+ // Gets a client id for a given service id.
+ bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
+ // Gets the shader cache
+ ProgramCache* program_cache() const;
+
+ // Marks a program as deleted. If it is not used the program will be deleted.
+ void MarkAsDeleted(ShaderManager* shader_manager, Program* program);
+
+ // Marks a program as used.
+ void UseProgram(Program* program);
+
+ // Makes a program as unused. If deleted the program will be removed.
+ void UnuseProgram(ShaderManager* shader_manager, Program* program);
+
+ // Clears the uniforms for this program.
+ void ClearUniforms(Program* program);
+
+ // Returns true if prefix is invalid for gl.
+ static bool IsInvalidPrefix(const char* name, size_t length);
+
+ // Check if a Program is owned by this ProgramManager.
+ bool IsOwned(Program* program);
+
+ static int32 MakeFakeLocation(int32 index, int32 element);
+
+ void DoCompileShader(Shader* shader,
+ ShaderTranslator* translator,
+ FeatureInfo* feature_info);
+
+ private:
+ friend class Program;
+
+ void StartTracking(Program* program);
+ void StopTracking(Program* program);
+
+ // Info for each "successfully linked" program by service side program Id.
+ // TODO(gman): Choose a faster container.
+ typedef std::map<GLuint, scoped_refptr<Program> > ProgramMap;
+ ProgramMap programs_;
+
+ // Counts the number of Program allocated with 'this' as its manager.
+ // Allows to check no Program will outlive this.
+ unsigned int program_count_;
+
+ bool have_context_;
+
+ bool disable_workarounds_;
+
+ // Used to clear uniforms.
+ std::vector<uint8> zero_;
+
+ ProgramCache* program_cache_;
+
+ void RemoveProgramInfoIfUnused(
+ ShaderManager* shader_manager, Program* program);
+
+ DISALLOW_COPY_AND_ASSIGN(ProgramManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_PROGRAM_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/program_manager_unittest.cc b/chromium/gpu/command_buffer/service/program_manager_unittest.cc
new file mode 100644
index 00000000000..90ce0af8eff
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/program_manager_unittest.cc
@@ -0,0 +1,1379 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/program_manager.h"
+
+#include <algorithm>
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/shader_manager.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::ReturnRef;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+void ShaderCacheCb(const std::string& key, const std::string& shader) {}
+} // namespace
+
+class ProgramManagerTest : public testing::Test {
+ public:
+ ProgramManagerTest() : manager_(NULL) { }
+ virtual ~ProgramManagerTest() {
+ manager_.Destroy(false);
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ ProgramManager manager_;
+};
+
+TEST_F(ProgramManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+ // Check we can create program.
+ manager_.CreateProgram(kClient1Id, kService1Id);
+ // Check program got created.
+ Program* program1 = manager_.GetProgram(kClient1Id);
+ ASSERT_TRUE(program1 != NULL);
+ GLuint client_id = 0;
+ EXPECT_TRUE(manager_.GetClientId(program1->service_id(), &client_id));
+ EXPECT_EQ(kClient1Id, client_id);
+ // Check we get nothing for a non-existent program.
+ EXPECT_TRUE(manager_.GetProgram(kClient2Id) == NULL);
+}
+
+TEST_F(ProgramManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create program.
+ Program* program0 = manager_.CreateProgram(kClient1Id, kService1Id);
+ ASSERT_TRUE(program0 != NULL);
+ // Check program got created.
+ Program* program1 = manager_.GetProgram(kClient1Id);
+ ASSERT_EQ(program0, program1);
+ EXPECT_CALL(*gl_, DeleteProgram(kService1Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_.Destroy(true);
+ // Check the resources were released.
+ program1 = manager_.GetProgram(kClient1Id);
+ ASSERT_TRUE(program1 == NULL);
+}
+
+TEST_F(ProgramManagerTest, DeleteBug) {
+ ShaderManager shader_manager;
+ const GLuint kClient1Id = 1;
+ const GLuint kClient2Id = 2;
+ const GLuint kService1Id = 11;
+ const GLuint kService2Id = 12;
+ // Check we can create program.
+ scoped_refptr<Program> program1(
+ manager_.CreateProgram(kClient1Id, kService1Id));
+ scoped_refptr<Program> program2(
+ manager_.CreateProgram(kClient2Id, kService2Id));
+ // Check program got created.
+ ASSERT_TRUE(program1.get());
+ ASSERT_TRUE(program2.get());
+ manager_.UseProgram(program1.get());
+ manager_.MarkAsDeleted(&shader_manager, program1.get());
+ // Program will be deleted when last ref is released.
+ EXPECT_CALL(*gl_, DeleteProgram(kService2Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_.MarkAsDeleted(&shader_manager, program2.get());
+ EXPECT_TRUE(manager_.IsOwned(program1.get()));
+ EXPECT_FALSE(manager_.IsOwned(program2.get()));
+}
+
+TEST_F(ProgramManagerTest, Program) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create program.
+ Program* program1 = manager_.CreateProgram(
+ kClient1Id, kService1Id);
+ ASSERT_TRUE(program1);
+ EXPECT_EQ(kService1Id, program1->service_id());
+ EXPECT_FALSE(program1->InUse());
+ EXPECT_FALSE(program1->IsValid());
+ EXPECT_FALSE(program1->IsDeleted());
+ EXPECT_FALSE(program1->CanLink());
+ EXPECT_TRUE(program1->log_info() == NULL);
+}
+
+class ProgramManagerWithShaderTest : public testing::Test {
+ public:
+ ProgramManagerWithShaderTest()
+ : manager_(NULL), program_(NULL) {
+ }
+
+ virtual ~ProgramManagerWithShaderTest() {
+ manager_.Destroy(false);
+ shader_manager_.Destroy(false);
+ }
+
+ static const GLint kNumVertexAttribs = 16;
+
+ static const GLuint kClientProgramId = 123;
+ static const GLuint kServiceProgramId = 456;
+ static const GLuint kVertexShaderClientId = 201;
+ static const GLuint kFragmentShaderClientId = 202;
+ static const GLuint kVertexShaderServiceId = 301;
+ static const GLuint kFragmentShaderServiceId = 302;
+
+ static const char* kAttrib1Name;
+ static const char* kAttrib2Name;
+ static const char* kAttrib3Name;
+ static const GLint kAttrib1Size = 1;
+ static const GLint kAttrib2Size = 1;
+ static const GLint kAttrib3Size = 1;
+ static const GLint kAttrib1Location = 0;
+ static const GLint kAttrib2Location = 1;
+ static const GLint kAttrib3Location = 2;
+ static const GLenum kAttrib1Type = GL_FLOAT_VEC4;
+ static const GLenum kAttrib2Type = GL_FLOAT_VEC2;
+ static const GLenum kAttrib3Type = GL_FLOAT_VEC3;
+ static const GLint kInvalidAttribLocation = 30;
+ static const GLint kBadAttribIndex = kNumVertexAttribs;
+
+ static const char* kUniform1Name;
+ static const char* kUniform2Name;
+ static const char* kUniform3BadName;
+ static const char* kUniform3GoodName;
+ static const GLint kUniform1Size = 1;
+ static const GLint kUniform2Size = 3;
+ static const GLint kUniform3Size = 2;
+ static const GLint kUniform1FakeLocation = 0; // These are hard coded
+ static const GLint kUniform2FakeLocation = 1; // to match
+ static const GLint kUniform3FakeLocation = 2; // ProgramManager.
+ static const GLint kUniform1RealLocation = 11;
+ static const GLint kUniform2RealLocation = 22;
+ static const GLint kUniform3RealLocation = 33;
+ static const GLint kUniform1DesiredLocation = -1;
+ static const GLint kUniform2DesiredLocation = -1;
+ static const GLint kUniform3DesiredLocation = -1;
+ static const GLenum kUniform1Type = GL_FLOAT_VEC4;
+ static const GLenum kUniform2Type = GL_INT_VEC2;
+ static const GLenum kUniform3Type = GL_FLOAT_VEC3;
+ static const GLint kInvalidUniformLocation = 30;
+ static const GLint kBadUniformIndex = 1000;
+
+ static const size_t kNumAttribs;
+ static const size_t kNumUniforms;
+
+ protected:
+ typedef TestHelper::AttribInfo AttribInfo;
+ typedef TestHelper::UniformInfo UniformInfo;
+
+ virtual void SetUp() {
+ gl_.reset(new StrictMock<gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ SetupDefaultShaderExpectations();
+
+ Shader* vertex_shader = shader_manager_.CreateShader(
+ kVertexShaderClientId, kVertexShaderServiceId, GL_VERTEX_SHADER);
+ Shader* fragment_shader =
+ shader_manager_.CreateShader(
+ kFragmentShaderClientId, kFragmentShaderServiceId,
+ GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(vertex_shader != NULL);
+ ASSERT_TRUE(fragment_shader != NULL);
+ vertex_shader->SetStatus(true, NULL, NULL);
+ fragment_shader->SetStatus(true, NULL, NULL);
+
+ program_ = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program_ != NULL);
+
+ program_->AttachShader(&shader_manager_, vertex_shader);
+ program_->AttachShader(&shader_manager_, fragment_shader);
+ program_->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+ }
+
+ void SetupShader(AttribInfo* attribs, size_t num_attribs,
+ UniformInfo* uniforms, size_t num_uniforms,
+ GLuint service_id) {
+ TestHelper::SetupShader(
+ gl_.get(), attribs, num_attribs, uniforms, num_uniforms, service_id);
+ }
+
+ void SetupDefaultShaderExpectations() {
+ SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
+ kServiceProgramId);
+ }
+
+ void SetupExpectationsForClearingUniforms(
+ UniformInfo* uniforms, size_t num_uniforms) {
+ TestHelper::SetupExpectationsForClearingUniforms(
+ gl_.get(), uniforms, num_uniforms);
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ }
+
+ // Return true if link status matches expected_link_status
+ bool LinkAsExpected(Program* program,
+ bool expected_link_status) {
+ GLuint service_id = program->service_id();
+ if (expected_link_status) {
+ SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
+ service_id);
+ }
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+ GLint link_status;
+ program->GetProgramiv(GL_LINK_STATUS, &link_status);
+ return (static_cast<bool>(link_status) == expected_link_status);
+ }
+
+ static AttribInfo kAttribs[];
+ static UniformInfo kUniforms[];
+
+ scoped_ptr<StrictMock<gfx::MockGLInterface> > gl_;
+
+ ProgramManager manager_;
+ Program* program_;
+ ShaderManager shader_manager_;
+};
+
+ProgramManagerWithShaderTest::AttribInfo
+ ProgramManagerWithShaderTest::kAttribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLint ProgramManagerWithShaderTest::kNumVertexAttribs;
+const GLuint ProgramManagerWithShaderTest::kClientProgramId;
+const GLuint ProgramManagerWithShaderTest::kServiceProgramId;
+const GLuint ProgramManagerWithShaderTest::kVertexShaderClientId;
+const GLuint ProgramManagerWithShaderTest::kFragmentShaderClientId;
+const GLuint ProgramManagerWithShaderTest::kVertexShaderServiceId;
+const GLuint ProgramManagerWithShaderTest::kFragmentShaderServiceId;
+const GLint ProgramManagerWithShaderTest::kAttrib1Size;
+const GLint ProgramManagerWithShaderTest::kAttrib2Size;
+const GLint ProgramManagerWithShaderTest::kAttrib3Size;
+const GLint ProgramManagerWithShaderTest::kAttrib1Location;
+const GLint ProgramManagerWithShaderTest::kAttrib2Location;
+const GLint ProgramManagerWithShaderTest::kAttrib3Location;
+const GLenum ProgramManagerWithShaderTest::kAttrib1Type;
+const GLenum ProgramManagerWithShaderTest::kAttrib2Type;
+const GLenum ProgramManagerWithShaderTest::kAttrib3Type;
+const GLint ProgramManagerWithShaderTest::kInvalidAttribLocation;
+const GLint ProgramManagerWithShaderTest::kBadAttribIndex;
+const GLint ProgramManagerWithShaderTest::kUniform1Size;
+const GLint ProgramManagerWithShaderTest::kUniform2Size;
+const GLint ProgramManagerWithShaderTest::kUniform3Size;
+const GLint ProgramManagerWithShaderTest::kUniform1FakeLocation;
+const GLint ProgramManagerWithShaderTest::kUniform2FakeLocation;
+const GLint ProgramManagerWithShaderTest::kUniform3FakeLocation;
+const GLint ProgramManagerWithShaderTest::kUniform1RealLocation;
+const GLint ProgramManagerWithShaderTest::kUniform2RealLocation;
+const GLint ProgramManagerWithShaderTest::kUniform3RealLocation;
+const GLint ProgramManagerWithShaderTest::kUniform1DesiredLocation;
+const GLint ProgramManagerWithShaderTest::kUniform2DesiredLocation;
+const GLint ProgramManagerWithShaderTest::kUniform3DesiredLocation;
+const GLenum ProgramManagerWithShaderTest::kUniform1Type;
+const GLenum ProgramManagerWithShaderTest::kUniform2Type;
+const GLenum ProgramManagerWithShaderTest::kUniform3Type;
+const GLint ProgramManagerWithShaderTest::kInvalidUniformLocation;
+const GLint ProgramManagerWithShaderTest::kBadUniformIndex;
+#endif
+
+const size_t ProgramManagerWithShaderTest::kNumAttribs =
+ arraysize(ProgramManagerWithShaderTest::kAttribs);
+
+ProgramManagerWithShaderTest::UniformInfo
+ ProgramManagerWithShaderTest::kUniforms[] = {
+ { kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1FakeLocation,
+ kUniform1RealLocation,
+ kUniform1DesiredLocation,
+ kUniform1Name,
+ },
+ { kUniform2Name,
+ kUniform2Size,
+ kUniform2Type,
+ kUniform2FakeLocation,
+ kUniform2RealLocation,
+ kUniform2DesiredLocation,
+ kUniform2Name,
+ },
+ { kUniform3BadName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3FakeLocation,
+ kUniform3RealLocation,
+ kUniform3DesiredLocation,
+ kUniform3GoodName,
+ },
+};
+
+const size_t ProgramManagerWithShaderTest::kNumUniforms =
+ arraysize(ProgramManagerWithShaderTest::kUniforms);
+
+const char* ProgramManagerWithShaderTest::kAttrib1Name = "attrib1";
+const char* ProgramManagerWithShaderTest::kAttrib2Name = "attrib2";
+const char* ProgramManagerWithShaderTest::kAttrib3Name = "attrib3";
+const char* ProgramManagerWithShaderTest::kUniform1Name = "uniform1";
+// Correctly has array spec.
+const char* ProgramManagerWithShaderTest::kUniform2Name = "uniform2[0]";
+// Incorrectly missing array spec.
+const char* ProgramManagerWithShaderTest::kUniform3BadName = "uniform3";
+const char* ProgramManagerWithShaderTest::kUniform3GoodName = "uniform3[0]";
+
+TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) {
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ ASSERT_TRUE(program != NULL);
+ const Program::AttribInfoVector& infos =
+ program->GetAttribInfos();
+ ASSERT_EQ(kNumAttribs, infos.size());
+ for (size_t ii = 0; ii < kNumAttribs; ++ii) {
+ const Program::VertexAttrib& info = infos[ii];
+ const AttribInfo& expected = kAttribs[ii];
+ EXPECT_EQ(expected.size, info.size);
+ EXPECT_EQ(expected.type, info.type);
+ EXPECT_EQ(expected.location, info.location);
+ EXPECT_STREQ(expected.name, info.name.c_str());
+ }
+}
+
+TEST_F(ProgramManagerWithShaderTest, GetAttribInfo) {
+ const GLint kValidIndex = 1;
+ const GLint kInvalidIndex = 1000;
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ ASSERT_TRUE(program != NULL);
+ const Program::VertexAttrib* info =
+ program->GetAttribInfo(kValidIndex);
+ ASSERT_TRUE(info != NULL);
+ EXPECT_EQ(kAttrib2Size, info->size);
+ EXPECT_EQ(kAttrib2Type, info->type);
+ EXPECT_EQ(kAttrib2Location, info->location);
+ EXPECT_STREQ(kAttrib2Name, info->name.c_str());
+ EXPECT_TRUE(program->GetAttribInfo(kInvalidIndex) == NULL);
+}
+
+TEST_F(ProgramManagerWithShaderTest, GetAttribLocation) {
+ const char* kInvalidName = "foo";
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_EQ(kAttrib2Location, program->GetAttribLocation(kAttrib2Name));
+ EXPECT_EQ(-1, program->GetAttribLocation(kInvalidName));
+}
+
+TEST_F(ProgramManagerWithShaderTest, GetUniformInfo) {
+ const GLint kInvalidIndex = 1000;
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ ASSERT_TRUE(program != NULL);
+ const Program::UniformInfo* info =
+ program->GetUniformInfo(0);
+ ASSERT_TRUE(info != NULL);
+ EXPECT_EQ(kUniform1Size, info->size);
+ EXPECT_EQ(kUniform1Type, info->type);
+ EXPECT_EQ(kUniform1RealLocation, info->element_locations[0]);
+ EXPECT_STREQ(kUniform1Name, info->name.c_str());
+ info = program->GetUniformInfo(1);
+ ASSERT_TRUE(info != NULL);
+ EXPECT_EQ(kUniform2Size, info->size);
+ EXPECT_EQ(kUniform2Type, info->type);
+ EXPECT_EQ(kUniform2RealLocation, info->element_locations[0]);
+ EXPECT_STREQ(kUniform2Name, info->name.c_str());
+ info = program->GetUniformInfo(2);
+ // We emulate certain OpenGL drivers by supplying the name without
+ // the array spec. Our implementation should correctly add the required spec.
+ ASSERT_TRUE(info != NULL);
+ EXPECT_EQ(kUniform3Size, info->size);
+ EXPECT_EQ(kUniform3Type, info->type);
+ EXPECT_EQ(kUniform3RealLocation, info->element_locations[0]);
+ EXPECT_STREQ(kUniform3GoodName, info->name.c_str());
+ EXPECT_TRUE(program->GetUniformInfo(kInvalidIndex) == NULL);
+}
+
+TEST_F(ProgramManagerWithShaderTest, AttachDetachShader) {
+ static const GLuint kClientProgramId = 124;
+ static const GLuint kServiceProgramId = 457;
+ Program* program = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_FALSE(program->CanLink());
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_FALSE(program->CanLink());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ EXPECT_TRUE(program->CanLink());
+ program->DetachShader(&shader_manager_, vshader);
+ EXPECT_FALSE(program->CanLink());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->CanLink());
+ program->DetachShader(&shader_manager_, fshader);
+ EXPECT_FALSE(program->CanLink());
+ EXPECT_FALSE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_FALSE(program->CanLink());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ EXPECT_TRUE(program->CanLink());
+ vshader->SetStatus(false, "", NULL);
+ EXPECT_FALSE(program->CanLink());
+ vshader->SetStatus(true, "", NULL);
+ EXPECT_TRUE(program->CanLink());
+ fshader->SetStatus(false, "", NULL);
+ EXPECT_FALSE(program->CanLink());
+ fshader->SetStatus(true, "", NULL);
+ EXPECT_TRUE(program->CanLink());
+ EXPECT_TRUE(program->DetachShader(&shader_manager_, fshader));
+ EXPECT_FALSE(program->DetachShader(&shader_manager_, fshader));
+}
+
+TEST_F(ProgramManagerWithShaderTest, GetUniformFakeLocation) {
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_EQ(kUniform1FakeLocation,
+ program->GetUniformFakeLocation(kUniform1Name));
+ EXPECT_EQ(kUniform2FakeLocation,
+ program->GetUniformFakeLocation(kUniform2Name));
+ EXPECT_EQ(kUniform3FakeLocation,
+ program->GetUniformFakeLocation(kUniform3BadName));
+ // Check we can get uniform2 as "uniform2" even though the name is
+ // "uniform2[0]"
+ EXPECT_EQ(kUniform2FakeLocation,
+ program->GetUniformFakeLocation("uniform2"));
+ // Check we can get uniform3 as "uniform3[0]" even though we simulated GL
+ // returning "uniform3"
+ EXPECT_EQ(kUniform3FakeLocation,
+ program->GetUniformFakeLocation(kUniform3GoodName));
+ // Check that we can get the locations of the array elements > 1
+ EXPECT_EQ(ProgramManager::MakeFakeLocation(kUniform2FakeLocation, 1),
+ program->GetUniformFakeLocation("uniform2[1]"));
+ EXPECT_EQ(ProgramManager::MakeFakeLocation(kUniform2FakeLocation, 2),
+ program->GetUniformFakeLocation("uniform2[2]"));
+ EXPECT_EQ(-1, program->GetUniformFakeLocation("uniform2[3]"));
+ EXPECT_EQ(ProgramManager::MakeFakeLocation(kUniform3FakeLocation, 1),
+ program->GetUniformFakeLocation("uniform3[1]"));
+ EXPECT_EQ(-1, program->GetUniformFakeLocation("uniform3[2]"));
+}
+
+TEST_F(ProgramManagerWithShaderTest, GetUniformInfoByFakeLocation) {
+ const GLint kInvalidLocation = 1234;
+ const Program::UniformInfo* info;
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ GLint real_location = -1;
+ GLint array_index = -1;
+ ASSERT_TRUE(program != NULL);
+ info = program->GetUniformInfoByFakeLocation(
+ kUniform2FakeLocation, &real_location, &array_index);
+ EXPECT_EQ(kUniform2RealLocation, real_location);
+ EXPECT_EQ(0, array_index);
+ ASSERT_TRUE(info != NULL);
+ EXPECT_EQ(kUniform2Type, info->type);
+ real_location = -1;
+ array_index = -1;
+ info = program->GetUniformInfoByFakeLocation(
+ kInvalidLocation, &real_location, &array_index);
+ EXPECT_TRUE(info == NULL);
+ EXPECT_EQ(-1, real_location);
+ EXPECT_EQ(-1, array_index);
+ GLint loc = program->GetUniformFakeLocation("uniform2[2]");
+ info = program->GetUniformInfoByFakeLocation(
+ loc, &real_location, &array_index);
+ ASSERT_TRUE(info != NULL);
+ EXPECT_EQ(kUniform2RealLocation + 2 * 2, real_location);
+ EXPECT_EQ(2, array_index);
+}
+
+// Some GL drivers incorrectly return gl_DepthRange and possibly other uniforms
+// that start with "gl_". Our implementation catches these and does not allow
+// them back to client.
+TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsGLUnderscoreUniform) {
+ static const char* kUniform2Name = "gl_longNameWeCanCheckFor";
+ static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
+ { kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1FakeLocation,
+ kUniform1RealLocation,
+ kUniform1DesiredLocation,
+ kUniform1Name,
+ },
+ { kUniform2Name,
+ kUniform2Size,
+ kUniform2Type,
+ kUniform2FakeLocation,
+ kUniform2RealLocation,
+ kUniform2DesiredLocation,
+ kUniform2Name,
+ },
+ { kUniform3BadName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3FakeLocation,
+ kUniform3RealLocation,
+ kUniform3DesiredLocation,
+ kUniform3GoodName,
+ },
+ };
+ const size_t kNumUniforms = arraysize(kUniforms);
+ static const GLuint kClientProgramId = 1234;
+ static const GLuint kServiceProgramId = 5679;
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ SetupShader(
+ kAttribs, kNumAttribs, kUniforms, kNumUniforms, kServiceProgramId);
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ Program* program =
+ manager_.CreateProgram(kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+ GLint value = 0;
+ program->GetProgramiv(GL_ACTIVE_ATTRIBUTES, &value);
+ EXPECT_EQ(3, value);
+ // Check that we skipped the "gl_" uniform.
+ program->GetProgramiv(GL_ACTIVE_UNIFORMS, &value);
+ EXPECT_EQ(2, value);
+ // Check that our max length adds room for the array spec and is not as long
+ // as the "gl_" uniform we skipped.
+ // +4u is to account for "gl_" and NULL terminator.
+ program->GetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH, &value);
+ EXPECT_EQ(strlen(kUniform3BadName) + 4u, static_cast<size_t>(value));
+}
+
+// Test the bug comparing similar array names is fixed.
+TEST_F(ProgramManagerWithShaderTest, SimilarArrayNames) {
+ static const char* kUniform2Name = "u_nameLong[0]";
+ static const char* kUniform3Name = "u_name[0]";
+ static const GLint kUniform2Size = 2;
+ static const GLint kUniform3Size = 2;
+ static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
+ { kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1FakeLocation,
+ kUniform1RealLocation,
+ kUniform1DesiredLocation,
+ kUniform1Name,
+ },
+ { kUniform2Name,
+ kUniform2Size,
+ kUniform2Type,
+ kUniform2FakeLocation,
+ kUniform2RealLocation,
+ kUniform2DesiredLocation,
+ kUniform2Name,
+ },
+ { kUniform3Name,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3FakeLocation,
+ kUniform3RealLocation,
+ kUniform3DesiredLocation,
+ kUniform3Name,
+ },
+ };
+ const size_t kNumUniforms = arraysize(kUniforms);
+ static const GLuint kClientProgramId = 1234;
+ static const GLuint kServiceProgramId = 5679;
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ SetupShader(
+ kAttribs, kNumAttribs, kUniforms, kNumUniforms, kServiceProgramId);
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ Program* program =
+ manager_.CreateProgram(kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+
+ // Check that we get the correct locations.
+ EXPECT_EQ(kUniform2FakeLocation,
+ program->GetUniformFakeLocation(kUniform2Name));
+ EXPECT_EQ(kUniform3FakeLocation,
+ program->GetUniformFakeLocation(kUniform3Name));
+}
+
+// Some GL drivers incorrectly return the wrong type. For example they return
+// GL_FLOAT_VEC2 when they should return GL_FLOAT_MAT2. Check we handle this.
+TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) {
+ static GLenum kAttrib2BadType = GL_FLOAT_VEC2;
+ static GLenum kAttrib2GoodType = GL_FLOAT_MAT2;
+ static GLenum kUniform2BadType = GL_FLOAT_VEC3;
+ static GLenum kUniform2GoodType = GL_FLOAT_MAT3;
+ MockShaderTranslator shader_translator;
+ ShaderTranslator::VariableMap attrib_map;
+ ShaderTranslator::VariableMap uniform_map;
+ attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
+ kAttrib1Type, kAttrib1Size, kAttrib1Name);
+ attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
+ kAttrib2GoodType, kAttrib2Size, kAttrib2Name);
+ attrib_map[kAttrib3Name] = ShaderTranslatorInterface::VariableInfo(
+ kAttrib3Type, kAttrib3Size, kAttrib3Name);
+ uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
+ kUniform1Type, kUniform1Size, kUniform1Name);
+ uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
+ kUniform2GoodType, kUniform2Size, kUniform2Name);
+ uniform_map[kUniform3GoodName] = ShaderTranslatorInterface::VariableInfo(
+ kUniform3Type, kUniform3Size, kUniform3GoodName);
+ EXPECT_CALL(shader_translator, attrib_map())
+ .WillRepeatedly(ReturnRef(attrib_map));
+ EXPECT_CALL(shader_translator, uniform_map())
+ .WillRepeatedly(ReturnRef(uniform_map));
+ ShaderTranslator::NameMap name_map;
+ EXPECT_CALL(shader_translator, name_map())
+ .WillRepeatedly(ReturnRef(name_map));
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", &shader_translator);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", &shader_translator);
+ static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2BadType, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
+ { kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1FakeLocation,
+ kUniform1RealLocation,
+ kUniform1DesiredLocation,
+ kUniform1Name,
+ },
+ { kUniform2Name,
+ kUniform2Size,
+ kUniform2BadType,
+ kUniform2FakeLocation,
+ kUniform2RealLocation,
+ kUniform2DesiredLocation,
+ kUniform2Name,
+ },
+ { kUniform3BadName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3FakeLocation,
+ kUniform3RealLocation,
+ kUniform3DesiredLocation,
+ kUniform3GoodName,
+ },
+ };
+ const size_t kNumAttribs= arraysize(kAttribs);
+ const size_t kNumUniforms = arraysize(kUniforms);
+ static const GLuint kClientProgramId = 1234;
+ static const GLuint kServiceProgramId = 5679;
+ SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
+ kServiceProgramId);
+ Program* program = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program!= NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+ // Check that we got the good type, not the bad.
+ // Check Attribs
+ for (unsigned index = 0; index < kNumAttribs; ++index) {
+ const Program::VertexAttrib* attrib_info =
+ program->GetAttribInfo(index);
+ ASSERT_TRUE(attrib_info != NULL);
+ ShaderTranslator::VariableMap::const_iterator it = attrib_map.find(
+ attrib_info->name);
+ ASSERT_TRUE(it != attrib_map.end());
+ EXPECT_EQ(it->first, attrib_info->name);
+ EXPECT_EQ(static_cast<GLenum>(it->second.type), attrib_info->type);
+ EXPECT_EQ(it->second.size, attrib_info->size);
+ EXPECT_EQ(it->second.name, attrib_info->name);
+ }
+ // Check Uniforms
+ for (unsigned index = 0; index < kNumUniforms; ++index) {
+ const Program::UniformInfo* uniform_info =
+ program->GetUniformInfo(index);
+ ASSERT_TRUE(uniform_info != NULL);
+ ShaderTranslator::VariableMap::const_iterator it = uniform_map.find(
+ uniform_info->name);
+ ASSERT_TRUE(it != uniform_map.end());
+ EXPECT_EQ(it->first, uniform_info->name);
+ EXPECT_EQ(static_cast<GLenum>(it->second.type), uniform_info->type);
+ EXPECT_EQ(it->second.size, uniform_info->size);
+ EXPECT_EQ(it->second.name, uniform_info->name);
+ }
+}
+
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount) {
+ static const GLuint kClientProgramId = 124;
+ static const GLuint kServiceProgramId = 457;
+ Program* program = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_FALSE(program->CanLink());
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(vshader->InUse());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ EXPECT_TRUE(fshader->InUse());
+ EXPECT_TRUE(program->CanLink());
+ EXPECT_FALSE(program->InUse());
+ EXPECT_FALSE(program->IsDeleted());
+ manager_.UseProgram(program);
+ EXPECT_TRUE(program->InUse());
+ manager_.UseProgram(program);
+ EXPECT_TRUE(program->InUse());
+ manager_.MarkAsDeleted(&shader_manager_, program);
+ EXPECT_TRUE(program->IsDeleted());
+ Program* info2 = manager_.GetProgram(kClientProgramId);
+ EXPECT_EQ(program, info2);
+ manager_.UnuseProgram(&shader_manager_, program);
+ EXPECT_TRUE(program->InUse());
+ // this should delete the info.
+ EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_.UnuseProgram(&shader_manager_, program);
+ info2 = manager_.GetProgram(kClientProgramId);
+ EXPECT_TRUE(info2 == NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+}
+
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount2) {
+ static const GLuint kClientProgramId = 124;
+ static const GLuint kServiceProgramId = 457;
+ Program* program = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_FALSE(program->CanLink());
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, "", NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, "", NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(vshader->InUse());
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ EXPECT_TRUE(fshader->InUse());
+ EXPECT_TRUE(program->CanLink());
+ EXPECT_FALSE(program->InUse());
+ EXPECT_FALSE(program->IsDeleted());
+ manager_.UseProgram(program);
+ EXPECT_TRUE(program->InUse());
+ manager_.UseProgram(program);
+ EXPECT_TRUE(program->InUse());
+ manager_.UnuseProgram(&shader_manager_, program);
+ EXPECT_TRUE(program->InUse());
+ manager_.UnuseProgram(&shader_manager_, program);
+ EXPECT_FALSE(program->InUse());
+ Program* info2 = manager_.GetProgram(kClientProgramId);
+ EXPECT_EQ(program, info2);
+ // this should delete the program.
+ EXPECT_CALL(*gl_, DeleteProgram(kServiceProgramId))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_.MarkAsDeleted(&shader_manager_, program);
+ info2 = manager_.GetProgram(kClientProgramId);
+ EXPECT_TRUE(info2 == NULL);
+ EXPECT_FALSE(vshader->InUse());
+ EXPECT_FALSE(fshader->InUse());
+}
+
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetProgramInfo) {
+ CommonDecoder::Bucket bucket;
+ const Program* program = manager_.GetProgram(kClientProgramId);
+ ASSERT_TRUE(program != NULL);
+ program->GetProgramInfo(&manager_, &bucket);
+ ProgramInfoHeader* header =
+ bucket.GetDataAs<ProgramInfoHeader*>(0, sizeof(ProgramInfoHeader));
+ ASSERT_TRUE(header != NULL);
+ EXPECT_EQ(1u, header->link_status);
+ EXPECT_EQ(arraysize(kAttribs), header->num_attribs);
+ EXPECT_EQ(arraysize(kUniforms), header->num_uniforms);
+ const ProgramInput* inputs = bucket.GetDataAs<const ProgramInput*>(
+ sizeof(*header),
+ sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
+ ASSERT_TRUE(inputs != NULL);
+ const ProgramInput* input = inputs;
+ // TODO(gman): Don't assume these are in order.
+ for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
+ const AttribInfo& expected = kAttribs[ii];
+ EXPECT_EQ(expected.size, input->size);
+ EXPECT_EQ(expected.type, input->type);
+ const int32* location = bucket.GetDataAs<const int32*>(
+ input->location_offset, sizeof(int32));
+ ASSERT_TRUE(location != NULL);
+ EXPECT_EQ(expected.location, *location);
+ const char* name_buf = bucket.GetDataAs<const char*>(
+ input->name_offset, input->name_length);
+ ASSERT_TRUE(name_buf != NULL);
+ std::string name(name_buf, input->name_length);
+ EXPECT_STREQ(expected.name, name.c_str());
+ ++input;
+ }
+ // TODO(gman): Don't assume these are in order.
+ for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
+ const UniformInfo& expected = kUniforms[ii];
+ EXPECT_EQ(expected.size, input->size);
+ EXPECT_EQ(expected.type, input->type);
+ const int32* locations = bucket.GetDataAs<const int32*>(
+ input->location_offset, sizeof(int32) * input->size);
+ ASSERT_TRUE(locations != NULL);
+ for (int32 jj = 0; jj < input->size; ++jj) {
+ EXPECT_EQ(
+ ProgramManager::MakeFakeLocation(expected.fake_location, jj),
+ locations[jj]);
+ }
+ const char* name_buf = bucket.GetDataAs<const char*>(
+ input->name_offset, input->name_length);
+ ASSERT_TRUE(name_buf != NULL);
+ std::string name(name_buf, input->name_length);
+ EXPECT_STREQ(expected.good_name, name.c_str());
+ ++input;
+ }
+ EXPECT_EQ(header->num_attribs + header->num_uniforms,
+ static_cast<uint32>(input - inputs));
+}
+
+TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) {
+ // Set up shader
+ const GLuint kVShaderClientId = 1;
+ const GLuint kVShaderServiceId = 11;
+ const GLuint kFShaderClientId = 2;
+ const GLuint kFShaderServiceId = 12;
+ MockShaderTranslator shader_translator;
+ ShaderTranslator::VariableMap attrib_map;
+ for (uint32 ii = 0; ii < kNumAttribs; ++ii) {
+ attrib_map[kAttribs[ii].name] = ShaderTranslatorInterface::VariableInfo(
+ kAttribs[ii].type, kAttribs[ii].size, kAttribs[ii].name);
+ }
+ ShaderTranslator::VariableMap uniform_map;
+ EXPECT_CALL(shader_translator, attrib_map())
+ .WillRepeatedly(ReturnRef(attrib_map));
+ EXPECT_CALL(shader_translator, uniform_map())
+ .WillRepeatedly(ReturnRef(uniform_map));
+ ShaderTranslator::NameMap name_map;
+ EXPECT_CALL(shader_translator, name_map())
+ .WillRepeatedly(ReturnRef(name_map));
+ // Check we can create shader.
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ // Check shader got created.
+ ASSERT_TRUE(vshader != NULL && fshader != NULL);
+ // Set Status
+ vshader->SetStatus(true, "", &shader_translator);
+ // Check attrib infos got copied.
+ for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin();
+ it != attrib_map.end(); ++it) {
+ const Shader::VariableInfo* variable_info =
+ vshader->GetAttribInfo(it->first);
+ ASSERT_TRUE(variable_info != NULL);
+ EXPECT_EQ(it->second.type, variable_info->type);
+ EXPECT_EQ(it->second.size, variable_info->size);
+ EXPECT_EQ(it->second.name, variable_info->name);
+ }
+ fshader->SetStatus(true, "", NULL);
+
+ // Set up program
+ const GLuint kClientProgramId = 6666;
+ const GLuint kServiceProgramId = 8888;
+ Program* program =
+ manager_.CreateProgram(kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+
+ EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+ EXPECT_TRUE(LinkAsExpected(program, true));
+
+ program->SetAttribLocationBinding(kAttrib1Name, 0);
+ EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+ EXPECT_TRUE(LinkAsExpected(program, true));
+
+ program->SetAttribLocationBinding("xxx", 0);
+ EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+ EXPECT_TRUE(LinkAsExpected(program, true));
+
+ program->SetAttribLocationBinding(kAttrib2Name, 1);
+ EXPECT_FALSE(program->DetectAttribLocationBindingConflicts());
+ EXPECT_TRUE(LinkAsExpected(program, true));
+
+ program->SetAttribLocationBinding(kAttrib2Name, 0);
+ EXPECT_TRUE(program->DetectAttribLocationBindingConflicts());
+ EXPECT_TRUE(LinkAsExpected(program, false));
+}
+
+TEST_F(ProgramManagerWithShaderTest, ClearWithSamplerTypes) {
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, NULL, NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, NULL, NULL);
+ static const GLuint kClientProgramId = 1234;
+ static const GLuint kServiceProgramId = 5679;
+ Program* program = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+
+ static const GLenum kSamplerTypes[] = {
+ GL_SAMPLER_2D,
+ GL_SAMPLER_CUBE,
+ GL_SAMPLER_EXTERNAL_OES,
+ GL_SAMPLER_3D_OES,
+ GL_SAMPLER_2D_RECT_ARB,
+ };
+ const size_t kNumSamplerTypes = arraysize(kSamplerTypes);
+ for (size_t ii = 0; ii < kNumSamplerTypes; ++ii) {
+ static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
+ { kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1FakeLocation,
+ kUniform1RealLocation,
+ kUniform1DesiredLocation,
+ kUniform1Name,
+ },
+ { kUniform2Name,
+ kUniform2Size,
+ kSamplerTypes[ii],
+ kUniform2FakeLocation,
+ kUniform2RealLocation,
+ kUniform2DesiredLocation,
+ kUniform2Name,
+ },
+ { kUniform3BadName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3FakeLocation,
+ kUniform3RealLocation,
+ kUniform3DesiredLocation,
+ kUniform3GoodName,
+ },
+ };
+ const size_t kNumAttribs = arraysize(kAttribs);
+ const size_t kNumUniforms = arraysize(kUniforms);
+ SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
+ kServiceProgramId);
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+ SetupExpectationsForClearingUniforms(kUniforms, kNumUniforms);
+ manager_.ClearUniforms(program);
+ }
+}
+
+TEST_F(ProgramManagerWithShaderTest, BindUniformLocation) {
+ const GLuint kVShaderClientId = 2001;
+ const GLuint kFShaderClientId = 2002;
+ const GLuint kVShaderServiceId = 3001;
+ const GLuint kFShaderServiceId = 3002;
+
+ const GLint kUniform1DesiredLocation = 10;
+ const GLint kUniform2DesiredLocation = -1;
+ const GLint kUniform3DesiredLocation = 5;
+
+ Shader* vshader = shader_manager_.CreateShader(
+ kVShaderClientId, kVShaderServiceId, GL_VERTEX_SHADER);
+ ASSERT_TRUE(vshader != NULL);
+ vshader->SetStatus(true, NULL, NULL);
+ Shader* fshader = shader_manager_.CreateShader(
+ kFShaderClientId, kFShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(fshader != NULL);
+ fshader->SetStatus(true, NULL, NULL);
+ static const GLuint kClientProgramId = 1234;
+ static const GLuint kServiceProgramId = 5679;
+ Program* program = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program != NULL);
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, vshader));
+ EXPECT_TRUE(program->AttachShader(&shader_manager_, fshader));
+ EXPECT_TRUE(program->SetUniformLocationBinding(
+ kUniform1Name, kUniform1DesiredLocation));
+ EXPECT_TRUE(program->SetUniformLocationBinding(
+ kUniform3BadName, kUniform3DesiredLocation));
+
+ static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = {
+ { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, },
+ { kAttrib2Name, kAttrib2Size, kAttrib2Type, kAttrib2Location, },
+ { kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
+ };
+ ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
+ { kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1FakeLocation,
+ kUniform1RealLocation,
+ kUniform1DesiredLocation,
+ kUniform1Name,
+ },
+ { kUniform2Name,
+ kUniform2Size,
+ kUniform2Type,
+ kUniform2FakeLocation,
+ kUniform2RealLocation,
+ kUniform2DesiredLocation,
+ kUniform2Name,
+ },
+ { kUniform3BadName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3FakeLocation,
+ kUniform3RealLocation,
+ kUniform3DesiredLocation,
+ kUniform3GoodName,
+ },
+ };
+
+ const size_t kNumAttribs = arraysize(kAttribs);
+ const size_t kNumUniforms = arraysize(kUniforms);
+ SetupShader(kAttribs, kNumAttribs, kUniforms, kNumUniforms,
+ kServiceProgramId);
+ program->Link(NULL, NULL, NULL, NULL, base::Bind(&ShaderCacheCb));
+
+ EXPECT_EQ(kUniform1DesiredLocation,
+ program->GetUniformFakeLocation(kUniform1Name));
+ EXPECT_EQ(kUniform3DesiredLocation,
+ program->GetUniformFakeLocation(kUniform3BadName));
+ EXPECT_EQ(kUniform3DesiredLocation,
+ program->GetUniformFakeLocation(kUniform3GoodName));
+}
+
+class ProgramManagerWithCacheTest : public testing::Test {
+ public:
+ static const GLuint kClientProgramId = 1;
+ static const GLuint kServiceProgramId = 10;
+ static const GLuint kVertexShaderClientId = 2;
+ static const GLuint kFragmentShaderClientId = 20;
+ static const GLuint kVertexShaderServiceId = 3;
+ static const GLuint kFragmentShaderServiceId = 30;
+
+ ProgramManagerWithCacheTest()
+ : cache_(new MockProgramCache()),
+ manager_(cache_.get()),
+ vertex_shader_(NULL),
+ fragment_shader_(NULL),
+ program_(NULL) {
+ }
+ virtual ~ProgramManagerWithCacheTest() {
+ manager_.Destroy(false);
+ shader_manager_.Destroy(false);
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new StrictMock<gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ vertex_shader_ = shader_manager_.CreateShader(
+ kVertexShaderClientId, kVertexShaderServiceId, GL_VERTEX_SHADER);
+ fragment_shader_ = shader_manager_.CreateShader(
+ kFragmentShaderClientId, kFragmentShaderServiceId, GL_FRAGMENT_SHADER);
+ ASSERT_TRUE(vertex_shader_ != NULL);
+ ASSERT_TRUE(fragment_shader_ != NULL);
+ vertex_shader_->UpdateSource("lka asjf bjajsdfj");
+ fragment_shader_->UpdateSource("lka asjf a fasgag 3rdsf3 bjajsdfj");
+
+ program_ = manager_.CreateProgram(
+ kClientProgramId, kServiceProgramId);
+ ASSERT_TRUE(program_ != NULL);
+
+ program_->AttachShader(&shader_manager_, vertex_shader_);
+ program_->AttachShader(&shader_manager_, fragment_shader_);
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ }
+
+ void SetShadersCompiled() {
+ vertex_shader_->SetStatus(true, NULL, NULL);
+ fragment_shader_->SetStatus(true, NULL, NULL);
+ }
+
+ void SetProgramCached() {
+ cache_->LinkedProgramCacheSuccess(
+ vertex_shader_->source()->c_str(),
+ NULL,
+ fragment_shader_->source()->c_str(),
+ NULL,
+ &program_->bind_attrib_location_map());
+ }
+
+ void SetExpectationsForProgramCached() {
+ SetExpectationsForProgramCached(program_,
+ vertex_shader_,
+ fragment_shader_);
+ }
+
+ void SetExpectationsForProgramCached(
+ Program* program,
+ Shader* vertex_shader,
+ Shader* fragment_shader) {
+ EXPECT_CALL(*cache_.get(), SaveLinkedProgram(
+ program->service_id(),
+ vertex_shader,
+ NULL,
+ fragment_shader,
+ NULL,
+ &program->bind_attrib_location_map(),
+ _)).Times(1);
+ }
+
+ void SetExpectationsForNotCachingProgram() {
+ SetExpectationsForNotCachingProgram(program_,
+ vertex_shader_,
+ fragment_shader_);
+ }
+
+ void SetExpectationsForNotCachingProgram(
+ Program* program,
+ Shader* vertex_shader,
+ Shader* fragment_shader) {
+ EXPECT_CALL(*cache_.get(), SaveLinkedProgram(
+ program->service_id(),
+ vertex_shader,
+ NULL,
+ fragment_shader,
+ NULL,
+ &program->bind_attrib_location_map(),
+ _)).Times(0);
+ }
+
+ void SetExpectationsForProgramLoad(ProgramCache::ProgramLoadResult result) {
+ SetExpectationsForProgramLoad(kServiceProgramId,
+ program_,
+ vertex_shader_,
+ fragment_shader_,
+ result);
+ }
+
+ void SetExpectationsForProgramLoad(
+ GLuint service_program_id,
+ Program* program,
+ Shader* vertex_shader,
+ Shader* fragment_shader,
+ ProgramCache::ProgramLoadResult result) {
+ EXPECT_CALL(*cache_.get(),
+ LoadLinkedProgram(service_program_id,
+ vertex_shader,
+ NULL,
+ fragment_shader,
+ NULL,
+ &program->bind_attrib_location_map(),
+ _))
+ .WillOnce(Return(result));
+ }
+
+ void SetExpectationsForProgramLoadSuccess() {
+ SetExpectationsForProgramLoadSuccess(kServiceProgramId);
+ }
+
+ void SetExpectationsForProgramLoadSuccess(GLuint service_program_id) {
+ TestHelper::SetupProgramSuccessExpectations(gl_.get(),
+ NULL,
+ 0,
+ NULL,
+ 0,
+ service_program_id);
+ }
+
+ void SetExpectationsForProgramLink() {
+ SetExpectationsForProgramLink(kServiceProgramId);
+ }
+
+ void SetExpectationsForProgramLink(GLuint service_program_id) {
+ TestHelper::SetupShader(gl_.get(), NULL, 0, NULL, 0, service_program_id);
+ if (gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) {
+ EXPECT_CALL(*gl_.get(),
+ ProgramParameteri(service_program_id,
+ PROGRAM_BINARY_RETRIEVABLE_HINT,
+ GL_TRUE)).Times(1);
+ }
+ }
+
+ void SetExpectationsForSuccessCompile(
+ const Shader* shader) {
+ const GLuint shader_id = shader->service_id();
+ const char* src = shader->source()->c_str();
+ EXPECT_CALL(*gl_.get(),
+ ShaderSource(shader_id, 1, Pointee(src), NULL)).Times(1);
+ EXPECT_CALL(*gl_.get(), CompileShader(shader_id)).Times(1);
+ EXPECT_CALL(*gl_.get(), GetShaderiv(shader_id, GL_COMPILE_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(GL_TRUE));
+ }
+
+ void SetExpectationsForNoCompile(const Shader* shader) {
+ const GLuint shader_id = shader->service_id();
+ const char* src = shader->source()->c_str();
+ EXPECT_CALL(*gl_.get(),
+ ShaderSource(shader_id, 1, Pointee(src), NULL)).Times(0);
+ EXPECT_CALL(*gl_.get(), CompileShader(shader_id)).Times(0);
+ EXPECT_CALL(*gl_.get(), GetShaderiv(shader_id, GL_COMPILE_STATUS, _))
+ .Times(0);
+ }
+
+ void SetExpectationsForErrorCompile(const Shader* shader) {
+ const GLuint shader_id = shader->service_id();
+ const char* src = shader->source()->c_str();
+ EXPECT_CALL(*gl_.get(),
+ ShaderSource(shader_id, 1, Pointee(src), NULL)).Times(1);
+ EXPECT_CALL(*gl_.get(), CompileShader(shader_id)).Times(1);
+ EXPECT_CALL(*gl_.get(), GetShaderiv(shader_id, GL_COMPILE_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(GL_FALSE));
+ EXPECT_CALL(*gl_.get(), GetShaderiv(shader_id, GL_INFO_LOG_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0));
+ EXPECT_CALL(*gl_.get(), GetShaderInfoLog(shader_id, 0, _, _))
+ .Times(1);
+ }
+
+ scoped_ptr<StrictMock<gfx::MockGLInterface> > gl_;
+
+ scoped_ptr<MockProgramCache> cache_;
+ ProgramManager manager_;
+
+ Shader* vertex_shader_;
+ Shader* fragment_shader_;
+ Program* program_;
+ ShaderManager shader_manager_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLuint ProgramManagerWithCacheTest::kClientProgramId;
+const GLuint ProgramManagerWithCacheTest::kServiceProgramId;
+const GLuint ProgramManagerWithCacheTest::kVertexShaderClientId;
+const GLuint ProgramManagerWithCacheTest::kFragmentShaderClientId;
+const GLuint ProgramManagerWithCacheTest::kVertexShaderServiceId;
+const GLuint ProgramManagerWithCacheTest::kFragmentShaderServiceId;
+#endif
+
+TEST_F(ProgramManagerWithCacheTest, CacheProgramOnSuccessfulLink) {
+ SetShadersCompiled();
+ SetExpectationsForProgramLink();
+ SetExpectationsForProgramCached();
+ EXPECT_TRUE(program_->Link(NULL, NULL, NULL, NULL,
+ base::Bind(&ShaderCacheCb)));
+}
+
+TEST_F(ProgramManagerWithCacheTest, LoadProgramOnProgramCacheHit) {
+ SetShadersCompiled();
+ SetProgramCached();
+
+ SetExpectationsForNoCompile(vertex_shader_);
+ SetExpectationsForNoCompile(fragment_shader_);
+ SetExpectationsForProgramLoad(ProgramCache::PROGRAM_LOAD_SUCCESS);
+ SetExpectationsForNotCachingProgram();
+ SetExpectationsForProgramLoadSuccess();
+
+ EXPECT_TRUE(program_->Link(NULL, NULL, NULL, NULL,
+ base::Bind(&ShaderCacheCb)));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/query_manager.cc b/chromium/gpu/command_buffer/service/query_manager.cc
new file mode 100644
index 00000000000..7566099b6f8
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/query_manager.cc
@@ -0,0 +1,679 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/query_manager.h"
+
+#include "base/atomicops.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/memory/shared_memory.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_manager.h"
+#include "gpu/command_buffer/service/error_state.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+namespace gpu {
+namespace gles2 {
+
+namespace {
+
+class AsyncPixelTransferCompletionObserverImpl
+ : public AsyncPixelTransferCompletionObserver {
+ public:
+ AsyncPixelTransferCompletionObserverImpl(uint32 submit_count)
+ : submit_count_(submit_count),
+ cancelled_(false) {}
+
+ void Cancel() {
+ base::AutoLock locked(lock_);
+ cancelled_ = true;
+ }
+
+ virtual void DidComplete(const AsyncMemoryParams& mem_params) OVERRIDE {
+ base::AutoLock locked(lock_);
+ if (!cancelled_) {
+ DCHECK(mem_params.shared_memory);
+ DCHECK(mem_params.shared_memory->memory());
+ void* data = static_cast<int8*>(mem_params.shared_memory->memory()) +
+ mem_params.shm_data_offset;
+ QuerySync* sync = static_cast<QuerySync*>(data);
+
+ // Need a MemoryBarrier here to ensure that upload completed before
+ // submit_count was written to sync->process_count.
+ base::subtle::MemoryBarrier();
+ sync->process_count = submit_count_;
+ }
+ }
+
+ private:
+ virtual ~AsyncPixelTransferCompletionObserverImpl() {}
+
+ uint32 submit_count_;
+
+ base::Lock lock_;
+ bool cancelled_;
+
+ DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferCompletionObserverImpl);
+};
+
+class AsyncPixelTransfersCompletedQuery
+ : public QueryManager::Query,
+ public base::SupportsWeakPtr<AsyncPixelTransfersCompletedQuery> {
+ public:
+ AsyncPixelTransfersCompletedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ virtual ~AsyncPixelTransfersCompletedQuery();
+
+ scoped_refptr<AsyncPixelTransferCompletionObserverImpl> observer_;
+};
+
+AsyncPixelTransfersCompletedQuery::AsyncPixelTransfersCompletedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+}
+
+bool AsyncPixelTransfersCompletedQuery::Begin() {
+ return true;
+}
+
+bool AsyncPixelTransfersCompletedQuery::End(uint32 submit_count) {
+ AsyncMemoryParams mem_params;
+ // Get the real shared memory since it might need to be duped to prevent
+ // use-after-free of the memory.
+ Buffer buffer = manager()->decoder()->GetSharedMemoryBuffer(shm_id());
+ if (!buffer.shared_memory)
+ return false;
+ mem_params.shared_memory = buffer.shared_memory;
+ mem_params.shm_size = buffer.size;
+ mem_params.shm_data_offset = shm_offset();
+ mem_params.shm_data_size = sizeof(QuerySync);
+
+ observer_ = new AsyncPixelTransferCompletionObserverImpl(submit_count);
+
+ // Ask AsyncPixelTransferDelegate to run completion callback after all
+ // previous async transfers are done. No guarantee that callback is run
+ // on the current thread.
+ manager()->decoder()->GetAsyncPixelTransferManager()
+ ->AsyncNotifyCompletion(mem_params, observer_);
+
+ return AddToPendingTransferQueue(submit_count);
+}
+
+bool AsyncPixelTransfersCompletedQuery::Process() {
+ QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
+ shm_id(), shm_offset(), sizeof(*sync));
+ if (!sync)
+ return false;
+
+ // Check if completion callback has been run. sync->process_count atomicity
+ // is guaranteed as this is already used to notify client of a completed
+ // query.
+ if (sync->process_count != submit_count())
+ return true;
+
+ UnmarkAsPending();
+ return true;
+}
+
+void AsyncPixelTransfersCompletedQuery::Destroy(bool /* have_context */) {
+ if (!IsDeleted()) {
+ MarkAsDeleted();
+ }
+}
+
+AsyncPixelTransfersCompletedQuery::~AsyncPixelTransfersCompletedQuery() {
+ if (observer_)
+ observer_->Cancel();
+}
+
+} // namespace
+
+class AllSamplesPassedQuery : public QueryManager::Query {
+ public:
+ AllSamplesPassedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
+ GLuint service_id);
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ virtual ~AllSamplesPassedQuery();
+
+ private:
+ // Service side query id.
+ GLuint service_id_;
+};
+
+AllSamplesPassedQuery::AllSamplesPassedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset,
+ GLuint service_id)
+ : Query(manager, target, shm_id, shm_offset),
+ service_id_(service_id) {
+}
+
+bool AllSamplesPassedQuery::Begin() {
+ BeginQueryHelper(target(), service_id_);
+ return true;
+}
+
+bool AllSamplesPassedQuery::End(uint32 submit_count) {
+ EndQueryHelper(target());
+ return AddToPendingQueue(submit_count);
+}
+
+bool AllSamplesPassedQuery::Process() {
+ GLuint available = 0;
+ glGetQueryObjectuivARB(
+ service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
+ if (!available) {
+ return true;
+ }
+ GLuint result = 0;
+ glGetQueryObjectuivARB(
+ service_id_, GL_QUERY_RESULT_EXT, &result);
+
+ return MarkAsCompleted(result != 0);
+}
+
+void AllSamplesPassedQuery::Destroy(bool have_context) {
+ if (have_context && !IsDeleted()) {
+ glDeleteQueriesARB(1, &service_id_);
+ MarkAsDeleted();
+ }
+}
+
+AllSamplesPassedQuery::~AllSamplesPassedQuery() {
+}
+
+class CommandsIssuedQuery : public QueryManager::Query {
+ public:
+ CommandsIssuedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ virtual ~CommandsIssuedQuery();
+
+ private:
+ base::TimeTicks begin_time_;
+};
+
+CommandsIssuedQuery::CommandsIssuedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+}
+
+bool CommandsIssuedQuery::Begin() {
+ begin_time_ = base::TimeTicks::HighResNow();
+ return true;
+}
+
+bool CommandsIssuedQuery::End(uint32 submit_count) {
+ base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
+ MarkAsPending(submit_count);
+ return MarkAsCompleted(elapsed.InMicroseconds());
+}
+
+bool CommandsIssuedQuery::Process() {
+ NOTREACHED();
+ return true;
+}
+
+void CommandsIssuedQuery::Destroy(bool /* have_context */) {
+ if (!IsDeleted()) {
+ MarkAsDeleted();
+ }
+}
+
+CommandsIssuedQuery::~CommandsIssuedQuery() {
+}
+
+class CommandLatencyQuery : public QueryManager::Query {
+ public:
+ CommandLatencyQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ virtual ~CommandLatencyQuery();
+};
+
+CommandLatencyQuery::CommandLatencyQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+}
+
+bool CommandLatencyQuery::Begin() {
+ return true;
+}
+
+bool CommandLatencyQuery::End(uint32 submit_count) {
+ base::TimeDelta now = base::TimeTicks::HighResNow() - base::TimeTicks();
+ MarkAsPending(submit_count);
+ return MarkAsCompleted(now.InMicroseconds());
+}
+
+bool CommandLatencyQuery::Process() {
+ NOTREACHED();
+ return true;
+}
+
+void CommandLatencyQuery::Destroy(bool /* have_context */) {
+ if (!IsDeleted()) {
+ MarkAsDeleted();
+ }
+}
+
+CommandLatencyQuery::~CommandLatencyQuery() {
+}
+
+
+class AsyncReadPixelsCompletedQuery
+ : public QueryManager::Query,
+ public base::SupportsWeakPtr<AsyncReadPixelsCompletedQuery> {
+ public:
+ AsyncReadPixelsCompletedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ void Complete();
+ virtual ~AsyncReadPixelsCompletedQuery();
+};
+
+AsyncReadPixelsCompletedQuery::AsyncReadPixelsCompletedQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+}
+
+bool AsyncReadPixelsCompletedQuery::Begin() {
+ return true;
+}
+
+bool AsyncReadPixelsCompletedQuery::End(uint32 submit_count) {
+ if (!AddToPendingQueue(submit_count)) {
+ return false;
+ }
+ manager()->decoder()->WaitForReadPixels(
+ base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
+ AsWeakPtr()));
+
+ return true;
+}
+
+void AsyncReadPixelsCompletedQuery::Complete() {
+ MarkAsCompleted(1);
+}
+
+bool AsyncReadPixelsCompletedQuery::Process() {
+ return true;
+}
+
+void AsyncReadPixelsCompletedQuery::Destroy(bool /* have_context */) {
+ if (!IsDeleted()) {
+ MarkAsDeleted();
+ }
+}
+
+AsyncReadPixelsCompletedQuery::~AsyncReadPixelsCompletedQuery() {
+}
+
+
+class GetErrorQuery : public QueryManager::Query {
+ public:
+ GetErrorQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ virtual bool Begin() OVERRIDE;
+ virtual bool End(uint32 submit_count) OVERRIDE;
+ virtual bool Process() OVERRIDE;
+ virtual void Destroy(bool have_context) OVERRIDE;
+
+ protected:
+ virtual ~GetErrorQuery();
+
+ private:
+};
+
+GetErrorQuery::GetErrorQuery(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : Query(manager, target, shm_id, shm_offset) {
+}
+
+bool GetErrorQuery::Begin() {
+ return true;
+}
+
+bool GetErrorQuery::End(uint32 submit_count) {
+ MarkAsPending(submit_count);
+ return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
+}
+
+bool GetErrorQuery::Process() {
+ NOTREACHED();
+ return true;
+}
+
+void GetErrorQuery::Destroy(bool /* have_context */) {
+ if (!IsDeleted()) {
+ MarkAsDeleted();
+ }
+}
+
+GetErrorQuery::~GetErrorQuery() {
+}
+
+QueryManager::QueryManager(
+ GLES2Decoder* decoder,
+ FeatureInfo* feature_info)
+ : decoder_(decoder),
+ use_arb_occlusion_query2_for_occlusion_query_boolean_(
+ feature_info->feature_flags(
+ ).use_arb_occlusion_query2_for_occlusion_query_boolean),
+ use_arb_occlusion_query_for_occlusion_query_boolean_(
+ feature_info->feature_flags(
+ ).use_arb_occlusion_query_for_occlusion_query_boolean),
+ query_count_(0) {
+ DCHECK(!(use_arb_occlusion_query_for_occlusion_query_boolean_ &&
+ use_arb_occlusion_query2_for_occlusion_query_boolean_));
+}
+
+QueryManager::~QueryManager() {
+ DCHECK(queries_.empty());
+
+ // If this triggers, that means something is keeping a reference to
+ // a Query belonging to this.
+ CHECK_EQ(query_count_, 0u);
+}
+
+void QueryManager::Destroy(bool have_context) {
+ pending_queries_.clear();
+ pending_transfer_queries_.clear();
+ while (!queries_.empty()) {
+ Query* query = queries_.begin()->second.get();
+ query->Destroy(have_context);
+ queries_.erase(queries_.begin());
+ }
+}
+
+QueryManager::Query* QueryManager::CreateQuery(
+ GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset) {
+ scoped_refptr<Query> query;
+ switch (target) {
+ case GL_COMMANDS_ISSUED_CHROMIUM:
+ query = new CommandsIssuedQuery(this, target, shm_id, shm_offset);
+ break;
+ case GL_LATENCY_QUERY_CHROMIUM:
+ query = new CommandLatencyQuery(this, target, shm_id, shm_offset);
+ break;
+ case GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM:
+ query = new AsyncPixelTransfersCompletedQuery(
+ this, target, shm_id, shm_offset);
+ break;
+ case GL_ASYNC_READ_PIXELS_COMPLETED_CHROMIUM:
+ query = new AsyncReadPixelsCompletedQuery(
+ this, target, shm_id, shm_offset);
+ break;
+ case GL_GET_ERROR_QUERY_CHROMIUM:
+ query = new GetErrorQuery(this, target, shm_id, shm_offset);
+ break;
+ default: {
+ GLuint service_id = 0;
+ glGenQueriesARB(1, &service_id);
+ DCHECK_NE(0u, service_id);
+ query = new AllSamplesPassedQuery(
+ this, target, shm_id, shm_offset, service_id);
+ break;
+ }
+ }
+ std::pair<QueryMap::iterator, bool> result =
+ queries_.insert(std::make_pair(client_id, query));
+ DCHECK(result.second);
+ return query.get();
+}
+
+QueryManager::Query* QueryManager::GetQuery(
+ GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ return it != queries_.end() ? it->second.get() : NULL;
+}
+
+void QueryManager::RemoveQuery(GLuint client_id) {
+ QueryMap::iterator it = queries_.find(client_id);
+ if (it != queries_.end()) {
+ Query* query = it->second.get();
+ RemovePendingQuery(query);
+ query->MarkAsDeleted();
+ queries_.erase(it);
+ }
+}
+
+void QueryManager::StartTracking(QueryManager::Query* /* query */) {
+ ++query_count_;
+}
+
+void QueryManager::StopTracking(QueryManager::Query* /* query */) {
+ --query_count_;
+}
+
+GLenum QueryManager::AdjustTargetForEmulation(GLenum target) {
+ switch (target) {
+ case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
+ case GL_ANY_SAMPLES_PASSED_EXT:
+ if (use_arb_occlusion_query2_for_occlusion_query_boolean_) {
+ // ARB_occlusion_query2 does not have a
+ // GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
+ // target.
+ target = GL_ANY_SAMPLES_PASSED_EXT;
+ } else if (use_arb_occlusion_query_for_occlusion_query_boolean_) {
+ // ARB_occlusion_query does not have a
+ // GL_ANY_SAMPLES_PASSED_EXT
+ // target.
+ target = GL_SAMPLES_PASSED_ARB;
+ }
+ break;
+ default:
+ break;
+ }
+ return target;
+}
+
+void QueryManager::BeginQueryHelper(GLenum target, GLuint id) {
+ target = AdjustTargetForEmulation(target);
+ glBeginQueryARB(target, id);
+}
+
+void QueryManager::EndQueryHelper(GLenum target) {
+ target = AdjustTargetForEmulation(target);
+ glEndQueryARB(target);
+}
+
+QueryManager::Query::Query(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset)
+ : manager_(manager),
+ target_(target),
+ shm_id_(shm_id),
+ shm_offset_(shm_offset),
+ submit_count_(0),
+ pending_(false),
+ deleted_(false) {
+ DCHECK(manager);
+ manager_->StartTracking(this);
+}
+
+void QueryManager::Query::RunCallbacks() {
+ for (size_t i = 0; i < callbacks_.size(); i++) {
+ callbacks_[i].Run();
+ }
+ callbacks_.clear();
+}
+
+void QueryManager::Query::AddCallback(base::Closure callback) {
+ if (pending_) {
+ callbacks_.push_back(callback);
+ } else {
+ callback.Run();
+ }
+}
+
+QueryManager::Query::~Query() {
+ // The query is getting deleted, either by the client or
+ // because the context was lost. Call any outstanding
+ // callbacks to avoid leaks.
+ RunCallbacks();
+ if (manager_) {
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+bool QueryManager::Query::MarkAsCompleted(uint64 result) {
+ DCHECK(pending_);
+ QuerySync* sync = manager_->decoder_->GetSharedMemoryAs<QuerySync*>(
+ shm_id_, shm_offset_, sizeof(*sync));
+ if (!sync) {
+ return false;
+ }
+
+ pending_ = false;
+ sync->result = result;
+ // Need a MemoryBarrier here so that sync->result is written before
+ // sync->process_count.
+ base::subtle::MemoryBarrier();
+ sync->process_count = submit_count_;
+
+ return true;
+}
+
+bool QueryManager::ProcessPendingQueries() {
+ while (!pending_queries_.empty()) {
+ Query* query = pending_queries_.front().get();
+ if (!query->Process()) {
+ return false;
+ }
+ if (query->pending()) {
+ break;
+ }
+ query->RunCallbacks();
+ pending_queries_.pop_front();
+ }
+
+ return true;
+}
+
+bool QueryManager::HavePendingQueries() {
+ return !pending_queries_.empty();
+}
+
+bool QueryManager::ProcessPendingTransferQueries() {
+ while (!pending_transfer_queries_.empty()) {
+ Query* query = pending_transfer_queries_.front().get();
+ if (!query->Process()) {
+ return false;
+ }
+ if (query->pending()) {
+ break;
+ }
+ query->RunCallbacks();
+ pending_transfer_queries_.pop_front();
+ }
+
+ return true;
+}
+
+bool QueryManager::HavePendingTransferQueries() {
+ return !pending_transfer_queries_.empty();
+}
+
+bool QueryManager::AddPendingQuery(Query* query, uint32 submit_count) {
+ DCHECK(query);
+ DCHECK(!query->IsDeleted());
+ if (!RemovePendingQuery(query)) {
+ return false;
+ }
+ query->MarkAsPending(submit_count);
+ pending_queries_.push_back(query);
+ return true;
+}
+
+bool QueryManager::AddPendingTransferQuery(Query* query, uint32 submit_count) {
+ DCHECK(query);
+ DCHECK(!query->IsDeleted());
+ if (!RemovePendingQuery(query)) {
+ return false;
+ }
+ query->MarkAsPending(submit_count);
+ pending_transfer_queries_.push_back(query);
+ return true;
+}
+
+bool QueryManager::RemovePendingQuery(Query* query) {
+ DCHECK(query);
+ if (query->pending()) {
+ // TODO(gman): Speed this up if this is a common operation. This would only
+ // happen if you do being/end begin/end on the same query without waiting
+ // for the first one to finish.
+ for (QueryQueue::iterator it = pending_queries_.begin();
+ it != pending_queries_.end(); ++it) {
+ if (it->get() == query) {
+ pending_queries_.erase(it);
+ break;
+ }
+ }
+ for (QueryQueue::iterator it = pending_transfer_queries_.begin();
+ it != pending_transfer_queries_.end(); ++it) {
+ if (it->get() == query) {
+ pending_transfer_queries_.erase(it);
+ break;
+ }
+ }
+ if (!query->MarkAsCompleted(0)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool QueryManager::BeginQuery(Query* query) {
+ DCHECK(query);
+ if (!RemovePendingQuery(query)) {
+ return false;
+ }
+ return query->Begin();
+}
+
+bool QueryManager::EndQuery(Query* query, uint32 submit_count) {
+ DCHECK(query);
+ if (!RemovePendingQuery(query)) {
+ return false;
+ }
+ return query->End(submit_count);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/query_manager.h b/chromium/gpu/command_buffer/service/query_manager.h
new file mode 100644
index 00000000000..d77982b897f
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/query_manager.h
@@ -0,0 +1,244 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_
+
+#include <deque>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class GLES2Decoder;
+
+namespace gles2 {
+
+class FeatureInfo;
+
+// This class keeps track of the queries and their state
+// As Queries are not shared there is one QueryManager per context.
+class GPU_EXPORT QueryManager {
+ public:
+ class GPU_EXPORT Query : public base::RefCounted<Query> {
+ public:
+ Query(
+ QueryManager* manager, GLenum target, int32 shm_id, uint32 shm_offset);
+
+ GLenum target() const {
+ return target_;
+ }
+
+ bool IsDeleted() const {
+ return deleted_;
+ }
+
+ bool IsValid() const {
+ return target() && !IsDeleted();
+ }
+
+ bool pending() const {
+ return pending_;
+ }
+
+ int32 shm_id() const {
+ return shm_id_;
+ }
+
+ uint32 shm_offset() const {
+ return shm_offset_;
+ }
+
+ // Returns false if shared memory for sync is invalid.
+ virtual bool Begin() = 0;
+
+ // Returns false if shared memory for sync is invalid.
+ virtual bool End(uint32 submit_count) = 0;
+
+ // Returns false if shared memory for sync is invalid.
+ virtual bool Process() = 0;
+
+ virtual void Destroy(bool have_context) = 0;
+
+ void AddCallback(base::Closure callback);
+
+ protected:
+ virtual ~Query();
+
+ QueryManager* manager() const {
+ return manager_;
+ }
+
+ void MarkAsDeleted() {
+ deleted_ = true;
+ }
+
+ // Returns false if shared memory for sync is invalid.
+ bool MarkAsCompleted(uint64 result);
+
+ void MarkAsPending(uint32 submit_count) {
+ DCHECK(!pending_);
+ pending_ = true;
+ submit_count_ = submit_count;
+ }
+
+ void UnmarkAsPending() {
+ DCHECK(pending_);
+ pending_ = false;
+ }
+
+ // Returns false if shared memory for sync is invalid.
+ bool AddToPendingQueue(uint32 submit_count) {
+ return manager_->AddPendingQuery(this, submit_count);
+ }
+
+ // Returns false if shared memory for sync is invalid.
+ bool AddToPendingTransferQueue(uint32 submit_count) {
+ return manager_->AddPendingTransferQuery(this, submit_count);
+ }
+
+ void BeginQueryHelper(GLenum target, GLuint id) {
+ manager_->BeginQueryHelper(target, id);
+ }
+
+ void EndQueryHelper(GLenum target) {
+ manager_->EndQueryHelper(target);
+ }
+
+ uint32 submit_count() const {
+ return submit_count_;
+ }
+
+ private:
+ friend class QueryManager;
+ friend class QueryManagerTest;
+ friend class base::RefCounted<Query>;
+
+ void RunCallbacks();
+
+ // The manager that owns this Query.
+ QueryManager* manager_;
+
+ // The type of query.
+ GLenum target_;
+
+ // The shared memory used with this Query.
+ int32 shm_id_;
+ uint32 shm_offset_;
+
+ // Count to set process count do when completed.
+ uint32 submit_count_;
+
+ // True if in the queue.
+ bool pending_;
+
+ // True if deleted.
+ bool deleted_;
+
+ // List of callbacks to run when result is available.
+ std::vector<base::Closure> callbacks_;
+ };
+
+ QueryManager(
+ GLES2Decoder* decoder,
+ FeatureInfo* feature_info);
+ ~QueryManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a Query for the given query.
+ Query* CreateQuery(
+ GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset);
+
+ // Gets the query info for the given query.
+ Query* GetQuery(GLuint client_id);
+
+ // Removes a query info for the given query.
+ void RemoveQuery(GLuint client_id);
+
+ // Returns false if any query is pointing to invalid shared memory.
+ bool BeginQuery(Query* query);
+
+ // Returns false if any query is pointing to invalid shared memory.
+ bool EndQuery(Query* query, uint32 submit_count);
+
+ // Processes pending queries. Returns false if any queries are pointing
+ // to invalid shared memory.
+ bool ProcessPendingQueries();
+
+ // True if there are pending queries.
+ bool HavePendingQueries();
+
+ // Processes pending transfer queries. Returns false if any queries are
+ // pointing to invalid shared memory.
+ bool ProcessPendingTransferQueries();
+
+ // True if there are pending transfer queries.
+ bool HavePendingTransferQueries();
+
+ GLES2Decoder* decoder() const {
+ return decoder_;
+ }
+
+ private:
+ void StartTracking(Query* query);
+ void StopTracking(Query* query);
+
+ // Wrappers for BeginQueryARB and EndQueryARB to hide differences between
+ // ARB_occlusion_query2 and EXT_occlusion_query_boolean.
+ void BeginQueryHelper(GLenum target, GLuint id);
+ void EndQueryHelper(GLenum target);
+
+ // Adds to queue of queries waiting for completion.
+ // Returns false if any query is pointing to invalid shared memory.
+ bool AddPendingQuery(Query* query, uint32 submit_count);
+
+ // Adds to queue of transfer queries waiting for completion.
+ // Returns false if any query is pointing to invalid shared memory.
+ bool AddPendingTransferQuery(Query* query, uint32 submit_count);
+
+ // Removes a query from the queue of pending queries.
+ // Returns false if any query is pointing to invalid shared memory.
+ bool RemovePendingQuery(Query* query);
+
+ // Returns a target used for the underlying GL extension
+ // used to emulate a query.
+ GLenum AdjustTargetForEmulation(GLenum target);
+
+ // Used to validate shared memory and get GL errors.
+ GLES2Decoder* decoder_;
+
+ bool use_arb_occlusion_query2_for_occlusion_query_boolean_;
+ bool use_arb_occlusion_query_for_occlusion_query_boolean_;
+
+ // Counts the number of Queries allocated with 'this' as their manager.
+ // Allows checking no Query will outlive this.
+ unsigned query_count_;
+
+ // Info for each query in the system.
+ typedef base::hash_map<GLuint, scoped_refptr<Query> > QueryMap;
+ QueryMap queries_;
+
+ // Queries waiting for completion.
+ typedef std::deque<scoped_refptr<Query> > QueryQueue;
+ QueryQueue pending_queries_;
+
+ // Async pixel transfer queries waiting for completion.
+ QueryQueue pending_transfer_queries_;
+
+ DISALLOW_COPY_AND_ASSIGN(QueryManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_QUERY_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/query_manager_unittest.cc b/chromium/gpu/command_buffer/service/query_manager_unittest.cc
new file mode 100644
index 00000000000..63ad4f5b27c
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/query_manager_unittest.cc
@@ -0,0 +1,574 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/query_manager.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/cmd_buffer_engine.h"
+#include "gpu/command_buffer/service/error_state_mock.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::_;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+
+namespace gpu {
+namespace gles2 {
+
+class QueryManagerTest : public testing::Test {
+ public:
+ static const int32 kSharedMemoryId = 401;
+ static const size_t kSharedBufferSize = 2048;
+ static const uint32 kSharedMemoryOffset = 132;
+ static const int32 kInvalidSharedMemoryId = 402;
+ static const uint32 kInvalidSharedMemoryOffset = kSharedBufferSize + 1;
+ static const uint32 kInitialResult = 0xBDBDBDBDu;
+ static const uint8 kInitialMemoryValue = 0xBDu;
+
+ QueryManagerTest() {
+ }
+ virtual ~QueryManagerTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ engine_.reset(new MockCommandBufferEngine());
+ decoder_.reset(new MockGLES2Decoder());
+ decoder_->set_engine(engine_.get());
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(),
+ "GL_EXT_occlusion_query_boolean");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize("*");
+ manager_.reset(new QueryManager(decoder_.get(), feature_info.get()));
+ }
+
+ virtual void TearDown() {
+ decoder_.reset();
+ manager_->Destroy(false);
+ manager_.reset();
+ engine_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ QueryManager::Query* CreateQuery(
+ GLenum target, GLuint client_id, int32 shm_id, uint32 shm_offset,
+ GLuint service_id) {
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(service_id))
+ .RetiresOnSaturation();
+ return manager_->CreateQuery(target, client_id, shm_id, shm_offset);
+ }
+
+ void QueueQuery(
+ QueryManager::Query* query, GLuint service_id, uint32 submit_count) {
+ EXPECT_CALL(*gl_, BeginQueryARB(query->target(), service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, EndQueryARB(query->target()))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->BeginQuery(query));
+ EXPECT_TRUE(manager_->EndQuery(query, submit_count));
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_ptr<MockGLES2Decoder> decoder_;
+ scoped_ptr<QueryManager> manager_;
+
+ private:
+ class MockCommandBufferEngine : public CommandBufferEngine {
+ public:
+ MockCommandBufferEngine() {
+ data_.reset(new int8[kSharedBufferSize]);
+ ClearSharedMemory();
+ valid_buffer_.ptr = data_.get();
+ valid_buffer_.size = kSharedBufferSize;
+ }
+
+ virtual ~MockCommandBufferEngine() {
+ }
+
+ virtual gpu::Buffer GetSharedMemoryBuffer(int32 shm_id) OVERRIDE {
+ return shm_id == kSharedMemoryId ? valid_buffer_ : invalid_buffer_;
+ }
+
+ void ClearSharedMemory() {
+ memset(data_.get(), kInitialMemoryValue, kSharedBufferSize);
+ }
+
+ virtual void set_token(int32 token) OVERRIDE {
+ DCHECK(false);
+ }
+
+ virtual bool SetGetBuffer(int32 /* transfer_buffer_id */) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual bool SetGetOffset(int32 offset) OVERRIDE {
+ DCHECK(false);
+ return false;
+ }
+
+ // Overridden from CommandBufferEngine.
+ virtual int32 GetGetOffset() OVERRIDE {
+ DCHECK(false);
+ return 0;
+ }
+
+ private:
+ scoped_ptr<int8[]> data_;
+ gpu::Buffer valid_buffer_;
+ gpu::Buffer invalid_buffer_;
+ };
+
+ scoped_ptr<MockCommandBufferEngine> engine_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const int32 QueryManagerTest::kSharedMemoryId;
+const size_t QueryManagerTest::kSharedBufferSize;
+const uint32 QueryManagerTest::kSharedMemoryOffset;
+const int32 QueryManagerTest::kInvalidSharedMemoryId;
+const uint32 QueryManagerTest::kInvalidSharedMemoryOffset;
+const uint32 QueryManagerTest::kInitialResult;
+const uint8 QueryManagerTest::kInitialMemoryValue;
+#endif
+
+TEST_F(QueryManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+
+ EXPECT_FALSE(manager_->HavePendingQueries());
+ // Check we can create a Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(GL_ANY_SAMPLES_PASSED_EXT, kClient1Id,
+ kSharedMemoryId, kSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ // Check we can get the same Query.
+ EXPECT_EQ(query.get(), manager_->GetQuery(kClient1Id));
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(manager_->GetQuery(kClient2Id) == NULL);
+ // Check we can delete the query.
+ manager_->RemoveQuery(kClient1Id);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(manager_->GetQuery(kClient1Id) == NULL);
+ // Check query is deleted
+ EXPECT_TRUE(query->IsDeleted());
+ EXPECT_FALSE(manager_->HavePendingQueries());
+}
+
+TEST_F(QueryManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+
+ // Create Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(GL_ANY_SAMPLES_PASSED_EXT, kClient1Id,
+ kSharedMemoryId, kSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+ EXPECT_CALL(*gl_, DeleteQueriesARB(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_->Destroy(true);
+ // Check we get nothing for a non-existent query.
+ EXPECT_TRUE(manager_->GetQuery(kClient1Id) == NULL);
+ // Check query is deleted
+ EXPECT_TRUE(query->IsDeleted());
+}
+
+TEST_F(QueryManagerTest, QueryBasic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+
+ // Create Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(kTarget, kClient1Id,
+ kSharedMemoryId, kSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ EXPECT_TRUE(query->IsValid());
+ EXPECT_FALSE(query->IsDeleted());
+ EXPECT_FALSE(query->pending());
+ EXPECT_EQ(kTarget, query->target());
+ EXPECT_EQ(kSharedMemoryId, query->shm_id());
+ EXPECT_EQ(kSharedMemoryOffset, query->shm_offset());
+}
+
+TEST_F(QueryManagerTest, ProcessPendingQuery) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+ const GLuint kResult = 1;
+
+ // Check nothing happens if there are no pending queries.
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+
+ // Create Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(kTarget, kClient1Id,
+ kSharedMemoryId, kSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ // Setup shared memory like client would.
+ QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync));
+ ASSERT_TRUE(sync != NULL);
+ sync->Reset();
+
+ // Queue it
+ QueueQuery(query.get(), kService1Id, kSubmitCount);
+ EXPECT_TRUE(query->pending());
+ EXPECT_TRUE(manager_->HavePendingQueries());
+
+ // Process with return not available.
+ // Expect 1 GL command.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(query->pending());
+ EXPECT_EQ(0u, sync->process_count);
+ EXPECT_EQ(0u, sync->result);
+
+ // Process with return available.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_FALSE(query->pending());
+ EXPECT_EQ(kSubmitCount, sync->process_count);
+ EXPECT_EQ(kResult, sync->result);
+ EXPECT_FALSE(manager_->HavePendingQueries());
+
+ // Process with no queries.
+ // Expect no GL commands/
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+}
+
+TEST_F(QueryManagerTest, ProcessPendingQueries) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+ const GLuint kService2Id = 12;
+ const GLuint kClient3Id = 3;
+ const GLuint kService3Id = 13;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount1 = 123;
+ const uint32 kSubmitCount2 = 123;
+ const uint32 kSubmitCount3 = 123;
+ const GLuint kResult1 = 1;
+ const GLuint kResult2 = 1;
+ const GLuint kResult3 = 1;
+
+ // Setup shared memory like client would.
+ QuerySync* sync1 = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync1) * 3);
+ ASSERT_TRUE(sync1 != NULL);
+ QuerySync* sync2 = sync1 + 1;
+ QuerySync* sync3 = sync2 + 1;
+
+ // Create Queries.
+ scoped_refptr<QueryManager::Query> query1(
+ CreateQuery(kTarget, kClient1Id,
+ kSharedMemoryId, kSharedMemoryOffset + sizeof(*sync1) * 0,
+ kService1Id));
+ scoped_refptr<QueryManager::Query> query2(
+ CreateQuery(kTarget, kClient2Id,
+ kSharedMemoryId, kSharedMemoryOffset + sizeof(*sync1) * 1,
+ kService2Id));
+ scoped_refptr<QueryManager::Query> query3(
+ CreateQuery(kTarget, kClient3Id,
+ kSharedMemoryId, kSharedMemoryOffset + sizeof(*sync1) * 2,
+ kService3Id));
+ ASSERT_TRUE(query1.get() != NULL);
+ ASSERT_TRUE(query2.get() != NULL);
+ ASSERT_TRUE(query3.get() != NULL);
+ EXPECT_FALSE(manager_->HavePendingQueries());
+
+ sync1->Reset();
+ sync2->Reset();
+ sync3->Reset();
+
+ // Queue them
+ QueueQuery(query1.get(), kService1Id, kSubmitCount1);
+ QueueQuery(query2.get(), kService2Id, kSubmitCount2);
+ QueueQuery(query3.get(), kService3Id, kSubmitCount3);
+ EXPECT_TRUE(query1->pending());
+ EXPECT_TRUE(query2->pending());
+ EXPECT_TRUE(query3->pending());
+ EXPECT_TRUE(manager_->HavePendingQueries());
+
+ // Process with return available for first 2 queries.
+ // Expect 4 GL commands.
+ {
+ InSequence s;
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService2Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService2Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult2))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+ }
+ EXPECT_FALSE(query1->pending());
+ EXPECT_FALSE(query2->pending());
+ EXPECT_TRUE(query3->pending());
+ EXPECT_EQ(kSubmitCount1, sync1->process_count);
+ EXPECT_EQ(kSubmitCount2, sync2->process_count);
+ EXPECT_EQ(kResult1, sync1->result);
+ EXPECT_EQ(kResult2, sync2->result);
+ EXPECT_EQ(0u, sync3->process_count);
+ EXPECT_EQ(0u, sync3->result);
+ EXPECT_TRUE(manager_->HavePendingQueries());
+
+ // Process with renaming query. No result.
+ // Expect 1 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(query3->pending());
+ EXPECT_EQ(0u, sync3->process_count);
+ EXPECT_EQ(0u, sync3->result);
+ EXPECT_TRUE(manager_->HavePendingQueries());
+
+ // Process with renaming query. With result.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult3))
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_FALSE(query3->pending());
+ EXPECT_EQ(kSubmitCount3, sync3->process_count);
+ EXPECT_EQ(kResult3, sync3->result);
+ EXPECT_FALSE(manager_->HavePendingQueries());
+}
+
+TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryId) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+ const GLuint kResult = 1;
+
+ // Create Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(kTarget, kClient1Id,
+ kInvalidSharedMemoryId, kSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ // Queue it
+ QueueQuery(query.get(), kService1Id, kSubmitCount);
+
+ // Process with return available.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult))
+ .RetiresOnSaturation();
+ EXPECT_FALSE(manager_->ProcessPendingQueries());
+}
+
+TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+ const GLuint kResult = 1;
+
+ // Create Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(kTarget, kClient1Id,
+ kSharedMemoryId, kInvalidSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ // Queue it
+ QueueQuery(query.get(), kService1Id, kSubmitCount);
+
+ // Process with return available.
+ // Expect 2 GL commands.
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_,
+ GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
+ .WillOnce(SetArgumentPointee<2>(kResult))
+ .RetiresOnSaturation();
+ EXPECT_FALSE(manager_->ProcessPendingQueries());
+}
+
+TEST_F(QueryManagerTest, ExitWithPendingQuery) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+
+ // Create Query.
+ scoped_refptr<QueryManager::Query> query(
+ CreateQuery(kTarget, kClient1Id,
+ kSharedMemoryId, kSharedMemoryOffset, kService1Id));
+ ASSERT_TRUE(query.get() != NULL);
+
+ // Queue it
+ QueueQuery(query.get(), kService1Id, kSubmitCount);
+}
+
+// Test that when based on ARB_occlusion_query2 we use GL_ANY_SAMPLES_PASSED_ARB
+// for GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT
+TEST_F(QueryManagerTest, ARBOcclusionQuery2) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT;
+ const uint32 kSubmitCount = 123;
+
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(),
+ "GL_ARB_occlusion_query2");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize("*");
+ scoped_ptr<QueryManager> manager(
+ new QueryManager(decoder_.get(), feature_info.get()));
+
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kService1Id))
+ .RetiresOnSaturation();
+ QueryManager::Query* query = manager->CreateQuery(
+ kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
+ ASSERT_TRUE(query != NULL);
+
+ EXPECT_CALL(*gl_, BeginQueryARB(GL_ANY_SAMPLES_PASSED_EXT, kService1Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, EndQueryARB(GL_ANY_SAMPLES_PASSED_EXT))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager->BeginQuery(query));
+ EXPECT_TRUE(manager->EndQuery(query, kSubmitCount));
+ manager->Destroy(false);
+}
+
+// Test that when based on ARB_occlusion_query we use GL_SAMPLES_PASSED_ARB
+// for GL_ANY_SAMPLES_PASSED_EXT
+TEST_F(QueryManagerTest, ARBOcclusionQuery) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kTarget = GL_ANY_SAMPLES_PASSED_EXT;
+ const uint32 kSubmitCount = 123;
+
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(),
+ "GL_ARB_occlusion_query");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize("*");
+ scoped_ptr<QueryManager> manager(
+ new QueryManager(decoder_.get(), feature_info.get()));
+
+ EXPECT_CALL(*gl_, GenQueriesARB(1, _))
+ .WillOnce(SetArgumentPointee<1>(kService1Id))
+ .RetiresOnSaturation();
+ QueryManager::Query* query = manager->CreateQuery(
+ kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
+ ASSERT_TRUE(query != NULL);
+
+ EXPECT_CALL(*gl_, BeginQueryARB(GL_SAMPLES_PASSED_ARB, kService1Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl_, EndQueryARB(GL_SAMPLES_PASSED_ARB))
+ .Times(1)
+ .RetiresOnSaturation();
+ EXPECT_TRUE(manager->BeginQuery(query));
+ EXPECT_TRUE(manager->EndQuery(query, kSubmitCount));
+ manager->Destroy(false);
+}
+
+TEST_F(QueryManagerTest, GetErrorQuery) {
+ const GLuint kClient1Id = 1;
+ const GLenum kTarget = GL_GET_ERROR_QUERY_CHROMIUM;
+ const uint32 kSubmitCount = 123;
+
+ TestHelper::SetupFeatureInfoInitExpectations(gl_.get(), "");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize("*");
+ scoped_ptr<QueryManager> manager(
+ new QueryManager(decoder_.get(), feature_info.get()));
+
+ QueryManager::Query* query = manager->CreateQuery(
+ kTarget, kClient1Id, kSharedMemoryId, kSharedMemoryOffset);
+ ASSERT_TRUE(query != NULL);
+
+ // Setup shared memory like client would.
+ QuerySync* sync = decoder_->GetSharedMemoryAs<QuerySync*>(
+ kSharedMemoryId, kSharedMemoryOffset, sizeof(*sync));
+ ASSERT_TRUE(sync != NULL);
+ sync->Reset();
+
+ EXPECT_TRUE(manager->BeginQuery(query));
+
+ MockErrorState mock_error_state;
+ EXPECT_CALL(*decoder_.get(), GetErrorState())
+ .WillRepeatedly(Return(&mock_error_state));
+ EXPECT_CALL(mock_error_state, GetGLError())
+ .WillOnce(Return(GL_INVALID_ENUM))
+ .RetiresOnSaturation();
+
+ EXPECT_TRUE(manager->EndQuery(query, kSubmitCount));
+ EXPECT_FALSE(query->pending());
+
+ EXPECT_EQ(static_cast<GLuint>(GL_INVALID_ENUM), sync->result);
+
+ manager->Destroy(false);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/renderbuffer_manager.cc b/chromium/gpu/command_buffer/service/renderbuffer_manager.cc
new file mode 100644
index 00000000000..0190c449452
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/renderbuffer_manager.cc
@@ -0,0 +1,191 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/strings/stringprintf.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "ui/gl/gl_implementation.h"
+
+namespace gpu {
+namespace gles2 {
+
+RenderbufferManager::RenderbufferManager(
+ MemoryTracker* memory_tracker,
+ GLint max_renderbuffer_size,
+ GLint max_samples)
+ : memory_tracker_(
+ new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
+ max_renderbuffer_size_(max_renderbuffer_size),
+ max_samples_(max_samples),
+ num_uncleared_renderbuffers_(0),
+ renderbuffer_count_(0),
+ have_context_(true) {
+}
+
+RenderbufferManager::~RenderbufferManager() {
+ DCHECK(renderbuffers_.empty());
+ // If this triggers, that means something is keeping a reference to
+ // a Renderbuffer belonging to this.
+ CHECK_EQ(renderbuffer_count_, 0u);
+
+ DCHECK_EQ(0, num_uncleared_renderbuffers_);
+}
+
+size_t Renderbuffer::EstimatedSize() {
+ uint32 size = 0;
+ RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ width_, height_, samples_, internal_format_, &size);
+ return size;
+}
+
+void Renderbuffer::AddToSignature(
+ std::string* signature) const {
+ DCHECK(signature);
+ *signature += base::StringPrintf(
+ "|Renderbuffer|internal_format=%04x|samples=%d|width=%d|height=%d",
+ internal_format_, samples_, width_, height_);
+}
+
+Renderbuffer::Renderbuffer(RenderbufferManager* manager,
+ GLuint client_id,
+ GLuint service_id)
+ : manager_(manager),
+ client_id_(client_id),
+ service_id_(service_id),
+ cleared_(true),
+ has_been_bound_(false),
+ samples_(0),
+ internal_format_(GL_RGBA4),
+ width_(0),
+ height_(0) {
+ manager_->StartTracking(this);
+}
+
+Renderbuffer::~Renderbuffer() {
+ if (manager_) {
+ if (manager_->have_context_) {
+ GLuint id = service_id();
+ glDeleteRenderbuffersEXT(1, &id);
+ }
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+void RenderbufferManager::Destroy(bool have_context) {
+ have_context_ = have_context;
+ renderbuffers_.clear();
+ DCHECK_EQ(0u, memory_tracker_->GetMemRepresented());
+}
+
+void RenderbufferManager::StartTracking(Renderbuffer* /* renderbuffer */) {
+ ++renderbuffer_count_;
+}
+
+void RenderbufferManager::StopTracking(Renderbuffer* renderbuffer) {
+ --renderbuffer_count_;
+ if (!renderbuffer->cleared()) {
+ --num_uncleared_renderbuffers_;
+ }
+ memory_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
+}
+
+void RenderbufferManager::SetInfo(
+ Renderbuffer* renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ DCHECK(renderbuffer);
+ if (!renderbuffer->cleared()) {
+ --num_uncleared_renderbuffers_;
+ }
+ memory_tracker_->TrackMemFree(renderbuffer->EstimatedSize());
+ renderbuffer->SetInfo(samples, internalformat, width, height);
+ memory_tracker_->TrackMemAlloc(renderbuffer->EstimatedSize());
+ if (!renderbuffer->cleared()) {
+ ++num_uncleared_renderbuffers_;
+ }
+}
+
+void RenderbufferManager::SetCleared(Renderbuffer* renderbuffer,
+ bool cleared) {
+ DCHECK(renderbuffer);
+ if (!renderbuffer->cleared()) {
+ --num_uncleared_renderbuffers_;
+ }
+ renderbuffer->set_cleared(cleared);
+ if (!renderbuffer->cleared()) {
+ ++num_uncleared_renderbuffers_;
+ }
+}
+
+void RenderbufferManager::CreateRenderbuffer(
+ GLuint client_id, GLuint service_id) {
+ scoped_refptr<Renderbuffer> renderbuffer(
+ new Renderbuffer(this, client_id, service_id));
+ std::pair<RenderbufferMap::iterator, bool> result =
+ renderbuffers_.insert(std::make_pair(client_id, renderbuffer));
+ DCHECK(result.second);
+ if (!renderbuffer->cleared()) {
+ ++num_uncleared_renderbuffers_;
+ }
+}
+
+Renderbuffer* RenderbufferManager::GetRenderbuffer(
+ GLuint client_id) {
+ RenderbufferMap::iterator it = renderbuffers_.find(client_id);
+ return it != renderbuffers_.end() ? it->second.get() : NULL;
+}
+
+void RenderbufferManager::RemoveRenderbuffer(GLuint client_id) {
+ RenderbufferMap::iterator it = renderbuffers_.find(client_id);
+ if (it != renderbuffers_.end()) {
+ Renderbuffer* renderbuffer = it->second.get();
+ renderbuffer->MarkAsDeleted();
+ renderbuffers_.erase(it);
+ }
+}
+
+bool RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ int width, int height, int samples, int internal_format, uint32* size) {
+ DCHECK(size);
+
+ uint32 temp = 0;
+ if (!SafeMultiplyUint32(width, height, &temp)) {
+ return false;
+ }
+ if (!SafeMultiplyUint32(temp, samples, &temp)) {
+ return false;
+ }
+ GLenum impl_format = InternalRenderbufferFormatToImplFormat(internal_format);
+ if (!SafeMultiplyUint32(
+ temp, GLES2Util::RenderbufferBytesPerPixel(impl_format), &temp)) {
+ return false;
+ }
+ *size = temp;
+ return true;
+}
+
+GLenum RenderbufferManager::InternalRenderbufferFormatToImplFormat(
+ GLenum impl_format) {
+ if (gfx::GetGLImplementation() != gfx::kGLImplementationEGLGLES2) {
+ switch (impl_format) {
+ case GL_DEPTH_COMPONENT16:
+ return GL_DEPTH_COMPONENT;
+ case GL_RGBA4:
+ case GL_RGB5_A1:
+ return GL_RGBA;
+ case GL_RGB565:
+ return GL_RGB;
+ }
+ }
+ return impl_format;
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/renderbuffer_manager.h b/chromium/gpu/command_buffer/service/renderbuffer_manager.h
new file mode 100644
index 00000000000..73fc2cb1974
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/renderbuffer_manager.h
@@ -0,0 +1,199 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_RENDERBUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_RENDERBUFFER_MANAGER_H_
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class RenderbufferManager;
+
+// Info about a Renderbuffer.
+class GPU_EXPORT Renderbuffer
+ : public base::RefCounted<Renderbuffer> {
+ public:
+ Renderbuffer(RenderbufferManager* manager,
+ GLuint client_id,
+ GLuint service_id);
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ GLuint client_id() const {
+ return client_id_;
+ }
+
+ bool cleared() const {
+ return cleared_;
+ }
+
+ GLenum internal_format() const {
+ return internal_format_;
+ }
+
+ GLsizei samples() const {
+ return samples_;
+ }
+
+ GLsizei width() const {
+ return width_;
+ }
+
+ GLsizei height() const {
+ return height_;
+ }
+
+ bool IsDeleted() const {
+ return client_id_ == 0;
+ }
+
+ void MarkAsValid() {
+ has_been_bound_ = true;
+ }
+
+ bool IsValid() const {
+ return has_been_bound_ && !IsDeleted();
+ }
+
+ size_t EstimatedSize();
+
+ void AddToSignature(std::string* signature) const;
+
+ private:
+ friend class RenderbufferManager;
+ friend class base::RefCounted<Renderbuffer>;
+
+ ~Renderbuffer();
+
+ void set_cleared(bool cleared) {
+ cleared_ = cleared;
+ }
+
+ void SetInfo(
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height) {
+ samples_ = samples;
+ internal_format_ = internalformat;
+ width_ = width;
+ height_ = height;
+ cleared_ = false;
+ }
+
+ void MarkAsDeleted() {
+ client_id_ = 0;
+ }
+
+ // RenderbufferManager that owns this Renderbuffer.
+ RenderbufferManager* manager_;
+
+ // Client side renderbuffer id.
+ GLuint client_id_;
+
+ // Service side renderbuffer id.
+ GLuint service_id_;
+
+ // Whether this renderbuffer has been cleared
+ bool cleared_;
+
+ // Whether this renderbuffer has ever been bound.
+ bool has_been_bound_;
+
+ // Number of samples (for multi-sampled renderbuffers)
+ GLsizei samples_;
+
+ // Renderbuffer internalformat set through RenderbufferStorage().
+ GLenum internal_format_;
+
+ // Dimensions of renderbuffer.
+ GLsizei width_;
+ GLsizei height_;
+};
+
+// This class keeps track of the renderbuffers and whether or not they have
+// been cleared.
+class GPU_EXPORT RenderbufferManager {
+ public:
+ RenderbufferManager(MemoryTracker* memory_tracker,
+ GLint max_renderbuffer_size,
+ GLint max_samples);
+ ~RenderbufferManager();
+
+ GLint max_renderbuffer_size() const {
+ return max_renderbuffer_size_;
+ }
+
+ GLint max_samples() const {
+ return max_samples_;
+ }
+
+ bool HaveUnclearedRenderbuffers() const {
+ return num_uncleared_renderbuffers_ != 0;
+ }
+
+ void SetInfo(
+ Renderbuffer* renderbuffer,
+ GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+
+ void SetCleared(Renderbuffer* renderbuffer, bool cleared);
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a Renderbuffer for the given renderbuffer ids.
+ void CreateRenderbuffer(GLuint client_id, GLuint service_id);
+
+ // Gets the renderbuffer for the given renderbuffer id.
+ Renderbuffer* GetRenderbuffer(GLuint client_id);
+
+ // Removes a renderbuffer for the given renderbuffer id.
+ void RemoveRenderbuffer(GLuint client_id);
+
+ size_t mem_represented() const {
+ return memory_tracker_->GetMemRepresented();
+ }
+
+ static bool ComputeEstimatedRenderbufferSize(
+ int width, int height, int samples, int internal_format, uint32* size);
+ static GLenum InternalRenderbufferFormatToImplFormat(GLenum impl_format);
+
+ private:
+ friend class Renderbuffer;
+
+ void StartTracking(Renderbuffer* renderbuffer);
+ void StopTracking(Renderbuffer* renderbuffer);
+
+ scoped_ptr<MemoryTypeTracker> memory_tracker_;
+
+ GLint max_renderbuffer_size_;
+ GLint max_samples_;
+
+ int num_uncleared_renderbuffers_;
+
+ // Counts the number of Renderbuffer allocated with 'this' as its manager.
+ // Allows to check no Renderbuffer will outlive this.
+ unsigned renderbuffer_count_;
+
+ bool have_context_;
+
+ // Info for each renderbuffer in the system.
+ typedef base::hash_map<GLuint, scoped_refptr<Renderbuffer> > RenderbufferMap;
+ RenderbufferMap renderbuffers_;
+
+ DISALLOW_COPY_AND_ASSIGN(RenderbufferManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_RENDERBUFFER_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/renderbuffer_manager_unittest.cc b/chromium/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
new file mode 100644
index 00000000000..20e18c1c7f1
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/renderbuffer_manager_unittest.cc
@@ -0,0 +1,297 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/renderbuffer_manager.h"
+
+#include <set>
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+class RenderbufferManagerTestBase : public testing::Test {
+ public:
+ static const GLint kMaxSize = 128;
+ static const GLint kMaxSamples = 4;
+
+ protected:
+ void SetUpBase(MemoryTracker* memory_tracker) {
+ gl_.reset(new ::testing::StrictMock<gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ manager_.reset(new RenderbufferManager(
+ memory_tracker, kMaxSize, kMaxSamples));
+ }
+
+ virtual void TearDown() {
+ manager_->Destroy(true);
+ manager_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_ptr<RenderbufferManager> manager_;
+};
+
+class RenderbufferManagerTest : public RenderbufferManagerTestBase {
+ protected:
+ virtual void SetUp() {
+ SetUpBase(NULL);
+ }
+};
+
+class RenderbufferManagerMemoryTrackerTest
+ : public RenderbufferManagerTestBase {
+ protected:
+ virtual void SetUp() {
+ mock_memory_tracker_ = new StrictMock<MockMemoryTracker>();
+ SetUpBase(mock_memory_tracker_.get());
+ }
+
+ scoped_refptr<MockMemoryTracker> mock_memory_tracker_;
+};
+
+#define EXPECT_MEMORY_ALLOCATION_CHANGE(old_size, new_size, pool) \
+ EXPECT_CALL(*mock_memory_tracker_.get(), \
+ TrackMemoryAllocatedChange(old_size, new_size, pool)) \
+ .Times(1).RetiresOnSaturation()
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLint RenderbufferManagerTestBase::kMaxSize;
+const GLint RenderbufferManagerTestBase::kMaxSamples;
+#endif
+
+TEST_F(RenderbufferManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+ EXPECT_EQ(kMaxSize, manager_->max_renderbuffer_size());
+ EXPECT_EQ(kMaxSamples, manager_->max_samples());
+ EXPECT_FALSE(manager_->HaveUnclearedRenderbuffers());
+ // Check we can create renderbuffer.
+ manager_->CreateRenderbuffer(kClient1Id, kService1Id);
+ // Check renderbuffer got created.
+ scoped_refptr<Renderbuffer> renderbuffer1 =
+ manager_->GetRenderbuffer(kClient1Id);
+ ASSERT_TRUE(renderbuffer1.get() != NULL);
+ EXPECT_FALSE(manager_->HaveUnclearedRenderbuffers());
+ EXPECT_EQ(kClient1Id, renderbuffer1->client_id());
+ // Check we get nothing for a non-existent renderbuffer.
+ EXPECT_TRUE(manager_->GetRenderbuffer(kClient2Id) == NULL);
+ // Check trying to a remove non-existent renderbuffers does not crash.
+ manager_->RemoveRenderbuffer(kClient2Id);
+ // Check that the renderbuffer is deleted when the last ref is released.
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ // Check we can't get the renderbuffer after we remove it.
+ manager_->RemoveRenderbuffer(kClient1Id);
+ EXPECT_TRUE(manager_->GetRenderbuffer(kClient1Id) == NULL);
+ EXPECT_FALSE(manager_->HaveUnclearedRenderbuffers());
+ EXPECT_EQ(0u, renderbuffer1->client_id());
+}
+
+TEST_F(RenderbufferManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create renderbuffer.
+ manager_->CreateRenderbuffer(kClient1Id, kService1Id);
+ // Check renderbuffer got created.
+ Renderbuffer* renderbuffer1 =
+ manager_->GetRenderbuffer(kClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_->Destroy(true);
+ renderbuffer1 = manager_->GetRenderbuffer(kClient1Id);
+ ASSERT_TRUE(renderbuffer1 == NULL);
+}
+
+TEST_F(RenderbufferManagerTest, Renderbuffer) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create renderbuffer.
+ manager_->CreateRenderbuffer(kClient1Id, kService1Id);
+ // Check renderbuffer got created.
+ Renderbuffer* renderbuffer1 =
+ manager_->GetRenderbuffer(kClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+ EXPECT_EQ(kService1Id, renderbuffer1->service_id());
+ EXPECT_EQ(0, renderbuffer1->samples());
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA4), renderbuffer1->internal_format());
+ EXPECT_EQ(0, renderbuffer1->width());
+ EXPECT_EQ(0, renderbuffer1->height());
+ EXPECT_TRUE(renderbuffer1->cleared());
+ EXPECT_EQ(0u, renderbuffer1->EstimatedSize());
+
+ // Check if we set the info it gets marked as not cleared.
+ const GLsizei kSamples = 4;
+ const GLenum kFormat = GL_RGBA4;
+ const GLsizei kWidth = 128;
+ const GLsizei kHeight = 64;
+ manager_->SetInfo(renderbuffer1, kSamples, kFormat, kWidth, kHeight);
+ EXPECT_EQ(kSamples, renderbuffer1->samples());
+ EXPECT_EQ(kFormat, renderbuffer1->internal_format());
+ EXPECT_EQ(kWidth, renderbuffer1->width());
+ EXPECT_EQ(kHeight, renderbuffer1->height());
+ EXPECT_FALSE(renderbuffer1->cleared());
+ EXPECT_FALSE(renderbuffer1->IsDeleted());
+ EXPECT_TRUE(manager_->HaveUnclearedRenderbuffers());
+ EXPECT_EQ(kWidth * kHeight * 4u * 4u, renderbuffer1->EstimatedSize());
+
+ manager_->SetCleared(renderbuffer1, true);
+ EXPECT_TRUE(renderbuffer1->cleared());
+ EXPECT_FALSE(manager_->HaveUnclearedRenderbuffers());
+
+ manager_->SetInfo(renderbuffer1, kSamples, kFormat, kWidth, kHeight);
+ EXPECT_TRUE(manager_->HaveUnclearedRenderbuffers());
+
+ // Check that the renderbuffer is deleted when the last ref is released.
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_->RemoveRenderbuffer(kClient1Id);
+ EXPECT_FALSE(manager_->HaveUnclearedRenderbuffers());
+}
+
+TEST_F(RenderbufferManagerMemoryTrackerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kUnmanaged);
+ manager_->CreateRenderbuffer(kClient1Id, kService1Id);
+ Renderbuffer* renderbuffer1 =
+ manager_->GetRenderbuffer(kClient1Id);
+ ASSERT_TRUE(renderbuffer1 != NULL);
+
+ const GLsizei kSamples = 4;
+ const GLenum kFormat = GL_RGBA4;
+ const GLsizei kWidth = 128;
+ const GLsizei kHeight1 = 64;
+ const GLsizei kHeight2 = 32;
+ uint32 expected_size_1 = 0;
+ uint32 expected_size_2 = 0;
+ RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ kWidth, kHeight1, kSamples, kFormat, &expected_size_1);
+ RenderbufferManager::ComputeEstimatedRenderbufferSize(
+ kWidth, kHeight2, kSamples, kFormat, &expected_size_2);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(
+ 0, expected_size_1, MemoryTracker::kUnmanaged);
+ manager_->SetInfo(renderbuffer1, kSamples, kFormat, kWidth, kHeight1);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(
+ expected_size_1, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(
+ 0, expected_size_2, MemoryTracker::kUnmanaged);
+ manager_->SetInfo(renderbuffer1, kSamples, kFormat, kWidth, kHeight2);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(
+ expected_size_2, 0, MemoryTracker::kUnmanaged);
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+TEST_F(RenderbufferManagerTest, UseDeletedRenderbufferInfo) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ manager_->CreateRenderbuffer(kClient1Id, kService1Id);
+ scoped_refptr<Renderbuffer> renderbuffer1(
+ manager_->GetRenderbuffer(kClient1Id));
+ ASSERT_TRUE(renderbuffer1.get() != NULL);
+ // Remove it.
+ manager_->RemoveRenderbuffer(kClient1Id);
+ // Use after removing.
+ const GLsizei kSamples = 4;
+ const GLenum kFormat = GL_RGBA4;
+ const GLsizei kWidth = 128;
+ const GLsizei kHeight = 64;
+ manager_->SetInfo(renderbuffer1.get(), kSamples, kFormat, kWidth, kHeight);
+ // See that it still affects manager.
+ EXPECT_TRUE(manager_->HaveUnclearedRenderbuffers());
+ manager_->SetCleared(renderbuffer1.get(), true);
+ EXPECT_FALSE(manager_->HaveUnclearedRenderbuffers());
+ // Check that the renderbuffer is deleted when the last ref is released.
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ renderbuffer1 = NULL;
+}
+
+namespace {
+
+bool InSet(std::set<std::string>* string_set, const std::string& str) {
+ std::pair<std::set<std::string>::iterator, bool> result =
+ string_set->insert(str);
+ return !result.second;
+}
+
+} // anonymous namespace
+
+TEST_F(RenderbufferManagerTest, AddToSignature) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ manager_->CreateRenderbuffer(kClient1Id, kService1Id);
+ scoped_refptr<Renderbuffer> renderbuffer1(
+ manager_->GetRenderbuffer(kClient1Id));
+ ASSERT_TRUE(renderbuffer1.get() != NULL);
+ const GLsizei kSamples = 4;
+ const GLenum kFormat = GL_RGBA4;
+ const GLsizei kWidth = 128;
+ const GLsizei kHeight = 64;
+ manager_->SetInfo(renderbuffer1.get(), kSamples, kFormat, kWidth, kHeight);
+ std::string signature1;
+ std::string signature2;
+ renderbuffer1->AddToSignature(&signature1);
+
+ std::set<std::string> string_set;
+ EXPECT_FALSE(InSet(&string_set, signature1));
+
+ // change things and see that the signatures change.
+ manager_->SetInfo(
+ renderbuffer1.get(), kSamples + 1, kFormat, kWidth, kHeight);
+ renderbuffer1->AddToSignature(&signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetInfo(
+ renderbuffer1.get(), kSamples, kFormat + 1, kWidth, kHeight);
+ signature2.clear();
+ renderbuffer1->AddToSignature(&signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetInfo(
+ renderbuffer1.get(), kSamples, kFormat, kWidth + 1, kHeight);
+ signature2.clear();
+ renderbuffer1->AddToSignature(&signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetInfo(
+ renderbuffer1.get(), kSamples, kFormat, kWidth, kHeight + 1);
+ signature2.clear();
+ renderbuffer1->AddToSignature(&signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ // put it back to the same and it should be the same.
+ manager_->SetInfo(renderbuffer1.get(), kSamples, kFormat, kWidth, kHeight);
+ signature2.clear();
+ renderbuffer1->AddToSignature(&signature2);
+ EXPECT_EQ(signature1, signature2);
+
+ // Check the set was acutally getting different signatures.
+ EXPECT_EQ(5u, string_set.size());
+
+ EXPECT_CALL(*gl_, DeleteRenderbuffersEXT(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/safe_shared_memory_pool.cc b/chromium/gpu/command_buffer/service/safe_shared_memory_pool.cc
new file mode 100644
index 00000000000..9ba5390d200
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/safe_shared_memory_pool.cc
@@ -0,0 +1,149 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/process/process_handle.h"
+#include "build/build_config.h"
+
+using base::SharedMemory;
+using base::SharedMemoryHandle;
+
+namespace gpu {
+
+ScopedSafeSharedMemory::ScopedSafeSharedMemory(SafeSharedMemoryPool* pool,
+ base::SharedMemory* memory,
+ size_t shm_size) {
+ DCHECK(pool);
+ DCHECK(memory);
+ DCHECK(memory->memory());
+ pool_ = pool;
+ original_handle_ = memory->handle();
+ safe_shared_memory_ = pool->AcquireSafeSharedMemory(memory, shm_size);
+ CHECK(safe_shared_memory_);
+}
+
+ScopedSafeSharedMemory::~ScopedSafeSharedMemory() {
+ // Release the handle. The pool will delete the SharedMemory
+ // object when it is no longer referenced.
+ pool_->ReleaseSafeSharedMemory(original_handle_);
+}
+
+base::SharedMemory* ScopedSafeSharedMemory::shared_memory() {
+ return safe_shared_memory_;
+}
+
+SafeSharedMemoryPool::SafeSharedMemoryPool()
+ : handles_acquired_(0),
+ handles_consumed_(0),
+ address_space_consumed_(0),
+ max_handles_acquired_(0),
+ max_handles_consumed_(0),
+ max_address_space_consumed_(0) {
+}
+
+SafeSharedMemoryPool::~SafeSharedMemoryPool() {
+}
+
+base::SharedMemory* SafeSharedMemoryPool::
+ AcquireSafeSharedMemory(base::SharedMemory* shared_memory,
+ size_t shm_size) {
+ DCHECK(shared_memory);
+ DCHECK(shared_memory->memory());
+ base::AutoLock scoped_lock(lock_);
+
+ // Adjust stats.
+ handles_acquired_++;
+ max_handles_acquired_ = std::max(max_handles_acquired_,
+ handles_acquired_);
+
+ MemoryMap::iterator it = memory_.find(shared_memory->handle());
+ // If we don't already have it, duplicated it.
+ if (it == memory_.end()) {
+ // Duplicate a new shared memory and track it.
+ TrackedMemory tracker;
+ tracker.safe_shared_memory = DuplicateSharedMemory(shared_memory, shm_size);
+ tracker.reference_count = 1;
+ tracker.shm_size = shm_size;
+ memory_[shared_memory->handle()] = tracker;
+
+ // Adjust stats.
+ handles_consumed_++;
+ address_space_consumed_ += shm_size;
+ max_handles_consumed_ = std::max(max_handles_consumed_,
+ handles_consumed_);
+ max_address_space_consumed_ = std::max(max_address_space_consumed_,
+ address_space_consumed_);
+ return tracker.safe_shared_memory;
+ }
+
+ // Otherwise, add a reference and return the existing one.
+ DCHECK(it->second.reference_count);
+ DCHECK(it->second.safe_shared_memory);
+ DCHECK(it->second.safe_shared_memory->memory());
+ it->second.reference_count++;
+ return it->second.safe_shared_memory;
+}
+
+void SafeSharedMemoryPool::
+ ReleaseSafeSharedMemory(const base::SharedMemoryHandle& handle) {
+ base::AutoLock scoped_lock(lock_);
+
+ // Adjust stats.
+ DCHECK_GT(handles_acquired_, 0);
+ handles_acquired_--;
+
+ MemoryMap::iterator it = memory_.find(handle);
+ CHECK(it != memory_.end());
+ CHECK(it->second.reference_count);
+ CHECK(it->second.safe_shared_memory);
+ if (--it->second.reference_count == 0) {
+ // Adjust stats.
+ DCHECK_GT(handles_consumed_, 0);
+ handles_consumed_--;
+ DCHECK_LE(it->second.shm_size, address_space_consumed_);
+ address_space_consumed_ -= it->second.shm_size;
+ // Delete the safe memory and remove it.
+ delete it->second.safe_shared_memory;
+ memory_.erase(it);
+ }
+}
+
+SharedMemory* SafeSharedMemoryPool::DuplicateSharedMemory(
+ SharedMemory* shared_memory, size_t size) {
+ // Duplicate the handle.
+ SharedMemoryHandle duped_shared_memory_handle;
+ if (!shared_memory->ShareToProcess(
+ base::GetCurrentProcessHandle(),
+ &duped_shared_memory_handle)) {
+ PLOG(ERROR) << "Failed SharedMemory::ShareToProcess";
+ LOG(ERROR) << "Total handles acquired " << handles_acquired_;
+ LOG(ERROR) << "Total handles open " << handles_consumed_;
+ LOG(ERROR) << "Total address space " << address_space_consumed_;
+ LOG(ERROR) << "Max handles acquired " << max_handles_acquired_;
+ LOG(ERROR) << "Max handles open " << max_handles_consumed_;
+ LOG(ERROR) << "Max address space " << max_address_space_consumed_;
+ CHECK(false); // Diagnosing a crash.
+ return NULL;
+ }
+ scoped_ptr<SharedMemory> duped_shared_memory(
+ new SharedMemory(duped_shared_memory_handle, false));
+ // Map the shared memory into this process. This validates the size.
+ if (!duped_shared_memory->Map(size)) {
+ PLOG(ERROR) << "Failed SharedMemory::Map(" << size << ")";
+ LOG(ERROR) << "Total handles acquired " << handles_acquired_;
+ LOG(ERROR) << "Total handles open " << handles_consumed_;
+ LOG(ERROR) << "Total address space " << address_space_consumed_;
+ LOG(ERROR) << "Max handles acquired " << max_handles_acquired_;
+ LOG(ERROR) << "Max handles open " << max_handles_consumed_;
+ LOG(ERROR) << "Max address space " << max_address_space_consumed_;
+ CHECK(false); // Diagnosing a crash.
+ return NULL;
+ }
+ return duped_shared_memory.release();
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/safe_shared_memory_pool.h b/chromium/gpu/command_buffer/service/safe_shared_memory_pool.h
new file mode 100644
index 00000000000..fed17ff3726
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/safe_shared_memory_pool.h
@@ -0,0 +1,82 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SAFE_SHARED_MEMORY_POOL_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SAFE_SHARED_MEMORY_POOL_H_
+
+#include <map>
+
+#include "base/basictypes.h"
+#include "base/memory/shared_memory.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+
+namespace gpu {
+class SafeSharedMemoryPool;
+
+// These classes exist to help protect against deletion of shared
+// memory that is being used on a worker thread. It's mainly a
+// security measure to prevent use-after-free in the browser, due
+// to a misbehaving client. That said, this should be removed
+// in favor of higher-level reference counting of an appropriate
+// opaque 'memory blob' data-structure.
+
+class ScopedSafeSharedMemory {
+ public:
+ base::SharedMemory* shared_memory();
+ ScopedSafeSharedMemory(SafeSharedMemoryPool* pool,
+ base::SharedMemory* memory,
+ size_t shm_size);
+ ~ScopedSafeSharedMemory();
+ private:
+ base::SharedMemory* safe_shared_memory_;
+ base::SharedMemoryHandle original_handle_;
+ SafeSharedMemoryPool* pool_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedSafeSharedMemory);
+};
+
+class SafeSharedMemoryPool {
+ public:
+ SafeSharedMemoryPool();
+ virtual ~SafeSharedMemoryPool();
+
+ private:
+ friend class ScopedSafeSharedMemory;
+
+ // Acquires and release shared memory. The acquired shared memory
+ // is guaranteed to live until it is released.
+ base::SharedMemory* AcquireSafeSharedMemory(base::SharedMemory*, size_t size);
+ void ReleaseSafeSharedMemory(const base::SharedMemoryHandle&);
+
+ // Utility function to duplicate shared memory.
+ base::SharedMemory* DuplicateSharedMemory(base::SharedMemory*, size_t size);
+
+ // Track all SharedMemory's that we have already duplicated.
+ struct TrackedMemory {
+ base::SharedMemory* safe_shared_memory;
+ size_t shm_size;
+ int reference_count;
+ };
+
+ typedef std::map<base::SharedMemoryHandle, TrackedMemory> MemoryMap;
+ MemoryMap memory_;
+
+ // Track usage to diagnose crashes.
+ int handles_acquired_;
+ int handles_consumed_;
+ size_t address_space_consumed_;
+ int max_handles_acquired_;
+ int max_handles_consumed_;
+ size_t max_address_space_consumed_;
+
+ base::Lock lock_;
+
+ DISALLOW_COPY_AND_ASSIGN(SafeSharedMemoryPool);
+};
+
+} // namespace gfx
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SAFE_SHARED_MEMORY_POOL_H_
+
diff --git a/chromium/gpu/command_buffer/service/shader_manager.cc b/chromium/gpu/command_buffer/service/shader_manager.cc
new file mode 100644
index 00000000000..a95b04ced08
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_manager.cc
@@ -0,0 +1,187 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/shader_manager.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+
+namespace gpu {
+namespace gles2 {
+
+Shader::Shader(GLuint service_id, GLenum shader_type)
+ : use_count_(0),
+ service_id_(service_id),
+ shader_type_(shader_type),
+ valid_(false) {
+}
+
+Shader::~Shader() {
+}
+
+void Shader::IncUseCount() {
+ ++use_count_;
+}
+
+void Shader::DecUseCount() {
+ --use_count_;
+ DCHECK_GE(use_count_, 0);
+}
+
+void Shader::MarkAsDeleted() {
+ DCHECK_NE(service_id_, 0u);
+ service_id_ = 0;
+}
+
+void Shader::SetStatus(
+ bool valid, const char* log, ShaderTranslatorInterface* translator) {
+ valid_ = valid;
+ log_info_.reset(log ? new std::string(log) : NULL);
+ if (translator && valid) {
+ attrib_map_ = translator->attrib_map();
+ uniform_map_ = translator->uniform_map();
+ name_map_ = translator->name_map();
+ } else {
+ attrib_map_.clear();
+ uniform_map_.clear();
+ name_map_.clear();
+ }
+ if (valid && source_.get()) {
+ signature_source_.reset(new std::string(source_->c_str()));
+ } else {
+ signature_source_.reset();
+ }
+}
+
+const Shader::VariableInfo*
+ Shader::GetAttribInfo(
+ const std::string& name) const {
+ VariableMap::const_iterator it = attrib_map_.find(name);
+ return it != attrib_map_.end() ? &it->second : NULL;
+}
+
+const std::string* Shader::GetAttribMappedName(
+ const std::string& original_name) const {
+ for (VariableMap::const_iterator it = attrib_map_.begin();
+ it != attrib_map_.end(); ++it) {
+ if (it->second.name == original_name)
+ return &(it->first);
+ }
+ return NULL;
+}
+
+const std::string* Shader::GetOriginalNameFromHashedName(
+ const std::string& hashed_name) const {
+ NameMap::const_iterator it = name_map_.find(hashed_name);
+ if (it != name_map_.end())
+ return &(it->second);
+ return NULL;
+}
+
+const Shader::VariableInfo*
+ Shader::GetUniformInfo(
+ const std::string& name) const {
+ VariableMap::const_iterator it = uniform_map_.find(name);
+ return it != uniform_map_.end() ? &it->second : NULL;
+}
+
+ShaderManager::ShaderManager() {}
+
+ShaderManager::~ShaderManager() {
+ DCHECK(shaders_.empty());
+}
+
+void ShaderManager::Destroy(bool have_context) {
+ while (!shaders_.empty()) {
+ if (have_context) {
+ Shader* shader = shaders_.begin()->second.get();
+ if (!shader->IsDeleted()) {
+ glDeleteShader(shader->service_id());
+ shader->MarkAsDeleted();
+ }
+ }
+ shaders_.erase(shaders_.begin());
+ }
+}
+
+Shader* ShaderManager::CreateShader(
+ GLuint client_id,
+ GLuint service_id,
+ GLenum shader_type) {
+ std::pair<ShaderMap::iterator, bool> result =
+ shaders_.insert(std::make_pair(
+ client_id, scoped_refptr<Shader>(
+ new Shader(service_id, shader_type))));
+ DCHECK(result.second);
+ return result.first->second.get();
+}
+
+Shader* ShaderManager::GetShader(GLuint client_id) {
+ ShaderMap::iterator it = shaders_.find(client_id);
+ return it != shaders_.end() ? it->second.get() : NULL;
+}
+
+bool ShaderManager::GetClientId(GLuint service_id, GLuint* client_id) const {
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (ShaderMap::const_iterator it = shaders_.begin();
+ it != shaders_.end(); ++it) {
+ if (it->second->service_id() == service_id) {
+ *client_id = it->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool ShaderManager::IsOwned(Shader* shader) {
+ for (ShaderMap::iterator it = shaders_.begin();
+ it != shaders_.end(); ++it) {
+ if (it->second.get() == shader) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void ShaderManager::RemoveShader(Shader* shader) {
+ DCHECK(shader);
+ DCHECK(IsOwned(shader));
+ if (shader->IsDeleted() && !shader->InUse()) {
+ for (ShaderMap::iterator it = shaders_.begin();
+ it != shaders_.end(); ++it) {
+ if (it->second.get() == shader) {
+ shaders_.erase(it);
+ return;
+ }
+ }
+ NOTREACHED();
+ }
+}
+
+void ShaderManager::MarkAsDeleted(Shader* shader) {
+ DCHECK(shader);
+ DCHECK(IsOwned(shader));
+ shader->MarkAsDeleted();
+ RemoveShader(shader);
+}
+
+void ShaderManager::UseShader(Shader* shader) {
+ DCHECK(shader);
+ DCHECK(IsOwned(shader));
+ shader->IncUseCount();
+}
+
+void ShaderManager::UnuseShader(Shader* shader) {
+ DCHECK(shader);
+ DCHECK(IsOwned(shader));
+ shader->DecUseCount();
+ RemoveShader(shader);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/shader_manager.h b/chromium/gpu/command_buffer/service/shader_manager.h
new file mode 100644
index 00000000000..bc68868bf27
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_manager.h
@@ -0,0 +1,209 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SHADER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SHADER_MANAGER_H_
+
+#include <string>
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+// This is used to keep the source code for a shader. This is because in order
+// to emluate GLES2 the shaders will have to be re-written before passed to
+// the underlying OpenGL. But, when the user calls glGetShaderSource they
+// should get the source they passed in, not the re-written source.
+class GPU_EXPORT Shader : public base::RefCounted<Shader> {
+ public:
+ typedef ShaderTranslator::VariableInfo VariableInfo;
+
+ void UpdateSource(const char* source) {
+ source_.reset(source ? new std::string(source) : NULL);
+ }
+
+ void UpdateTranslatedSource(const char* translated_source) {
+ translated_source_.reset(
+ translated_source ? new std::string(translated_source) : NULL);
+ }
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ GLenum shader_type() const {
+ return shader_type_;
+ }
+
+ const std::string* source() const {
+ return source_.get();
+ }
+
+ const std::string* translated_source() const {
+ return translated_source_.get();
+ }
+
+ const std::string* signature_source() const {
+ return signature_source_.get();
+ }
+
+ void SetStatus(
+ bool valid, const char* log,
+ ShaderTranslatorInterface* translator);
+
+ const VariableInfo* GetAttribInfo(const std::string& name) const;
+ const VariableInfo* GetUniformInfo(const std::string& name) const;
+
+ // If the original_name is not found, return NULL.
+ const std::string* GetAttribMappedName(
+ const std::string& original_name) const;
+
+ // If the hashed_name is not found, return NULL.
+ const std::string* GetOriginalNameFromHashedName(
+ const std::string& hashed_name) const;
+
+ const std::string* log_info() const {
+ return log_info_.get();
+ }
+
+ bool IsValid() const {
+ return valid_;
+ }
+
+ bool IsDeleted() const {
+ return service_id_ == 0;
+ }
+
+ bool InUse() const {
+ DCHECK_GE(use_count_, 0);
+ return use_count_ != 0;
+ }
+
+ // Used by program cache.
+ const ShaderTranslator::VariableMap& attrib_map() const {
+ return attrib_map_;
+ }
+
+ // Used by program cache.
+ const ShaderTranslator::VariableMap& uniform_map() const {
+ return uniform_map_;
+ }
+
+ // Used by program cache.
+ void set_attrib_map(const ShaderTranslator::VariableMap& attrib_map) {
+ // copied because cache might be cleared
+ attrib_map_ = ShaderTranslator::VariableMap(attrib_map);
+ }
+
+ // Used by program cache.
+ void set_uniform_map(const ShaderTranslator::VariableMap& uniform_map) {
+ // copied because cache might be cleared
+ uniform_map_ = ShaderTranslator::VariableMap(uniform_map);
+ }
+
+ private:
+ typedef ShaderTranslator::VariableMap VariableMap;
+ typedef ShaderTranslator::NameMap NameMap;
+
+ friend class base::RefCounted<Shader>;
+ friend class ShaderManager;
+
+ Shader(GLuint service_id, GLenum shader_type);
+ ~Shader();
+
+ void IncUseCount();
+ void DecUseCount();
+ void MarkAsDeleted();
+
+ int use_count_;
+
+ // The shader this Shader is tracking.
+ GLuint service_id_;
+ // Type of shader - GL_VERTEX_SHADER or GL_FRAGMENT_SHADER.
+ GLenum shader_type_;
+
+ // True if compilation succeeded.
+ bool valid_;
+
+ // The shader source as passed to glShaderSource.
+ scoped_ptr<std::string> source_;
+
+ // The source the last compile used.
+ scoped_ptr<std::string> signature_source_;
+
+ // The translated shader source.
+ scoped_ptr<std::string> translated_source_;
+
+ // The shader translation log.
+ scoped_ptr<std::string> log_info_;
+
+ // The type info when the shader was last compiled.
+ VariableMap attrib_map_;
+ VariableMap uniform_map_;
+
+ // The name hashing info when the shader was last compiled.
+ NameMap name_map_;
+};
+
+// Tracks the Shaders.
+//
+// NOTE: To support shared resources an instance of this class will
+// need to be shared by multiple GLES2Decoders.
+class GPU_EXPORT ShaderManager {
+ public:
+ ShaderManager();
+ ~ShaderManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a shader for the given shader ID.
+ Shader* CreateShader(
+ GLuint client_id,
+ GLuint service_id,
+ GLenum shader_type);
+
+ // Gets an existing shader info for the given shader ID. Returns NULL if none
+ // exists.
+ Shader* GetShader(GLuint client_id);
+
+ // Gets a client id for a given service id.
+ bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
+ void MarkAsDeleted(Shader* shader);
+
+ // Mark a shader as used
+ void UseShader(Shader* shader);
+
+ // Unmark a shader as used. If it has been deleted and is not used
+ // then we free the shader.
+ void UnuseShader(Shader* shader);
+
+ // Check if a Shader is owned by this ShaderManager.
+ bool IsOwned(Shader* shader);
+
+ private:
+ friend class Shader;
+
+ // Info for each shader by service side shader Id.
+ typedef base::hash_map<GLuint, scoped_refptr<Shader> > ShaderMap;
+ ShaderMap shaders_;
+
+ void RemoveShader(Shader* shader);
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SHADER_MANAGER_H_
+
diff --git a/chromium/gpu/command_buffer/service/shader_manager_unittest.cc b/chromium/gpu/command_buffer/service/shader_manager_unittest.cc
new file mode 100644
index 00000000000..a225a3cc8c1
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_manager_unittest.cc
@@ -0,0 +1,252 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/shader_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::Return;
+using ::testing::ReturnRef;
+
+namespace gpu {
+namespace gles2 {
+
+class ShaderManagerTest : public testing::Test {
+ public:
+ ShaderManagerTest() {
+ }
+
+ virtual ~ShaderManagerTest() {
+ manager_.Destroy(false);
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ ShaderManager manager_;
+};
+
+TEST_F(ShaderManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kShader1Type = GL_VERTEX_SHADER;
+ const GLuint kClient2Id = 2;
+ // Check we can create shader.
+ Shader* info0 = manager_.CreateShader(
+ kClient1Id, kService1Id, kShader1Type);
+ // Check shader got created.
+ ASSERT_TRUE(info0 != NULL);
+ Shader* shader1 = manager_.GetShader(kClient1Id);
+ ASSERT_EQ(info0, shader1);
+ // Check we get nothing for a non-existent shader.
+ EXPECT_TRUE(manager_.GetShader(kClient2Id) == NULL);
+ // Check we can't get the shader after we remove it.
+ manager_.MarkAsDeleted(shader1);
+ EXPECT_TRUE(manager_.GetShader(kClient1Id) == NULL);
+}
+
+TEST_F(ShaderManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kShader1Type = GL_VERTEX_SHADER;
+ // Check we can create shader.
+ Shader* shader1 = manager_.CreateShader(
+ kClient1Id, kService1Id, kShader1Type);
+ // Check shader got created.
+ ASSERT_TRUE(shader1 != NULL);
+ EXPECT_CALL(*gl_, DeleteShader(kService1Id))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager_.Destroy(true);
+ // Check that resources got freed.
+ shader1 = manager_.GetShader(kClient1Id);
+ ASSERT_TRUE(shader1 == NULL);
+}
+
+TEST_F(ShaderManagerTest, DeleteBug) {
+ const GLuint kClient1Id = 1;
+ const GLuint kClient2Id = 2;
+ const GLuint kService1Id = 11;
+ const GLuint kService2Id = 12;
+ const GLenum kShaderType = GL_VERTEX_SHADER;
+ // Check we can create shader.
+ scoped_refptr<Shader> shader1(
+ manager_.CreateShader(kClient1Id, kService1Id, kShaderType));
+ scoped_refptr<Shader> shader2(
+ manager_.CreateShader(kClient2Id, kService2Id, kShaderType));
+ ASSERT_TRUE(shader1.get());
+ ASSERT_TRUE(shader2.get());
+ manager_.UseShader(shader1.get());
+ manager_.MarkAsDeleted(shader1.get());
+ manager_.MarkAsDeleted(shader2.get());
+ EXPECT_TRUE(manager_.IsOwned(shader1.get()));
+ EXPECT_FALSE(manager_.IsOwned(shader2.get()));
+}
+
+TEST_F(ShaderManagerTest, Shader) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kShader1Type = GL_VERTEX_SHADER;
+ const char* kClient1Source = "hello world";
+ // Check we can create shader.
+ Shader* shader1 = manager_.CreateShader(
+ kClient1Id, kService1Id, kShader1Type);
+ // Check shader got created.
+ ASSERT_TRUE(shader1 != NULL);
+ EXPECT_EQ(kService1Id, shader1->service_id());
+ // Check if the shader has correct type.
+ EXPECT_EQ(kShader1Type, shader1->shader_type());
+ EXPECT_FALSE(shader1->IsValid());
+ EXPECT_FALSE(shader1->InUse());
+ EXPECT_TRUE(shader1->source() == NULL);
+ EXPECT_TRUE(shader1->log_info() == NULL);
+ const char* kLog = "foo";
+ shader1->SetStatus(true, kLog, NULL);
+ EXPECT_TRUE(shader1->IsValid());
+ EXPECT_STREQ(kLog, shader1->log_info()->c_str());
+ // Check we can set its source.
+ shader1->UpdateSource(kClient1Source);
+ EXPECT_STREQ(kClient1Source, shader1->source()->c_str());
+ EXPECT_EQ(NULL, shader1->translated_source());
+ // Check we can set its translated source.
+ shader1->UpdateTranslatedSource(kClient1Source);
+ EXPECT_STREQ(kClient1Source,
+ shader1->translated_source()->c_str());
+}
+
+TEST_F(ShaderManagerTest, GetInfo) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kShader1Type = GL_VERTEX_SHADER;
+ const GLenum kAttrib1Type = GL_FLOAT_VEC2;
+ const GLsizei kAttrib1Size = 2;
+ const char* kAttrib1Name = "attr1";
+ const GLenum kAttrib2Type = GL_FLOAT_VEC3;
+ const GLsizei kAttrib2Size = 4;
+ const char* kAttrib2Name = "attr2";
+ const GLenum kUniform1Type = GL_FLOAT_MAT2;
+ const GLsizei kUniform1Size = 3;
+ const char* kUniform1Name = "uni1";
+ const GLenum kUniform2Type = GL_FLOAT_MAT3;
+ const GLsizei kUniform2Size = 5;
+ const char* kUniform2Name = "uni2";
+ MockShaderTranslator shader_translator;
+ ShaderTranslator::VariableMap attrib_map;
+ attrib_map[kAttrib1Name] = ShaderTranslatorInterface::VariableInfo(
+ kAttrib1Type, kAttrib1Size, kAttrib1Name);
+ attrib_map[kAttrib2Name] = ShaderTranslatorInterface::VariableInfo(
+ kAttrib2Type, kAttrib2Size, kAttrib2Name);
+ ShaderTranslator::VariableMap uniform_map;
+ uniform_map[kUniform1Name] = ShaderTranslatorInterface::VariableInfo(
+ kUniform1Type, kUniform1Size, kUniform1Name);
+ uniform_map[kUniform2Name] = ShaderTranslatorInterface::VariableInfo(
+ kUniform2Type, kUniform2Size, kUniform2Name);
+ EXPECT_CALL(shader_translator, attrib_map())
+ .WillRepeatedly(ReturnRef(attrib_map));
+ EXPECT_CALL(shader_translator, uniform_map())
+ .WillRepeatedly(ReturnRef(uniform_map));
+ ShaderTranslator::NameMap name_map;
+ EXPECT_CALL(shader_translator, name_map())
+ .WillRepeatedly(ReturnRef(name_map));
+ // Check we can create shader.
+ Shader* shader1 = manager_.CreateShader(
+ kClient1Id, kService1Id, kShader1Type);
+ // Check shader got created.
+ ASSERT_TRUE(shader1 != NULL);
+ // Set Status
+ shader1->SetStatus(true, "", &shader_translator);
+ // Check attrib and uniform infos got copied.
+ for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin();
+ it != attrib_map.end(); ++it) {
+ const Shader::VariableInfo* variable_info =
+ shader1->GetAttribInfo(it->first);
+ ASSERT_TRUE(variable_info != NULL);
+ EXPECT_EQ(it->second.type, variable_info->type);
+ EXPECT_EQ(it->second.size, variable_info->size);
+ EXPECT_EQ(it->second.name, variable_info->name);
+ }
+ for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin();
+ it != uniform_map.end(); ++it) {
+ const Shader::VariableInfo* variable_info =
+ shader1->GetUniformInfo(it->first);
+ ASSERT_TRUE(variable_info != NULL);
+ EXPECT_EQ(it->second.type, variable_info->type);
+ EXPECT_EQ(it->second.size, variable_info->size);
+ EXPECT_EQ(it->second.name, variable_info->name);
+ }
+ // Check attrib and uniform get cleared.
+ shader1->SetStatus(true, NULL, NULL);
+ EXPECT_TRUE(shader1->log_info() == NULL);
+ for (ShaderTranslator::VariableMap::const_iterator it = attrib_map.begin();
+ it != attrib_map.end(); ++it) {
+ const Shader::VariableInfo* variable_info =
+ shader1->GetAttribInfo(it->first);
+ EXPECT_TRUE(variable_info == NULL);
+ }
+ for (ShaderTranslator::VariableMap::const_iterator it = uniform_map.begin();
+ it != uniform_map.end(); ++it) {
+ const Shader::VariableInfo* variable_info =
+ shader1->GetUniformInfo(it->first);
+ ASSERT_TRUE(variable_info == NULL);
+ }
+}
+
+TEST_F(ShaderManagerTest, ShaderInfoUseCount) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLenum kShader1Type = GL_VERTEX_SHADER;
+ // Check we can create shader.
+ Shader* shader1 = manager_.CreateShader(
+ kClient1Id, kService1Id, kShader1Type);
+ // Check shader got created.
+ ASSERT_TRUE(shader1 != NULL);
+ EXPECT_FALSE(shader1->InUse());
+ EXPECT_FALSE(shader1->IsDeleted());
+ manager_.UseShader(shader1);
+ EXPECT_TRUE(shader1->InUse());
+ manager_.UseShader(shader1);
+ EXPECT_TRUE(shader1->InUse());
+ manager_.MarkAsDeleted(shader1);
+ EXPECT_TRUE(shader1->IsDeleted());
+ Shader* shader2 = manager_.GetShader(kClient1Id);
+ EXPECT_EQ(shader1, shader2);
+ manager_.UnuseShader(shader1);
+ EXPECT_TRUE(shader1->InUse());
+ manager_.UnuseShader(shader1); // this should delete the info.
+ shader2 = manager_.GetShader(kClient1Id);
+ EXPECT_TRUE(shader2 == NULL);
+
+ shader1 = manager_.CreateShader(kClient1Id, kService1Id, kShader1Type);
+ ASSERT_TRUE(shader1 != NULL);
+ EXPECT_FALSE(shader1->InUse());
+ manager_.UseShader(shader1);
+ EXPECT_TRUE(shader1->InUse());
+ manager_.UseShader(shader1);
+ EXPECT_TRUE(shader1->InUse());
+ manager_.UnuseShader(shader1);
+ EXPECT_TRUE(shader1->InUse());
+ manager_.UnuseShader(shader1);
+ EXPECT_FALSE(shader1->InUse());
+ shader2 = manager_.GetShader(kClient1Id);
+ EXPECT_EQ(shader1, shader2);
+ manager_.MarkAsDeleted(shader1); // this should delete the shader.
+ shader2 = manager_.GetShader(kClient1Id);
+ EXPECT_TRUE(shader2 == NULL);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/shader_translator.cc b/chromium/gpu/command_buffer/service/shader_translator.cc
new file mode 100644
index 00000000000..5129bfce734
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_translator.cc
@@ -0,0 +1,318 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/shader_translator.h"
+
+#include <string.h>
+#include <algorithm>
+
+#include "base/at_exit.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+
+namespace {
+
+using gpu::gles2::ShaderTranslator;
+
+void FinalizeShaderTranslator(void* /* dummy */) {
+ TRACE_EVENT0("gpu", "ShFinalize");
+ ShFinalize();
+}
+
+bool InitializeShaderTranslator() {
+ static bool initialized = false;
+ if (!initialized) {
+ TRACE_EVENT0("gpu", "ShInitialize");
+ CHECK(ShInitialize());
+ base::AtExitManager::RegisterCallback(&FinalizeShaderTranslator, NULL);
+ initialized = true;
+ }
+ return initialized;
+}
+
+#if !defined(ANGLE_SH_VERSION) || ANGLE_SH_VERSION < 108
+typedef int ANGLEGetInfoType;
+#else
+typedef size_t ANGLEGetInfoType;
+#endif
+
+void GetVariableInfo(ShHandle compiler, ShShaderInfo var_type,
+ ShaderTranslator::VariableMap* var_map) {
+ ANGLEGetInfoType name_len = 0, mapped_name_len = 0;
+ switch (var_type) {
+ case SH_ACTIVE_ATTRIBUTES:
+ ShGetInfo(compiler, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH, &name_len);
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ ShGetInfo(compiler, SH_ACTIVE_UNIFORM_MAX_LENGTH, &name_len);
+ break;
+ default: NOTREACHED();
+ }
+ ShGetInfo(compiler, SH_MAPPED_NAME_MAX_LENGTH, &mapped_name_len);
+ if (name_len <= 1 || mapped_name_len <= 1) return;
+ scoped_ptr<char[]> name(new char[name_len]);
+ scoped_ptr<char[]> mapped_name(new char[mapped_name_len]);
+
+ ANGLEGetInfoType num_vars = 0;
+ ShGetInfo(compiler, var_type, &num_vars);
+ for (ANGLEGetInfoType i = 0; i < num_vars; ++i) {
+ ANGLEGetInfoType len = 0;
+ int size = 0;
+ ShDataType type = SH_NONE;
+
+ switch (var_type) {
+ case SH_ACTIVE_ATTRIBUTES:
+ ShGetActiveAttrib(
+ compiler, i, &len, &size, &type, name.get(), mapped_name.get());
+ break;
+ case SH_ACTIVE_UNIFORMS:
+ ShGetActiveUniform(
+ compiler, i, &len, &size, &type, name.get(), mapped_name.get());
+ break;
+ default: NOTREACHED();
+ }
+
+ // In theory we should CHECK(len <= name_len - 1) here, but ANGLE needs
+ // to handle long struct field name mapping before we can do this.
+ // Also, we should modify the ANGLE interface to also return a length
+ // for mapped_name.
+ std::string name_string(name.get(), std::min(len, name_len - 1));
+ mapped_name.get()[mapped_name_len - 1] = '\0';
+
+ ShaderTranslator::VariableInfo info(type, size, name_string);
+ (*var_map)[mapped_name.get()] = info;
+ }
+}
+
+void GetNameHashingInfo(
+ ShHandle compiler, ShaderTranslator::NameMap* name_map) {
+ ANGLEGetInfoType hashed_names_count = 0;
+ ShGetInfo(compiler, SH_HASHED_NAMES_COUNT, &hashed_names_count);
+ if (hashed_names_count == 0)
+ return;
+
+ ANGLEGetInfoType name_max_len = 0, hashed_name_max_len = 0;
+ ShGetInfo(compiler, SH_NAME_MAX_LENGTH, &name_max_len);
+ ShGetInfo(compiler, SH_HASHED_NAME_MAX_LENGTH, &hashed_name_max_len);
+
+ scoped_ptr<char[]> name(new char[name_max_len]);
+ scoped_ptr<char[]> hashed_name(new char[hashed_name_max_len]);
+
+ for (ANGLEGetInfoType i = 0; i < hashed_names_count; ++i) {
+ ShGetNameHashingEntry(compiler, i, name.get(), hashed_name.get());
+ (*name_map)[hashed_name.get()] = name.get();
+ }
+}
+
+} // namespace
+
+namespace gpu {
+namespace gles2 {
+
+ShaderTranslator::DestructionObserver::DestructionObserver() {
+}
+
+ShaderTranslator::DestructionObserver::~DestructionObserver() {
+}
+
+ShaderTranslator::ShaderTranslator()
+ : compiler_(NULL),
+ implementation_is_glsl_es_(false),
+ needs_built_in_function_emulation_(false) {
+}
+
+bool ShaderTranslator::Init(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources* resources,
+ ShaderTranslatorInterface::GlslImplementationType glsl_implementation_type,
+ ShaderTranslatorInterface::GlslBuiltInFunctionBehavior
+ glsl_built_in_function_behavior) {
+ // Make sure Init is called only once.
+ DCHECK(compiler_ == NULL);
+ DCHECK(shader_type == SH_FRAGMENT_SHADER || shader_type == SH_VERTEX_SHADER);
+ DCHECK(shader_spec == SH_GLES2_SPEC || shader_spec == SH_WEBGL_SPEC);
+ DCHECK(resources != NULL);
+
+ if (!InitializeShaderTranslator())
+ return false;
+
+ ShShaderOutput shader_output =
+ (glsl_implementation_type == kGlslES ? SH_ESSL_OUTPUT : SH_GLSL_OUTPUT);
+
+ {
+ TRACE_EVENT0("gpu", "ShConstructCompiler");
+ compiler_ = ShConstructCompiler(
+ shader_type, shader_spec, shader_output, resources);
+ }
+ compiler_options_ = *resources;
+ implementation_is_glsl_es_ = (glsl_implementation_type == kGlslES);
+ needs_built_in_function_emulation_ =
+ (glsl_built_in_function_behavior == kGlslBuiltInFunctionEmulated);
+ return compiler_ != NULL;
+}
+
+int ShaderTranslator::GetCompileOptions() const {
+ int compile_options =
+ SH_OBJECT_CODE | SH_ATTRIBUTES_UNIFORMS |
+ SH_MAP_LONG_VARIABLE_NAMES | SH_ENFORCE_PACKING_RESTRICTIONS |
+ SH_LIMIT_EXPRESSION_COMPLEXITY | SH_LIMIT_CALL_STACK_DEPTH;
+
+ compile_options |= SH_CLAMP_INDIRECT_ARRAY_BOUNDS;
+
+ if (needs_built_in_function_emulation_)
+ compile_options |= SH_EMULATE_BUILT_IN_FUNCTIONS;
+
+ return compile_options;
+}
+
+bool ShaderTranslator::Translate(const char* shader) {
+ // Make sure this instance is initialized.
+ DCHECK(compiler_ != NULL);
+ DCHECK(shader != NULL);
+ ClearResults();
+
+ bool success = false;
+ {
+ TRACE_EVENT0("gpu", "ShCompile");
+ success = !!ShCompile(compiler_, &shader, 1, GetCompileOptions());
+ }
+ if (success) {
+ // Get translated shader.
+ ANGLEGetInfoType obj_code_len = 0;
+ ShGetInfo(compiler_, SH_OBJECT_CODE_LENGTH, &obj_code_len);
+ if (obj_code_len > 1) {
+ translated_shader_.reset(new char[obj_code_len]);
+ ShGetObjectCode(compiler_, translated_shader_.get());
+ }
+ // Get info for attribs and uniforms.
+ GetVariableInfo(compiler_, SH_ACTIVE_ATTRIBUTES, &attrib_map_);
+ GetVariableInfo(compiler_, SH_ACTIVE_UNIFORMS, &uniform_map_);
+ // Get info for name hashing.
+ GetNameHashingInfo(compiler_, &name_map_);
+ }
+
+ // Get info log.
+ ANGLEGetInfoType info_log_len = 0;
+ ShGetInfo(compiler_, SH_INFO_LOG_LENGTH, &info_log_len);
+ if (info_log_len > 1) {
+ info_log_.reset(new char[info_log_len]);
+ ShGetInfoLog(compiler_, info_log_.get());
+ } else {
+ info_log_.reset();
+ }
+
+ return success;
+}
+
+std::string ShaderTranslator::GetStringForOptionsThatWouldEffectCompilation()
+ const {
+ const size_t kNumIntFields = 16;
+ const size_t kNumEnumFields = 1;
+ const size_t kNumFunctionPointerFields = 1;
+ struct MustMatchShBuiltInResource {
+ typedef khronos_uint64_t (*FunctionPointer)(const char*, size_t);
+ enum Enum {
+ kFirst,
+ };
+ int int_fields[kNumIntFields];
+ FunctionPointer pointer_fields[kNumFunctionPointerFields];
+ Enum enum_fields[kNumEnumFields];
+ };
+ // If this assert fails most likely that means something below needs updating.
+ COMPILE_ASSERT(
+ sizeof(ShBuiltInResources) == sizeof(MustMatchShBuiltInResource),
+ Fields_Have_Changed_In_ShBuiltInResource_So_Update_Below);
+
+ return std::string(
+ ":CompileOptions:" +
+ base::IntToString(GetCompileOptions()) +
+ ":MaxVertexAttribs:" +
+ base::IntToString(compiler_options_.MaxVertexAttribs) +
+ ":MaxVertexUniformVectors:" +
+ base::IntToString(compiler_options_.MaxVertexUniformVectors) +
+ ":MaxVaryingVectors:" +
+ base::IntToString(compiler_options_.MaxVaryingVectors) +
+ ":MaxVertexTextureImageUnits:" +
+ base::IntToString(compiler_options_.MaxVertexTextureImageUnits) +
+ ":MaxCombinedTextureImageUnits:" +
+ base::IntToString(compiler_options_.MaxCombinedTextureImageUnits) +
+ ":MaxTextureImageUnits:" +
+ base::IntToString(compiler_options_.MaxTextureImageUnits) +
+ ":MaxFragmentUniformVectors:" +
+ base::IntToString(compiler_options_.MaxFragmentUniformVectors) +
+ ":MaxDrawBuffers:" +
+ base::IntToString(compiler_options_.MaxDrawBuffers) +
+ ":OES_standard_derivatives:" +
+ base::IntToString(compiler_options_.OES_standard_derivatives) +
+ ":OES_EGL_image_external:" +
+ base::IntToString(compiler_options_.OES_EGL_image_external) +
+ ":ARB_texture_rectangle:" +
+ base::IntToString(compiler_options_.ARB_texture_rectangle) +
+ ":EXT_draw_buffers:" +
+ base::IntToString(compiler_options_.EXT_draw_buffers) +
+ ":FragmentPrecisionHigh:" +
+ base::IntToString(compiler_options_.FragmentPrecisionHigh) +
+ ":MaxExpressionComplexity:" +
+ base::IntToString(compiler_options_.MaxExpressionComplexity) +
+ ":MaxCallStackDepth:" +
+ base::IntToString(compiler_options_.MaxCallStackDepth) +
+ ":EXT_frag_depth:" +
+ base::IntToString(compiler_options_.EXT_frag_depth));
+}
+
+const char* ShaderTranslator::translated_shader() const {
+ return translated_shader_.get();
+}
+
+const char* ShaderTranslator::info_log() const {
+ return info_log_.get();
+}
+
+const ShaderTranslatorInterface::VariableMap&
+ShaderTranslator::attrib_map() const {
+ return attrib_map_;
+}
+
+const ShaderTranslatorInterface::VariableMap&
+ShaderTranslator::uniform_map() const {
+ return uniform_map_;
+}
+
+const ShaderTranslatorInterface::NameMap&
+ShaderTranslator::name_map() const {
+ return name_map_;
+}
+
+void ShaderTranslator::AddDestructionObserver(
+ DestructionObserver* observer) {
+ destruction_observers_.AddObserver(observer);
+}
+
+void ShaderTranslator::RemoveDestructionObserver(
+ DestructionObserver* observer) {
+ destruction_observers_.RemoveObserver(observer);
+}
+
+ShaderTranslator::~ShaderTranslator() {
+ FOR_EACH_OBSERVER(DestructionObserver,
+ destruction_observers_,
+ OnDestruct(this));
+
+ if (compiler_ != NULL)
+ ShDestruct(compiler_);
+}
+
+void ShaderTranslator::ClearResults() {
+ translated_shader_.reset();
+ info_log_.reset();
+ attrib_map_.clear();
+ uniform_map_.clear();
+ name_map_.clear();
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/shader_translator.h b/chromium/gpu/command_buffer/service/shader_translator.h
new file mode 100644
index 00000000000..957f721bec7
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_translator.h
@@ -0,0 +1,164 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SHADER_TRANSLATOR_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SHADER_TRANSLATOR_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/observer_list.h"
+#include "gpu/gpu_export.h"
+#include "third_party/angle_dx11/include/GLSLANG/ShaderLang.h"
+
+namespace gpu {
+namespace gles2 {
+
+// Translates a GLSL ES 2.0 shader to desktop GLSL shader, or just
+// validates GLSL ES 2.0 shaders on a true GLSL ES implementation.
+class ShaderTranslatorInterface {
+ public:
+ enum GlslImplementationType {
+ kGlsl,
+ kGlslES
+ };
+
+ enum GlslBuiltInFunctionBehavior {
+ kGlslBuiltInFunctionOriginal,
+ kGlslBuiltInFunctionEmulated
+ };
+
+ struct VariableInfo {
+ VariableInfo()
+ : type(0),
+ size(0) {
+ }
+
+ VariableInfo(int _type, int _size, std::string _name)
+ : type(_type),
+ size(_size),
+ name(_name) {
+ }
+ bool operator==(
+ const ShaderTranslatorInterface::VariableInfo& other) const {
+ return type == other.type &&
+ size == other.size &&
+ strcmp(name.c_str(), other.name.c_str()) == 0;
+ }
+
+ int type;
+ int size;
+ std::string name; // name in the original shader source.
+ };
+
+ // Mapping between variable name and info.
+ typedef base::hash_map<std::string, VariableInfo> VariableMap;
+ // Mapping between hashed name and original name.
+ typedef base::hash_map<std::string, std::string> NameMap;
+
+ // Initializes the translator.
+ // Must be called once before using the translator object.
+ virtual bool Init(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources* resources,
+ GlslImplementationType glsl_implementation_type,
+ GlslBuiltInFunctionBehavior glsl_built_in_function_behavior) = 0;
+
+ // Translates the given shader source.
+ // Returns true if translation is successful, false otherwise.
+ virtual bool Translate(const char* shader) = 0;
+
+ // The following functions return results from the last translation.
+ // The results are NULL/empty if the translation was unsuccessful.
+ // A valid info-log is always returned irrespective of whether translation
+ // was successful or not.
+ virtual const char* translated_shader() const = 0;
+ virtual const char* info_log() const = 0;
+
+ virtual const VariableMap& attrib_map() const = 0;
+ virtual const VariableMap& uniform_map() const = 0;
+ virtual const NameMap& name_map() const = 0;
+
+ // Return a string that is unique for a specfic set of options that would
+ // possibly effect compilation.
+ virtual std::string GetStringForOptionsThatWouldEffectCompilation() const = 0;
+
+ protected:
+ virtual ~ShaderTranslatorInterface() {}
+};
+
+// Implementation of ShaderTranslatorInterface
+class GPU_EXPORT ShaderTranslator
+ : public base::RefCounted<ShaderTranslator>,
+ NON_EXPORTED_BASE(public ShaderTranslatorInterface) {
+ public:
+ class DestructionObserver {
+ public:
+ DestructionObserver();
+ virtual ~DestructionObserver();
+
+ virtual void OnDestruct(ShaderTranslator* translator) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
+ };
+
+ ShaderTranslator();
+
+ // Overridden from ShaderTranslatorInterface.
+ virtual bool Init(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources* resources,
+ GlslImplementationType glsl_implementation_type,
+ GlslBuiltInFunctionBehavior glsl_built_in_function_behavior) OVERRIDE;
+
+ // Overridden from ShaderTranslatorInterface.
+ virtual bool Translate(const char* shader) OVERRIDE;
+
+ // Overridden from ShaderTranslatorInterface.
+ virtual const char* translated_shader() const OVERRIDE;
+ virtual const char* info_log() const OVERRIDE;
+
+ // Overridden from ShaderTranslatorInterface.
+ virtual const VariableMap& attrib_map() const OVERRIDE;
+ virtual const VariableMap& uniform_map() const OVERRIDE;
+ virtual const NameMap& name_map() const OVERRIDE;
+
+ virtual std::string GetStringForOptionsThatWouldEffectCompilation() const
+ OVERRIDE;
+
+ void AddDestructionObserver(DestructionObserver* observer);
+ void RemoveDestructionObserver(DestructionObserver* observer);
+
+ private:
+ friend class base::RefCounted<ShaderTranslator>;
+
+ virtual ~ShaderTranslator();
+ void ClearResults();
+ int GetCompileOptions() const;
+
+ ShHandle compiler_;
+ ShBuiltInResources compiler_options_;
+ scoped_ptr<char[]> translated_shader_;
+ scoped_ptr<char[]> info_log_;
+ VariableMap attrib_map_;
+ VariableMap uniform_map_;
+ NameMap name_map_;
+ bool implementation_is_glsl_es_;
+ bool needs_built_in_function_emulation_;
+ ObserverList<DestructionObserver> destruction_observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderTranslator);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SHADER_TRANSLATOR_H_
+
diff --git a/chromium/gpu/command_buffer/service/shader_translator_cache.cc b/chromium/gpu/command_buffer/service/shader_translator_cache.cc
new file mode 100644
index 00000000000..6e888d56c98
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_translator_cache.cc
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/shader_translator_cache.h"
+
+namespace gpu {
+namespace gles2 {
+
+ShaderTranslatorCache* ShaderTranslatorCache::GetInstance() {
+ return Singleton<ShaderTranslatorCache>::get();
+}
+
+ShaderTranslatorCache::ShaderTranslatorCache() {
+}
+
+ShaderTranslatorCache::~ShaderTranslatorCache() {
+}
+
+void ShaderTranslatorCache::OnDestruct(ShaderTranslator* translator) {
+ Cache::iterator it = cache_.begin();
+ while (it != cache_.end()) {
+ if (it->second == translator) {
+ cache_.erase(it);
+ return;
+ }
+ it++;
+ }
+}
+
+scoped_refptr<ShaderTranslator> ShaderTranslatorCache::GetTranslator(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources* resources,
+ ShaderTranslatorInterface::GlslImplementationType
+ glsl_implementation_type,
+ ShaderTranslatorInterface::GlslBuiltInFunctionBehavior
+ glsl_built_in_function_behavior) {
+ ShaderTranslatorInitParams params(shader_type,
+ shader_spec,
+ *resources,
+ glsl_implementation_type,
+ glsl_built_in_function_behavior);
+
+ Cache::iterator it = cache_.find(params);
+ if (it != cache_.end())
+ return it->second;
+
+ ShaderTranslator* translator = new ShaderTranslator();
+ if (translator->Init(shader_type, shader_spec, resources,
+ glsl_implementation_type,
+ glsl_built_in_function_behavior)) {
+ cache_[params] = translator;
+ translator->AddDestructionObserver(this);
+ return translator;
+ } else {
+ return NULL;
+ }
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/shader_translator_cache.h b/chromium/gpu/command_buffer/service/shader_translator_cache.h
new file mode 100644
index 00000000000..0d3e777bc20
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_translator_cache.h
@@ -0,0 +1,95 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SHADER_TRANSLATOR_CACHE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SHADER_TRANSLATOR_CACHE_H_
+
+#include <string.h>
+
+#include <map>
+
+#include "base/memory/ref_counted.h"
+#include "base/memory/singleton.h"
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "third_party/angle_dx11/include/GLSLANG/ShaderLang.h"
+
+namespace gpu {
+namespace gles2 {
+
+// This singleton and the cache that it implements is NOT thread safe.
+// We're relying on the fact that the all GLES2DecoderImpl's are used
+// on one thread.
+//
+// TODO(backer): Investigate using glReleaseShaderCompiler as an alternative to
+// to this cache.
+class ShaderTranslatorCache : public ShaderTranslator::DestructionObserver {
+ public:
+ static ShaderTranslatorCache* GetInstance();
+
+ // ShaderTranslator::DestructionObserver implementation
+ virtual void OnDestruct(ShaderTranslator* translator) OVERRIDE;
+
+ scoped_refptr<ShaderTranslator> GetTranslator(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources* resources,
+ ShaderTranslatorInterface::GlslImplementationType
+ glsl_implementation_type,
+ ShaderTranslatorInterface::GlslBuiltInFunctionBehavior
+ glsl_built_in_function_behavior);
+
+ private:
+ ShaderTranslatorCache();
+ virtual ~ShaderTranslatorCache();
+
+ friend struct DefaultSingletonTraits<ShaderTranslatorCache>;
+
+ // Parameters passed into ShaderTranslator::Init
+ struct ShaderTranslatorInitParams {
+ ShShaderType shader_type;
+ ShShaderSpec shader_spec;
+ ShBuiltInResources resources;
+ ShaderTranslatorInterface::GlslImplementationType
+ glsl_implementation_type;
+ ShaderTranslatorInterface::GlslBuiltInFunctionBehavior
+ glsl_built_in_function_behavior;
+
+ ShaderTranslatorInitParams(
+ ShShaderType shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources& resources,
+ ShaderTranslatorInterface::GlslImplementationType
+ glsl_implementation_type,
+ ShaderTranslatorInterface::GlslBuiltInFunctionBehavior
+ glsl_built_in_function_behavior)
+ : shader_type(shader_type),
+ shader_spec(shader_spec),
+ resources(resources),
+ glsl_implementation_type(glsl_implementation_type),
+ glsl_built_in_function_behavior(glsl_built_in_function_behavior) {
+ }
+
+ ShaderTranslatorInitParams(const ShaderTranslatorInitParams& params) {
+ memcpy(this, &params, sizeof(*this));
+ }
+
+ bool operator== (const ShaderTranslatorInitParams& params) const {
+ return memcmp(&params, this, sizeof(*this)) == 0;
+ }
+
+ bool operator< (const ShaderTranslatorInitParams& params) const {
+ return memcmp(&params, this, sizeof(*this)) < 0;
+ }
+ };
+
+ typedef std::map<ShaderTranslatorInitParams, ShaderTranslator* > Cache;
+ Cache cache_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShaderTranslatorCache);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_SHADER_TRANSLATOR_CACHE_H_
diff --git a/chromium/gpu/command_buffer/service/shader_translator_unittest.cc b/chromium/gpu/command_buffer/service/shader_translator_unittest.cc
new file mode 100644
index 00000000000..a08851adcf8
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -0,0 +1,263 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/shader_translator.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ShaderTranslatorTest : public testing::Test {
+ public:
+ ShaderTranslatorTest() {
+ }
+
+ virtual ~ShaderTranslatorTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ ShBuiltInResources resources;
+ resources.MaxExpressionComplexity = 32;
+ resources.MaxCallStackDepth = 32;
+ ShInitBuiltInResources(&resources);
+ vertex_translator_ = new ShaderTranslator();
+ fragment_translator_ = new ShaderTranslator();
+
+ ASSERT_TRUE(vertex_translator_->Init(
+ SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources,
+ ShaderTranslatorInterface::kGlsl,
+ ShaderTranslatorInterface::kGlslBuiltInFunctionEmulated));
+ ASSERT_TRUE(fragment_translator_->Init(
+ SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources,
+ ShaderTranslatorInterface::kGlsl,
+ ShaderTranslatorInterface::kGlslBuiltInFunctionOriginal));
+ // Post-init the results must be empty.
+ // Vertex translator results.
+ EXPECT_TRUE(vertex_translator_->translated_shader() == NULL);
+ EXPECT_TRUE(vertex_translator_->info_log() == NULL);
+ EXPECT_TRUE(vertex_translator_->attrib_map().empty());
+ EXPECT_TRUE(vertex_translator_->uniform_map().empty());
+ // Fragment translator results.
+ EXPECT_TRUE(fragment_translator_->translated_shader() == NULL);
+ EXPECT_TRUE(fragment_translator_->info_log() == NULL);
+ EXPECT_TRUE(fragment_translator_->attrib_map().empty());
+ EXPECT_TRUE(fragment_translator_->uniform_map().empty());
+ }
+ virtual void TearDown() {
+ vertex_translator_ = NULL;
+ fragment_translator_ = NULL;
+ }
+
+ scoped_refptr<ShaderTranslator> vertex_translator_;
+ scoped_refptr<ShaderTranslator> fragment_translator_;
+};
+
+TEST_F(ShaderTranslatorTest, ValidVertexShader) {
+ const char* shader =
+ "void main() {\n"
+ " gl_Position = vec4(1.0);\n"
+ "}";
+
+ // A valid shader should be successfully translated.
+ EXPECT_TRUE(vertex_translator_->Translate(shader));
+ // Info log must be NULL.
+ EXPECT_TRUE(vertex_translator_->info_log() == NULL);
+ // Translated shader must be valid and non-empty.
+ ASSERT_TRUE(vertex_translator_->translated_shader() != NULL);
+ EXPECT_GT(strlen(vertex_translator_->translated_shader()), 0u);
+ // There should be no attributes or uniforms.
+ EXPECT_TRUE(vertex_translator_->attrib_map().empty());
+ EXPECT_TRUE(vertex_translator_->uniform_map().empty());
+}
+
+TEST_F(ShaderTranslatorTest, InvalidVertexShader) {
+ const char* bad_shader = "foo-bar";
+ const char* good_shader =
+ "void main() {\n"
+ " gl_Position = vec4(1.0);\n"
+ "}";
+
+ // An invalid shader should fail.
+ EXPECT_FALSE(vertex_translator_->Translate(bad_shader));
+ // Info log must be valid and non-empty.
+ ASSERT_TRUE(vertex_translator_->info_log() != NULL);
+ EXPECT_GT(strlen(vertex_translator_->info_log()), 0u);
+ // Translated shader must be NULL.
+ EXPECT_TRUE(vertex_translator_->translated_shader() == NULL);
+ // There should be no attributes or uniforms.
+ EXPECT_TRUE(vertex_translator_->attrib_map().empty());
+ EXPECT_TRUE(vertex_translator_->uniform_map().empty());
+
+ // Try a good shader after bad.
+ EXPECT_TRUE(vertex_translator_->Translate(good_shader));
+ EXPECT_TRUE(vertex_translator_->info_log() == NULL);
+ ASSERT_TRUE(vertex_translator_->translated_shader() != NULL);
+ EXPECT_GT(strlen(vertex_translator_->translated_shader()), 0u);
+}
+
+TEST_F(ShaderTranslatorTest, ValidFragmentShader) {
+ const char* shader =
+ "void main() {\n"
+ " gl_FragColor = vec4(1.0);\n"
+ "}";
+
+ // A valid shader should be successfully translated.
+ EXPECT_TRUE(fragment_translator_->Translate(shader));
+ // Info log must be NULL.
+ EXPECT_TRUE(fragment_translator_->info_log() == NULL);
+ // Translated shader must be valid and non-empty.
+ ASSERT_TRUE(fragment_translator_->translated_shader() != NULL);
+ EXPECT_GT(strlen(fragment_translator_->translated_shader()), 0u);
+ // There should be no attributes or uniforms.
+ EXPECT_TRUE(fragment_translator_->attrib_map().empty());
+ EXPECT_TRUE(fragment_translator_->uniform_map().empty());
+}
+
+TEST_F(ShaderTranslatorTest, InvalidFragmentShader) {
+ const char* shader = "foo-bar";
+
+ // An invalid shader should fail.
+ EXPECT_FALSE(fragment_translator_->Translate(shader));
+ // Info log must be valid and non-empty.
+ ASSERT_TRUE(fragment_translator_->info_log() != NULL);
+ EXPECT_GT(strlen(fragment_translator_->info_log()), 0u);
+ // Translated shader must be NULL.
+ EXPECT_TRUE(fragment_translator_->translated_shader() == NULL);
+ // There should be no attributes or uniforms.
+ EXPECT_TRUE(fragment_translator_->attrib_map().empty());
+ EXPECT_TRUE(fragment_translator_->uniform_map().empty());
+}
+
+TEST_F(ShaderTranslatorTest, GetAttributes) {
+ const char* shader =
+ "attribute vec4 vPosition;\n"
+ "void main() {\n"
+ " gl_Position = vPosition;\n"
+ "}";
+
+ EXPECT_TRUE(vertex_translator_->Translate(shader));
+ // Info log must be NULL.
+ EXPECT_TRUE(vertex_translator_->info_log() == NULL);
+ // Translated shader must be valid and non-empty.
+ ASSERT_TRUE(vertex_translator_->translated_shader() != NULL);
+ EXPECT_GT(strlen(vertex_translator_->translated_shader()), 0u);
+ // There should be no uniforms.
+ EXPECT_TRUE(vertex_translator_->uniform_map().empty());
+ // There should be one attribute with following characteristics:
+ // name:vPosition type:SH_FLOAT_VEC4 size:1.
+ const ShaderTranslator::VariableMap& attrib_map =
+ vertex_translator_->attrib_map();
+ EXPECT_EQ(1u, attrib_map.size());
+ ShaderTranslator::VariableMap::const_iterator iter =
+ attrib_map.find("vPosition");
+ EXPECT_TRUE(iter != attrib_map.end());
+ EXPECT_EQ(SH_FLOAT_VEC4, iter->second.type);
+ EXPECT_EQ(1, iter->second.size);
+ EXPECT_EQ("vPosition", iter->second.name);
+}
+
+TEST_F(ShaderTranslatorTest, GetUniforms) {
+ const char* shader =
+ "precision mediump float;\n"
+ "struct Foo {\n"
+ " vec4 color[1];\n"
+ "};\n"
+ "struct Bar {\n"
+ " Foo foo;\n"
+ "};\n"
+ "uniform Bar bar[2];\n"
+ "void main() {\n"
+ " gl_FragColor = bar[0].foo.color[0] + bar[1].foo.color[0];\n"
+ "}";
+
+ EXPECT_TRUE(fragment_translator_->Translate(shader));
+ // Info log must be NULL.
+ EXPECT_TRUE(fragment_translator_->info_log() == NULL);
+ // Translated shader must be valid and non-empty.
+ ASSERT_TRUE(fragment_translator_->translated_shader() != NULL);
+ EXPECT_GT(strlen(fragment_translator_->translated_shader()), 0u);
+ // There should be no attributes.
+ EXPECT_TRUE(fragment_translator_->attrib_map().empty());
+ // There should be two uniforms with following characteristics:
+ // 1. name:bar[0].foo.color[0] type:SH_FLOAT_VEC4 size:1
+ // 2. name:bar[1].foo.color[0] type:SH_FLOAT_VEC4 size:1
+ const ShaderTranslator::VariableMap& uniform_map =
+ fragment_translator_->uniform_map();
+ EXPECT_EQ(2u, uniform_map.size());
+ // First uniform.
+ ShaderTranslator::VariableMap::const_iterator iter =
+ uniform_map.find("bar[0].foo.color[0]");
+ EXPECT_TRUE(iter != uniform_map.end());
+ EXPECT_EQ(SH_FLOAT_VEC4, iter->second.type);
+ EXPECT_EQ(1, iter->second.size);
+ EXPECT_EQ("bar[0].foo.color[0]", iter->second.name);
+ // Second uniform.
+ iter = uniform_map.find("bar[1].foo.color[0]");
+ EXPECT_TRUE(iter != uniform_map.end());
+ EXPECT_EQ(SH_FLOAT_VEC4, iter->second.type);
+ EXPECT_EQ(1, iter->second.size);
+ EXPECT_EQ("bar[1].foo.color[0]", iter->second.name);
+}
+
+#if defined(OS_MACOSX)
+TEST_F(ShaderTranslatorTest, BuiltInFunctionEmulation) {
+ // This test might become invalid in the future when ANGLE Translator is no
+ // longer emulate dot(float, float) in Mac, or the emulated function name is
+ // no longer webgl_dot_emu.
+ const char* shader =
+ "void main() {\n"
+ " gl_Position = vec4(dot(1.0, 1.0), 1.0, 1.0, 1.0);\n"
+ "}";
+
+ EXPECT_TRUE(vertex_translator_->Translate(shader));
+ // Info log must be NULL.
+ EXPECT_TRUE(vertex_translator_->info_log() == NULL);
+ // Translated shader must be valid and non-empty.
+ ASSERT_TRUE(vertex_translator_->translated_shader() != NULL);
+ EXPECT_TRUE(strstr(vertex_translator_->translated_shader(),
+ "webgl_dot_emu") != NULL);
+}
+#endif
+
+TEST_F(ShaderTranslatorTest, OptionsString) {
+ scoped_refptr<ShaderTranslator> translator_1 = new ShaderTranslator();
+ scoped_refptr<ShaderTranslator> translator_2 = new ShaderTranslator();
+ scoped_refptr<ShaderTranslator> translator_3 = new ShaderTranslator();
+
+ ShBuiltInResources resources;
+ ShInitBuiltInResources(&resources);
+
+ ASSERT_TRUE(translator_1->Init(
+ SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources,
+ ShaderTranslatorInterface::kGlsl,
+ ShaderTranslatorInterface::kGlslBuiltInFunctionEmulated));
+ ASSERT_TRUE(translator_2->Init(
+ SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources,
+ ShaderTranslatorInterface::kGlsl,
+ ShaderTranslatorInterface::kGlslBuiltInFunctionOriginal));
+ resources.EXT_draw_buffers = 1;
+ ASSERT_TRUE(translator_3->Init(
+ SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources,
+ ShaderTranslatorInterface::kGlsl,
+ ShaderTranslatorInterface::kGlslBuiltInFunctionEmulated));
+
+ std::string options_1(
+ translator_1->GetStringForOptionsThatWouldEffectCompilation());
+ std::string options_2(
+ translator_1->GetStringForOptionsThatWouldEffectCompilation());
+ std::string options_3(
+ translator_2->GetStringForOptionsThatWouldEffectCompilation());
+ std::string options_4(
+ translator_3->GetStringForOptionsThatWouldEffectCompilation());
+
+ EXPECT_EQ(options_1, options_2);
+ EXPECT_NE(options_1, options_3);
+ EXPECT_NE(options_1, options_4);
+ EXPECT_NE(options_3, options_4);
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/stream_texture.h b/chromium/gpu/command_buffer/service/stream_texture.h
new file mode 100644
index 00000000000..bcddc82dd82
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/stream_texture.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_H_
+#define GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_H_
+
+#include "base/basictypes.h"
+#include "ui/gfx/size.h"
+
+namespace gpu {
+
+class StreamTexture {
+ public:
+ StreamTexture() {
+ }
+
+ virtual ~StreamTexture() {
+ }
+
+ virtual void Update() = 0;
+
+ // Get the size of the StreamTexture.
+ virtual gfx::Size GetSize() = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StreamTexture);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_H_
diff --git a/chromium/gpu/command_buffer/service/stream_texture_manager.h b/chromium/gpu/command_buffer/service/stream_texture_manager.h
new file mode 100644
index 00000000000..b4f0a534954
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/stream_texture_manager.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+
+namespace gpu {
+
+class StreamTexture;
+
+// Interface used by the cmd decoder to create and lookup stream textures.
+class StreamTextureManager {
+ public:
+ StreamTextureManager() {
+ }
+
+ virtual ~StreamTextureManager() {
+ }
+
+ // Returns an identifier for the object, or NULL if not successful.
+ virtual GLuint CreateStreamTexture(uint32 service_id,
+ uint32 client_id) = 0;
+
+ virtual void DestroyStreamTexture(uint32 service_id) = 0;
+
+ virtual StreamTexture* LookupStreamTexture(uint32 service_id) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(StreamTextureManager);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/stream_texture_manager_mock.cc b/chromium/gpu/command_buffer/service/stream_texture_manager_mock.cc
new file mode 100644
index 00000000000..75268b86205
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/stream_texture_manager_mock.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/stream_texture_manager_mock.h"
+
+namespace gpu {
+
+MockStreamTextureManager::MockStreamTextureManager() {
+}
+
+MockStreamTextureManager::~MockStreamTextureManager() {
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/stream_texture_manager_mock.h b/chromium/gpu/command_buffer/service/stream_texture_manager_mock.h
new file mode 100644
index 00000000000..ac145ec89f2
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/stream_texture_manager_mock.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_MOCK_H_
+#define GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_MOCK_H_
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/service/stream_texture_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+class StreamTexture;
+
+class MockStreamTextureManager : public StreamTextureManager {
+ public:
+ MockStreamTextureManager();
+ virtual ~MockStreamTextureManager();
+
+ MOCK_METHOD2(CreateStreamTexture, GLuint(uint32 service_id,
+ uint32 client_id));
+ MOCK_METHOD1(DestroyStreamTexture, void(uint32 service_id));
+ MOCK_METHOD1(LookupStreamTexture, StreamTexture*(uint32 service_id));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockStreamTextureManager);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MANAGER_MOCK_H_
diff --git a/chromium/gpu/command_buffer/service/stream_texture_mock.cc b/chromium/gpu/command_buffer/service/stream_texture_mock.cc
new file mode 100644
index 00000000000..742a4f71ec0
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/stream_texture_mock.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/stream_texture_mock.h"
+
+namespace gpu {
+
+MockStreamTexture::MockStreamTexture() {
+}
+
+MockStreamTexture::~MockStreamTexture() {
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/stream_texture_mock.h b/chromium/gpu/command_buffer/service/stream_texture_mock.h
new file mode 100644
index 00000000000..cd951d22618
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/stream_texture_mock.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MOCK_H_
+#define GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MOCK_H_
+
+#include "base/memory/ref_counted.h"
+#include "gpu/command_buffer/service/stream_texture.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace gpu {
+
+class MockStreamTexture : public StreamTexture {
+ public:
+ MockStreamTexture();
+ virtual ~MockStreamTexture();
+
+ MOCK_METHOD0(Update, void());
+ MOCK_METHOD0(GetSize, gfx::Size(void));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockStreamTexture);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_STREAM_TEXTURE_MOCK_H_
diff --git a/chromium/gpu/command_buffer/service/test_helper.cc b/chromium/gpu/command_buffer/service/test_helper.cc
new file mode 100644
index 00000000000..074e3019f8a
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/test_helper.cc
@@ -0,0 +1,553 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/test_helper.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "gpu/command_buffer/common/types.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/error_state_mock.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::InSequence;
+using ::testing::MatcherCast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArrayArgument;
+using ::testing::SetArgumentPointee;
+using ::testing::StrEq;
+using ::testing::StrictMock;
+
+namespace gpu {
+namespace gles2 {
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLuint TestHelper::kServiceBlackTexture2dId;
+const GLuint TestHelper::kServiceDefaultTexture2dId;
+const GLuint TestHelper::kServiceBlackTextureCubemapId;
+const GLuint TestHelper::kServiceDefaultTextureCubemapId;
+const GLuint TestHelper::kServiceBlackExternalTextureId;
+const GLuint TestHelper::kServiceDefaultExternalTextureId;
+const GLuint TestHelper::kServiceBlackRectangleTextureId;
+const GLuint TestHelper::kServiceDefaultRectangleTextureId;
+
+const GLint TestHelper::kMaxSamples;
+const GLint TestHelper::kMaxRenderbufferSize;
+const GLint TestHelper::kMaxTextureSize;
+const GLint TestHelper::kMaxCubeMapTextureSize;
+const GLint TestHelper::kNumVertexAttribs;
+const GLint TestHelper::kNumTextureUnits;
+const GLint TestHelper::kMaxTextureImageUnits;
+const GLint TestHelper::kMaxVertexTextureImageUnits;
+const GLint TestHelper::kMaxFragmentUniformVectors;
+const GLint TestHelper::kMaxFragmentUniformComponents;
+const GLint TestHelper::kMaxVaryingVectors;
+const GLint TestHelper::kMaxVaryingFloats;
+const GLint TestHelper::kMaxVertexUniformVectors;
+const GLint TestHelper::kMaxVertexUniformComponents;
+#endif
+
+void TestHelper::SetupTextureInitializationExpectations(
+ ::gfx::MockGLInterface* gl, GLenum target) {
+ InSequence sequence;
+
+ bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
+ bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
+
+ static GLuint texture_2d_ids[] = {
+ kServiceBlackTexture2dId,
+ kServiceDefaultTexture2dId };
+ static GLuint texture_cube_map_ids[] = {
+ kServiceBlackTextureCubemapId,
+ kServiceDefaultTextureCubemapId };
+ static GLuint texture_external_oes_ids[] = {
+ kServiceBlackExternalTextureId,
+ kServiceDefaultExternalTextureId };
+ static GLuint texture_rectangle_arb_ids[] = {
+ kServiceBlackRectangleTextureId,
+ kServiceDefaultRectangleTextureId };
+
+ const GLuint* texture_ids = NULL;
+ switch (target) {
+ case GL_TEXTURE_2D:
+ texture_ids = &texture_2d_ids[0];
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture_ids = &texture_cube_map_ids[0];
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture_ids = &texture_external_oes_ids[0];
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ texture_ids = &texture_rectangle_arb_ids[0];
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ int array_size = 2;
+
+ EXPECT_CALL(*gl, GenTextures(array_size, _))
+ .WillOnce(SetArrayArgument<1>(texture_ids,
+ texture_ids + array_size))
+ .RetiresOnSaturation();
+ for (int ii = 0; ii < array_size; ++ii) {
+ EXPECT_CALL(*gl, BindTexture(target, texture_ids[ii]))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (needs_initialization) {
+ if (needs_faces) {
+ static GLenum faces[] = {
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ };
+ for (size_t ii = 0; ii < arraysize(faces); ++ii) {
+ EXPECT_CALL(*gl, TexImage2D(faces[ii], 0, GL_RGBA, 1, 1, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ } else {
+ EXPECT_CALL(*gl, TexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ }
+ }
+ EXPECT_CALL(*gl, BindTexture(target, 0))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+void TestHelper::SetupTextureManagerInitExpectations(
+ ::gfx::MockGLInterface* gl,
+ const char* extensions) {
+ InSequence sequence;
+
+ SetupTextureInitializationExpectations(gl, GL_TEXTURE_2D);
+ SetupTextureInitializationExpectations(gl, GL_TEXTURE_CUBE_MAP);
+
+ bool ext_image_external = false;
+ bool arb_texture_rectangle = false;
+ base::CStringTokenizer t(extensions, extensions + strlen(extensions), " ");
+ while (t.GetNext()) {
+ if (t.token() == "GL_OES_EGL_image_external") {
+ ext_image_external = true;
+ break;
+ }
+ if (t.token() == "GL_ARB_texture_rectangle") {
+ arb_texture_rectangle = true;
+ break;
+ }
+ }
+
+ if (ext_image_external) {
+ SetupTextureInitializationExpectations(gl, GL_TEXTURE_EXTERNAL_OES);
+ }
+ if (arb_texture_rectangle) {
+ SetupTextureInitializationExpectations(gl, GL_TEXTURE_RECTANGLE_ARB);
+ }
+}
+
+void TestHelper::SetupTextureDestructionExpectations(
+ ::gfx::MockGLInterface* gl, GLenum target) {
+ GLuint texture_id = 0;
+ switch (target) {
+ case GL_TEXTURE_2D:
+ texture_id = kServiceDefaultTexture2dId;
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ texture_id = kServiceDefaultTextureCubemapId;
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture_id = kServiceDefaultExternalTextureId;
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ texture_id = kServiceDefaultRectangleTextureId;
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ EXPECT_CALL(*gl, DeleteTextures(1, Pointee(texture_id)))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+void TestHelper::SetupTextureManagerDestructionExpectations(
+ ::gfx::MockGLInterface* gl,
+ const char* extensions) {
+ SetupTextureDestructionExpectations(gl, GL_TEXTURE_2D);
+ SetupTextureDestructionExpectations(gl, GL_TEXTURE_CUBE_MAP);
+
+ bool ext_image_external = false;
+ bool arb_texture_rectangle = false;
+ base::CStringTokenizer t(extensions, extensions + strlen(extensions), " ");
+ while (t.GetNext()) {
+ if (t.token() == "GL_OES_EGL_image_external") {
+ ext_image_external = true;
+ break;
+ }
+ if (t.token() == "GL_ARB_texture_rectangle") {
+ arb_texture_rectangle = true;
+ break;
+ }
+ }
+
+ if (ext_image_external) {
+ SetupTextureDestructionExpectations(gl, GL_TEXTURE_EXTERNAL_OES);
+ }
+ if (arb_texture_rectangle) {
+ SetupTextureDestructionExpectations(gl, GL_TEXTURE_RECTANGLE_ARB);
+ }
+
+ EXPECT_CALL(*gl, DeleteTextures(4, _))
+ .Times(1)
+ .RetiresOnSaturation();
+}
+
+void TestHelper::SetupContextGroupInitExpectations(
+ ::gfx::MockGLInterface* gl,
+ const DisallowedFeatures& disallowed_features,
+ const char* extensions) {
+ InSequence sequence;
+
+ SetupFeatureInfoInitExpectations(gl, extensions);
+
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_RENDERBUFFER_SIZE, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxRenderbufferSize))
+ .RetiresOnSaturation();
+ if (strstr(extensions, "GL_EXT_framebuffer_multisample")) {
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_SAMPLES, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxSamples))
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_ATTRIBS, _))
+ .WillOnce(SetArgumentPointee<1>(kNumVertexAttribs))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, _))
+ .WillOnce(SetArgumentPointee<1>(kNumTextureUnits))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_TEXTURE_SIZE, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxTextureSize))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxCubeMapTextureSize))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxTextureImageUnits))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxVertexTextureImageUnits))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxFragmentUniformComponents))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VARYING_FLOATS, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxVaryingFloats))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, _))
+ .WillOnce(SetArgumentPointee<1>(kMaxVertexUniformComponents))
+ .RetiresOnSaturation();
+
+ SetupTextureManagerInitExpectations(gl, extensions);
+}
+
+void TestHelper::SetupFeatureInfoInitExpectations(
+ ::gfx::MockGLInterface* gl, const char* extensions) {
+ SetupFeatureInfoInitExpectationsWithGLVersion(gl, extensions, "");
+}
+
+void TestHelper::SetupFeatureInfoInitExpectationsWithGLVersion(
+ ::gfx::MockGLInterface* gl,
+ const char* extensions,
+ const char* version) {
+ InSequence sequence;
+
+ EXPECT_CALL(*gl, GetString(GL_EXTENSIONS))
+ .WillOnce(Return(reinterpret_cast<const uint8*>(extensions)))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl, GetString(GL_VERSION))
+ .WillOnce(Return(reinterpret_cast<const uint8*>(version)))
+ .RetiresOnSaturation();
+}
+
+void TestHelper::SetupExpectationsForClearingUniforms(
+ ::gfx::MockGLInterface* gl, UniformInfo* uniforms, size_t num_uniforms) {
+ for (size_t ii = 0; ii < num_uniforms; ++ii) {
+ const UniformInfo& info = uniforms[ii];
+ switch (info.type) {
+ case GL_FLOAT:
+ EXPECT_CALL(*gl, Uniform1fv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_FLOAT_VEC2:
+ EXPECT_CALL(*gl, Uniform2fv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_FLOAT_VEC3:
+ EXPECT_CALL(*gl, Uniform3fv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_FLOAT_VEC4:
+ EXPECT_CALL(*gl, Uniform4fv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_INT:
+ case GL_BOOL:
+ case GL_SAMPLER_2D:
+ case GL_SAMPLER_CUBE:
+ case GL_SAMPLER_EXTERNAL_OES:
+ case GL_SAMPLER_3D_OES:
+ case GL_SAMPLER_2D_RECT_ARB:
+ EXPECT_CALL(*gl, Uniform1iv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_INT_VEC2:
+ case GL_BOOL_VEC2:
+ EXPECT_CALL(*gl, Uniform2iv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_INT_VEC3:
+ case GL_BOOL_VEC3:
+ EXPECT_CALL(*gl, Uniform3iv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_INT_VEC4:
+ case GL_BOOL_VEC4:
+ EXPECT_CALL(*gl, Uniform4iv(info.real_location, info.size, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_FLOAT_MAT2:
+ EXPECT_CALL(*gl, UniformMatrix2fv(
+ info.real_location, info.size, false, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_FLOAT_MAT3:
+ EXPECT_CALL(*gl, UniformMatrix3fv(
+ info.real_location, info.size, false, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ case GL_FLOAT_MAT4:
+ EXPECT_CALL(*gl, UniformMatrix4fv(
+ info.real_location, info.size, false, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+void TestHelper::SetupProgramSuccessExpectations(
+ ::gfx::MockGLInterface* gl,
+ AttribInfo* attribs, size_t num_attribs,
+ UniformInfo* uniforms, size_t num_uniforms,
+ GLuint service_id) {
+ EXPECT_CALL(*gl,
+ GetProgramiv(service_id, GL_LINK_STATUS, _))
+ .WillOnce(SetArgumentPointee<2>(1))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl,
+ GetProgramiv(service_id, GL_INFO_LOG_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(0))
+ .RetiresOnSaturation();
+ EXPECT_CALL(*gl,
+ GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTES, _))
+ .WillOnce(SetArgumentPointee<2>(num_attribs))
+ .RetiresOnSaturation();
+ size_t max_attrib_len = 0;
+ for (size_t ii = 0; ii < num_attribs; ++ii) {
+ size_t len = strlen(attribs[ii].name) + 1;
+ max_attrib_len = std::max(max_attrib_len, len);
+ }
+ EXPECT_CALL(*gl,
+ GetProgramiv(service_id, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(max_attrib_len))
+ .RetiresOnSaturation();
+
+ for (size_t ii = 0; ii < num_attribs; ++ii) {
+ const AttribInfo& info = attribs[ii];
+ EXPECT_CALL(*gl,
+ GetActiveAttrib(service_id, ii,
+ max_attrib_len, _, _, _, _))
+ .WillOnce(DoAll(
+ SetArgumentPointee<3>(strlen(info.name)),
+ SetArgumentPointee<4>(info.size),
+ SetArgumentPointee<5>(info.type),
+ SetArrayArgument<6>(info.name,
+ info.name + strlen(info.name) + 1)))
+ .RetiresOnSaturation();
+ if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) {
+ EXPECT_CALL(*gl, GetAttribLocation(service_id, StrEq(info.name)))
+ .WillOnce(Return(info.location))
+ .RetiresOnSaturation();
+ }
+ }
+ EXPECT_CALL(*gl,
+ GetProgramiv(service_id, GL_ACTIVE_UNIFORMS, _))
+ .WillOnce(SetArgumentPointee<2>(num_uniforms))
+ .RetiresOnSaturation();
+
+ size_t max_uniform_len = 0;
+ for (size_t ii = 0; ii < num_uniforms; ++ii) {
+ size_t len = strlen(uniforms[ii].name) + 1;
+ max_uniform_len = std::max(max_uniform_len, len);
+ }
+ EXPECT_CALL(*gl,
+ GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
+ .WillOnce(SetArgumentPointee<2>(max_uniform_len))
+ .RetiresOnSaturation();
+ for (size_t ii = 0; ii < num_uniforms; ++ii) {
+ const UniformInfo& info = uniforms[ii];
+ EXPECT_CALL(*gl,
+ GetActiveUniform(service_id, ii,
+ max_uniform_len, _, _, _, _))
+ .WillOnce(DoAll(
+ SetArgumentPointee<3>(strlen(info.name)),
+ SetArgumentPointee<4>(info.size),
+ SetArgumentPointee<5>(info.type),
+ SetArrayArgument<6>(info.name,
+ info.name + strlen(info.name) + 1)))
+ .RetiresOnSaturation();
+ }
+
+ for (int pass = 0; pass < 2; ++pass) {
+ for (size_t ii = 0; ii < num_uniforms; ++ii) {
+ const UniformInfo& info = uniforms[ii];
+ if (ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) {
+ continue;
+ }
+ if (pass == 0) {
+ EXPECT_CALL(*gl, GetUniformLocation(service_id, StrEq(info.name)))
+ .WillOnce(Return(info.real_location))
+ .RetiresOnSaturation();
+ }
+ if ((pass == 0 && info.desired_location >= 0) ||
+ (pass == 1 && info.desired_location < 0)) {
+ if (info.size > 1) {
+ std::string base_name = info.name;
+ size_t array_pos = base_name.rfind("[0]");
+ if (base_name.size() > 3 && array_pos == base_name.size() - 3) {
+ base_name = base_name.substr(0, base_name.size() - 3);
+ }
+ for (GLsizei jj = 1; jj < info.size; ++jj) {
+ std::string element_name(
+ std::string(base_name) + "[" + base::IntToString(jj) + "]");
+ EXPECT_CALL(*gl, GetUniformLocation(
+ service_id, StrEq(element_name)))
+ .WillOnce(Return(info.real_location + jj * 2))
+ .RetiresOnSaturation();
+ }
+ }
+ }
+ }
+ }
+}
+
+void TestHelper::SetupShader(
+ ::gfx::MockGLInterface* gl,
+ AttribInfo* attribs, size_t num_attribs,
+ UniformInfo* uniforms, size_t num_uniforms,
+ GLuint service_id) {
+ InSequence s;
+
+ EXPECT_CALL(*gl,
+ LinkProgram(service_id))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ SetupProgramSuccessExpectations(
+ gl, attribs, num_attribs, uniforms, num_uniforms, service_id);
+}
+
+void TestHelper::DoBufferData(
+ ::gfx::MockGLInterface* gl, MockErrorState* error_state,
+ BufferManager* manager, Buffer* buffer, GLsizeiptr size, GLenum usage,
+ const GLvoid* data, GLenum error) {
+ EXPECT_CALL(*error_state, CopyRealGLErrorsToWrapper(_, _, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ if (manager->IsUsageClientSideArray(usage)) {
+ EXPECT_CALL(*gl, BufferData(
+ buffer->target(), 0, _, usage))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*gl, BufferData(
+ buffer->target(), size, _, usage))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ EXPECT_CALL(*error_state, PeekGLError(_, _, _))
+ .WillOnce(Return(error))
+ .RetiresOnSaturation();
+ manager->DoBufferData(error_state, buffer, size, usage, data);
+}
+
+void TestHelper::SetTexParameterWithExpectations(
+ ::gfx::MockGLInterface* gl, MockErrorState* error_state,
+ TextureManager* manager, TextureRef* texture_ref,
+ GLenum pname, GLint value, GLenum error) {
+ if (error == GL_NO_ERROR) {
+ if (pname != GL_TEXTURE_POOL_CHROMIUM) {
+ EXPECT_CALL(*gl, TexParameteri(texture_ref->texture()->target(),
+ pname, value))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ } else if (error == GL_INVALID_ENUM) {
+ EXPECT_CALL(*error_state, SetGLErrorInvalidEnum(_, _, _, value, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ } else {
+ EXPECT_CALL(*error_state, SetGLErrorInvalidParam(_, _, error, _, _, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ manager->SetParameter("", error_state, texture_ref, pname, value);
+}
+
+ScopedGLImplementationSetter::ScopedGLImplementationSetter(
+ gfx::GLImplementation implementation)
+ : old_implementation_(gfx::GetGLImplementation()) {
+ gfx::SetGLImplementation(implementation);
+}
+
+ScopedGLImplementationSetter::~ScopedGLImplementationSetter() {
+ gfx::SetGLImplementation(old_implementation_);
+}
+
+} // namespace gles2
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/test_helper.h b/chromium/gpu/command_buffer/service/test_helper.h
new file mode 100644
index 00000000000..11f7004a768
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/test_helper.h
@@ -0,0 +1,127 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_TEST_HELPER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_TEST_HELPER_H_
+
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+struct DisallowedFeatures;
+class Buffer;
+class BufferManager;
+class MockErrorState;
+class TextureRef;
+class TextureManager;
+
+class TestHelper {
+ public:
+ static const GLuint kServiceBlackTexture2dId = 701;
+ static const GLuint kServiceDefaultTexture2dId = 702;
+ static const GLuint kServiceBlackTextureCubemapId = 703;
+ static const GLuint kServiceDefaultTextureCubemapId = 704;
+ static const GLuint kServiceBlackExternalTextureId = 705;
+ static const GLuint kServiceDefaultExternalTextureId = 706;
+ static const GLuint kServiceBlackRectangleTextureId = 707;
+ static const GLuint kServiceDefaultRectangleTextureId = 708;
+
+ static const GLint kMaxSamples = 4;
+ static const GLint kMaxRenderbufferSize = 1024;
+ static const GLint kMaxTextureSize = 2048;
+ static const GLint kMaxCubeMapTextureSize = 256;
+ static const GLint kNumVertexAttribs = 16;
+ static const GLint kNumTextureUnits = 8;
+ static const GLint kMaxTextureImageUnits = 8;
+ static const GLint kMaxVertexTextureImageUnits = 2;
+ static const GLint kMaxFragmentUniformVectors = 16;
+ static const GLint kMaxFragmentUniformComponents =
+ kMaxFragmentUniformVectors * 4;
+ static const GLint kMaxVaryingVectors = 8;
+ static const GLint kMaxVaryingFloats = kMaxVaryingVectors * 4;
+ static const GLint kMaxVertexUniformVectors = 128;
+ static const GLint kMaxVertexUniformComponents = kMaxVertexUniformVectors * 4;
+
+ struct AttribInfo {
+ const char* name;
+ GLint size;
+ GLenum type;
+ GLint location;
+ };
+
+ struct UniformInfo {
+ const char* name;
+ GLint size;
+ GLenum type;
+ GLint fake_location;
+ GLint real_location;
+ GLint desired_location;
+ const char* good_name;
+ };
+
+ static void SetupContextGroupInitExpectations(
+ ::gfx::MockGLInterface* gl,
+ const DisallowedFeatures& disallowed_features,
+ const char* extensions);
+ static void SetupFeatureInfoInitExpectations(
+ ::gfx::MockGLInterface* gl, const char* extensions);
+ static void SetupFeatureInfoInitExpectationsWithGLVersion(
+ ::gfx::MockGLInterface* gl,
+ const char* extensions,
+ const char* version);
+ static void SetupTextureManagerInitExpectations(
+ ::gfx::MockGLInterface* gl, const char* extensions);
+ static void SetupTextureManagerDestructionExpectations(
+ ::gfx::MockGLInterface* gl, const char* extensions);
+
+ static void SetupExpectationsForClearingUniforms(
+ ::gfx::MockGLInterface* gl, UniformInfo* uniforms, size_t num_uniforms);
+
+ static void SetupShader(
+ ::gfx::MockGLInterface* gl,
+ AttribInfo* attribs, size_t num_attribs,
+ UniformInfo* uniforms, size_t num_uniforms,
+ GLuint service_id);
+
+ static void SetupProgramSuccessExpectations(::gfx::MockGLInterface* gl,
+ AttribInfo* attribs, size_t num_attribs,
+ UniformInfo* uniforms, size_t num_uniforms,
+ GLuint service_id);
+
+ static void DoBufferData(
+ ::gfx::MockGLInterface* gl, MockErrorState* error_state,
+ BufferManager* manager, Buffer* buffer, GLsizeiptr size, GLenum usage,
+ const GLvoid* data, GLenum error);
+
+ static void SetTexParameterWithExpectations(
+ ::gfx::MockGLInterface* gl, MockErrorState* error_state,
+ TextureManager* manager, TextureRef* texture_ref,
+ GLenum pname, GLint value, GLenum error);
+
+ private:
+ static void SetupTextureInitializationExpectations(
+ ::gfx::MockGLInterface* gl, GLenum target);
+ static void SetupTextureDestructionExpectations(
+ ::gfx::MockGLInterface* gl, GLenum target);
+};
+
+// This object temporaritly Sets what gfx::GetGLImplementation returns. During
+// testing the GLImplementation is set to kGLImplemenationMockGL but lots of
+// code branches based on what gfx::GetGLImplementation returns.
+class ScopedGLImplementationSetter {
+ public:
+ explicit ScopedGLImplementationSetter(gfx::GLImplementation implementation);
+ ~ScopedGLImplementationSetter();
+
+ private:
+ gfx::GLImplementation old_implementation_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_TEST_HELPER_H_
+
diff --git a/chromium/gpu/command_buffer/service/texture_manager.cc b/chromium/gpu/command_buffer/service/texture_manager.cc
new file mode 100644
index 00000000000..deb8c8e6645
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/texture_manager.cc
@@ -0,0 +1,1474 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/texture_manager.h"
+#include "base/bits.h"
+#include "base/strings/stringprintf.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/context_state.h"
+#include "gpu/command_buffer/service/error_state.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/stream_texture_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+static size_t GLTargetToFaceIndex(GLenum target) {
+ switch (target) {
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_EXTERNAL_OES:
+ case GL_TEXTURE_RECTANGLE_ARB:
+ return 0;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ return 0;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ return 1;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ return 2;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ return 3;
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ return 4;
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ return 5;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+static size_t FaceIndexToGLTarget(size_t index) {
+ switch (index) {
+ case 0:
+ return GL_TEXTURE_CUBE_MAP_POSITIVE_X;
+ case 1:
+ return GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
+ case 2:
+ return GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
+ case 3:
+ return GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ case 4:
+ return GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
+ case 5:
+ return GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ default:
+ NOTREACHED();
+ return 0;
+ }
+}
+
+TextureManager::DestructionObserver::DestructionObserver() {}
+
+TextureManager::DestructionObserver::~DestructionObserver() {}
+
+TextureManager::~TextureManager() {
+ FOR_EACH_OBSERVER(DestructionObserver,
+ destruction_observers_,
+ OnTextureManagerDestroying(this));
+
+ DCHECK(textures_.empty());
+
+ // If this triggers, that means something is keeping a reference to
+ // a Texture belonging to this.
+ CHECK_EQ(texture_count_, 0u);
+
+ DCHECK_EQ(0, num_unrenderable_textures_);
+ DCHECK_EQ(0, num_unsafe_textures_);
+ DCHECK_EQ(0, num_uncleared_mips_);
+}
+
+void TextureManager::Destroy(bool have_context) {
+ have_context_ = have_context;
+ textures_.clear();
+ for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
+ default_textures_[ii] = NULL;
+ }
+
+ if (have_context) {
+ glDeleteTextures(arraysize(black_texture_ids_), black_texture_ids_);
+ }
+
+ DCHECK_EQ(0u, memory_tracker_managed_->GetMemRepresented());
+ DCHECK_EQ(0u, memory_tracker_unmanaged_->GetMemRepresented());
+}
+
+Texture::Texture(GLuint service_id)
+ : mailbox_manager_(NULL),
+ memory_tracking_ref_(NULL),
+ service_id_(service_id),
+ cleared_(true),
+ num_uncleared_mips_(0),
+ target_(0),
+ min_filter_(GL_NEAREST_MIPMAP_LINEAR),
+ mag_filter_(GL_LINEAR),
+ wrap_s_(GL_REPEAT),
+ wrap_t_(GL_REPEAT),
+ usage_(GL_NONE),
+ pool_(GL_TEXTURE_POOL_UNMANAGED_CHROMIUM),
+ max_level_set_(-1),
+ texture_complete_(false),
+ cube_complete_(false),
+ npot_(false),
+ has_been_bound_(false),
+ framebuffer_attachment_count_(0),
+ stream_texture_(false),
+ immutable_(false),
+ estimated_size_(0),
+ can_render_condition_(CAN_RENDER_ALWAYS) {
+}
+
+Texture::~Texture() {
+ if (mailbox_manager_)
+ mailbox_manager_->TextureDeleted(this);
+}
+
+void Texture::AddTextureRef(TextureRef* ref) {
+ DCHECK(refs_.find(ref) == refs_.end());
+ refs_.insert(ref);
+ if (!memory_tracking_ref_) {
+ memory_tracking_ref_ = ref;
+ GetMemTracker()->TrackMemAlloc(estimated_size());
+ }
+}
+
+void Texture::RemoveTextureRef(TextureRef* ref, bool have_context) {
+ if (memory_tracking_ref_ == ref) {
+ GetMemTracker()->TrackMemFree(estimated_size());
+ memory_tracking_ref_ = NULL;
+ }
+ size_t result = refs_.erase(ref);
+ DCHECK_EQ(result, 1u);
+ if (refs_.empty()) {
+ if (have_context) {
+ GLuint id = service_id();
+ glDeleteTextures(1, &id);
+ }
+ delete this;
+ } else if (memory_tracking_ref_ == NULL) {
+ // TODO(piman): tune ownership semantics for cross-context group shared
+ // textures.
+ memory_tracking_ref_ = *refs_.begin();
+ GetMemTracker()->TrackMemAlloc(estimated_size());
+ }
+}
+
+MemoryTypeTracker* Texture::GetMemTracker() {
+ DCHECK(memory_tracking_ref_);
+ return memory_tracking_ref_->manager()->GetMemTracker(pool_);
+}
+
+Texture::LevelInfo::LevelInfo()
+ : cleared(true),
+ target(0),
+ level(-1),
+ internal_format(0),
+ width(0),
+ height(0),
+ depth(0),
+ border(0),
+ format(0),
+ type(0),
+ estimated_size(0) {
+}
+
+Texture::LevelInfo::LevelInfo(const LevelInfo& rhs)
+ : cleared(rhs.cleared),
+ target(rhs.target),
+ level(rhs.level),
+ internal_format(rhs.internal_format),
+ width(rhs.width),
+ height(rhs.height),
+ depth(rhs.depth),
+ border(rhs.border),
+ format(rhs.format),
+ type(rhs.type),
+ image(rhs.image),
+ estimated_size(rhs.estimated_size) {
+}
+
+Texture::LevelInfo::~LevelInfo() {
+}
+
+Texture::CanRenderCondition Texture::GetCanRenderCondition() const {
+ if (target_ == 0)
+ return CAN_RENDER_ALWAYS;
+
+ if (target_ == GL_TEXTURE_EXTERNAL_OES) {
+ if (!IsStreamTexture()) {
+ return CAN_RENDER_NEVER;
+ }
+ } else {
+ if (level_infos_.empty()) {
+ return CAN_RENDER_NEVER;
+ }
+
+ const Texture::LevelInfo& first_face = level_infos_[0][0];
+ if (first_face.width == 0 ||
+ first_face.height == 0 ||
+ first_face.depth == 0) {
+ return CAN_RENDER_NEVER;
+ }
+ }
+
+ bool needs_mips = NeedsMips();
+ if (needs_mips) {
+ if (!texture_complete())
+ return CAN_RENDER_NEVER;
+ if (target_ == GL_TEXTURE_CUBE_MAP && !cube_complete())
+ return CAN_RENDER_NEVER;
+ }
+
+ bool is_npot_compatible = !needs_mips &&
+ wrap_s_ == GL_CLAMP_TO_EDGE &&
+ wrap_t_ == GL_CLAMP_TO_EDGE;
+
+ if (!is_npot_compatible) {
+ if (target_ == GL_TEXTURE_RECTANGLE_ARB)
+ return CAN_RENDER_NEVER;
+ else if (npot())
+ return CAN_RENDER_ONLY_IF_NPOT;
+ }
+
+ return CAN_RENDER_ALWAYS;
+}
+
+bool Texture::CanRender(const FeatureInfo* feature_info) const {
+ switch (can_render_condition_) {
+ case CAN_RENDER_ALWAYS:
+ return true;
+ case CAN_RENDER_NEVER:
+ return false;
+ case CAN_RENDER_ONLY_IF_NPOT:
+ break;
+ }
+ return feature_info->feature_flags().npot_ok;
+}
+
+void Texture::AddToSignature(
+ const FeatureInfo* feature_info,
+ GLenum target,
+ GLint level,
+ std::string* signature) const {
+ DCHECK(feature_info);
+ DCHECK(signature);
+ DCHECK_GE(level, 0);
+ DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
+ level_infos_.size());
+ DCHECK_LT(static_cast<size_t>(level),
+ level_infos_[GLTargetToFaceIndex(target)].size());
+ const Texture::LevelInfo& info =
+ level_infos_[GLTargetToFaceIndex(target)][level];
+ *signature += base::StringPrintf(
+ "|Texture|target=%04x|level=%d|internal_format=%04x"
+ "|width=%d|height=%d|depth=%d|border=%d|format=%04x|type=%04x"
+ "|image=%d|canrender=%d|canrenderto=%d|npot_=%d"
+ "|min_filter=%04x|mag_filter=%04x|wrap_s=%04x|wrap_t=%04x"
+ "|usage=%04x",
+ target, level, info.internal_format,
+ info.width, info.height, info.depth, info.border,
+ info.format, info.type, info.image.get() != NULL,
+ CanRender(feature_info), CanRenderTo(), npot_,
+ min_filter_, mag_filter_, wrap_s_, wrap_t_,
+ usage_);
+}
+
+void Texture::SetMailboxManager(MailboxManager* mailbox_manager) {
+ DCHECK(!mailbox_manager_ || mailbox_manager_ == mailbox_manager);
+ mailbox_manager_ = mailbox_manager;
+}
+
+bool Texture::MarkMipmapsGenerated(
+ const FeatureInfo* feature_info) {
+ if (!CanGenerateMipmaps(feature_info)) {
+ return false;
+ }
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ const Texture::LevelInfo& info1 = level_infos_[ii][0];
+ GLsizei width = info1.width;
+ GLsizei height = info1.height;
+ GLsizei depth = info1.depth;
+ GLenum target = target_ == GL_TEXTURE_2D ? GL_TEXTURE_2D :
+ FaceIndexToGLTarget(ii);
+ int num_mips = TextureManager::ComputeMipMapCount(width, height, depth);
+ for (int level = 1; level < num_mips; ++level) {
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
+ depth = std::max(1, depth >> 1);
+ SetLevelInfo(feature_info,
+ target,
+ level,
+ info1.internal_format,
+ width,
+ height,
+ depth,
+ info1.border,
+ info1.format,
+ info1.type,
+ true);
+ }
+ }
+
+ return true;
+}
+
+void Texture::SetTarget(
+ const FeatureInfo* feature_info, GLenum target, GLint max_levels) {
+ DCHECK_EQ(0u, target_); // you can only set this once.
+ target_ = target;
+ size_t num_faces = (target == GL_TEXTURE_CUBE_MAP) ? 6 : 1;
+ level_infos_.resize(num_faces);
+ for (size_t ii = 0; ii < num_faces; ++ii) {
+ level_infos_[ii].resize(max_levels);
+ }
+
+ if (target == GL_TEXTURE_EXTERNAL_OES || target == GL_TEXTURE_RECTANGLE_ARB) {
+ min_filter_ = GL_LINEAR;
+ wrap_s_ = wrap_t_ = GL_CLAMP_TO_EDGE;
+ }
+
+ if (target == GL_TEXTURE_EXTERNAL_OES) {
+ immutable_ = true;
+ }
+ Update(feature_info);
+ UpdateCanRenderCondition();
+}
+
+bool Texture::CanGenerateMipmaps(
+ const FeatureInfo* feature_info) const {
+ if ((npot() && !feature_info->feature_flags().npot_ok) ||
+ level_infos_.empty() ||
+ target_ == GL_TEXTURE_EXTERNAL_OES ||
+ target_ == GL_TEXTURE_RECTANGLE_ARB) {
+ return false;
+ }
+
+ // Can't generate mips for depth or stencil textures.
+ const Texture::LevelInfo& first = level_infos_[0][0];
+ uint32 channels = GLES2Util::GetChannelsForFormat(first.format);
+ if (channels & (GLES2Util::kDepth | GLES2Util::kStencil)) {
+ return false;
+ }
+
+ // TODO(gman): Check internal_format, format and type.
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ const LevelInfo& info = level_infos_[ii][0];
+ if ((info.target == 0) || (info.width != first.width) ||
+ (info.height != first.height) || (info.depth != 1) ||
+ (info.format != first.format) ||
+ (info.internal_format != first.internal_format) ||
+ (info.type != first.type) ||
+ feature_info->validators()->compressed_texture_format.IsValid(
+ info.internal_format) ||
+ info.image.get()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Texture::SetLevelCleared(GLenum target, GLint level, bool cleared) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
+ level_infos_.size());
+ DCHECK_LT(static_cast<size_t>(level),
+ level_infos_[GLTargetToFaceIndex(target)].size());
+ Texture::LevelInfo& info =
+ level_infos_[GLTargetToFaceIndex(target)][level];
+ UpdateMipCleared(&info, cleared);
+ UpdateCleared();
+}
+
+void Texture::UpdateCleared() {
+ if (level_infos_.empty()) {
+ return;
+ }
+
+ const Texture::LevelInfo& first_face = level_infos_[0][0];
+ int levels_needed = TextureManager::ComputeMipMapCount(
+ first_face.width, first_face.height, first_face.depth);
+ bool cleared = true;
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ for (GLint jj = 0; jj < levels_needed; ++jj) {
+ const Texture::LevelInfo& info = level_infos_[ii][jj];
+ if (info.width > 0 && info.height > 0 && info.depth > 0 &&
+ !info.cleared) {
+ cleared = false;
+ break;
+ }
+ }
+ }
+ UpdateSafeToRenderFrom(cleared);
+}
+
+void Texture::UpdateSafeToRenderFrom(bool cleared) {
+ if (cleared_ == cleared)
+ return;
+ cleared_ = cleared;
+ int delta = cleared ? -1 : +1;
+ for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
+ (*it)->manager()->UpdateSafeToRenderFrom(delta);
+}
+
+void Texture::UpdateMipCleared(LevelInfo* info, bool cleared) {
+ if (info->cleared == cleared)
+ return;
+ info->cleared = cleared;
+ int delta = cleared ? -1 : +1;
+ num_uncleared_mips_ += delta;
+ for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
+ (*it)->manager()->UpdateUnclearedMips(delta);
+}
+
+void Texture::UpdateCanRenderCondition() {
+ CanRenderCondition can_render_condition = GetCanRenderCondition();
+ if (can_render_condition_ == can_render_condition)
+ return;
+ for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
+ (*it)->manager()->UpdateCanRenderCondition(can_render_condition_,
+ can_render_condition);
+ can_render_condition_ = can_render_condition;
+}
+
+void Texture::IncAllFramebufferStateChangeCount() {
+ for (RefSet::iterator it = refs_.begin(); it != refs_.end(); ++it)
+ (*it)->manager()->IncFramebufferStateChangeCount();
+}
+
+void Texture::SetLevelInfo(
+ const FeatureInfo* feature_info,
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ bool cleared) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
+ level_infos_.size());
+ DCHECK_LT(static_cast<size_t>(level),
+ level_infos_[GLTargetToFaceIndex(target)].size());
+ DCHECK_GE(width, 0);
+ DCHECK_GE(height, 0);
+ DCHECK_GE(depth, 0);
+ Texture::LevelInfo& info =
+ level_infos_[GLTargetToFaceIndex(target)][level];
+ info.target = target;
+ info.level = level;
+ info.internal_format = internal_format;
+ info.width = width;
+ info.height = height;
+ info.depth = depth;
+ info.border = border;
+ info.format = format;
+ info.type = type;
+ info.image = 0;
+
+ estimated_size_ -= info.estimated_size;
+ GLES2Util::ComputeImageDataSizes(
+ width, height, format, type, 4, &info.estimated_size, NULL, NULL);
+ estimated_size_ += info.estimated_size;
+
+ UpdateMipCleared(&info, cleared);
+ max_level_set_ = std::max(max_level_set_, level);
+ Update(feature_info);
+ UpdateCleared();
+ UpdateCanRenderCondition();
+ if (IsAttachedToFramebuffer()) {
+ // TODO(gman): If textures tracked which framebuffers they were attached to
+ // we could just mark those framebuffers as not complete.
+ IncAllFramebufferStateChangeCount();
+ }
+}
+
+bool Texture::ValidForTexture(
+ GLint target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type) const {
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (level >= 0 && face_index < level_infos_.size() &&
+ static_cast<size_t>(level) < level_infos_[face_index].size()) {
+ const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
+ int32 right;
+ int32 top;
+ return SafeAddInt32(xoffset, width, &right) &&
+ SafeAddInt32(yoffset, height, &top) &&
+ xoffset >= 0 &&
+ yoffset >= 0 &&
+ right <= info.width &&
+ top <= info.height &&
+ format == info.internal_format &&
+ type == info.type;
+ }
+ return false;
+}
+
+bool Texture::GetLevelSize(
+ GLint target, GLint level, GLsizei* width, GLsizei* height) const {
+ DCHECK(width);
+ DCHECK(height);
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (level >= 0 && face_index < level_infos_.size() &&
+ static_cast<size_t>(level) < level_infos_[face_index].size()) {
+ const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
+ if (info.target != 0) {
+ *width = info.width;
+ *height = info.height;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool Texture::GetLevelType(
+ GLint target, GLint level, GLenum* type, GLenum* internal_format) const {
+ DCHECK(type);
+ DCHECK(internal_format);
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (level >= 0 && face_index < level_infos_.size() &&
+ static_cast<size_t>(level) < level_infos_[face_index].size()) {
+ const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
+ if (info.target != 0) {
+ *type = info.type;
+ *internal_format = info.internal_format;
+ return true;
+ }
+ }
+ return false;
+}
+
+GLenum Texture::SetParameter(
+ const FeatureInfo* feature_info, GLenum pname, GLint param) {
+ DCHECK(feature_info);
+
+ if (target_ == GL_TEXTURE_EXTERNAL_OES ||
+ target_ == GL_TEXTURE_RECTANGLE_ARB) {
+ if (pname == GL_TEXTURE_MIN_FILTER &&
+ (param != GL_NEAREST && param != GL_LINEAR))
+ return GL_INVALID_ENUM;
+ if ((pname == GL_TEXTURE_WRAP_S || pname == GL_TEXTURE_WRAP_T) &&
+ param != GL_CLAMP_TO_EDGE)
+ return GL_INVALID_ENUM;
+ }
+
+ switch (pname) {
+ case GL_TEXTURE_MIN_FILTER:
+ if (!feature_info->validators()->texture_min_filter_mode.IsValid(param)) {
+ return GL_INVALID_ENUM;
+ }
+ min_filter_ = param;
+ break;
+ case GL_TEXTURE_MAG_FILTER:
+ if (!feature_info->validators()->texture_mag_filter_mode.IsValid(param)) {
+ return GL_INVALID_ENUM;
+ }
+ mag_filter_ = param;
+ break;
+ case GL_TEXTURE_POOL_CHROMIUM:
+ if (!feature_info->validators()->texture_pool.IsValid(param)) {
+ return GL_INVALID_ENUM;
+ }
+ GetMemTracker()->TrackMemFree(estimated_size());
+ pool_ = param;
+ GetMemTracker()->TrackMemAlloc(estimated_size());
+ break;
+ case GL_TEXTURE_WRAP_S:
+ if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
+ return GL_INVALID_ENUM;
+ }
+ wrap_s_ = param;
+ break;
+ case GL_TEXTURE_WRAP_T:
+ if (!feature_info->validators()->texture_wrap_mode.IsValid(param)) {
+ return GL_INVALID_ENUM;
+ }
+ wrap_t_ = param;
+ break;
+ case GL_TEXTURE_MAX_ANISOTROPY_EXT:
+ if (param < 1) {
+ return GL_INVALID_VALUE;
+ }
+ break;
+ case GL_TEXTURE_USAGE_ANGLE:
+ if (!feature_info->validators()->texture_usage.IsValid(param)) {
+ return GL_INVALID_ENUM;
+ }
+ usage_ = param;
+ break;
+ default:
+ NOTREACHED();
+ return GL_INVALID_ENUM;
+ }
+ Update(feature_info);
+ UpdateCleared();
+ UpdateCanRenderCondition();
+ return GL_NO_ERROR;
+}
+
+void Texture::Update(const FeatureInfo* feature_info) {
+ // Update npot status.
+ // Assume GL_TEXTURE_EXTERNAL_OES textures are npot, all others
+ npot_ = target_ == GL_TEXTURE_EXTERNAL_OES;
+
+ if (level_infos_.empty()) {
+ texture_complete_ = false;
+ cube_complete_ = false;
+ return;
+ }
+
+ // checks that the first mip of any face is npot.
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ const Texture::LevelInfo& info = level_infos_[ii][0];
+ if (GLES2Util::IsNPOT(info.width) ||
+ GLES2Util::IsNPOT(info.height) ||
+ GLES2Util::IsNPOT(info.depth)) {
+ npot_ = true;
+ break;
+ }
+ }
+
+ // Update texture_complete and cube_complete status.
+ const Texture::LevelInfo& first_face = level_infos_[0][0];
+ int levels_needed = TextureManager::ComputeMipMapCount(
+ first_face.width, first_face.height, first_face.depth);
+ texture_complete_ =
+ max_level_set_ >= (levels_needed - 1) && max_level_set_ >= 0;
+ cube_complete_ = (level_infos_.size() == 6) &&
+ (first_face.width == first_face.height);
+
+ if (first_face.width == 0 || first_face.height == 0) {
+ texture_complete_ = false;
+ }
+ if (first_face.type == GL_FLOAT &&
+ !feature_info->feature_flags().enable_texture_float_linear &&
+ (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
+ mag_filter_ != GL_NEAREST)) {
+ texture_complete_ = false;
+ } else if (first_face.type == GL_HALF_FLOAT_OES &&
+ !feature_info->feature_flags().enable_texture_half_float_linear &&
+ (min_filter_ != GL_NEAREST_MIPMAP_NEAREST ||
+ mag_filter_ != GL_NEAREST)) {
+ texture_complete_ = false;
+ }
+ for (size_t ii = 0;
+ ii < level_infos_.size() && (cube_complete_ || texture_complete_);
+ ++ii) {
+ const Texture::LevelInfo& level0 = level_infos_[ii][0];
+ if (level0.target == 0 ||
+ level0.width != first_face.width ||
+ level0.height != first_face.height ||
+ level0.depth != 1 ||
+ level0.internal_format != first_face.internal_format ||
+ level0.format != first_face.format ||
+ level0.type != first_face.type) {
+ cube_complete_ = false;
+ }
+ // Get level0 dimensions
+ GLsizei width = level0.width;
+ GLsizei height = level0.height;
+ GLsizei depth = level0.depth;
+ for (GLint jj = 1; jj < levels_needed; ++jj) {
+ // compute required size for mip.
+ width = std::max(1, width >> 1);
+ height = std::max(1, height >> 1);
+ depth = std::max(1, depth >> 1);
+ const Texture::LevelInfo& info = level_infos_[ii][jj];
+ if (info.target == 0 ||
+ info.width != width ||
+ info.height != height ||
+ info.depth != depth ||
+ info.internal_format != level0.internal_format ||
+ info.format != level0.format ||
+ info.type != level0.type) {
+ texture_complete_ = false;
+ break;
+ }
+ }
+ }
+}
+
+bool Texture::ClearRenderableLevels(GLES2Decoder* decoder) {
+ DCHECK(decoder);
+ if (cleared_) {
+ return true;
+ }
+
+ const Texture::LevelInfo& first_face = level_infos_[0][0];
+ int levels_needed = TextureManager::ComputeMipMapCount(
+ first_face.width, first_face.height, first_face.depth);
+
+ for (size_t ii = 0; ii < level_infos_.size(); ++ii) {
+ for (GLint jj = 0; jj < levels_needed; ++jj) {
+ Texture::LevelInfo& info = level_infos_[ii][jj];
+ if (info.target != 0) {
+ if (!ClearLevel(decoder, info.target, jj)) {
+ return false;
+ }
+ }
+ }
+ }
+ UpdateSafeToRenderFrom(true);
+ return true;
+}
+
+bool Texture::IsLevelCleared(GLenum target, GLint level) const {
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (face_index >= level_infos_.size() ||
+ level >= static_cast<GLint>(level_infos_[face_index].size())) {
+ return true;
+ }
+
+ const Texture::LevelInfo& info = level_infos_[face_index][level];
+
+ return info.cleared;
+}
+
+bool Texture::ClearLevel(
+ GLES2Decoder* decoder, GLenum target, GLint level) {
+ DCHECK(decoder);
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (face_index >= level_infos_.size() ||
+ level >= static_cast<GLint>(level_infos_[face_index].size())) {
+ return true;
+ }
+
+ Texture::LevelInfo& info = level_infos_[face_index][level];
+
+ DCHECK(target == info.target);
+
+ if (info.target == 0 ||
+ info.cleared ||
+ info.width == 0 ||
+ info.height == 0 ||
+ info.depth == 0) {
+ return true;
+ }
+
+ // NOTE: It seems kind of gross to call back into the decoder for this
+ // but only the decoder knows all the state (like unpack_alignment_) that's
+ // needed to be able to call GL correctly.
+ bool cleared = decoder->ClearLevel(
+ service_id_, target_, info.target, info.level, info.format, info.type,
+ info.width, info.height, immutable_);
+ UpdateMipCleared(&info, cleared);
+ return info.cleared;
+}
+
+void Texture::SetLevelImage(
+ const FeatureInfo* feature_info,
+ GLenum target,
+ GLint level,
+ gfx::GLImage* image) {
+ DCHECK_GE(level, 0);
+ DCHECK_LT(static_cast<size_t>(GLTargetToFaceIndex(target)),
+ level_infos_.size());
+ DCHECK_LT(static_cast<size_t>(level),
+ level_infos_[GLTargetToFaceIndex(target)].size());
+ Texture::LevelInfo& info =
+ level_infos_[GLTargetToFaceIndex(target)][level];
+ DCHECK_EQ(info.target, target);
+ DCHECK_EQ(info.level, level);
+ info.image = image;
+ UpdateCanRenderCondition();
+}
+
+gfx::GLImage* Texture::GetLevelImage(
+ GLint target, GLint level) const {
+ size_t face_index = GLTargetToFaceIndex(target);
+ if (level >= 0 && face_index < level_infos_.size() &&
+ static_cast<size_t>(level) < level_infos_[face_index].size()) {
+ const LevelInfo& info = level_infos_[GLTargetToFaceIndex(target)][level];
+ if (info.target != 0) {
+ return info.image.get();
+ }
+ }
+ return 0;
+}
+
+
+TextureRef::TextureRef(TextureManager* manager,
+ GLuint client_id,
+ Texture* texture)
+ : manager_(manager),
+ texture_(texture),
+ client_id_(client_id),
+ is_stream_texture_owner_(false) {
+ DCHECK(manager_);
+ DCHECK(texture_);
+ texture_->AddTextureRef(this);
+ manager_->StartTracking(this);
+}
+
+scoped_refptr<TextureRef> TextureRef::Create(TextureManager* manager,
+ GLuint client_id,
+ GLuint service_id) {
+ return new TextureRef(manager, client_id, new Texture(service_id));
+}
+
+TextureRef::~TextureRef() {
+ manager_->StopTracking(this);
+ texture_->RemoveTextureRef(this, manager_->have_context_);
+ manager_ = NULL;
+}
+
+TextureManager::TextureManager(
+ MemoryTracker* memory_tracker,
+ FeatureInfo* feature_info,
+ GLint max_texture_size,
+ GLint max_cube_map_texture_size)
+ : memory_tracker_managed_(
+ new MemoryTypeTracker(memory_tracker, MemoryTracker::kManaged)),
+ memory_tracker_unmanaged_(
+ new MemoryTypeTracker(memory_tracker, MemoryTracker::kUnmanaged)),
+ feature_info_(feature_info),
+ framebuffer_manager_(NULL),
+ stream_texture_manager_(NULL),
+ max_texture_size_(max_texture_size),
+ max_cube_map_texture_size_(max_cube_map_texture_size),
+ max_levels_(ComputeMipMapCount(max_texture_size,
+ max_texture_size,
+ max_texture_size)),
+ max_cube_map_levels_(ComputeMipMapCount(max_cube_map_texture_size,
+ max_cube_map_texture_size,
+ max_cube_map_texture_size)),
+ num_unrenderable_textures_(0),
+ num_unsafe_textures_(0),
+ num_uncleared_mips_(0),
+ texture_count_(0),
+ have_context_(true) {
+ for (int ii = 0; ii < kNumDefaultTextures; ++ii) {
+ black_texture_ids_[ii] = 0;
+ }
+}
+
+bool TextureManager::Initialize() {
+ // TODO(gman): The default textures have to be real textures, not the 0
+ // texture because we simulate non shared resources on top of shared
+ // resources and all contexts that share resource share the same default
+ // texture.
+ default_textures_[kTexture2D] = CreateDefaultAndBlackTextures(
+ GL_TEXTURE_2D, &black_texture_ids_[kTexture2D]);
+ default_textures_[kCubeMap] = CreateDefaultAndBlackTextures(
+ GL_TEXTURE_CUBE_MAP, &black_texture_ids_[kCubeMap]);
+
+ if (feature_info_->feature_flags().oes_egl_image_external) {
+ default_textures_[kExternalOES] = CreateDefaultAndBlackTextures(
+ GL_TEXTURE_EXTERNAL_OES, &black_texture_ids_[kExternalOES]);
+ }
+
+ if (feature_info_->feature_flags().arb_texture_rectangle) {
+ default_textures_[kRectangleARB] = CreateDefaultAndBlackTextures(
+ GL_TEXTURE_RECTANGLE_ARB, &black_texture_ids_[kRectangleARB]);
+ }
+
+ return true;
+}
+
+scoped_refptr<TextureRef>
+ TextureManager::CreateDefaultAndBlackTextures(
+ GLenum target,
+ GLuint* black_texture) {
+ static uint8 black[] = {0, 0, 0, 255};
+
+ // Sampling a texture not associated with any EGLImage sibling will return
+ // black values according to the spec.
+ bool needs_initialization = (target != GL_TEXTURE_EXTERNAL_OES);
+ bool needs_faces = (target == GL_TEXTURE_CUBE_MAP);
+
+ // Make default textures and texture for replacing non-renderable textures.
+ GLuint ids[2];
+ glGenTextures(arraysize(ids), ids);
+ for (unsigned long ii = 0; ii < arraysize(ids); ++ii) {
+ glBindTexture(target, ids[ii]);
+ if (needs_initialization) {
+ if (needs_faces) {
+ for (int jj = 0; jj < GLES2Util::kNumFaces; ++jj) {
+ glTexImage2D(GLES2Util::IndexToGLFaceTarget(jj), 0, GL_RGBA, 1, 1, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, black);
+ }
+ } else {
+ glTexImage2D(target, 0, GL_RGBA, 1, 1, 0, GL_RGBA,
+ GL_UNSIGNED_BYTE, black);
+ }
+ }
+ }
+ glBindTexture(target, 0);
+
+ scoped_refptr<TextureRef> default_texture(
+ TextureRef::Create(this, 0, ids[1]));
+ SetTarget(default_texture.get(), target);
+ if (needs_faces) {
+ for (int ii = 0; ii < GLES2Util::kNumFaces; ++ii) {
+ SetLevelInfo(default_texture.get(),
+ GLES2Util::IndexToGLFaceTarget(ii),
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ }
+ } else {
+ if (needs_initialization) {
+ SetLevelInfo(default_texture.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ } else {
+ SetLevelInfo(default_texture.get(),
+ GL_TEXTURE_EXTERNAL_OES,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ }
+ }
+
+ *black_texture = ids[0];
+ return default_texture;
+}
+
+bool TextureManager::ValidForTarget(
+ GLenum target, GLint level, GLsizei width, GLsizei height, GLsizei depth) {
+ GLsizei max_size = MaxSizeForTarget(target) >> level;
+ return level >= 0 &&
+ width >= 0 &&
+ height >= 0 &&
+ depth >= 0 &&
+ level < MaxLevelsForTarget(target) &&
+ width <= max_size &&
+ height <= max_size &&
+ depth <= max_size &&
+ (level == 0 || feature_info_->feature_flags().npot_ok ||
+ (!GLES2Util::IsNPOT(width) &&
+ !GLES2Util::IsNPOT(height) &&
+ !GLES2Util::IsNPOT(depth))) &&
+ (target != GL_TEXTURE_CUBE_MAP || (width == height && depth == 1)) &&
+ (target != GL_TEXTURE_2D || (depth == 1));
+}
+
+void TextureManager::SetTarget(TextureRef* ref, GLenum target) {
+ DCHECK(ref);
+ ref->texture()
+ ->SetTarget(feature_info_.get(), target, MaxLevelsForTarget(target));
+}
+
+void TextureManager::SetStreamTexture(TextureRef* ref, bool stream_texture) {
+ DCHECK(ref);
+ // Only the owner can mark as non-stream texture.
+ DCHECK_EQ(stream_texture, !ref->is_stream_texture_owner_);
+ ref->texture()->SetStreamTexture(stream_texture);
+ ref->set_is_stream_texture_owner(stream_texture);
+}
+
+bool TextureManager::IsStreamTextureOwner(TextureRef* ref) {
+ DCHECK(ref);
+ return ref->is_stream_texture_owner();
+}
+
+void TextureManager::SetLevelCleared(TextureRef* ref,
+ GLenum target,
+ GLint level,
+ bool cleared) {
+ DCHECK(ref);
+ ref->texture()->SetLevelCleared(target, level, cleared);
+}
+
+bool TextureManager::ClearRenderableLevels(
+ GLES2Decoder* decoder, TextureRef* ref) {
+ DCHECK(ref);
+ return ref->texture()->ClearRenderableLevels(decoder);
+}
+
+bool TextureManager::ClearTextureLevel(
+ GLES2Decoder* decoder, TextureRef* ref,
+ GLenum target, GLint level) {
+ DCHECK(ref);
+ Texture* texture = ref->texture();
+ if (texture->num_uncleared_mips() == 0) {
+ return true;
+ }
+ bool result = texture->ClearLevel(decoder, target, level);
+ texture->UpdateCleared();
+ return result;
+}
+
+void TextureManager::SetLevelInfo(
+ TextureRef* ref,
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ bool cleared) {
+ DCHECK(ref);
+ Texture* texture = ref->texture();
+
+ texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
+ texture->SetLevelInfo(feature_info_.get(),
+ target,
+ level,
+ internal_format,
+ width,
+ height,
+ depth,
+ border,
+ format,
+ type,
+ cleared);
+ texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
+}
+
+Texture* TextureManager::Produce(TextureRef* ref) {
+ DCHECK(ref);
+ return ref->texture();
+}
+
+TextureRef* TextureManager::Consume(
+ GLuint client_id,
+ Texture* texture) {
+ DCHECK(client_id);
+ scoped_refptr<TextureRef> ref(new TextureRef(this, client_id, texture));
+ bool result = textures_.insert(std::make_pair(client_id, ref)).second;
+ DCHECK(result);
+ return ref.get();
+}
+
+void TextureManager::SetParameter(
+ const char* function_name, ErrorState* error_state,
+ TextureRef* ref, GLenum pname, GLint param) {
+ DCHECK(error_state);
+ DCHECK(ref);
+ Texture* texture = ref->texture();
+ GLenum result = texture->SetParameter(feature_info_.get(), pname, param);
+ if (result != GL_NO_ERROR) {
+ if (result == GL_INVALID_ENUM) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, function_name, param, "param");
+ } else {
+ ERRORSTATE_SET_GL_ERROR_INVALID_PARAM(
+ error_state, result, function_name, pname, static_cast<GLint>(param));
+ }
+ } else {
+ // Texture tracking pools exist only for the command decoder, so
+ // do not pass them on to the native GL implementation.
+ if (pname != GL_TEXTURE_POOL_CHROMIUM) {
+ glTexParameteri(texture->target(), pname, param);
+ }
+ }
+}
+
+bool TextureManager::MarkMipmapsGenerated(TextureRef* ref) {
+ DCHECK(ref);
+ Texture* texture = ref->texture();
+ texture->GetMemTracker()->TrackMemFree(texture->estimated_size());
+ bool result = texture->MarkMipmapsGenerated(feature_info_.get());
+ texture->GetMemTracker()->TrackMemAlloc(texture->estimated_size());
+ return result;
+}
+
+TextureRef* TextureManager::CreateTexture(
+ GLuint client_id, GLuint service_id) {
+ DCHECK_NE(0u, service_id);
+ scoped_refptr<TextureRef> ref(TextureRef::Create(
+ this, client_id, service_id));
+ std::pair<TextureMap::iterator, bool> result =
+ textures_.insert(std::make_pair(client_id, ref));
+ DCHECK(result.second);
+ return ref.get();
+}
+
+TextureRef* TextureManager::GetTexture(
+ GLuint client_id) const {
+ TextureMap::const_iterator it = textures_.find(client_id);
+ return it != textures_.end() ? it->second.get() : NULL;
+}
+
+void TextureManager::RemoveTexture(GLuint client_id) {
+ TextureMap::iterator it = textures_.find(client_id);
+ if (it != textures_.end()) {
+ it->second->reset_client_id();
+ textures_.erase(it);
+ }
+}
+
+void TextureManager::StartTracking(TextureRef* ref) {
+ Texture* texture = ref->texture();
+ ++texture_count_;
+ num_uncleared_mips_ += texture->num_uncleared_mips();
+ if (!texture->SafeToRenderFrom())
+ ++num_unsafe_textures_;
+ if (!texture->CanRender(feature_info_.get()))
+ ++num_unrenderable_textures_;
+}
+
+void TextureManager::StopTracking(TextureRef* ref) {
+ FOR_EACH_OBSERVER(DestructionObserver,
+ destruction_observers_,
+ OnTextureRefDestroying(ref));
+
+ Texture* texture = ref->texture();
+ if (ref->is_stream_texture_owner_ && stream_texture_manager_) {
+ DCHECK(texture->IsStreamTexture());
+ stream_texture_manager_->DestroyStreamTexture(texture->service_id());
+ }
+
+ --texture_count_;
+ if (!texture->CanRender(feature_info_.get())) {
+ DCHECK_NE(0, num_unrenderable_textures_);
+ --num_unrenderable_textures_;
+ }
+ if (!texture->SafeToRenderFrom()) {
+ DCHECK_NE(0, num_unsafe_textures_);
+ --num_unsafe_textures_;
+ }
+ num_uncleared_mips_ -= texture->num_uncleared_mips();
+ DCHECK_GE(num_uncleared_mips_, 0);
+}
+
+MemoryTypeTracker* TextureManager::GetMemTracker(GLenum tracking_pool) {
+ switch(tracking_pool) {
+ case GL_TEXTURE_POOL_MANAGED_CHROMIUM:
+ return memory_tracker_managed_.get();
+ break;
+ case GL_TEXTURE_POOL_UNMANAGED_CHROMIUM:
+ return memory_tracker_unmanaged_.get();
+ break;
+ default:
+ break;
+ }
+ NOTREACHED();
+ return NULL;
+}
+
+Texture* TextureManager::GetTextureForServiceId(GLuint service_id) const {
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (TextureMap::const_iterator it = textures_.begin();
+ it != textures_.end(); ++it) {
+ Texture* texture = it->second->texture();
+ if (texture->service_id() == service_id)
+ return texture;
+ }
+ return NULL;
+}
+
+GLsizei TextureManager::ComputeMipMapCount(
+ GLsizei width, GLsizei height, GLsizei depth) {
+ return 1 + base::bits::Log2Floor(std::max(std::max(width, height), depth));
+}
+
+void TextureManager::SetLevelImage(
+ TextureRef* ref,
+ GLenum target,
+ GLint level,
+ gfx::GLImage* image) {
+ DCHECK(ref);
+ ref->texture()->SetLevelImage(feature_info_.get(), target, level, image);
+}
+
+void TextureManager::AddToSignature(
+ TextureRef* ref,
+ GLenum target,
+ GLint level,
+ std::string* signature) const {
+ ref->texture()->AddToSignature(feature_info_.get(), target, level, signature);
+}
+
+void TextureManager::UpdateSafeToRenderFrom(int delta) {
+ num_unsafe_textures_ += delta;
+ DCHECK_GE(num_unsafe_textures_, 0);
+}
+
+void TextureManager::UpdateUnclearedMips(int delta) {
+ num_uncleared_mips_ += delta;
+ DCHECK_GE(num_uncleared_mips_, 0);
+}
+
+void TextureManager::UpdateCanRenderCondition(
+ Texture::CanRenderCondition old_condition,
+ Texture::CanRenderCondition new_condition) {
+ if (old_condition == Texture::CAN_RENDER_NEVER ||
+ (old_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
+ !feature_info_->feature_flags().npot_ok)) {
+ DCHECK_GT(num_unrenderable_textures_, 0);
+ --num_unrenderable_textures_;
+ }
+ if (new_condition == Texture::CAN_RENDER_NEVER ||
+ (new_condition == Texture::CAN_RENDER_ONLY_IF_NPOT &&
+ !feature_info_->feature_flags().npot_ok))
+ ++num_unrenderable_textures_;
+}
+
+void TextureManager::IncFramebufferStateChangeCount() {
+ if (framebuffer_manager_)
+ framebuffer_manager_->IncFramebufferStateChangeCount();
+
+}
+
+bool TextureManager::ValidateTextureParameters(
+ ErrorState* error_state, const char* function_name,
+ GLenum target, GLenum format, GLenum type, GLint level) {
+ if (!feature_info_->GetTextureFormatValidator(format).IsValid(type)) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ (std::string("invalid type ") +
+ GLES2Util::GetStringEnum(type) + " for format " +
+ GLES2Util::GetStringEnum(format)).c_str());
+ return false;
+ }
+
+ uint32 channels = GLES2Util::GetChannelsForFormat(format);
+ if ((channels & (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && level) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ (std::string("invalid type ") +
+ GLES2Util::GetStringEnum(type) + " for format " +
+ GLES2Util::GetStringEnum(format)).c_str());
+ return false;
+ }
+ return true;
+}
+
+// Gets the texture id for a given target.
+TextureRef* TextureManager::GetTextureInfoForTarget(
+ ContextState* state, GLenum target) {
+ TextureUnit& unit = state->texture_units[state->active_texture_unit];
+ TextureRef* texture = NULL;
+ switch (target) {
+ case GL_TEXTURE_2D:
+ texture = unit.bound_texture_2d.get();
+ break;
+ case GL_TEXTURE_CUBE_MAP:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
+ case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
+ case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
+ texture = unit.bound_texture_cube_map.get();
+ break;
+ case GL_TEXTURE_EXTERNAL_OES:
+ texture = unit.bound_texture_external_oes.get();
+ break;
+ case GL_TEXTURE_RECTANGLE_ARB:
+ texture = unit.bound_texture_rectangle_arb.get();
+ break;
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+ return texture;
+}
+
+TextureRef* TextureManager::GetTextureInfoForTargetUnlessDefault(
+ ContextState* state, GLenum target) {
+ TextureRef* texture = GetTextureInfoForTarget(state, target);
+ if (!texture)
+ return NULL;
+ if (texture == GetDefaultTextureInfo(target))
+ return NULL;
+ return texture;
+}
+
+bool TextureManager::ValidateTexImage2D(
+ ContextState* state,
+ const char* function_name,
+ const DoTextImage2DArguments& args,
+ TextureRef** texture_ref) {
+ ErrorState* error_state = state->GetErrorState();
+ const Validators* validators = feature_info_->validators();
+ if (!validators->texture_target.IsValid(args.target)) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, function_name, args.target, "target");
+ return false;
+ }
+ if (!validators->texture_format.IsValid(args.internal_format)) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, function_name, args.internal_format,
+ "internal_format");
+ return false;
+ }
+ if (!validators->texture_format.IsValid(args.format)) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, function_name, args.format, "format");
+ return false;
+ }
+ if (!validators->pixel_type.IsValid(args.type)) {
+ ERRORSTATE_SET_GL_ERROR_INVALID_ENUM(
+ error_state, function_name, args.type, "type");
+ return false;
+ }
+ if (args.format != args.internal_format) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ "format != internalFormat");
+ return false;
+ }
+ if (!ValidateTextureParameters(
+ error_state, function_name, args.target, args.format, args.type,
+ args.level)) {
+ return false;
+ }
+ if (!ValidForTarget(args.target, args.level, args.width, args.height, 1) ||
+ args.border != 0) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_VALUE, function_name,
+ "dimensions out of range");
+ return false;
+ }
+ if ((GLES2Util::GetChannelsForFormat(args.format) &
+ (GLES2Util::kDepth | GLES2Util::kStencil)) != 0 && args.pixels) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION,
+ function_name, "can not supply data for depth or stencil textures");
+ return false;
+ }
+
+ TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target);
+ if (!local_texture_ref) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ "unknown texture for target");
+ return false;
+ }
+ if (local_texture_ref->texture()->IsImmutable()) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ "texture is immutable");
+ return false;
+ }
+
+ // TODO - verify that using the managed vs unmanaged does not matter.
+ // They both use the same MemoryTracker, and this call just re-routes
+ // to it.
+ if (!memory_tracker_managed_->EnsureGPUMemoryAvailable(args.pixels_size)) {
+ ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, "glTexImage2D",
+ "out of memory");
+ return false;
+ }
+
+ // Write the TextureReference since this is valid.
+ *texture_ref = local_texture_ref;
+ return true;
+}
+
+void TextureManager::ValidateAndDoTexImage2D(
+ DecoderTextureState* texture_state,
+ ContextState* state,
+ DecoderFramebufferState* framebuffer_state,
+ const DoTextImage2DArguments& args) {
+ TextureRef* texture_ref;
+ if (!ValidateTexImage2D(state, "glTexImage2D", args, &texture_ref)) {
+ return;
+ }
+
+ DoTexImage2D(texture_state, state->GetErrorState(), framebuffer_state,
+ texture_ref, args);
+}
+
+void TextureManager::DoTexImage2D(
+ DecoderTextureState* texture_state,
+ ErrorState* error_state,
+ DecoderFramebufferState* framebuffer_state,
+ TextureRef* texture_ref,
+ const DoTextImage2DArguments& args) {
+ Texture* texture = texture_ref->texture();
+ GLsizei tex_width = 0;
+ GLsizei tex_height = 0;
+ GLenum tex_type = 0;
+ GLenum tex_format = 0;
+ bool level_is_same =
+ texture->GetLevelSize(args.target, args.level, &tex_width, &tex_height) &&
+ texture->GetLevelType(args.target, args.level, &tex_type, &tex_format) &&
+ args.width == tex_width && args.height == tex_height &&
+ args.type == tex_type && args.format == tex_format;
+
+ if (level_is_same && !args.pixels) {
+ // Just set the level texture but mark the texture as uncleared.
+ SetLevelInfo(
+ texture_ref,
+ args.target, args.level, args.internal_format, args.width, args.height,
+ 1, args.border, args.format, args.type, false);
+ texture_state->tex_image_2d_failed = false;
+ return;
+ }
+
+ if (texture->IsAttachedToFramebuffer()) {
+ framebuffer_state->clear_state_dirty = true;
+ }
+
+ if (!texture_state->teximage2d_faster_than_texsubimage2d &&
+ level_is_same && args.pixels) {
+ {
+ ScopedTextureUploadTimer timer(texture_state);
+ glTexSubImage2D(args.target, args.level, 0, 0, args.width, args.height,
+ args.format, args.type, args.pixels);
+ }
+ SetLevelCleared(texture_ref, args.target, args.level, true);
+ texture_state->tex_image_2d_failed = false;
+ return;
+ }
+
+ ERRORSTATE_COPY_REAL_GL_ERRORS_TO_WRAPPER(error_state, "glTexImage2D");
+ {
+ ScopedTextureUploadTimer timer(texture_state);
+ glTexImage2D(
+ args.target, args.level, args.internal_format, args.width, args.height,
+ args.border, args.format, args.type, args.pixels);
+ }
+ GLenum error = ERRORSTATE_PEEK_GL_ERROR(error_state, "glTexImage2D");
+ if (error == GL_NO_ERROR) {
+ SetLevelInfo(
+ texture_ref,
+ args.target, args.level, args.internal_format, args.width, args.height,
+ 1, args.border, args.format, args.type, args.pixels != NULL);
+ texture_state->tex_image_2d_failed = false;
+ }
+}
+
+ScopedTextureUploadTimer::ScopedTextureUploadTimer(
+ DecoderTextureState* texture_state)
+ : texture_state_(texture_state),
+ begin_time_(base::TimeTicks::HighResNow()) {
+}
+
+ScopedTextureUploadTimer::~ScopedTextureUploadTimer() {
+ texture_state_->texture_upload_count++;
+ texture_state_->total_texture_upload_time +=
+ base::TimeTicks::HighResNow() - begin_time_;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/texture_manager.h b/chromium/gpu/command_buffer/service/texture_manager.h
new file mode 100644
index 00000000000..db470045751
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/texture_manager.h
@@ -0,0 +1,817 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
+
+#include <list>
+#include <set>
+#include <string>
+#include <vector>
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/observer_list.h"
+#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/gpu_export.h"
+#include "ui/gl/gl_image.h"
+
+namespace gpu {
+
+class StreamTextureManager;
+
+namespace gles2 {
+
+class GLES2Decoder;
+struct ContextState;
+struct DecoderFramebufferState;
+class Display;
+class ErrorState;
+class FeatureInfo;
+class FramebufferManager;
+class MailboxManager;
+class TextureManager;
+class TextureRef;
+
+// Info about Textures currently in the system.
+// This class wraps a real GL texture, keeping track of its meta-data. It is
+// jointly owned by possibly multiple TextureRef.
+class GPU_EXPORT Texture {
+ public:
+ explicit Texture(GLuint service_id);
+
+ GLenum min_filter() const {
+ return min_filter_;
+ }
+
+ GLenum mag_filter() const {
+ return mag_filter_;
+ }
+
+ GLenum wrap_s() const {
+ return wrap_s_;
+ }
+
+ GLenum wrap_t() const {
+ return wrap_t_;
+ }
+
+ GLenum usage() const {
+ return usage_;
+ }
+
+ GLenum pool() const {
+ return pool_;
+ }
+
+ int num_uncleared_mips() const {
+ return num_uncleared_mips_;
+ }
+
+ uint32 estimated_size() const {
+ return estimated_size_;
+ }
+
+ bool CanRenderTo() const {
+ return !stream_texture_ && target_ != GL_TEXTURE_EXTERNAL_OES;
+ }
+
+ // The service side OpenGL id of the texture.
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ void SetServiceId(GLuint service_id) {
+ DCHECK(service_id);
+ service_id_ = service_id;
+ }
+
+ // Returns the target this texure was first bound to or 0 if it has not
+ // been bound. Once a texture is bound to a specific target it can never be
+ // bound to a different target.
+ GLenum target() const {
+ return target_;
+ }
+
+ bool SafeToRenderFrom() const {
+ return cleared_;
+ }
+
+ // Get the width and height for a particular level. Returns false if level
+ // does not exist.
+ bool GetLevelSize(
+ GLint target, GLint level, GLsizei* width, GLsizei* height) const;
+
+ // Get the type of a level. Returns false if level does not exist.
+ bool GetLevelType(
+ GLint target, GLint level, GLenum* type, GLenum* internal_format) const;
+
+ // Get the image bound to a particular level. Returns NULL if level
+ // does not exist.
+ gfx::GLImage* GetLevelImage(GLint target, GLint level) const;
+
+ // Returns true of the given dimensions are inside the dimensions of the
+ // level and if the format and type match the level.
+ bool ValidForTexture(
+ GLint target,
+ GLint level,
+ GLint xoffset,
+ GLint yoffset,
+ GLsizei width,
+ GLsizei height,
+ GLenum format,
+ GLenum type) const;
+
+ bool IsValid() const {
+ return !!target();
+ }
+
+ bool IsAttachedToFramebuffer() const {
+ return framebuffer_attachment_count_ != 0;
+ }
+
+ void AttachToFramebuffer() {
+ ++framebuffer_attachment_count_;
+ }
+
+ void DetachFromFramebuffer() {
+ DCHECK_GT(framebuffer_attachment_count_, 0);
+ --framebuffer_attachment_count_;
+ }
+
+ bool IsStreamTexture() const {
+ return stream_texture_;
+ }
+
+ void SetImmutable(bool immutable) {
+ immutable_ = immutable;
+ }
+
+ bool IsImmutable() const {
+ return immutable_;
+ }
+
+ // Whether a particular level/face is cleared.
+ bool IsLevelCleared(GLenum target, GLint level) const;
+
+ // Whether the texture has been defined
+ bool IsDefined() const {
+ return estimated_size() > 0;
+ }
+
+ private:
+ friend class MailboxManager;
+ friend class MailboxManagerTest;
+ friend class TextureManager;
+ friend class TextureRef;
+ friend class TextureTestHelper;
+
+ ~Texture();
+ void AddTextureRef(TextureRef* ref);
+ void RemoveTextureRef(TextureRef* ref, bool have_context);
+ MemoryTypeTracker* GetMemTracker();
+
+ // Condition on which this texture is renderable. Can be ONLY_IF_NPOT if it
+ // depends on context support for non-power-of-two textures (i.e. will be
+ // renderable if NPOT support is in the context, otherwise not, e.g. texture
+ // with a NPOT level). ALWAYS means it doesn't depend on context features
+ // (e.g. complete POT), NEVER means it's not renderable regardless (e.g.
+ // incomplete).
+ enum CanRenderCondition {
+ CAN_RENDER_ALWAYS,
+ CAN_RENDER_NEVER,
+ CAN_RENDER_ONLY_IF_NPOT
+ };
+
+ struct LevelInfo {
+ LevelInfo();
+ LevelInfo(const LevelInfo& rhs);
+ ~LevelInfo();
+
+ bool cleared;
+ GLenum target;
+ GLint level;
+ GLenum internal_format;
+ GLsizei width;
+ GLsizei height;
+ GLsizei depth;
+ GLint border;
+ GLenum format;
+ GLenum type;
+ scoped_refptr<gfx::GLImage> image;
+ uint32 estimated_size;
+ };
+
+ // Set the info for a particular level.
+ void SetLevelInfo(
+ const FeatureInfo* feature_info,
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ bool cleared);
+
+ // In GLES2 "texture complete" means it has all required mips for filtering
+ // down to a 1x1 pixel texture, they are in the correct order, they are all
+ // the same format.
+ bool texture_complete() const {
+ return texture_complete_;
+ }
+
+ // In GLES2 "cube complete" means all 6 faces level 0 are defined, all the
+ // same format, all the same dimensions and all width = height.
+ bool cube_complete() const {
+ return cube_complete_;
+ }
+
+ // Whether or not this texture is a non-power-of-two texture.
+ bool npot() const {
+ return npot_;
+ }
+
+ void SetStreamTexture(bool stream_texture) {
+ stream_texture_ = stream_texture;
+ UpdateCanRenderCondition();
+ }
+
+ // Marks a particular level as cleared or uncleared.
+ void SetLevelCleared(GLenum target, GLint level, bool cleared);
+
+ // Updates the cleared flag for this texture by inspecting all the mips.
+ void UpdateCleared();
+
+ // Clears any renderable uncleared levels.
+ // Returns false if a GL error was generated.
+ bool ClearRenderableLevels(GLES2Decoder* decoder);
+
+ // Clears the level.
+ // Returns false if a GL error was generated.
+ bool ClearLevel(GLES2Decoder* decoder, GLenum target, GLint level);
+
+ // Sets a texture parameter.
+ // TODO(gman): Expand to SetParameteri,f,iv,fv
+ // Returns GL_NO_ERROR on success. Otherwise the error to generate.
+ GLenum SetParameter(
+ const FeatureInfo* feature_info, GLenum pname, GLint param);
+
+ // Makes each of the mip levels as though they were generated.
+ bool MarkMipmapsGenerated(const FeatureInfo* feature_info);
+
+ bool NeedsMips() const {
+ return min_filter_ != GL_NEAREST && min_filter_ != GL_LINEAR;
+ }
+
+ // True if this texture meets all the GLES2 criteria for rendering.
+ // See section 3.8.2 of the GLES2 spec.
+ bool CanRender(const FeatureInfo* feature_info) const;
+
+ // Returns true if mipmaps can be generated by GL.
+ bool CanGenerateMipmaps(const FeatureInfo* feature_info) const;
+
+ // Sets the Texture's target
+ // Parameters:
+ // target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP or
+ // GL_TEXTURE_EXTERNAL_OES or GL_TEXTURE_RECTANGLE_ARB
+ // max_levels: The maximum levels this type of target can have.
+ void SetTarget(
+ const FeatureInfo* feature_info, GLenum target, GLint max_levels);
+
+ // Update info about this texture.
+ void Update(const FeatureInfo* feature_info);
+
+ // Set the image for a particular level.
+ void SetLevelImage(
+ const FeatureInfo* feature_info,
+ GLenum target,
+ GLint level,
+ gfx::GLImage* image);
+
+ // Appends a signature for the given level.
+ void AddToSignature(
+ const FeatureInfo* feature_info,
+ GLenum target, GLint level, std::string* signature) const;
+
+ void SetMailboxManager(MailboxManager* mailbox_manager);
+
+ // Updates the unsafe textures count in all the managers referencing this
+ // texture.
+ void UpdateSafeToRenderFrom(bool cleared);
+
+ // Updates the uncleared mip count in all the managers referencing this
+ // texture.
+ void UpdateMipCleared(LevelInfo* info, bool cleared);
+
+ // Computes the CanRenderCondition flag.
+ CanRenderCondition GetCanRenderCondition() const;
+
+ // Updates the unrenderable texture count in all the managers referencing this
+ // texture.
+ void UpdateCanRenderCondition();
+
+ // Increment the framebuffer state change count in all the managers
+ // referencing this texture.
+ void IncAllFramebufferStateChangeCount();
+
+ MailboxManager* mailbox_manager_;
+
+ // Info about each face and level of texture.
+ std::vector<std::vector<LevelInfo> > level_infos_;
+
+ // The texture refs that point to this Texture.
+ typedef std::set<TextureRef*> RefSet;
+ RefSet refs_;
+
+ // The single TextureRef that accounts for memory for this texture. Must be
+ // one of refs_.
+ TextureRef* memory_tracking_ref_;
+
+ // The id of the texure
+ GLuint service_id_;
+
+ // Whether all renderable mips of this texture have been cleared.
+ bool cleared_;
+
+ int num_uncleared_mips_;
+
+ // The target. 0 if unset, otherwise GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP.
+ GLenum target_;
+
+ // Texture parameters.
+ GLenum min_filter_;
+ GLenum mag_filter_;
+ GLenum wrap_s_;
+ GLenum wrap_t_;
+ GLenum usage_;
+ GLenum pool_;
+
+ // The maximum level that has been set.
+ GLint max_level_set_;
+
+ // Whether or not this texture is "texture complete"
+ bool texture_complete_;
+
+ // Whether or not this texture is "cube complete"
+ bool cube_complete_;
+
+ // Whether or not this texture is non-power-of-two
+ bool npot_;
+
+ // Whether this texture has ever been bound.
+ bool has_been_bound_;
+
+ // The number of framebuffers this texture is attached to.
+ int framebuffer_attachment_count_;
+
+ // Whether this is a special streaming texture.
+ bool stream_texture_;
+
+ // Whether the texture is immutable and no further changes to the format
+ // or dimensions of the texture object can be made.
+ bool immutable_;
+
+ // Size in bytes this texture is assumed to take in memory.
+ uint32 estimated_size_;
+
+ // Cache of the computed CanRenderCondition flag.
+ CanRenderCondition can_render_condition_;
+
+ DISALLOW_COPY_AND_ASSIGN(Texture);
+};
+
+// This class represents a texture in a client context group. It's mostly 1:1
+// with a client id, though it can outlive the client id if it's still bound to
+// a FBO or another context when destroyed.
+// Multiple TextureRef can point to the same texture with cross-context sharing.
+//
+// Note: for stream textures, the TextureRef that created the stream texture is
+// set as the "owner" of the stream texture, i.e. it will call
+// DestroyStreamTexture on destruction. This is because the StreamTextureManager
+// isn't generally shared between ContextGroups, so ownership can't be at the
+// Texture level. We also can't have multiple StreamTexture on the same service
+// id, so there can be only one owner.
+class GPU_EXPORT TextureRef : public base::RefCounted<TextureRef> {
+ public:
+ TextureRef(TextureManager* manager, GLuint client_id, Texture* texture);
+ static scoped_refptr<TextureRef> Create(TextureManager* manager,
+ GLuint client_id,
+ GLuint service_id);
+ const Texture* texture() const { return texture_; }
+ Texture* texture() { return texture_; }
+ GLuint client_id() const { return client_id_; }
+ GLuint service_id() const { return texture_->service_id(); }
+
+ private:
+ friend class base::RefCounted<TextureRef>;
+ friend class Texture;
+ friend class TextureManager;
+
+ ~TextureRef();
+ const TextureManager* manager() const { return manager_; }
+ TextureManager* manager() { return manager_; }
+ void reset_client_id() { client_id_ = 0; }
+ void set_is_stream_texture_owner(bool owner) {
+ is_stream_texture_owner_ = owner;
+ }
+ bool is_stream_texture_owner() const { return is_stream_texture_owner_; }
+
+ TextureManager* manager_;
+ Texture* texture_;
+ GLuint client_id_;
+ bool is_stream_texture_owner_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureRef);
+};
+
+// Holds data that is per gles2_cmd_decoder, but is related to to the
+// TextureManager.
+struct DecoderTextureState {
+ // total_texture_upload_time automatically initialized to 0 in default
+ // constructor.
+ DecoderTextureState():
+ tex_image_2d_failed(false),
+ texture_upload_count(0),
+ teximage2d_faster_than_texsubimage2d(true) {}
+
+ // This indicates all the following texSubImage2D calls that are part of the
+ // failed texImage2D call should be ignored.
+ bool tex_image_2d_failed;
+
+ // Command buffer stats.
+ int texture_upload_count;
+ base::TimeDelta total_texture_upload_time;
+
+ // This is really not per-decoder, but the logic to decide this value is in
+ // the decoder for now, so it is simpler to leave it there.
+ bool teximage2d_faster_than_texsubimage2d;
+};
+
+// This class keeps track of the textures and their sizes so we can do NPOT and
+// texture complete checking.
+//
+// NOTE: To support shared resources an instance of this class will need to be
+// shared by multiple GLES2Decoders.
+class GPU_EXPORT TextureManager {
+ public:
+ class GPU_EXPORT DestructionObserver {
+ public:
+ DestructionObserver();
+ virtual ~DestructionObserver();
+
+ // Called in ~TextureManager.
+ virtual void OnTextureManagerDestroying(TextureManager* manager) = 0;
+
+ // Called via ~TextureRef.
+ virtual void OnTextureRefDestroying(TextureRef* texture) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(DestructionObserver);
+ };
+
+ enum DefaultAndBlackTextures {
+ kTexture2D,
+ kCubeMap,
+ kExternalOES,
+ kRectangleARB,
+ kNumDefaultTextures
+ };
+
+ TextureManager(MemoryTracker* memory_tracker,
+ FeatureInfo* feature_info,
+ GLsizei max_texture_size,
+ GLsizei max_cube_map_texture_size);
+ ~TextureManager();
+
+ void set_framebuffer_manager(FramebufferManager* manager) {
+ framebuffer_manager_ = manager;
+ }
+
+ void set_stream_texture_manager(StreamTextureManager* manager) {
+ stream_texture_manager_ = manager;
+ }
+
+ // Init the texture manager.
+ bool Initialize();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Returns the maximum number of levels.
+ GLint MaxLevelsForTarget(GLenum target) const {
+ switch (target) {
+ case GL_TEXTURE_2D:
+ return max_levels_;
+ case GL_TEXTURE_EXTERNAL_OES:
+ return 1;
+ default:
+ return max_cube_map_levels_;
+ }
+ }
+
+ // Returns the maximum size.
+ GLsizei MaxSizeForTarget(GLenum target) const {
+ switch (target) {
+ case GL_TEXTURE_2D:
+ case GL_TEXTURE_EXTERNAL_OES:
+ return max_texture_size_;
+ default:
+ return max_cube_map_texture_size_;
+ }
+ }
+
+ // Returns the maxium number of levels a texture of the given size can have.
+ static GLsizei ComputeMipMapCount(
+ GLsizei width, GLsizei height, GLsizei depth);
+
+ // Checks if a dimensions are valid for a given target.
+ bool ValidForTarget(
+ GLenum target, GLint level,
+ GLsizei width, GLsizei height, GLsizei depth);
+
+ // True if this texture meets all the GLES2 criteria for rendering.
+ // See section 3.8.2 of the GLES2 spec.
+ bool CanRender(const TextureRef* ref) const {
+ return ref->texture()->CanRender(feature_info_.get());
+ }
+
+ // Returns true if mipmaps can be generated by GL.
+ bool CanGenerateMipmaps(const TextureRef* ref) const {
+ return ref->texture()->CanGenerateMipmaps(feature_info_.get());
+ }
+
+ // Sets the Texture's target
+ // Parameters:
+ // target: GL_TEXTURE_2D or GL_TEXTURE_CUBE_MAP
+ // max_levels: The maximum levels this type of target can have.
+ void SetTarget(
+ TextureRef* ref,
+ GLenum target);
+
+ // Marks a texture as a stream texture, and the ref as the stream texture
+ // owner.
+ void SetStreamTexture(TextureRef* ref, bool stream_texture);
+
+ // Whether the TextureRef is the stream texture owner.
+ bool IsStreamTextureOwner(TextureRef* ref);
+
+ // Set the info for a particular level in a TexureInfo.
+ void SetLevelInfo(
+ TextureRef* ref,
+ GLenum target,
+ GLint level,
+ GLenum internal_format,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum format,
+ GLenum type,
+ bool cleared);
+
+ // Adapter to call above function.
+ void SetLevelInfoFromParams(TextureRef* ref,
+ const gpu::AsyncTexImage2DParams& params) {
+ SetLevelInfo(
+ ref, params.target, params.level, params.internal_format,
+ params.width, params.height, 1 /* depth */,
+ params.border, params.format,
+ params.type, true /* cleared */ );
+ }
+
+ Texture* Produce(TextureRef* ref);
+
+ // Maps an existing texture into the texture manager, at a given client ID.
+ TextureRef* Consume(GLuint client_id, Texture* texture);
+
+ // Sets a mip as cleared.
+ void SetLevelCleared(TextureRef* ref, GLenum target,
+ GLint level, bool cleared);
+
+ // Sets a texture parameter of a Texture
+ // Returns GL_NO_ERROR on success. Otherwise the error to generate.
+ // TODO(gman): Expand to SetParameteri,f,iv,fv
+ void SetParameter(
+ const char* function_name, ErrorState* error_state,
+ TextureRef* ref, GLenum pname, GLint param);
+
+ // Makes each of the mip levels as though they were generated.
+ // Returns false if that's not allowed for the given texture.
+ bool MarkMipmapsGenerated(TextureRef* ref);
+
+ // Clears any uncleared renderable levels.
+ bool ClearRenderableLevels(GLES2Decoder* decoder, TextureRef* ref);
+
+ // Clear a specific level.
+ bool ClearTextureLevel(
+ GLES2Decoder* decoder, TextureRef* ref, GLenum target, GLint level);
+
+ // Creates a new texture info.
+ TextureRef* CreateTexture(GLuint client_id, GLuint service_id);
+
+ // Gets the texture info for the given texture.
+ TextureRef* GetTexture(GLuint client_id) const;
+
+ // Removes a texture info.
+ void RemoveTexture(GLuint client_id);
+
+ // Gets a Texture for a given service id (note: it assumes the texture object
+ // is still mapped in this TextureManager).
+ Texture* GetTextureForServiceId(GLuint service_id) const;
+
+ TextureRef* GetDefaultTextureInfo(GLenum target) {
+ switch (target) {
+ case GL_TEXTURE_2D:
+ return default_textures_[kTexture2D].get();
+ case GL_TEXTURE_CUBE_MAP:
+ return default_textures_[kCubeMap].get();
+ case GL_TEXTURE_EXTERNAL_OES:
+ return default_textures_[kExternalOES].get();
+ case GL_TEXTURE_RECTANGLE_ARB:
+ return default_textures_[kRectangleARB].get();
+ default:
+ NOTREACHED();
+ return NULL;
+ }
+ }
+
+ bool HaveUnrenderableTextures() const {
+ return num_unrenderable_textures_ > 0;
+ }
+
+ bool HaveUnsafeTextures() const {
+ return num_unsafe_textures_ > 0;
+ }
+
+ bool HaveUnclearedMips() const {
+ return num_uncleared_mips_ > 0;
+ }
+
+ GLuint black_texture_id(GLenum target) const {
+ switch (target) {
+ case GL_SAMPLER_2D:
+ return black_texture_ids_[kTexture2D];
+ case GL_SAMPLER_CUBE:
+ return black_texture_ids_[kCubeMap];
+ case GL_SAMPLER_EXTERNAL_OES:
+ return black_texture_ids_[kExternalOES];
+ case GL_SAMPLER_2D_RECT_ARB:
+ return black_texture_ids_[kRectangleARB];
+ default:
+ NOTREACHED();
+ return 0;
+ }
+ }
+
+ size_t mem_represented() const {
+ return
+ memory_tracker_managed_->GetMemRepresented() +
+ memory_tracker_unmanaged_->GetMemRepresented();
+ }
+
+ void SetLevelImage(
+ TextureRef* ref,
+ GLenum target,
+ GLint level,
+ gfx::GLImage* image);
+
+ void AddToSignature(
+ TextureRef* ref,
+ GLenum target,
+ GLint level,
+ std::string* signature) const;
+
+ void AddObserver(DestructionObserver* observer) {
+ destruction_observers_.AddObserver(observer);
+ }
+
+ void RemoveObserver(DestructionObserver* observer) {
+ destruction_observers_.RemoveObserver(observer);
+ }
+
+ struct DoTextImage2DArguments {
+ GLenum target;
+ GLint level;
+ GLenum internal_format;
+ GLsizei width;
+ GLsizei height;
+ GLint border;
+ GLenum format;
+ GLenum type;
+ const void* pixels;
+ uint32 pixels_size;
+ };
+
+ bool ValidateTexImage2D(
+ ContextState* state,
+ const char* function_name,
+ const DoTextImage2DArguments& args,
+ // Pointer to TextureRef filled in if validation successful.
+ // Presumes the pointer is valid.
+ TextureRef** texture_ref);
+
+ void ValidateAndDoTexImage2D(
+ DecoderTextureState* texture_state,
+ ContextState* state,
+ DecoderFramebufferState* framebuffer_state,
+ const DoTextImage2DArguments& args);
+
+ // TODO(kloveless): Make GetTexture* private once this is no longer called
+ // from gles2_cmd_decoder.
+ TextureRef* GetTextureInfoForTarget(ContextState* state, GLenum target);
+ TextureRef* GetTextureInfoForTargetUnlessDefault(
+ ContextState* state, GLenum target);
+
+ bool ValidateTextureParameters(
+ ErrorState* error_state, const char* function_name,
+ GLenum target, GLenum format, GLenum type, GLint level);
+
+ private:
+ friend class Texture;
+ friend class TextureRef;
+
+ // Helper for Initialize().
+ scoped_refptr<TextureRef> CreateDefaultAndBlackTextures(
+ GLenum target,
+ GLuint* black_texture);
+
+ void DoTexImage2D(
+ DecoderTextureState* texture_state,
+ ErrorState* error_state,
+ DecoderFramebufferState* framebuffer_state,
+ TextureRef* texture_ref,
+ const DoTextImage2DArguments& args);
+
+ void StartTracking(TextureRef* texture);
+ void StopTracking(TextureRef* texture);
+
+ void UpdateSafeToRenderFrom(int delta);
+ void UpdateUnclearedMips(int delta);
+ void UpdateCanRenderCondition(Texture::CanRenderCondition old_condition,
+ Texture::CanRenderCondition new_condition);
+ void IncFramebufferStateChangeCount();
+
+ MemoryTypeTracker* GetMemTracker(GLenum texture_pool);
+ scoped_ptr<MemoryTypeTracker> memory_tracker_managed_;
+ scoped_ptr<MemoryTypeTracker> memory_tracker_unmanaged_;
+
+ scoped_refptr<FeatureInfo> feature_info_;
+
+ FramebufferManager* framebuffer_manager_;
+ StreamTextureManager* stream_texture_manager_;
+
+ // Info for each texture in the system.
+ typedef base::hash_map<GLuint, scoped_refptr<TextureRef> > TextureMap;
+ TextureMap textures_;
+
+ GLsizei max_texture_size_;
+ GLsizei max_cube_map_texture_size_;
+ GLint max_levels_;
+ GLint max_cube_map_levels_;
+
+ int num_unrenderable_textures_;
+ int num_unsafe_textures_;
+ int num_uncleared_mips_;
+
+ // Counts the number of Textures allocated with 'this' as its manager.
+ // Allows to check no Texture will outlive this.
+ unsigned int texture_count_;
+
+ bool have_context_;
+
+ // Black (0,0,0,1) textures for when non-renderable textures are used.
+ // NOTE: There is no corresponding Texture for these textures.
+ // TextureInfos are only for textures the client side can access.
+ GLuint black_texture_ids_[kNumDefaultTextures];
+
+ // The default textures for each target (texture name = 0)
+ scoped_refptr<TextureRef> default_textures_[kNumDefaultTextures];
+
+ ObserverList<DestructionObserver> destruction_observers_;
+
+ DISALLOW_COPY_AND_ASSIGN(TextureManager);
+};
+
+// This class records texture upload time when in scope.
+class ScopedTextureUploadTimer {
+ public:
+ explicit ScopedTextureUploadTimer(DecoderTextureState* texture_state);
+ ~ScopedTextureUploadTimer();
+
+ private:
+ DecoderTextureState* texture_state_;
+ base::TimeTicks begin_time_;
+ DISALLOW_COPY_AND_ASSIGN(ScopedTextureUploadTimer);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_TEXTURE_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/texture_manager_unittest.cc b/chromium/gpu/command_buffer/service/texture_manager_unittest.cc
new file mode 100644
index 00000000000..402cc8d0eff
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/texture_manager_unittest.cc
@@ -0,0 +1,2353 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/texture_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/error_state_mock.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/framebuffer_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
+#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/service/memory_tracking.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::AtLeast;
+using ::testing::Pointee;
+using ::testing::Return;
+using ::testing::SetArgumentPointee;
+using ::testing::StrictMock;
+using ::testing::_;
+
+namespace gpu {
+namespace gles2 {
+
+class TextureTestHelper {
+ public:
+ static bool IsNPOT(const Texture* texture) {
+ return texture->npot();
+ }
+ static bool IsTextureComplete(const Texture* texture) {
+ return texture->texture_complete();
+ }
+ static bool IsCubeComplete(const Texture* texture) {
+ return texture->cube_complete();
+ }
+};
+
+class TextureManagerTest : public testing::Test {
+ public:
+ static const GLint kMaxTextureSize = 16;
+ static const GLint kMaxCubeMapTextureSize = 8;
+ static const GLint kMaxExternalTextureSize = 16;
+ static const GLint kMax2dLevels = 5;
+ static const GLint kMaxCubeMapLevels = 4;
+ static const GLint kMaxExternalLevels = 1;
+
+ TextureManagerTest()
+ : feature_info_(new FeatureInfo()) {
+ }
+
+ virtual ~TextureManagerTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ manager_.reset(new TextureManager(
+ NULL, feature_info_.get(),
+ kMaxTextureSize, kMaxCubeMapTextureSize));
+ TestHelper::SetupTextureManagerInitExpectations(gl_.get(), "");
+ manager_->Initialize();
+ error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
+ }
+
+ virtual void TearDown() {
+ manager_->Destroy(false);
+ manager_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ void SetParameter(
+ TextureRef* texture_ref, GLenum pname, GLint value, GLenum error) {
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), manager_.get(),
+ texture_ref, pname, value, error);
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_refptr<FeatureInfo> feature_info_;
+ scoped_ptr<TextureManager> manager_;
+ scoped_ptr<MockErrorState> error_state_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const GLint TextureManagerTest::kMaxTextureSize;
+const GLint TextureManagerTest::kMaxCubeMapTextureSize;
+const GLint TextureManagerTest::kMaxExternalTextureSize;
+const GLint TextureManagerTest::kMax2dLevels;
+const GLint TextureManagerTest::kMaxCubeMapLevels;
+const GLint TextureManagerTest::kMaxExternalLevels;
+#endif
+
+TEST_F(TextureManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ // Check we can create texture.
+ manager_->CreateTexture(kClient1Id, kService1Id);
+ // Check texture got created.
+ scoped_refptr<TextureRef> texture = manager_->GetTexture(kClient1Id);
+ ASSERT_TRUE(texture.get() != NULL);
+ EXPECT_EQ(kService1Id, texture->service_id());
+ EXPECT_EQ(kClient1Id, texture->client_id());
+ EXPECT_EQ(texture->texture(), manager_->GetTextureForServiceId(
+ texture->service_id()));
+ // Check we get nothing for a non-existent texture.
+ EXPECT_TRUE(manager_->GetTexture(kClient2Id) == NULL);
+ // Check trying to a remove non-existent textures does not crash.
+ manager_->RemoveTexture(kClient2Id);
+ // Check that it gets deleted when the last reference is released.
+ EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ // Check we can't get the texture after we remove it.
+ manager_->RemoveTexture(kClient1Id);
+ EXPECT_TRUE(manager_->GetTexture(kClient1Id) == NULL);
+ EXPECT_EQ(0u, texture->client_id());
+}
+
+TEST_F(TextureManagerTest, SetParameter) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create texture.
+ manager_->CreateTexture(kClient1Id, kService1Id);
+ // Check texture got created.
+ TextureRef* texture_ref = manager_->GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+ manager_->SetTarget(texture_ref, GL_TEXTURE_2D);
+ SetParameter(texture_ref, GL_TEXTURE_MIN_FILTER, GL_NEAREST, GL_NO_ERROR);
+ EXPECT_EQ(static_cast<GLenum>(GL_NEAREST), texture->min_filter());
+ SetParameter(texture_ref, GL_TEXTURE_MAG_FILTER, GL_NEAREST, GL_NO_ERROR);
+ EXPECT_EQ(static_cast<GLenum>(GL_NEAREST), texture->mag_filter());
+ SetParameter(texture_ref, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE, GL_NO_ERROR);
+ EXPECT_EQ(static_cast<GLenum>(GL_CLAMP_TO_EDGE), texture->wrap_s());
+ SetParameter(texture_ref, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE, GL_NO_ERROR);
+ EXPECT_EQ(static_cast<GLenum>(GL_CLAMP_TO_EDGE), texture->wrap_t());
+ SetParameter(texture_ref, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1, GL_NO_ERROR);
+ SetParameter(texture_ref, GL_TEXTURE_MAX_ANISOTROPY_EXT, 2, GL_NO_ERROR);
+ SetParameter(
+ texture_ref, GL_TEXTURE_MIN_FILTER, GL_CLAMP_TO_EDGE, GL_INVALID_ENUM);
+ EXPECT_EQ(static_cast<GLenum>(GL_NEAREST), texture->min_filter());
+ SetParameter(
+ texture_ref, GL_TEXTURE_MAG_FILTER, GL_CLAMP_TO_EDGE, GL_INVALID_ENUM);
+ EXPECT_EQ(static_cast<GLenum>(GL_NEAREST), texture->min_filter());
+ SetParameter(texture_ref, GL_TEXTURE_WRAP_S, GL_NEAREST, GL_INVALID_ENUM);
+ EXPECT_EQ(static_cast<GLenum>(GL_CLAMP_TO_EDGE), texture->wrap_s());
+ SetParameter(texture_ref, GL_TEXTURE_WRAP_T, GL_NEAREST, GL_INVALID_ENUM);
+ EXPECT_EQ(static_cast<GLenum>(GL_CLAMP_TO_EDGE), texture->wrap_t());
+ SetParameter(texture_ref, GL_TEXTURE_MAX_ANISOTROPY_EXT, 0, GL_INVALID_VALUE);
+}
+
+TEST_F(TextureManagerTest, TextureUsageExt) {
+ TestHelper::SetupTextureManagerInitExpectations(gl_.get(),
+ "GL_ANGLE_texture_usage");
+ TextureManager manager(
+ NULL, feature_info_.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.Initialize();
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ // Check we can create texture.
+ manager.CreateTexture(kClient1Id, kService1Id);
+ // Check texture got created.
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), &manager, texture_ref,
+ GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE,GL_NO_ERROR);
+ EXPECT_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_ATTACHMENT_ANGLE),
+ texture_ref->texture()->usage());
+ manager.Destroy(false);
+}
+
+TEST_F(TextureManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ TestHelper::SetupTextureManagerInitExpectations(gl_.get(), "");
+ TextureManager manager(
+ NULL, feature_info_.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.Initialize();
+ // Check we can create texture.
+ manager.CreateTexture(kClient1Id, kService1Id);
+ // Check texture got created.
+ TextureRef* texture = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture != NULL);
+ EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ TestHelper::SetupTextureManagerDestructionExpectations(gl_.get(), "");
+ manager.Destroy(true);
+ // Check that resources got freed.
+ texture = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture == NULL);
+}
+
+TEST_F(TextureManagerTest, MaxValues) {
+ // Check we get the right values for the max sizes.
+ EXPECT_EQ(kMax2dLevels, manager_->MaxLevelsForTarget(GL_TEXTURE_2D));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP_NEGATIVE_X));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_Y));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_Z));
+ EXPECT_EQ(kMaxCubeMapLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z));
+ EXPECT_EQ(kMaxExternalLevels,
+ manager_->MaxLevelsForTarget(GL_TEXTURE_EXTERNAL_OES));
+ EXPECT_EQ(kMaxTextureSize, manager_->MaxSizeForTarget(GL_TEXTURE_2D));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_X));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP_NEGATIVE_X));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_Y));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP_POSITIVE_Z));
+ EXPECT_EQ(kMaxCubeMapTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z));
+ EXPECT_EQ(kMaxExternalTextureSize,
+ manager_->MaxSizeForTarget(GL_TEXTURE_EXTERNAL_OES));
+}
+
+TEST_F(TextureManagerTest, ValidForTarget) {
+ // check 2d
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, 0, kMaxTextureSize, kMaxTextureSize, 1));
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, kMax2dLevels - 1, 1, 1, 1));
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, kMax2dLevels - 1, 1, 2, 1));
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, kMax2dLevels - 1, 2, 1, 1));
+ // check level out of range.
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, kMax2dLevels, kMaxTextureSize, 1, 1));
+ // check has depth.
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, kMax2dLevels, kMaxTextureSize, 1, 2));
+ // Check NPOT width on level 0
+ EXPECT_TRUE(manager_->ValidForTarget(GL_TEXTURE_2D, 0, 5, 2, 1));
+ // Check NPOT height on level 0
+ EXPECT_TRUE(manager_->ValidForTarget(GL_TEXTURE_2D, 0, 2, 5, 1));
+ // Check NPOT width on level 1
+ EXPECT_FALSE(manager_->ValidForTarget(GL_TEXTURE_2D, 1, 5, 2, 1));
+ // Check NPOT height on level 1
+ EXPECT_FALSE(manager_->ValidForTarget(GL_TEXTURE_2D, 1, 2, 5, 1));
+
+ // check cube
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, 0,
+ kMaxCubeMapTextureSize, kMaxCubeMapTextureSize, 1));
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, kMaxCubeMapLevels - 1, 1, 1, 1));
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, kMaxCubeMapLevels - 1, 2, 2, 1));
+ // check level out of range.
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, kMaxCubeMapLevels,
+ kMaxCubeMapTextureSize, 1, 1));
+ // check not square.
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, kMaxCubeMapLevels,
+ kMaxCubeMapTextureSize, 1, 1));
+ // check has depth.
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, kMaxCubeMapLevels,
+ kMaxCubeMapTextureSize, 1, 2));
+
+ for (GLint level = 0; level < kMax2dLevels; ++level) {
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, level, kMaxTextureSize >> level, 1, 1));
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, level, 1, kMaxTextureSize >> level, 1));
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, level, (kMaxTextureSize >> level) + 1, 1, 1));
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_2D, level, 1, (kMaxTextureSize >> level) + 1, 1));
+ }
+
+ for (GLint level = 0; level < kMaxCubeMapLevels; ++level) {
+ EXPECT_TRUE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, level,
+ kMaxCubeMapTextureSize >> level,
+ kMaxCubeMapTextureSize >> level,
+ 1));
+ EXPECT_FALSE(manager_->ValidForTarget(
+ GL_TEXTURE_CUBE_MAP, level,
+ (kMaxCubeMapTextureSize >> level) * 2,
+ (kMaxCubeMapTextureSize >> level) * 2,
+ 1));
+ }
+}
+
+TEST_F(TextureManagerTest, ValidForTargetNPOT) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_texture_npot");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ // Check NPOT width on level 0
+ EXPECT_TRUE(manager.ValidForTarget(GL_TEXTURE_2D, 0, 5, 2, 1));
+ // Check NPOT height on level 0
+ EXPECT_TRUE(manager.ValidForTarget(GL_TEXTURE_2D, 0, 2, 5, 1));
+ // Check NPOT width on level 1
+ EXPECT_TRUE(manager.ValidForTarget(GL_TEXTURE_2D, 1, 5, 2, 1));
+ // Check NPOT height on level 1
+ EXPECT_TRUE(manager.ValidForTarget(GL_TEXTURE_2D, 1, 2, 5, 1));
+ manager.Destroy(false);
+}
+
+class TextureTestBase : public testing::Test {
+ public:
+ static const GLint kMaxTextureSize = 16;
+ static const GLint kMaxCubeMapTextureSize = 8;
+ static const GLint kMax2dLevels = 5;
+ static const GLint kMaxCubeMapLevels = 4;
+ static const GLuint kClient1Id = 1;
+ static const GLuint kService1Id = 11;
+
+ TextureTestBase()
+ : feature_info_(new FeatureInfo()) {
+ }
+ virtual ~TextureTestBase() {
+ texture_ref_ = NULL;
+ }
+
+ protected:
+ void SetUpBase(MemoryTracker* memory_tracker, std::string extensions) {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ if (!extensions.empty()) {
+ TestHelper::SetupFeatureInfoInitExpectations(gl_.get(),
+ extensions.c_str());
+ feature_info_->Initialize(NULL);
+ }
+
+ manager_.reset(new TextureManager(
+ memory_tracker, feature_info_.get(),
+ kMaxTextureSize, kMaxCubeMapTextureSize));
+ decoder_.reset(new ::testing::StrictMock<gles2::MockGLES2Decoder>());
+ error_state_.reset(new ::testing::StrictMock<gles2::MockErrorState>());
+ manager_->CreateTexture(kClient1Id, kService1Id);
+ texture_ref_ = manager_->GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref_.get() != NULL);
+ }
+
+ virtual void TearDown() {
+ if (texture_ref_.get()) {
+ // If it's not in the manager then setting texture_ref_ to NULL will
+ // delete the texture.
+ if (!texture_ref_->client_id()) {
+ // Check that it gets deleted when the last reference is released.
+ EXPECT_CALL(*gl_,
+ DeleteTextures(1, ::testing::Pointee(texture_ref_->service_id())))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+ texture_ref_ = NULL;
+ }
+ manager_->Destroy(false);
+ manager_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ void SetParameter(
+ TextureRef* texture_ref, GLenum pname, GLint value, GLenum error) {
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), manager_.get(),
+ texture_ref, pname, value, error);
+ }
+
+ scoped_ptr<MockGLES2Decoder> decoder_;
+ scoped_ptr<MockErrorState> error_state_;
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_refptr<FeatureInfo> feature_info_;
+ scoped_ptr<TextureManager> manager_;
+ scoped_refptr<TextureRef> texture_ref_;
+};
+
+class TextureTest : public TextureTestBase {
+ protected:
+ virtual void SetUp() {
+ SetUpBase(NULL, std::string());
+ }
+};
+
+class TextureMemoryTrackerTest : public TextureTestBase {
+ protected:
+ virtual void SetUp() {
+ mock_memory_tracker_ = new StrictMock<MockMemoryTracker>();
+ SetUpBase(mock_memory_tracker_.get(), std::string());
+ }
+
+ scoped_refptr<MockMemoryTracker> mock_memory_tracker_;
+};
+
+#define EXPECT_MEMORY_ALLOCATION_CHANGE(old_size, new_size, pool) \
+ EXPECT_CALL(*mock_memory_tracker_.get(), \
+ TrackMemoryAllocatedChange(old_size, new_size, pool)) \
+ .Times(1).RetiresOnSaturation()
+
+TEST_F(TextureTest, Basic) {
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(0u, texture->target());
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(texture->IsImmutable());
+ EXPECT_EQ(static_cast<GLenum>(GL_NEAREST_MIPMAP_LINEAR),
+ texture->min_filter());
+ EXPECT_EQ(static_cast<GLenum>(GL_LINEAR), texture->mag_filter());
+ EXPECT_EQ(static_cast<GLenum>(GL_REPEAT), texture->wrap_s());
+ EXPECT_EQ(static_cast<GLenum>(GL_REPEAT), texture->wrap_t());
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_EQ(0u, texture->estimated_size());
+}
+
+TEST_F(TextureTest, SetTargetTexture2D) {
+ Texture* texture = texture_ref_->texture();
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(texture->IsImmutable());
+}
+
+TEST_F(TextureTest, SetTargetTextureExternalOES) {
+ Texture* texture = texture_ref_->texture();
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES);
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_TRUE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(texture->IsImmutable());
+ manager_->SetStreamTexture(texture_ref_.get(), true);
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+}
+
+TEST_F(TextureTest, ZeroSizeCanNotRender) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 0,
+ 0,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+}
+
+TEST_F(TextureTest, EstimatedSize) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_EQ(8u * 4u * 4u, texture_ref_->texture()->estimated_size());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 2,
+ GL_RGBA,
+ 8,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_EQ(8u * 4u * 4u * 2u, texture_ref_->texture()->estimated_size());
+}
+
+TEST_F(TextureMemoryTrackerTest, EstimatedSize) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 128, MemoryTracker::kUnmanaged);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(128, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 256, MemoryTracker::kUnmanaged);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 2,
+ GL_RGBA,
+ 8,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ // Add expectation for texture deletion.
+ EXPECT_MEMORY_ALLOCATION_CHANGE(256, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kUnmanaged);
+}
+
+TEST_F(TextureMemoryTrackerTest, SetParameterPool) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 128, MemoryTracker::kUnmanaged);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(128, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 128, MemoryTracker::kManaged);
+ SetParameter(texture_ref_.get(),
+ GL_TEXTURE_POOL_CHROMIUM,
+ GL_TEXTURE_POOL_MANAGED_CHROMIUM,
+ GL_NO_ERROR);
+ // Add expectation for texture deletion.
+ EXPECT_MEMORY_ALLOCATION_CHANGE(128, 0, MemoryTracker::kManaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kManaged);
+}
+
+TEST_F(TextureTest, POT2D) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ // Check Setting level 0 to POT
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ // Set filters to something that will work with a single mip.
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_MIN_FILTER, GL_LINEAR, GL_NO_ERROR);
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ // Set them back.
+ SetParameter(texture_ref_.get(),
+ GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR_MIPMAP_LINEAR,
+ GL_NO_ERROR);
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ // Make mips.
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ // Change a mip.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ // Set a level past the number of mips that would get generated.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 3,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ // Make mips.
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+}
+
+TEST_F(TextureMemoryTrackerTest, MarkMipmapsGenerated) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 64, MemoryTracker::kUnmanaged);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(64, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 84, MemoryTracker::kUnmanaged);
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_MEMORY_ALLOCATION_CHANGE(84, 0, MemoryTracker::kUnmanaged);
+ EXPECT_MEMORY_ALLOCATION_CHANGE(0, 0, MemoryTracker::kUnmanaged);
+}
+
+TEST_F(TextureTest, UnusedMips) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ // Set level zero to large size.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ // Set level zero to large smaller (levels unused mips)
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ // Set an unused level to some size
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 4,
+ GL_RGBA,
+ 16,
+ 16,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+}
+
+TEST_F(TextureTest, NPOT2D) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ // Check Setting level 0 to NPOT
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 5,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_MIN_FILTER, GL_LINEAR, GL_NO_ERROR);
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE, GL_NO_ERROR);
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE, GL_NO_ERROR);
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ // Change it to POT.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+}
+
+TEST_F(TextureTest, NPOT2DNPOTOK) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_texture_npot");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ Texture* texture = texture_ref->texture();
+
+ manager.SetTarget(texture_ref, GL_TEXTURE_2D);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ // Check Setting level 0 to NPOT
+ manager.SetLevelInfo(texture_ref,
+ GL_TEXTURE_2D, 0, GL_RGBA, 4, 5, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, true);
+ EXPECT_TRUE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager.CanGenerateMipmaps(texture_ref));
+ EXPECT_FALSE(manager.CanRender(texture_ref));
+ EXPECT_TRUE(manager.HaveUnrenderableTextures());
+ EXPECT_TRUE(manager.MarkMipmapsGenerated(texture_ref));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(manager.CanRender(texture_ref));
+ EXPECT_FALSE(manager.HaveUnrenderableTextures());
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, POTCubeMap) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_CUBE_MAP);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP), texture->target());
+ // Check Setting level 0 each face to POT
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_FALSE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_FALSE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ EXPECT_FALSE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+
+ // Make mips.
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_TRUE(manager_->CanRender(texture_ref_.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+
+ // Change a mip.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ 1,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(TextureTestHelper::IsNPOT(texture));
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(TextureTestHelper::IsCubeComplete(texture));
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ // Set a level past the number of mips that would get generated.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ 3,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(manager_->CanGenerateMipmaps(texture_ref_.get()));
+ // Make mips.
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_TRUE(TextureTestHelper::IsCubeComplete(texture));
+}
+
+TEST_F(TextureTest, GetLevelSize) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 5,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ GLsizei width = -1;
+ GLsizei height = -1;
+ Texture* texture = texture_ref_->texture();
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, -1, &width, &height));
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 1000, &width, &height));
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height));
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 1, &width, &height));
+ EXPECT_EQ(4, width);
+ EXPECT_EQ(5, height);
+ manager_->RemoveTexture(kClient1Id);
+ EXPECT_TRUE(texture->GetLevelSize(GL_TEXTURE_2D, 1, &width, &height));
+ EXPECT_EQ(4, width);
+ EXPECT_EQ(5, height);
+}
+
+TEST_F(TextureTest, GetLevelType) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 5,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ GLenum type = -1;
+ GLenum format = -1;
+ Texture* texture = texture_ref_->texture();
+ EXPECT_FALSE(texture->GetLevelType(GL_TEXTURE_2D, -1, &type, &format));
+ EXPECT_FALSE(texture->GetLevelType(GL_TEXTURE_2D, 1000, &type, &format));
+ EXPECT_FALSE(texture->GetLevelType(GL_TEXTURE_2D, 0, &type, &format));
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 1, &type, &format));
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), format);
+ manager_->RemoveTexture(kClient1Id);
+ EXPECT_TRUE(texture->GetLevelType(GL_TEXTURE_2D, 1, &type, &format));
+ EXPECT_EQ(static_cast<GLenum>(GL_UNSIGNED_BYTE), type);
+ EXPECT_EQ(static_cast<GLenum>(GL_RGBA), format);
+}
+
+TEST_F(TextureTest, ValidForTexture) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 5,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ // Check bad face.
+ Texture* texture = texture_ref_->texture();
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad level.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 0, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad xoffset.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, -1, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad xoffset + width > width.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 1, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad yoffset.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, -1, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad yoffset + height > height.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 1, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad width.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 0, 5, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad height.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 0, 4, 6, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check bad format.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGB, GL_UNSIGNED_BYTE));
+ // Check bad type.
+ EXPECT_FALSE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4));
+ // Check valid full size
+ EXPECT_TRUE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+ // Check valid particial size.
+ EXPECT_TRUE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 1, 1, 2, 3, GL_RGBA, GL_UNSIGNED_BYTE));
+ manager_->RemoveTexture(kClient1Id);
+ EXPECT_TRUE(texture->ValidForTexture(
+ GL_TEXTURE_2D, 1, 0, 0, 4, 5, GL_RGBA, GL_UNSIGNED_BYTE));
+}
+
+TEST_F(TextureTest, FloatNotLinear) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_texture_float");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ manager.SetTarget(texture_ref, GL_TEXTURE_2D);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ manager.SetLevelInfo(texture_ref,
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT, true);
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), &manager,
+ texture_ref, GL_TEXTURE_MAG_FILTER, GL_NEAREST, GL_NO_ERROR);
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), &manager, texture_ref,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST, GL_NO_ERROR);
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, FloatLinear) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_texture_float GL_OES_texture_float_linear");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ manager.SetTarget(texture_ref, GL_TEXTURE_2D);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ manager.SetLevelInfo(texture_ref,
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_FLOAT, true);
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, HalfFloatNotLinear) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_texture_half_float");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ manager.SetTarget(texture_ref, GL_TEXTURE_2D);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ manager.SetLevelInfo(texture_ref,
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES, true);
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), &manager,
+ texture_ref, GL_TEXTURE_MAG_FILTER, GL_NEAREST, GL_NO_ERROR);
+ EXPECT_FALSE(TextureTestHelper::IsTextureComplete(texture));
+ TestHelper::SetTexParameterWithExpectations(
+ gl_.get(), error_state_.get(), &manager, texture_ref,
+ GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST, GL_NO_ERROR);
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, HalfFloatLinear) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_texture_half_float GL_OES_texture_half_float_linear");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ manager.SetTarget(texture_ref, GL_TEXTURE_2D);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ manager.SetLevelInfo(texture_ref,
+ GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 1, 0, GL_RGBA, GL_HALF_FLOAT_OES, true);
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, EGLImageExternal) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_OES_EGL_image_external");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ manager.SetTarget(texture_ref, GL_TEXTURE_EXTERNAL_OES);
+ Texture* texture = texture_ref->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), texture->target());
+ EXPECT_FALSE(manager.CanGenerateMipmaps(texture_ref));
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, DepthTexture) {
+ TestHelper::SetupFeatureInfoInitExpectations(
+ gl_.get(), "GL_ANGLE_depth_texture");
+ scoped_refptr<FeatureInfo> feature_info(new FeatureInfo());
+ feature_info->Initialize(NULL);
+ TextureManager manager(
+ NULL, feature_info.get(), kMaxTextureSize, kMaxCubeMapTextureSize);
+ manager.CreateTexture(kClient1Id, kService1Id);
+ TextureRef* texture_ref = manager.GetTexture(kClient1Id);
+ ASSERT_TRUE(texture_ref != NULL);
+ manager.SetTarget(texture_ref, GL_TEXTURE_2D);
+ manager.SetLevelInfo(
+ texture_ref, GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 4, 4, 1, 0,
+ GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false);
+ EXPECT_FALSE(manager.CanGenerateMipmaps(texture_ref));
+ manager.Destroy(false);
+}
+
+TEST_F(TextureTest, SafeUnsafe) {
+ static const GLuint kClient2Id = 2;
+ static const GLuint kService2Id = 12;
+ static const GLuint kClient3Id = 3;
+ static const GLuint kService3Id = 13;
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture->num_uncleared_mips());
+ manager_->SetLevelCleared(texture_ref_.get(), GL_TEXTURE_2D, 0, true);
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture->num_uncleared_mips());
+ manager_->SetLevelCleared(texture_ref_.get(), GL_TEXTURE_2D, 1, true);
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(2, texture->num_uncleared_mips());
+ manager_->SetLevelCleared(texture_ref_.get(), GL_TEXTURE_2D, 0, true);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture->num_uncleared_mips());
+ manager_->SetLevelCleared(texture_ref_.get(), GL_TEXTURE_2D, 1, true);
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture->num_uncleared_mips());
+ manager_->MarkMipmapsGenerated(texture_ref_.get());
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+
+ manager_->CreateTexture(kClient2Id, kService2Id);
+ scoped_refptr<TextureRef> texture_ref2(
+ manager_->GetTexture(kClient2Id));
+ ASSERT_TRUE(texture_ref2.get() != NULL);
+ manager_->SetTarget(texture_ref2.get(), GL_TEXTURE_2D);
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ Texture* texture2 = texture_ref2->texture();
+ EXPECT_EQ(0, texture2->num_uncleared_mips());
+ manager_->SetLevelInfo(texture_ref2.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture2->num_uncleared_mips());
+ manager_->SetLevelInfo(texture_ref2.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture2->num_uncleared_mips());
+
+ manager_->CreateTexture(kClient3Id, kService3Id);
+ scoped_refptr<TextureRef> texture_ref3(
+ manager_->GetTexture(kClient3Id));
+ ASSERT_TRUE(texture_ref3.get() != NULL);
+ manager_->SetTarget(texture_ref3.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref3.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ Texture* texture3 = texture_ref3->texture();
+ EXPECT_EQ(1, texture3->num_uncleared_mips());
+ manager_->SetLevelCleared(texture_ref2.get(), GL_TEXTURE_2D, 0, true);
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture2->num_uncleared_mips());
+ manager_->SetLevelCleared(texture_ref3.get(), GL_TEXTURE_2D, 0, true);
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture3->num_uncleared_mips());
+
+ manager_->SetLevelInfo(texture_ref2.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ manager_->SetLevelInfo(texture_ref3.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 8,
+ 8,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture2->num_uncleared_mips());
+ EXPECT_EQ(1, texture3->num_uncleared_mips());
+ manager_->RemoveTexture(kClient3Id);
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ manager_->RemoveTexture(kClient2Id);
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService2Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ texture_ref2 = NULL;
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService3Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ texture_ref3 = NULL;
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+}
+
+TEST_F(TextureTest, ClearTexture) {
+ EXPECT_CALL(*decoder_, ClearLevel(_, _, _, _, _, _, _, _, _))
+ .WillRepeatedly(Return(true));
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(2, texture->num_uncleared_mips());
+ manager_->ClearRenderableLevels(decoder_.get(), texture_ref_.get());
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(2, texture->num_uncleared_mips());
+ manager_->ClearTextureLevel(
+ decoder_.get(), texture_ref_.get(), GL_TEXTURE_2D, 0);
+ EXPECT_FALSE(texture->SafeToRenderFrom());
+ EXPECT_TRUE(manager_->HaveUnsafeTextures());
+ EXPECT_TRUE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(1, texture->num_uncleared_mips());
+ manager_->ClearTextureLevel(
+ decoder_.get(), texture_ref_.get(), GL_TEXTURE_2D, 1);
+ EXPECT_TRUE(texture->SafeToRenderFrom());
+ EXPECT_FALSE(manager_->HaveUnsafeTextures());
+ EXPECT_FALSE(manager_->HaveUnclearedMips());
+ EXPECT_EQ(0, texture->num_uncleared_mips());
+}
+
+TEST_F(TextureTest, UseDeletedTexture) {
+ static const GLuint kClient2Id = 2;
+ static const GLuint kService2Id = 12;
+ // Make the default texture renderable
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ // Make a new texture
+ manager_->CreateTexture(kClient2Id, kService2Id);
+ scoped_refptr<TextureRef> texture_ref(
+ manager_->GetTexture(kClient2Id));
+ manager_->SetTarget(texture_ref.get(), GL_TEXTURE_2D);
+ EXPECT_FALSE(manager_->CanRender(texture_ref.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ // Remove it.
+ manager_->RemoveTexture(kClient2Id);
+ EXPECT_FALSE(manager_->CanRender(texture_ref.get()));
+ EXPECT_TRUE(manager_->HaveUnrenderableTextures());
+ // Check that we can still manipulate it and it effects the manager.
+ manager_->SetLevelInfo(texture_ref.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_TRUE(manager_->CanRender(texture_ref.get()));
+ EXPECT_FALSE(manager_->HaveUnrenderableTextures());
+ EXPECT_CALL(*gl_, DeleteTextures(1, ::testing::Pointee(kService2Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ texture_ref = NULL;
+}
+
+TEST_F(TextureTest, GetLevelImage) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
+ // Set image.
+ manager_->SetLevelImage(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ gfx::GLImage::CreateGLImage(0).get());
+ EXPECT_FALSE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
+ // Remove it.
+ manager_->SetLevelImage(texture_ref_.get(), GL_TEXTURE_2D, 1, NULL);
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
+ manager_->SetLevelImage(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ gfx::GLImage::CreateGLImage(0).get());
+ // Image should be reset when SetLevelInfo is called.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 1) == NULL);
+}
+
+namespace {
+
+bool InSet(std::set<std::string>* string_set, const std::string& str) {
+ std::pair<std::set<std::string>::iterator, bool> result =
+ string_set->insert(str);
+ return !result.second;
+}
+
+} // anonymous namespace
+
+TEST_F(TextureTest, AddToSignature) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ std::string signature1;
+ std::string signature2;
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature1);
+
+ std::set<std::string> string_set;
+ EXPECT_FALSE(InSet(&string_set, signature1));
+
+ // check changing 1 thing makes a different signature.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 4,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ // check putting it back makes the same signature.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_EQ(signature1, signature2);
+
+ // Check setting cleared status does not change signature.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_EQ(signature1, signature2);
+
+ // Check changing other settings changes signature.
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 4,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 2,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 1,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGB,
+ GL_UNSIGNED_BYTE,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_FLOAT,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ // put it back
+ manager_->SetLevelInfo(texture_ref_.get(),
+ GL_TEXTURE_2D,
+ 1,
+ GL_RGBA,
+ 2,
+ 2,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_EQ(signature1, signature2);
+
+ // check changing parameters changes signature.
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_MIN_FILTER, GL_NEAREST, GL_NO_ERROR);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ SetParameter(texture_ref_.get(),
+ GL_TEXTURE_MIN_FILTER,
+ GL_NEAREST_MIPMAP_LINEAR,
+ GL_NO_ERROR);
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_MAG_FILTER, GL_NEAREST, GL_NO_ERROR);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_MAG_FILTER, GL_LINEAR, GL_NO_ERROR);
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE, GL_NO_ERROR);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ SetParameter(texture_ref_.get(), GL_TEXTURE_WRAP_S, GL_REPEAT, GL_NO_ERROR);
+ SetParameter(
+ texture_ref_.get(), GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE, GL_NO_ERROR);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_FALSE(InSet(&string_set, signature2));
+
+ // Check putting it back genenerates the same signature
+ SetParameter(texture_ref_.get(), GL_TEXTURE_WRAP_T, GL_REPEAT, GL_NO_ERROR);
+ signature2.clear();
+ manager_->AddToSignature(texture_ref_.get(), GL_TEXTURE_2D, 1, &signature2);
+ EXPECT_EQ(signature1, signature2);
+
+ // Check the set was acutally getting different signatures.
+ EXPECT_EQ(11u, string_set.size());
+}
+
+class ProduceConsumeTextureTest : public TextureTest {
+ public:
+ virtual void SetUp() {
+ TextureTest::SetUpBase(NULL, "GL_OES_EGL_image_external");
+ manager_->CreateTexture(kClient2Id, kService2Id);
+ texture2_ = manager_->GetTexture(kClient2Id);
+
+ EXPECT_CALL(*decoder_.get(), GetErrorState())
+ .WillRepeatedly(Return(error_state_.get()));
+ }
+
+ virtual void TearDown() {
+ if (texture2_.get()) {
+ // If it's not in the manager then setting texture2_ to NULL will
+ // delete the texture.
+ if (!texture2_->client_id()) {
+ // Check that it gets deleted when the last reference is released.
+ EXPECT_CALL(
+ *gl_,
+ DeleteTextures(1, ::testing::Pointee(texture2_->service_id())))
+ .Times(1).RetiresOnSaturation();
+ }
+ texture2_ = NULL;
+ }
+ TextureTest::TearDown();
+ }
+
+ protected:
+ struct LevelInfo {
+ LevelInfo(GLenum target,
+ GLenum format,
+ GLsizei width,
+ GLsizei height,
+ GLsizei depth,
+ GLint border,
+ GLenum type,
+ bool cleared)
+ : target(target),
+ format(format),
+ width(width),
+ height(height),
+ depth(depth),
+ border(border),
+ type(type),
+ cleared(cleared) {}
+
+ LevelInfo()
+ : target(0),
+ format(0),
+ width(-1),
+ height(-1),
+ depth(1),
+ border(0),
+ type(0),
+ cleared(false) {}
+
+ bool operator==(const LevelInfo& other) const {
+ return target == other.target && format == other.format &&
+ width == other.width && height == other.height &&
+ depth == other.depth && border == other.border &&
+ type == other.type && cleared == other.cleared;
+ }
+
+ GLenum target;
+ GLenum format;
+ GLsizei width;
+ GLsizei height;
+ GLsizei depth;
+ GLint border;
+ GLenum type;
+ bool cleared;
+ };
+
+ void SetLevelInfo(TextureRef* texture_ref,
+ GLint level,
+ const LevelInfo& info) {
+ manager_->SetLevelInfo(texture_ref,
+ info.target,
+ level,
+ info.format,
+ info.width,
+ info.height,
+ info.depth,
+ info.border,
+ info.format,
+ info.type,
+ info.cleared);
+ }
+
+ static LevelInfo GetLevelInfo(const TextureRef* texture_ref,
+ GLint target,
+ GLint level) {
+ const Texture* texture = texture_ref->texture();
+ LevelInfo info;
+ info.target = target;
+ EXPECT_TRUE(texture->GetLevelSize(target, level, &info.width,
+ &info.height));
+ EXPECT_TRUE(texture->GetLevelType(target, level, &info.type,
+ &info.format));
+ info.cleared = texture->IsLevelCleared(target, level);
+ return info;
+ }
+
+ Texture* Produce(TextureRef* texture_ref) {
+ Texture* texture = manager_->Produce(texture_ref);
+ EXPECT_TRUE(texture != NULL);
+ return texture;
+ }
+
+ void Consume(GLuint client_id, Texture* texture) {
+ EXPECT_TRUE(manager_->Consume(client_id, texture));
+ }
+
+ scoped_refptr<TextureRef> texture2_;
+
+ private:
+ static const GLuint kClient2Id;
+ static const GLuint kService2Id;
+};
+
+const GLuint ProduceConsumeTextureTest::kClient2Id = 2;
+const GLuint ProduceConsumeTextureTest::kService2Id = 12;
+
+TEST_F(ProduceConsumeTextureTest, ProduceConsume2D) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_2D);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D), texture->target());
+ LevelInfo level0(
+ GL_TEXTURE_2D, GL_RGBA, 4, 4, 1, 0, GL_UNSIGNED_BYTE, true);
+ SetLevelInfo(texture_ref_.get(), 0, level0);
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture_ref_.get()));
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ LevelInfo level1 = GetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 1);
+ LevelInfo level2 = GetLevelInfo(texture_ref_.get(), GL_TEXTURE_2D, 2);
+ Texture* produced_texture = Produce(texture_ref_.get());
+ EXPECT_EQ(produced_texture, texture);
+
+ // Make this texture bigger with more levels, and make sure they get
+ // clobbered correctly during Consume().
+ manager_->SetTarget(texture2_.get(), GL_TEXTURE_2D);
+ SetLevelInfo(
+ texture2_.get(),
+ 0,
+ LevelInfo(GL_TEXTURE_2D, GL_RGBA, 16, 16, 1, 0, GL_UNSIGNED_BYTE, false));
+ EXPECT_TRUE(manager_->MarkMipmapsGenerated(texture2_.get()));
+ texture = texture2_->texture();
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ EXPECT_EQ(1024U + 256U + 64U + 16U + 4U, texture->estimated_size());
+
+ GLuint client_id = texture2_->client_id();
+ manager_->RemoveTexture(client_id);
+ Consume(client_id, produced_texture);
+ scoped_refptr<TextureRef> restored_texture = manager_->GetTexture(client_id);
+ EXPECT_EQ(produced_texture, restored_texture->texture());
+ EXPECT_EQ(level0, GetLevelInfo(restored_texture.get(), GL_TEXTURE_2D, 0));
+ EXPECT_EQ(level1, GetLevelInfo(restored_texture.get(), GL_TEXTURE_2D, 1));
+ EXPECT_EQ(level2, GetLevelInfo(restored_texture.get(), GL_TEXTURE_2D, 2));
+ texture = restored_texture->texture();
+ EXPECT_EQ(64U + 16U + 4U, texture->estimated_size());
+ GLint w, h;
+ EXPECT_FALSE(texture->GetLevelSize(GL_TEXTURE_2D, 3, &w, &h));
+
+ // However the old texture ref still exists if it was referenced somewhere.
+ EXPECT_EQ(1024U + 256U + 64U + 16U + 4U,
+ texture2_->texture()->estimated_size());
+}
+
+TEST_F(ProduceConsumeTextureTest, ProduceConsumeClearRectangle) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_RECTANGLE_ARB);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB), texture->target());
+ LevelInfo level0(
+ GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, 1, 1, 1, 0, GL_UNSIGNED_BYTE, false);
+ SetLevelInfo(texture_ref_.get(), 0, level0);
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ Texture* produced_texture = Produce(texture_ref_.get());
+ EXPECT_EQ(produced_texture, texture);
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_RECTANGLE_ARB),
+ produced_texture->target());
+
+ GLuint client_id = texture2_->client_id();
+ manager_->RemoveTexture(client_id);
+ Consume(client_id, produced_texture);
+ scoped_refptr<TextureRef> restored_texture = manager_->GetTexture(client_id);
+ EXPECT_EQ(produced_texture, restored_texture->texture());
+
+ // See if we can clear the previously uncleared level now.
+ EXPECT_EQ(level0,
+ GetLevelInfo(restored_texture.get(), GL_TEXTURE_RECTANGLE_ARB, 0));
+ EXPECT_CALL(*decoder_, ClearLevel(_, _, _, _, _, _, _, _, _))
+ .WillRepeatedly(Return(true));
+ EXPECT_TRUE(manager_->ClearTextureLevel(
+ decoder_.get(), restored_texture.get(), GL_TEXTURE_RECTANGLE_ARB, 0));
+}
+
+TEST_F(ProduceConsumeTextureTest, ProduceConsumeStreamTexture) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_EXTERNAL_OES);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES), texture->target());
+ manager_->SetStreamTexture(texture_ref_.get(), true);
+ GLuint service_id = texture->service_id();
+ Texture* produced_texture = Produce(texture_ref_.get());
+ EXPECT_TRUE(texture->IsStreamTexture());
+
+ GLuint client_id = texture2_->client_id();
+ manager_->RemoveTexture(client_id);
+ Consume(client_id, produced_texture);
+ scoped_refptr<TextureRef> restored_texture = manager_->GetTexture(client_id);
+ EXPECT_EQ(produced_texture, restored_texture->texture());
+ EXPECT_TRUE(restored_texture->texture()->IsStreamTexture());
+ EXPECT_TRUE(restored_texture->texture()->IsImmutable());
+ EXPECT_EQ(service_id, restored_texture->service_id());
+}
+
+TEST_F(ProduceConsumeTextureTest, ProduceConsumeCube) {
+ manager_->SetTarget(texture_ref_.get(), GL_TEXTURE_CUBE_MAP);
+ Texture* texture = texture_ref_->texture();
+ EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP), texture->target());
+ LevelInfo face0(GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_UNSIGNED_BYTE,
+ true);
+ LevelInfo face5(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ GL_RGBA,
+ 3,
+ 3,
+ 1,
+ 0,
+ GL_UNSIGNED_BYTE,
+ true);
+ SetLevelInfo(texture_ref_.get(), 0, face0);
+ SetLevelInfo(texture_ref_.get(), 0, face5);
+ EXPECT_TRUE(TextureTestHelper::IsTextureComplete(texture));
+ Texture* produced_texture = Produce(texture_ref_.get());
+ EXPECT_EQ(produced_texture, texture);
+
+ GLuint client_id = texture2_->client_id();
+ manager_->RemoveTexture(client_id);
+ Consume(client_id, produced_texture);
+ scoped_refptr<TextureRef> restored_texture = manager_->GetTexture(client_id);
+ EXPECT_EQ(produced_texture, restored_texture->texture());
+ EXPECT_EQ(
+ face0,
+ GetLevelInfo(restored_texture.get(), GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0));
+ EXPECT_EQ(
+ face5,
+ GetLevelInfo(restored_texture.get(), GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0));
+}
+
+class CountingMemoryTracker : public MemoryTracker {
+ public:
+ CountingMemoryTracker() {
+ current_size_[0] = 0;
+ current_size_[1] = 0;
+ }
+
+ virtual void TrackMemoryAllocatedChange(size_t old_size,
+ size_t new_size,
+ Pool pool) OVERRIDE {
+ DCHECK_LT(static_cast<size_t>(pool), arraysize(current_size_));
+ current_size_[pool] += new_size - old_size;
+ }
+
+ virtual bool EnsureGPUMemoryAvailable(size_t size_needed) OVERRIDE {
+ return true;
+ }
+
+ size_t GetSize(Pool pool) {
+ DCHECK_LT(static_cast<size_t>(pool), arraysize(current_size_));
+ return current_size_[pool];
+ }
+
+ private:
+ virtual ~CountingMemoryTracker() {}
+
+ size_t current_size_[2];
+ DISALLOW_COPY_AND_ASSIGN(CountingMemoryTracker);
+};
+
+class SharedTextureTest : public testing::Test {
+ public:
+ SharedTextureTest()
+ : feature_info_(new FeatureInfo()) {
+ }
+
+ virtual ~SharedTextureTest() {
+ }
+
+ virtual void SetUp() {
+ gl_.reset(new ::gfx::MockGLInterface());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ memory_tracker1_ = new CountingMemoryTracker;
+ texture_manager1_.reset(
+ new TextureManager(memory_tracker1_.get(),
+ feature_info_.get(),
+ TextureManagerTest::kMaxTextureSize,
+ TextureManagerTest::kMaxCubeMapTextureSize));
+ memory_tracker2_ = new CountingMemoryTracker;
+ texture_manager2_.reset(
+ new TextureManager(memory_tracker2_.get(),
+ feature_info_.get(),
+ TextureManagerTest::kMaxTextureSize,
+ TextureManagerTest::kMaxCubeMapTextureSize));
+ TestHelper::SetupTextureManagerInitExpectations(gl_.get(), "");
+ texture_manager1_->Initialize();
+ TestHelper::SetupTextureManagerInitExpectations(gl_.get(), "");
+ texture_manager2_->Initialize();
+ }
+
+ virtual void TearDown() {
+ texture_manager2_->Destroy(false);
+ texture_manager2_.reset();
+ texture_manager1_->Destroy(false);
+ texture_manager1_.reset();
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ protected:
+ scoped_ptr< ::gfx::MockGLInterface > gl_;
+ scoped_refptr<FeatureInfo> feature_info_;
+ scoped_refptr<CountingMemoryTracker> memory_tracker1_;
+ scoped_ptr<TextureManager> texture_manager1_;
+ scoped_refptr<CountingMemoryTracker> memory_tracker2_;
+ scoped_ptr<TextureManager> texture_manager2_;
+};
+
+TEST_F(SharedTextureTest, DeleteTextures) {
+ scoped_refptr<TextureRef> ref1 = texture_manager1_->CreateTexture(10, 10);
+ scoped_refptr<TextureRef> ref2 =
+ texture_manager2_->Consume(20, ref1->texture());
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(0);
+ ref1 = NULL;
+ texture_manager1_->RemoveTexture(10);
+ testing::Mock::VerifyAndClearExpectations(gl_.get());
+
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ ref2 = NULL;
+ texture_manager2_->RemoveTexture(20);
+ testing::Mock::VerifyAndClearExpectations(gl_.get());
+}
+
+TEST_F(SharedTextureTest, TextureSafetyAccounting) {
+ EXPECT_FALSE(texture_manager1_->HaveUnrenderableTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnclearedMips());
+ EXPECT_FALSE(texture_manager2_->HaveUnrenderableTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnclearedMips());
+
+ // Newly created texture is renderable.
+ scoped_refptr<TextureRef> ref1 = texture_manager1_->CreateTexture(10, 10);
+ EXPECT_FALSE(texture_manager1_->HaveUnrenderableTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnclearedMips());
+
+ // Associate new texture ref to other texture manager, should account for it
+ // too.
+ scoped_refptr<TextureRef> ref2 =
+ texture_manager2_->Consume(20, ref1->texture());
+ EXPECT_FALSE(texture_manager2_->HaveUnrenderableTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnclearedMips());
+
+ // Make texture renderable but uncleared on one texture manager, should affect
+ // other one.
+ texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D);
+ EXPECT_TRUE(texture_manager1_->HaveUnrenderableTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnclearedMips());
+ EXPECT_TRUE(texture_manager2_->HaveUnrenderableTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnclearedMips());
+
+ texture_manager1_->SetLevelInfo(ref1.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+ EXPECT_FALSE(texture_manager1_->HaveUnrenderableTextures());
+ EXPECT_TRUE(texture_manager1_->HaveUnsafeTextures());
+ EXPECT_TRUE(texture_manager1_->HaveUnclearedMips());
+ EXPECT_FALSE(texture_manager2_->HaveUnrenderableTextures());
+ EXPECT_TRUE(texture_manager2_->HaveUnsafeTextures());
+ EXPECT_TRUE(texture_manager2_->HaveUnclearedMips());
+
+ // Make texture cleared on one texture manager, should affect other one.
+ texture_manager1_->SetLevelCleared(ref1.get(), GL_TEXTURE_2D, 0, true);
+ EXPECT_FALSE(texture_manager1_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager1_->HaveUnclearedMips());
+ EXPECT_FALSE(texture_manager2_->HaveUnsafeTextures());
+ EXPECT_FALSE(texture_manager2_->HaveUnclearedMips());
+
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ texture_manager1_->RemoveTexture(10);
+ texture_manager2_->RemoveTexture(20);
+}
+
+TEST_F(SharedTextureTest, FBOCompletenessCheck) {
+ const GLenum kCompleteValue = GL_FRAMEBUFFER_COMPLETE;
+ FramebufferManager framebuffer_manager1(1, 1);
+ texture_manager1_->set_framebuffer_manager(&framebuffer_manager1);
+ FramebufferManager framebuffer_manager2(1, 1);
+ texture_manager2_->set_framebuffer_manager(&framebuffer_manager2);
+
+ scoped_refptr<TextureRef> ref1 = texture_manager1_->CreateTexture(10, 10);
+ framebuffer_manager1.CreateFramebuffer(10, 10);
+ scoped_refptr<Framebuffer> framebuffer1 =
+ framebuffer_manager1.GetFramebuffer(10);
+ framebuffer1->AttachTexture(
+ GL_COLOR_ATTACHMENT0, ref1.get(), GL_TEXTURE_2D, 0, 0);
+ EXPECT_FALSE(framebuffer_manager1.IsComplete(framebuffer1.get()));
+ EXPECT_NE(kCompleteValue, framebuffer1->IsPossiblyComplete());
+
+ // Make FBO complete in manager 1.
+ texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D);
+ texture_manager1_->SetLevelInfo(ref1.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_EQ(kCompleteValue, framebuffer1->IsPossiblyComplete());
+ framebuffer_manager1.MarkAsComplete(framebuffer1.get());
+ EXPECT_TRUE(framebuffer_manager1.IsComplete(framebuffer1.get()));
+
+ // Share texture with manager 2.
+ scoped_refptr<TextureRef> ref2 =
+ texture_manager2_->Consume(20, ref1->texture());
+ framebuffer_manager2.CreateFramebuffer(20, 20);
+ scoped_refptr<Framebuffer> framebuffer2 =
+ framebuffer_manager2.GetFramebuffer(20);
+ framebuffer2->AttachTexture(
+ GL_COLOR_ATTACHMENT0, ref2.get(), GL_TEXTURE_2D, 0, 0);
+ EXPECT_FALSE(framebuffer_manager2.IsComplete(framebuffer2.get()));
+ EXPECT_EQ(kCompleteValue, framebuffer2->IsPossiblyComplete());
+ framebuffer_manager2.MarkAsComplete(framebuffer2.get());
+ EXPECT_TRUE(framebuffer_manager2.IsComplete(framebuffer2.get()));
+
+ // Change level for texture, both FBOs should be marked incomplete
+ texture_manager1_->SetLevelInfo(ref1.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ EXPECT_FALSE(framebuffer_manager1.IsComplete(framebuffer1.get()));
+ EXPECT_EQ(kCompleteValue, framebuffer1->IsPossiblyComplete());
+ framebuffer_manager1.MarkAsComplete(framebuffer1.get());
+ EXPECT_TRUE(framebuffer_manager1.IsComplete(framebuffer1.get()));
+ EXPECT_FALSE(framebuffer_manager2.IsComplete(framebuffer2.get()));
+ EXPECT_EQ(kCompleteValue, framebuffer2->IsPossiblyComplete());
+ framebuffer_manager2.MarkAsComplete(framebuffer2.get());
+ EXPECT_TRUE(framebuffer_manager2.IsComplete(framebuffer2.get()));
+
+ EXPECT_CALL(*gl_, DeleteFramebuffersEXT(1, _))
+ .Times(2)
+ .RetiresOnSaturation();
+ framebuffer_manager1.RemoveFramebuffer(10);
+ framebuffer_manager2.RemoveFramebuffer(20);
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ texture_manager1_->RemoveTexture(10);
+ texture_manager2_->RemoveTexture(20);
+}
+
+TEST_F(SharedTextureTest, Memory) {
+ size_t initial_memory1 = memory_tracker1_->GetSize(MemoryTracker::kUnmanaged);
+ size_t initial_memory2 = memory_tracker2_->GetSize(MemoryTracker::kUnmanaged);
+
+ // Newly created texture is unrenderable.
+ scoped_refptr<TextureRef> ref1 = texture_manager1_->CreateTexture(10, 10);
+ texture_manager1_->SetTarget(ref1.get(), GL_TEXTURE_2D);
+ texture_manager1_->SetLevelInfo(ref1.get(),
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 10,
+ 10,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ false);
+
+ EXPECT_LT(0u, ref1->texture()->estimated_size());
+ EXPECT_EQ(initial_memory1 + ref1->texture()->estimated_size(),
+ memory_tracker1_->GetSize(MemoryTracker::kUnmanaged));
+
+ // Associate new texture ref to other texture manager, it doesn't account for
+ // the texture memory, the first memory tracker still has it.
+ scoped_refptr<TextureRef> ref2 =
+ texture_manager2_->Consume(20, ref1->texture());
+ EXPECT_EQ(initial_memory1 + ref1->texture()->estimated_size(),
+ memory_tracker1_->GetSize(MemoryTracker::kUnmanaged));
+ EXPECT_EQ(initial_memory2,
+ memory_tracker2_->GetSize(MemoryTracker::kUnmanaged));
+
+ // Delete the texture, memory should go to the remaining tracker.
+ texture_manager1_->RemoveTexture(10);
+ ref1 = NULL;
+ EXPECT_EQ(initial_memory1,
+ memory_tracker1_->GetSize(MemoryTracker::kUnmanaged));
+ EXPECT_EQ(initial_memory2 + ref2->texture()->estimated_size(),
+ memory_tracker2_->GetSize(MemoryTracker::kUnmanaged));
+
+ EXPECT_CALL(*gl_, DeleteTextures(1, _))
+ .Times(1)
+ .RetiresOnSaturation();
+ ref2 = NULL;
+ texture_manager2_->RemoveTexture(20);
+ EXPECT_EQ(initial_memory2,
+ memory_tracker2_->GetSize(MemoryTracker::kUnmanaged));
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/transfer_buffer_manager.cc b/chromium/gpu/command_buffer/service/transfer_buffer_manager.cc
new file mode 100644
index 00000000000..76443a1f250
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/transfer_buffer_manager.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+
+#include <limits>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/debug/trace_event.h"
+#include "base/process/process_handle.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+
+using ::base::SharedMemory;
+
+namespace gpu {
+
+TransferBufferManagerInterface::~TransferBufferManagerInterface() {
+}
+
+TransferBufferManager::TransferBufferManager()
+ : shared_memory_bytes_allocated_(0) {
+}
+
+TransferBufferManager::~TransferBufferManager() {
+ while (!registered_buffers_.empty()) {
+ BufferMap::iterator it = registered_buffers_.begin();
+ DCHECK(shared_memory_bytes_allocated_ >= it->second.size);
+ shared_memory_bytes_allocated_ -= it->second.size;
+ delete it->second.shared_memory;
+ registered_buffers_.erase(it);
+ }
+ DCHECK(!shared_memory_bytes_allocated_);
+}
+
+bool TransferBufferManager::Initialize() {
+ return true;
+}
+
+bool TransferBufferManager::RegisterTransferBuffer(
+ int32 id,
+ base::SharedMemory* shared_memory,
+ size_t size) {
+ if (id <= 0) {
+ DVLOG(0) << "Cannot register transfer buffer with non-positive ID.";
+ return false;
+ }
+
+ // Fail if the ID is in use.
+ if (registered_buffers_.find(id) != registered_buffers_.end()) {
+ DVLOG(0) << "Buffer ID already in use.";
+ return false;
+ }
+
+ // Duplicate the handle.
+ base::SharedMemoryHandle duped_shared_memory_handle;
+ if (!shared_memory->ShareToProcess(base::GetCurrentProcessHandle(),
+ &duped_shared_memory_handle)) {
+ DVLOG(0) << "Failed to duplicate shared memory handle.";
+ return false;
+ }
+ scoped_ptr<SharedMemory> duped_shared_memory(
+ new SharedMemory(duped_shared_memory_handle, false));
+
+ // Map the shared memory into this process. This validates the size.
+ if (!duped_shared_memory->Map(size)) {
+ DVLOG(0) << "Failed to map shared memory.";
+ return false;
+ }
+
+ // If it could be mapped register the shared memory with the ID.
+ Buffer buffer;
+ buffer.ptr = duped_shared_memory->memory();
+ buffer.size = size;
+ buffer.shared_memory = duped_shared_memory.release();
+
+ shared_memory_bytes_allocated_ += size;
+ TRACE_COUNTER_ID1(
+ "gpu", "GpuTransferBufferMemory", this, shared_memory_bytes_allocated_);
+
+ registered_buffers_[id] = buffer;
+
+ return true;
+}
+
+void TransferBufferManager::DestroyTransferBuffer(int32 id) {
+ BufferMap::iterator it = registered_buffers_.find(id);
+ if (it == registered_buffers_.end()) {
+ DVLOG(0) << "Transfer buffer ID was not registered.";
+ return;
+ }
+
+ DCHECK(shared_memory_bytes_allocated_ >= it->second.size);
+ shared_memory_bytes_allocated_ -= it->second.size;
+ TRACE_COUNTER_ID1(
+ "gpu", "GpuTransferBufferMemory", this, shared_memory_bytes_allocated_);
+
+ delete it->second.shared_memory;
+ registered_buffers_.erase(it);
+}
+
+Buffer TransferBufferManager::GetTransferBuffer(int32 id) {
+ if (id == 0)
+ return Buffer();
+
+ BufferMap::iterator it = registered_buffers_.find(id);
+ if (it == registered_buffers_.end())
+ return Buffer();
+
+ return it->second;
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/command_buffer/service/transfer_buffer_manager.h b/chromium/gpu/command_buffer/service/transfer_buffer_manager.h
new file mode 100644
index 00000000000..5e1a7464824
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/transfer_buffer_manager.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_TRANSFER_BUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_TRANSFER_BUFFER_MANAGER_H_
+
+#include <set>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/shared_memory.h"
+#include "gpu/command_buffer/common/command_buffer_shared.h"
+
+namespace gpu {
+
+class GPU_EXPORT TransferBufferManagerInterface {
+ public:
+ virtual ~TransferBufferManagerInterface();
+
+ virtual bool RegisterTransferBuffer(int32 id,
+ base::SharedMemory* shared_memory,
+ size_t size) = 0;
+ virtual void DestroyTransferBuffer(int32 id) = 0;
+ virtual Buffer GetTransferBuffer(int32 id) = 0;
+
+};
+
+class GPU_EXPORT TransferBufferManager
+ : public TransferBufferManagerInterface {
+ public:
+ TransferBufferManager();
+
+ bool Initialize();
+ virtual bool RegisterTransferBuffer(int32 id,
+ base::SharedMemory* shared_memory,
+ size_t size) OVERRIDE;
+ virtual void DestroyTransferBuffer(int32 id) OVERRIDE;
+ virtual Buffer GetTransferBuffer(int32 id) OVERRIDE;
+
+ private:
+ virtual ~TransferBufferManager();
+
+ typedef base::hash_map<int32, Buffer> BufferMap;
+ BufferMap registered_buffers_;
+ size_t shared_memory_bytes_allocated_;
+
+ DISALLOW_COPY_AND_ASSIGN(TransferBufferManager);
+};
+
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_TRANSFER_BUFFER_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc b/chromium/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc
new file mode 100644
index 00000000000..68c5c2ec21c
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/transfer_buffer_manager_unittest.cc
@@ -0,0 +1,115 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gmock/include/gmock/gmock.h"
+
+using base::SharedMemory;
+
+namespace gpu {
+
+const static size_t kBufferSize = 1024;
+
+class TransferBufferManagerTest : public testing::Test {
+ protected:
+ virtual void SetUp() {
+ for (size_t i = 0; i < arraysize(buffers_); ++i) {
+ buffers_[i].CreateAnonymous(kBufferSize);
+ buffers_[i].Map(kBufferSize);
+ }
+
+ TransferBufferManager* manager = new TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ ASSERT_TRUE(manager->Initialize());
+ }
+
+ base::SharedMemory buffers_[3];
+ scoped_ptr<TransferBufferManagerInterface> transfer_buffer_manager_;
+};
+
+TEST_F(TransferBufferManagerTest, ZeroHandleMapsToNull) {
+ EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(0).ptr);
+}
+
+TEST_F(TransferBufferManagerTest, NegativeHandleMapsToNull) {
+ EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(-1).ptr);
+}
+
+TEST_F(TransferBufferManagerTest, OutOfRangeHandleMapsToNull) {
+ EXPECT_TRUE(NULL == transfer_buffer_manager_->GetTransferBuffer(1).ptr);
+}
+
+TEST_F(TransferBufferManagerTest, CanRegisterTransferBuffer) {
+ EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[0],
+ kBufferSize));
+ Buffer registered = transfer_buffer_manager_->GetTransferBuffer(1);
+
+ // Distinct memory range and shared memory handle from that originally
+ // registered.
+ EXPECT_NE(static_cast<void*>(NULL), registered.ptr);
+ EXPECT_NE(buffers_[0].memory(), registered.ptr);
+ EXPECT_EQ(kBufferSize, registered.size);
+ EXPECT_NE(&buffers_[0], registered.shared_memory);
+
+ // But maps to the same physical memory.
+ *static_cast<int*>(registered.ptr) = 7;
+ *static_cast<int*>(buffers_[0].memory()) = 8;
+ EXPECT_EQ(8, *static_cast<int*>(registered.ptr));
+}
+
+TEST_F(TransferBufferManagerTest, CanDestroyTransferBuffer) {
+ EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[0],
+ kBufferSize));
+ transfer_buffer_manager_->DestroyTransferBuffer(1);
+ Buffer registered = transfer_buffer_manager_->GetTransferBuffer(1);
+
+ EXPECT_EQ(static_cast<void*>(NULL), registered.ptr);
+ EXPECT_EQ(0U, registered.size);
+ EXPECT_EQ(static_cast<base::SharedMemory*>(NULL), registered.shared_memory);
+}
+
+TEST_F(TransferBufferManagerTest, CannotRegregisterTransferBufferId) {
+ EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[0],
+ kBufferSize));
+ EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[0],
+ kBufferSize));
+ EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[1],
+ kBufferSize));
+}
+
+TEST_F(TransferBufferManagerTest, CanReuseTransferBufferIdAfterDestroying) {
+ EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[0],
+ kBufferSize));
+ transfer_buffer_manager_->DestroyTransferBuffer(1);
+ EXPECT_TRUE(transfer_buffer_manager_->RegisterTransferBuffer(1,
+ &buffers_[1],
+ kBufferSize));
+}
+
+TEST_F(TransferBufferManagerTest, DestroyUnusedTransferBufferIdDoesNotCrash) {
+ transfer_buffer_manager_->DestroyTransferBuffer(1);
+}
+
+TEST_F(TransferBufferManagerTest, CannotRegisterNullTransferBuffer) {
+ EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(0,
+ &buffers_[0],
+ kBufferSize));
+}
+
+TEST_F(TransferBufferManagerTest, CannotRegisterNegativeTransferBufferId) {
+ EXPECT_FALSE(transfer_buffer_manager_->RegisterTransferBuffer(-1,
+ &buffers_[0],
+ kBufferSize));
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/vertex_array_manager.cc b/chromium/gpu/command_buffer/service/vertex_array_manager.cc
new file mode 100644
index 00000000000..974751941ce
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/vertex_array_manager.cc
@@ -0,0 +1,83 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/vertex_array_manager.h"
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+VertexArrayManager::VertexArrayManager()
+ : vertex_attrib_manager_count_(0),
+ have_context_(true) {
+}
+
+VertexArrayManager::~VertexArrayManager() {
+ DCHECK(vertex_attrib_managers_.empty());
+ CHECK_EQ(vertex_attrib_manager_count_, 0u);
+}
+
+void VertexArrayManager::Destroy(bool have_context) {
+ have_context_ = have_context;
+ vertex_attrib_managers_.clear();
+}
+
+void VertexArrayManager::CreateVertexAttribManager(
+ GLuint client_id, GLuint service_id, uint32 num_vertex_attribs) {
+ scoped_refptr<VertexAttribManager> vertex_attrib_manager(
+ new VertexAttribManager(this, service_id, num_vertex_attribs));
+ std::pair<VertexAttribManagerMap::iterator, bool> result =
+ vertex_attrib_managers_.insert(
+ std::make_pair(client_id, vertex_attrib_manager));
+ DCHECK(result.second);
+}
+
+VertexAttribManager* VertexArrayManager::GetVertexAttribManager(
+ GLuint client_id) {
+ VertexAttribManagerMap::iterator it = vertex_attrib_managers_.find(client_id);
+ return it != vertex_attrib_managers_.end() ? it->second.get() : NULL;
+}
+
+void VertexArrayManager::RemoveVertexAttribManager(GLuint client_id) {
+ VertexAttribManagerMap::iterator it = vertex_attrib_managers_.find(client_id);
+ if (it != vertex_attrib_managers_.end()) {
+ VertexAttribManager* vertex_attrib_manager = it->second.get();
+ vertex_attrib_manager->MarkAsDeleted();
+ vertex_attrib_managers_.erase(it);
+ }
+}
+
+void VertexArrayManager::StartTracking(
+ VertexAttribManager* /* vertex_attrib_manager */) {
+ ++vertex_attrib_manager_count_;
+}
+
+void VertexArrayManager::StopTracking(
+ VertexAttribManager* /* vertex_attrib_manager */) {
+ --vertex_attrib_manager_count_;
+}
+
+bool VertexArrayManager::GetClientId(
+ GLuint service_id, GLuint* client_id) const {
+ // This doesn't need to be fast. It's only used during slow queries.
+ for (VertexAttribManagerMap::const_iterator it =
+ vertex_attrib_managers_.begin();
+ it != vertex_attrib_managers_.end(); ++it) {
+ if (it->second->service_id() == service_id) {
+ *client_id = it->first;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/vertex_array_manager.h b/chromium/gpu/command_buffer/service/vertex_array_manager.h
new file mode 100644
index 00000000000..4fc567c7b79
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/vertex_array_manager.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_VERTEX_ARRAY_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_VERTEX_ARRAY_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class VertexAttribManager;
+
+// This class keeps track of the vertex arrays and their sizes so we can do
+// bounds checking.
+class GPU_EXPORT VertexArrayManager {
+ public:
+ VertexArrayManager();
+ ~VertexArrayManager();
+
+ // Must call before destruction.
+ void Destroy(bool have_context);
+
+ // Creates a VertexArrayInfo for the given vertex array.
+ void CreateVertexAttribManager(GLuint client_id, GLuint service_id,
+ uint32 num_vertex_attribs);
+
+ // Gets the vertex attrib manager for the given vertex array.
+ VertexAttribManager* GetVertexAttribManager(GLuint client_id);
+
+ // Removes the vertex attrib manager for the given vertex array.
+ void RemoveVertexAttribManager(GLuint client_id);
+
+ // Gets a client id for a given service id.
+ bool GetClientId(GLuint service_id, GLuint* client_id) const;
+
+ private:
+ friend class VertexAttribManager;
+
+ void StartTracking(VertexAttribManager* vertex_attrib_manager);
+ void StopTracking(VertexAttribManager* vertex_attrib_manager);
+
+ // Info for each vertex array in the system.
+ typedef base::hash_map<GLuint, scoped_refptr<VertexAttribManager> >
+ VertexAttribManagerMap;
+ VertexAttribManagerMap vertex_attrib_managers_;
+
+ // Counts the number of VertexArrayInfo allocated with 'this' as its manager.
+ // Allows to check no VertexArrayInfo will outlive this.
+ unsigned int vertex_attrib_manager_count_;
+
+ bool have_context_;
+
+ DISALLOW_COPY_AND_ASSIGN(VertexArrayManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_VERTEX_ARRAY_MANAGER_H_
diff --git a/chromium/gpu/command_buffer/service/vertex_array_manager_unittest.cc b/chromium/gpu/command_buffer/service/vertex_array_manager_unittest.cc
new file mode 100644
index 00000000000..50ce07752a4
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/vertex_array_manager_unittest.cc
@@ -0,0 +1,103 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/vertex_array_manager.h"
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::Pointee;
+using ::testing::_;
+
+namespace gpu {
+namespace gles2 {
+
+class VertexArrayManagerTest : public testing::Test {
+ public:
+ static const uint32 kNumVertexAttribs = 8;
+
+ VertexArrayManagerTest() {
+ }
+
+ virtual ~VertexArrayManagerTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ manager_ = new VertexArrayManager();
+ }
+
+ virtual void TearDown() {
+ delete manager_;
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ VertexArrayManager* manager_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const uint32 VertexArrayManagerTest::kNumVertexAttribs;
+#endif
+
+TEST_F(VertexArrayManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ const GLuint kClient2Id = 2;
+
+ // Check we can create
+ manager_->CreateVertexAttribManager(
+ kClient1Id, kService1Id, kNumVertexAttribs);
+ // Check creation success
+ VertexAttribManager* info1 = manager_->GetVertexAttribManager(kClient1Id);
+ ASSERT_TRUE(info1 != NULL);
+ EXPECT_EQ(kService1Id, info1->service_id());
+ GLuint client_id = 0;
+ EXPECT_TRUE(manager_->GetClientId(info1->service_id(), &client_id));
+ EXPECT_EQ(kClient1Id, client_id);
+ // Check we get nothing for a non-existent name.
+ EXPECT_TRUE(manager_->GetVertexAttribManager(kClient2Id) == NULL);
+ // Check trying to a remove non-existent name does not crash.
+ manager_->RemoveVertexAttribManager(kClient2Id);
+ // Check that it gets deleted when the last reference is released.
+ EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ // Check we can't get the texture after we remove it.
+ manager_->RemoveVertexAttribManager(kClient1Id);
+ EXPECT_TRUE(manager_->GetVertexAttribManager(kClient1Id) == NULL);
+}
+
+TEST_F(VertexArrayManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ const GLuint kService1Id = 11;
+ VertexArrayManager manager;
+ // Check we can create
+ manager.CreateVertexAttribManager(kClient1Id, kService1Id, kNumVertexAttribs);
+ // Check creation success
+ VertexAttribManager* info1 = manager.GetVertexAttribManager(kClient1Id);
+ ASSERT_TRUE(info1 != NULL);
+ EXPECT_CALL(*gl_, DeleteVertexArraysOES(1, ::testing::Pointee(kService1Id)))
+ .Times(1)
+ .RetiresOnSaturation();
+ manager.Destroy(true);
+ // Check that resources got freed.
+ info1 = manager.GetVertexAttribManager(kClient1Id);
+ ASSERT_TRUE(info1 == NULL);
+}
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer/service/vertex_attrib_manager.cc b/chromium/gpu/command_buffer/service/vertex_attrib_manager.cc
new file mode 100644
index 00000000000..23e592cf5f5
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/vertex_attrib_manager.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+
+#include <list>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "build/build_config.h"
+#define GLES2_GPU_SERVICE 1
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/error_state.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/service/program_manager.h"
+#include "gpu/command_buffer/service/vertex_array_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+VertexAttrib::VertexAttrib()
+ : index_(0),
+ enabled_(false),
+ size_(4),
+ type_(GL_FLOAT),
+ offset_(0),
+ normalized_(GL_FALSE),
+ gl_stride_(0),
+ real_stride_(16),
+ divisor_(0),
+ is_client_side_array_(false),
+ list_(NULL) {
+}
+
+VertexAttrib::~VertexAttrib() {
+}
+
+void VertexAttrib::SetInfo(
+ Buffer* buffer,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei gl_stride,
+ GLsizei real_stride,
+ GLsizei offset) {
+ DCHECK_GT(real_stride, 0);
+ buffer_ = buffer;
+ size_ = size;
+ type_ = type;
+ normalized_ = normalized;
+ gl_stride_ = gl_stride;
+ real_stride_ = real_stride;
+ offset_ = offset;
+}
+
+void VertexAttrib::Unbind(Buffer* buffer) {
+ if (buffer_.get() == buffer) {
+ buffer_ = NULL;
+ }
+}
+
+bool VertexAttrib::CanAccess(GLuint index) const {
+ if (!enabled_) {
+ return true;
+ }
+
+ if (!buffer_.get() || buffer_->IsDeleted()) {
+ return false;
+ }
+
+ // The number of elements that can be accessed.
+ GLsizeiptr buffer_size = buffer_->size();
+ if (offset_ > buffer_size || real_stride_ == 0) {
+ return false;
+ }
+
+ uint32 usable_size = buffer_size - offset_;
+ GLuint num_elements = usable_size / real_stride_ +
+ ((usable_size % real_stride_) >=
+ (GLES2Util::GetGLTypeSizeForTexturesAndBuffers(type_) * size_) ? 1 : 0);
+ return index < num_elements;
+}
+
+VertexAttribManager::VertexAttribManager()
+ : num_fixed_attribs_(0),
+ element_array_buffer_(NULL),
+ manager_(NULL),
+ deleted_(false),
+ service_id_(0) {
+}
+
+VertexAttribManager::VertexAttribManager(
+ VertexArrayManager* manager, GLuint service_id, uint32 num_vertex_attribs)
+ : num_fixed_attribs_(0),
+ element_array_buffer_(NULL),
+ manager_(manager),
+ deleted_(false),
+ service_id_(service_id) {
+ manager_->StartTracking(this);
+ Initialize(num_vertex_attribs, false);
+}
+
+VertexAttribManager::~VertexAttribManager() {
+ if (manager_) {
+ if (manager_->have_context_) {
+ if (service_id_ != 0) // 0 indicates an emulated VAO
+ glDeleteVertexArraysOES(1, &service_id_);
+ }
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+void VertexAttribManager::Initialize(
+ uint32 max_vertex_attribs, bool init_attribs) {
+ vertex_attribs_.resize(max_vertex_attribs);
+ bool disable_workarounds = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kDisableGpuDriverBugWorkarounds);
+
+ for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
+ vertex_attribs_[vv].set_index(vv);
+ vertex_attribs_[vv].SetList(&disabled_vertex_attribs_);
+
+ if (!disable_workarounds && init_attribs) {
+ glVertexAttrib4f(vv, 0.0f, 0.0f, 0.0f, 1.0f);
+ }
+ }
+}
+
+void VertexAttribManager::SetElementArrayBuffer(Buffer* buffer) {
+ element_array_buffer_ = buffer;
+}
+
+bool VertexAttribManager::Enable(GLuint index, bool enable) {
+ if (index >= vertex_attribs_.size()) {
+ return false;
+ }
+ VertexAttrib& info = vertex_attribs_[index];
+ if (info.enabled() != enable) {
+ info.set_enabled(enable);
+ info.SetList(enable ? &enabled_vertex_attribs_ : &disabled_vertex_attribs_);
+ }
+ return true;
+}
+
+void VertexAttribManager::Unbind(Buffer* buffer) {
+ if (element_array_buffer_.get() == buffer) {
+ element_array_buffer_ = NULL;
+ }
+ for (uint32 vv = 0; vv < vertex_attribs_.size(); ++vv) {
+ vertex_attribs_[vv].Unbind(buffer);
+ }
+}
+
+bool VertexAttribManager::ValidateBindings(
+ const char* function_name,
+ GLES2Decoder* decoder,
+ FeatureInfo* feature_info,
+ Program* current_program,
+ GLuint max_vertex_accessed,
+ GLsizei primcount) {
+ ErrorState* error_state = decoder->GetErrorState();
+ // true if any enabled, used divisor is zero
+ bool divisor0 = false;
+ const GLuint kInitialBufferId = 0xFFFFFFFFU;
+ GLuint current_buffer_id = kInitialBufferId;
+ bool use_client_side_arrays_for_stream_buffers = feature_info->workarounds(
+ ).use_client_side_arrays_for_stream_buffers;
+ // Validate all attribs currently enabled. If they are used by the current
+ // program then check that they have enough elements to handle the draw call.
+ // If they are not used by the current program check that they have a buffer
+ // assigned.
+ for (VertexAttribList::iterator it = enabled_vertex_attribs_.begin();
+ it != enabled_vertex_attribs_.end(); ++it) {
+ VertexAttrib* attrib = *it;
+ const Program::VertexAttrib* attrib_info =
+ current_program->GetAttribInfoByLocation(attrib->index());
+ if (attrib_info) {
+ divisor0 |= (attrib->divisor() == 0);
+ GLuint count = attrib->MaxVertexAccessed(primcount, max_vertex_accessed);
+ // This attrib is used in the current program.
+ if (!attrib->CanAccess(count)) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ (std::string(
+ "attempt to access out of range vertices in attribute ") +
+ base::IntToString(attrib->index())).c_str());
+ return false;
+ }
+ if (use_client_side_arrays_for_stream_buffers) {
+ Buffer* buffer = attrib->buffer();
+ glEnableVertexAttribArray(attrib->index());
+ if (buffer->IsClientSideArray()) {
+ if (current_buffer_id != 0) {
+ current_buffer_id = 0;
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+ attrib->set_is_client_side_array(true);
+ const void* ptr = buffer->GetRange(attrib->offset(), 0);
+ DCHECK(ptr);
+ glVertexAttribPointer(
+ attrib->index(),
+ attrib->size(),
+ attrib->type(),
+ attrib->normalized(),
+ attrib->gl_stride(),
+ ptr);
+ } else if (attrib->is_client_side_array()) {
+ attrib->set_is_client_side_array(false);
+ GLuint new_buffer_id = buffer->service_id();
+ if (new_buffer_id != current_buffer_id) {
+ current_buffer_id = new_buffer_id;
+ glBindBuffer(GL_ARRAY_BUFFER, current_buffer_id);
+ }
+ const void* ptr = reinterpret_cast<const void*>(attrib->offset());
+ glVertexAttribPointer(
+ attrib->index(),
+ attrib->size(),
+ attrib->type(),
+ attrib->normalized(),
+ attrib->gl_stride(),
+ ptr);
+ }
+ }
+ } else {
+ // This attrib is not used in the current program.
+ if (!attrib->buffer()) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ (std::string(
+ "attempt to render with no buffer attached to "
+ "enabled attribute ") +
+ base::IntToString(attrib->index())).c_str());
+ return false;
+ } else if (use_client_side_arrays_for_stream_buffers) {
+ Buffer* buffer = attrib->buffer();
+ // Disable client side arrays for unused attributes else we'll
+ // read bad memory
+ if (buffer->IsClientSideArray()) {
+ // Don't disable attrib 0 since it's special.
+ if (attrib->index() > 0) {
+ glDisableVertexAttribArray(attrib->index());
+ }
+ }
+ }
+ }
+ }
+
+ if (primcount && !divisor0) {
+ ERRORSTATE_SET_GL_ERROR(
+ error_state, GL_INVALID_OPERATION, function_name,
+ "attempt instanced render with all attributes having "
+ "non-zero divisors");
+ return false;
+ }
+
+ if (current_buffer_id != kInitialBufferId) {
+ // Restore the buffer binding.
+ decoder->RestoreBufferBindings();
+ }
+
+ return true;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/chromium/gpu/command_buffer/service/vertex_attrib_manager.h b/chromium/gpu/command_buffer/service/vertex_attrib_manager.h
new file mode 100644
index 00000000000..2eff3ccfe30
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/vertex_attrib_manager.h
@@ -0,0 +1,296 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_VERTEX_ATTRIB_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_VERTEX_ATTRIB_MANAGER_H_
+
+#include <list>
+#include <vector>
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "build/build_config.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class FeatureInfo;
+class GLES2Decoder;
+class Program;
+class VertexArrayManager;
+
+// Info about a Vertex Attribute. This is used to track what the user currently
+// has bound on each Vertex Attribute so that checking can be done at
+// glDrawXXX time.
+class GPU_EXPORT VertexAttrib {
+ public:
+ typedef std::list<VertexAttrib*> VertexAttribList;
+
+ VertexAttrib();
+ ~VertexAttrib();
+
+ // Returns true if this VertexAttrib can access index.
+ bool CanAccess(GLuint index) const;
+
+ Buffer* buffer() const { return buffer_.get(); }
+
+ GLsizei offset() const {
+ return offset_;
+ }
+
+ GLuint index() const {
+ return index_;
+ }
+
+ GLint size() const {
+ return size_;
+ }
+
+ GLenum type() const {
+ return type_;
+ }
+
+ GLboolean normalized() const {
+ return normalized_;
+ }
+
+ GLsizei gl_stride() const {
+ return gl_stride_;
+ }
+
+ GLuint divisor() const {
+ return divisor_;
+ }
+
+ bool enabled() const {
+ return enabled_;
+ }
+
+ // Find the maximum vertex accessed, accounting for instancing.
+ GLuint MaxVertexAccessed(GLsizei primcount,
+ GLuint max_vertex_accessed) const {
+ return (primcount && divisor_) ? ((primcount - 1) / divisor_) :
+ max_vertex_accessed;
+ }
+
+ bool is_client_side_array() const {
+ return is_client_side_array_;
+ }
+
+ void set_is_client_side_array(bool value) {
+ is_client_side_array_ = value;
+ }
+
+ private:
+ friend class VertexAttribManager;
+
+ void set_enabled(bool enabled) {
+ enabled_ = enabled;
+ }
+
+ void set_index(GLuint index) {
+ index_ = index;
+ }
+
+ void SetList(VertexAttribList* new_list) {
+ DCHECK(new_list);
+
+ if (list_) {
+ list_->erase(it_);
+ }
+
+ it_ = new_list->insert(new_list->end(), this);
+ list_ = new_list;
+ }
+
+ void SetInfo(
+ Buffer* buffer,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei gl_stride,
+ GLsizei real_stride,
+ GLsizei offset);
+
+ void SetDivisor(GLsizei divisor) {
+ divisor_ = divisor;
+ }
+
+ void Unbind(Buffer* buffer);
+
+ // The index of this attrib.
+ GLuint index_;
+
+ // Whether or not this attribute is enabled.
+ bool enabled_;
+
+ // number of components (1, 2, 3, 4)
+ GLint size_;
+
+ // GL_BYTE, GL_FLOAT, etc. See glVertexAttribPointer.
+ GLenum type_;
+
+ // The offset into the buffer.
+ GLsizei offset_;
+
+ GLboolean normalized_;
+
+ // The stride passed to glVertexAttribPointer.
+ GLsizei gl_stride_;
+
+ // The stride that will be used to access the buffer. This is the actual
+ // stide, NOT the GL bogus stride. In other words there is never a stride
+ // of 0.
+ GLsizei real_stride_;
+
+ GLsizei divisor_;
+
+ // Will be true if this was assigned to a client side array.
+ bool is_client_side_array_;
+
+ // The buffer bound to this attribute.
+ scoped_refptr<Buffer> buffer_;
+
+ // List this info is on.
+ VertexAttribList* list_;
+
+ // Iterator for list this info is on. Enabled/Disabled
+ VertexAttribList::iterator it_;
+};
+
+// Manages vertex attributes.
+// This class also acts as the service-side representation of a
+// vertex array object and it's contained state.
+class GPU_EXPORT VertexAttribManager :
+ public base::RefCounted<VertexAttribManager> {
+ public:
+ typedef std::list<VertexAttrib*> VertexAttribList;
+
+ VertexAttribManager();
+
+ void Initialize(uint32 num_vertex_attribs, bool init_attribs = true);
+
+ bool Enable(GLuint index, bool enable);
+
+ bool HaveFixedAttribs() const {
+ return num_fixed_attribs_ != 0;
+ }
+
+ const VertexAttribList& GetEnabledVertexAttribs() const {
+ return enabled_vertex_attribs_;
+ }
+
+ VertexAttrib* GetVertexAttrib(GLuint index) {
+ if (index < vertex_attribs_.size()) {
+ return &vertex_attribs_[index];
+ }
+ return NULL;
+ }
+
+ void SetAttribInfo(
+ GLuint index,
+ Buffer* buffer,
+ GLint size,
+ GLenum type,
+ GLboolean normalized,
+ GLsizei gl_stride,
+ GLsizei real_stride,
+ GLsizei offset) {
+ VertexAttrib* attrib = GetVertexAttrib(index);
+ if (attrib) {
+ if (attrib->type() == GL_FIXED) {
+ --num_fixed_attribs_;
+ }
+ if (type == GL_FIXED) {
+ ++num_fixed_attribs_;
+ }
+ attrib->SetInfo(
+ buffer, size, type, normalized, gl_stride, real_stride, offset);
+ }
+ }
+
+ void SetDivisor(GLuint index, GLuint divisor) {
+ VertexAttrib* attrib = GetVertexAttrib(index);
+ if (attrib) {
+ attrib->SetDivisor(divisor);
+ }
+ }
+
+ void SetElementArrayBuffer(Buffer* buffer);
+
+ Buffer* element_array_buffer() const { return element_array_buffer_.get(); }
+
+ GLuint service_id() const {
+ return service_id_;
+ }
+
+ void Unbind(Buffer* buffer);
+
+ bool IsDeleted() const {
+ return deleted_;
+ }
+
+ bool IsValid() const {
+ return !IsDeleted();
+ }
+
+ size_t num_attribs() const {
+ return vertex_attribs_.size();
+ }
+
+ bool ValidateBindings(
+ const char* function_name,
+ GLES2Decoder* decoder,
+ FeatureInfo* feature_info,
+ Program* current_program,
+ GLuint max_vertex_accessed,
+ GLsizei primcount);
+
+ private:
+ friend class VertexArrayManager;
+ friend class VertexArrayManagerTest;
+ friend class base::RefCounted<VertexAttribManager>;
+
+ // Used when creating from a VertexArrayManager
+ VertexAttribManager(VertexArrayManager* manager, GLuint service_id,
+ uint32 num_vertex_attribs);
+
+ ~VertexAttribManager();
+
+ void MarkAsDeleted() {
+ deleted_ = true;
+ }
+
+ // number of attribs using type GL_FIXED.
+ int num_fixed_attribs_;
+
+ // Info for each vertex attribute saved so we can check at glDrawXXX time
+ // if it is safe to draw.
+ std::vector<VertexAttrib> vertex_attribs_;
+
+ // The currently bound element array buffer. If this is 0 it is illegal
+ // to call glDrawElements.
+ scoped_refptr<Buffer> element_array_buffer_;
+
+ // Lists for which vertex attribs are enabled, disabled.
+ VertexAttribList enabled_vertex_attribs_;
+ VertexAttribList disabled_vertex_attribs_;
+
+ // The VertexArrayManager that owns this VertexAttribManager
+ VertexArrayManager* manager_;
+
+ // True if deleted.
+ bool deleted_;
+
+ // Service side vertex array object id.
+ GLuint service_id_;
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_VERTEX_ATTRIB_MANAGER_H_
+
diff --git a/chromium/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc b/chromium/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
new file mode 100644
index 00000000000..28a051c97b2
--- /dev/null
+++ b/chromium/gpu/command_buffer/service/vertex_attrib_manager_unittest.cc
@@ -0,0 +1,233 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/command_buffer/service/vertex_attrib_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/buffer_manager.h"
+#include "gpu/command_buffer/service/error_state_mock.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_mock.h"
+
+using ::testing::Pointee;
+using ::testing::_;
+
+namespace gpu {
+namespace gles2 {
+
+class VertexAttribManagerTest : public testing::Test {
+ public:
+ static const uint32 kNumVertexAttribs = 8;
+
+ VertexAttribManagerTest() {
+ }
+
+ virtual ~VertexAttribManagerTest() {
+ }
+
+ protected:
+ virtual void SetUp() {
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+
+ for (uint32 ii = 0; ii < kNumVertexAttribs; ++ii) {
+ EXPECT_CALL(*gl_, VertexAttrib4f(ii, 0.0f, 0.0f, 0.0f, 1.0f))
+ .Times(1)
+ .RetiresOnSaturation();
+ }
+
+ manager_ = new VertexAttribManager();
+ manager_->Initialize(kNumVertexAttribs);
+ }
+
+ virtual void TearDown() {
+ manager_ = NULL;
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ scoped_refptr<VertexAttribManager> manager_;
+};
+
+// GCC requires these declarations, but MSVC requires they not be present
+#ifndef COMPILER_MSVC
+const uint32 VertexAttribManagerTest::kNumVertexAttribs;
+#endif
+
+TEST_F(VertexAttribManagerTest, Basic) {
+ EXPECT_TRUE(manager_->GetVertexAttrib(kNumVertexAttribs) == NULL);
+ EXPECT_FALSE(manager_->HaveFixedAttribs());
+
+ const VertexAttribManager::VertexAttribList& enabled_attribs =
+ manager_->GetEnabledVertexAttribs();
+ EXPECT_EQ(0u, enabled_attribs.size());
+
+ for (uint32 ii = 0; ii < kNumVertexAttribs; ii += kNumVertexAttribs - 1) {
+ VertexAttrib* attrib = manager_->GetVertexAttrib(ii);
+ ASSERT_TRUE(attrib != NULL);
+ EXPECT_EQ(ii, attrib->index());
+ EXPECT_TRUE(attrib->buffer() == NULL);
+ EXPECT_EQ(0, attrib->offset());
+ EXPECT_EQ(4, attrib->size());
+ EXPECT_EQ(static_cast<GLenum>(GL_FLOAT), attrib->type());
+ EXPECT_EQ(GL_FALSE, attrib->normalized());
+ EXPECT_EQ(0, attrib->gl_stride());
+ EXPECT_FALSE(attrib->enabled());
+ manager_->Enable(ii, true);
+ EXPECT_TRUE(attrib->enabled());
+ }
+}
+
+TEST_F(VertexAttribManagerTest, Enable) {
+ const VertexAttribManager::VertexAttribList& enabled_attribs =
+ manager_->GetEnabledVertexAttribs();
+
+ VertexAttrib* attrib1 = manager_->GetVertexAttrib(1);
+ VertexAttrib* attrib2 = manager_->GetVertexAttrib(3);
+
+ manager_->Enable(1, true);
+ ASSERT_EQ(1u, enabled_attribs.size());
+ EXPECT_TRUE(attrib1->enabled());
+ manager_->Enable(3, true);
+ ASSERT_EQ(2u, enabled_attribs.size());
+ EXPECT_TRUE(attrib2->enabled());
+
+ manager_->Enable(1, false);
+ ASSERT_EQ(1u, enabled_attribs.size());
+ EXPECT_FALSE(attrib1->enabled());
+
+ manager_->Enable(3, false);
+ ASSERT_EQ(0u, enabled_attribs.size());
+ EXPECT_FALSE(attrib2->enabled());
+}
+
+TEST_F(VertexAttribManagerTest, SetAttribInfo) {
+ BufferManager buffer_manager(NULL, NULL);
+ buffer_manager.CreateBuffer(1, 2);
+ Buffer* buffer = buffer_manager.GetBuffer(1);
+ ASSERT_TRUE(buffer != NULL);
+
+ VertexAttrib* attrib = manager_->GetVertexAttrib(1);
+
+ manager_->SetAttribInfo(1, buffer, 3, GL_SHORT, GL_TRUE, 32, 32, 4);
+
+ EXPECT_EQ(buffer, attrib->buffer());
+ EXPECT_EQ(4, attrib->offset());
+ EXPECT_EQ(3, attrib->size());
+ EXPECT_EQ(static_cast<GLenum>(GL_SHORT), attrib->type());
+ EXPECT_EQ(GL_TRUE, attrib->normalized());
+ EXPECT_EQ(32, attrib->gl_stride());
+
+ // The VertexAttribManager must be destroyed before the BufferManager
+ // so it releases its buffers.
+ manager_ = NULL;
+ buffer_manager.Destroy(false);
+}
+
+TEST_F(VertexAttribManagerTest, HaveFixedAttribs) {
+ EXPECT_FALSE(manager_->HaveFixedAttribs());
+ manager_->SetAttribInfo(1, NULL, 4, GL_FIXED, GL_FALSE, 0, 16, 0);
+ EXPECT_TRUE(manager_->HaveFixedAttribs());
+ manager_->SetAttribInfo(3, NULL, 4, GL_FIXED, GL_FALSE, 0, 16, 0);
+ EXPECT_TRUE(manager_->HaveFixedAttribs());
+ manager_->SetAttribInfo(1, NULL, 4, GL_FLOAT, GL_FALSE, 0, 16, 0);
+ EXPECT_TRUE(manager_->HaveFixedAttribs());
+ manager_->SetAttribInfo(3, NULL, 4, GL_FLOAT, GL_FALSE, 0, 16, 0);
+ EXPECT_FALSE(manager_->HaveFixedAttribs());
+}
+
+TEST_F(VertexAttribManagerTest, CanAccess) {
+ MockErrorState error_state;
+ BufferManager buffer_manager(NULL, NULL);
+ buffer_manager.CreateBuffer(1, 2);
+ Buffer* buffer = buffer_manager.GetBuffer(1);
+ ASSERT_TRUE(buffer != NULL);
+
+ VertexAttrib* attrib = manager_->GetVertexAttrib(1);
+
+ EXPECT_TRUE(attrib->CanAccess(0));
+ manager_->Enable(1, true);
+ EXPECT_FALSE(attrib->CanAccess(0));
+
+ manager_->SetAttribInfo(1, buffer, 4, GL_FLOAT, GL_FALSE, 0, 16, 0);
+ EXPECT_FALSE(attrib->CanAccess(0));
+
+ EXPECT_TRUE(buffer_manager.SetTarget(buffer, GL_ARRAY_BUFFER));
+ TestHelper::DoBufferData(
+ gl_.get(), &error_state, &buffer_manager, buffer, 15, GL_STATIC_DRAW,
+ NULL, GL_NO_ERROR);
+
+ EXPECT_FALSE(attrib->CanAccess(0));
+ TestHelper::DoBufferData(
+ gl_.get(), &error_state, &buffer_manager, buffer, 16, GL_STATIC_DRAW,
+ NULL, GL_NO_ERROR);
+ EXPECT_TRUE(attrib->CanAccess(0));
+ EXPECT_FALSE(attrib->CanAccess(1));
+
+ manager_->SetAttribInfo(1, buffer, 4, GL_FLOAT, GL_FALSE, 0, 16, 1);
+ EXPECT_FALSE(attrib->CanAccess(0));
+
+ TestHelper::DoBufferData(
+ gl_.get(), &error_state, &buffer_manager, buffer, 32, GL_STATIC_DRAW,
+ NULL, GL_NO_ERROR);
+ EXPECT_TRUE(attrib->CanAccess(0));
+ EXPECT_FALSE(attrib->CanAccess(1));
+ manager_->SetAttribInfo(1, buffer, 4, GL_FLOAT, GL_FALSE, 0, 16, 0);
+ EXPECT_TRUE(attrib->CanAccess(1));
+ manager_->SetAttribInfo(1, buffer, 4, GL_FLOAT, GL_FALSE, 0, 20, 0);
+ EXPECT_TRUE(attrib->CanAccess(0));
+ EXPECT_FALSE(attrib->CanAccess(1));
+
+ // The VertexAttribManager must be destroyed before the BufferManager
+ // so it releases its buffers.
+ manager_ = NULL;
+ buffer_manager.Destroy(false);
+}
+
+TEST_F(VertexAttribManagerTest, Unbind) {
+ BufferManager buffer_manager(NULL, NULL);
+ buffer_manager.CreateBuffer(1, 2);
+ buffer_manager.CreateBuffer(3, 4);
+ Buffer* buffer1 = buffer_manager.GetBuffer(1);
+ Buffer* buffer2 = buffer_manager.GetBuffer(3);
+ ASSERT_TRUE(buffer1 != NULL);
+ ASSERT_TRUE(buffer2 != NULL);
+
+ VertexAttrib* attrib1 = manager_->GetVertexAttrib(1);
+ VertexAttrib* attrib3 = manager_->GetVertexAttrib(3);
+
+ // Attach to 2 buffers.
+ manager_->SetAttribInfo(1, buffer1, 3, GL_SHORT, GL_TRUE, 32, 32, 4);
+ manager_->SetAttribInfo(3, buffer1, 3, GL_SHORT, GL_TRUE, 32, 32, 4);
+ // Check they were attached.
+ EXPECT_EQ(buffer1, attrib1->buffer());
+ EXPECT_EQ(buffer1, attrib3->buffer());
+ // Unbind unattached buffer.
+ manager_->Unbind(buffer2);
+ // Should be no-op.
+ EXPECT_EQ(buffer1, attrib1->buffer());
+ EXPECT_EQ(buffer1, attrib3->buffer());
+ // Unbind buffer.
+ manager_->Unbind(buffer1);
+ // Check they were detached
+ EXPECT_TRUE(NULL == attrib1->buffer());
+ EXPECT_TRUE(NULL == attrib3->buffer());
+
+ // The VertexAttribManager must be destroyed before the BufferManager
+ // so it releases its buffers.
+ manager_ = NULL;
+ buffer_manager.Destroy(false);
+}
+
+// TODO(gman): Test ValidateBindings
+// TODO(gman): Test ValidateBindings with client side arrays.
+
+} // namespace gles2
+} // namespace gpu
+
+
diff --git a/chromium/gpu/command_buffer_client.gypi b/chromium/gpu/command_buffer_client.gypi
new file mode 100644
index 00000000000..b4d5b7886fb
--- /dev/null
+++ b/chromium/gpu/command_buffer_client.gypi
@@ -0,0 +1,32 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'include_dirs': [
+ '..',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'dependencies': [
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'sources': [
+ 'command_buffer/client/atomicops.cc',
+ 'command_buffer/client/atomicops.h',
+ 'command_buffer/client/cmd_buffer_helper.cc',
+ 'command_buffer/client/cmd_buffer_helper.h',
+ 'command_buffer/client/fenced_allocator.cc',
+ 'command_buffer/client/fenced_allocator.h',
+ 'command_buffer/client/hash_tables.h',
+ 'command_buffer/client/mapped_memory.cc',
+ 'command_buffer/client/mapped_memory.h',
+ 'command_buffer/client/ring_buffer.cc',
+ 'command_buffer/client/ring_buffer.h',
+ 'command_buffer/client/transfer_buffer.cc',
+ 'command_buffer/client/transfer_buffer.h',
+ ],
+}
diff --git a/chromium/gpu/command_buffer_common.gypi b/chromium/gpu/command_buffer_common.gypi
new file mode 100644
index 00000000000..85431e492e5
--- /dev/null
+++ b/chromium/gpu/command_buffer_common.gypi
@@ -0,0 +1,32 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'dependencies': [
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'sources': [
+ 'command_buffer/common/bitfield_helpers.h',
+ 'command_buffer/common/buffer.h',
+ 'command_buffer/common/cmd_buffer_common.h',
+ 'command_buffer/common/cmd_buffer_common.cc',
+ 'command_buffer/common/command_buffer.h',
+ 'command_buffer/common/compiler_specific.h',
+ 'command_buffer/common/constants.h',
+ 'command_buffer/common/debug_marker_manager.cc',
+ 'command_buffer/common/debug_marker_manager.h',
+ 'command_buffer/common/gles2_cmd_ids_autogen.h',
+ 'command_buffer/common/gles2_cmd_ids.h',
+ 'command_buffer/common/gles2_cmd_format_autogen.h',
+ 'command_buffer/common/gles2_cmd_format.cc',
+ 'command_buffer/common/gles2_cmd_format.h',
+ 'command_buffer/common/id_allocator.cc',
+ 'command_buffer/common/id_allocator.h',
+ 'command_buffer/common/mailbox.cc',
+ 'command_buffer/common/mailbox.h',
+ 'command_buffer/common/thread_local.h',
+ 'command_buffer/common/time.h',
+ 'command_buffer/common/types.h',
+ ],
+}
diff --git a/chromium/gpu/command_buffer_service.gypi b/chromium/gpu/command_buffer_service.gypi
new file mode 100644
index 00000000000..f8e94c18eb2
--- /dev/null
+++ b/chromium/gpu/command_buffer_service.gypi
@@ -0,0 +1,143 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'include_dirs': [
+ '..',
+ ],
+ 'all_dependent_settings': {
+ 'include_dirs': [
+ '..',
+ ],
+ },
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../crypto/crypto.gyp:crypto',
+ '../ui/gl/gl.gyp:gl',
+ '../ui/ui.gyp:ui',
+ '../third_party/angle_dx11/src/build_angle.gyp:translator_glsl',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ '../third_party/protobuf/protobuf.gyp:protobuf_lite',
+ '../third_party/smhasher/smhasher.gyp:cityhash',
+ '../third_party/re2/re2.gyp:re2',
+ ],
+ 'sources': [
+ 'command_buffer/service/async_pixel_transfer_delegate.cc',
+ 'command_buffer/service/async_pixel_transfer_delegate.h',
+ 'command_buffer/service/async_pixel_transfer_manager_android.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_idle.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_idle.h',
+ 'command_buffer/service/async_pixel_transfer_manager_linux.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_mac.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_share_group.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_share_group.h',
+ 'command_buffer/service/async_pixel_transfer_manager_stub.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_stub.h',
+ 'command_buffer/service/async_pixel_transfer_manager_sync.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_sync.h',
+ 'command_buffer/service/async_pixel_transfer_manager_win.cc',
+ 'command_buffer/service/async_pixel_transfer_manager.cc',
+ 'command_buffer/service/async_pixel_transfer_manager.h',
+ 'command_buffer/service/buffer_manager.h',
+ 'command_buffer/service/buffer_manager.cc',
+ 'command_buffer/service/cmd_buffer_engine.h',
+ 'command_buffer/service/cmd_parser.cc',
+ 'command_buffer/service/cmd_parser.h',
+ 'command_buffer/service/command_buffer_service.cc',
+ 'command_buffer/service/command_buffer_service.h',
+ 'command_buffer/service/common_decoder.cc',
+ 'command_buffer/service/common_decoder.h',
+ 'command_buffer/service/context_group.h',
+ 'command_buffer/service/context_group.cc',
+ 'command_buffer/service/context_state.h',
+ 'command_buffer/service/context_state_autogen.h',
+ 'command_buffer/service/context_state_impl_autogen.h',
+ 'command_buffer/service/context_state.cc',
+ 'command_buffer/service/error_state.cc',
+ 'command_buffer/service/error_state.h',
+ 'command_buffer/service/feature_info.h',
+ 'command_buffer/service/feature_info.cc',
+ 'command_buffer/service/framebuffer_manager.h',
+ 'command_buffer/service/framebuffer_manager.cc',
+ 'command_buffer/service/gles2_cmd_copy_texture_chromium.cc',
+ 'command_buffer/service/gles2_cmd_copy_texture_chromium.h',
+ 'command_buffer/service/gles2_cmd_decoder.h',
+ 'command_buffer/service/gles2_cmd_decoder_autogen.h',
+ 'command_buffer/service/gles2_cmd_decoder.cc',
+ 'command_buffer/service/gles2_cmd_validation.h',
+ 'command_buffer/service/gles2_cmd_validation.cc',
+ 'command_buffer/service/gles2_cmd_validation_autogen.h',
+ 'command_buffer/service/gles2_cmd_validation_implementation_autogen.h',
+ 'command_buffer/service/gl_context_virtual.cc',
+ 'command_buffer/service/gl_context_virtual.h',
+ 'command_buffer/service/gl_state_restorer_impl.cc',
+ 'command_buffer/service/gl_state_restorer_impl.h',
+ 'command_buffer/service/gl_utils.h',
+ 'command_buffer/service/gpu_scheduler.h',
+ 'command_buffer/service/gpu_scheduler.cc',
+ 'command_buffer/service/gpu_scheduler_mock.h',
+ 'command_buffer/service/gpu_switches.h',
+ 'command_buffer/service/gpu_switches.cc',
+ 'command_buffer/service/gpu_tracer.h',
+ 'command_buffer/service/gpu_tracer.cc',
+ 'command_buffer/service/id_manager.h',
+ 'command_buffer/service/id_manager.cc',
+ 'command_buffer/service/image_manager.cc',
+ 'command_buffer/service/image_manager.h',
+ 'command_buffer/service/in_process_command_buffer.cc',
+ 'command_buffer/service/in_process_command_buffer.h',
+ 'command_buffer/service/logger.cc',
+ 'command_buffer/service/logger.h',
+ 'command_buffer/service/mailbox_manager.cc',
+ 'command_buffer/service/mailbox_manager.h',
+ 'command_buffer/service/memory_program_cache.h',
+ 'command_buffer/service/memory_program_cache.cc',
+ 'command_buffer/service/mocks.h',
+ 'command_buffer/service/program_manager.h',
+ 'command_buffer/service/program_manager.cc',
+ 'command_buffer/service/query_manager.h',
+ 'command_buffer/service/query_manager.cc',
+ 'command_buffer/service/renderbuffer_manager.h',
+ 'command_buffer/service/renderbuffer_manager.cc',
+ 'command_buffer/service/program_cache.h',
+ 'command_buffer/service/program_cache.cc',
+ 'command_buffer/service/safe_shared_memory_pool.h',
+ 'command_buffer/service/safe_shared_memory_pool.cc',
+ 'command_buffer/service/shader_manager.h',
+ 'command_buffer/service/shader_manager.cc',
+ 'command_buffer/service/shader_translator.h',
+ 'command_buffer/service/shader_translator.cc',
+ 'command_buffer/service/shader_translator_cache.h',
+ 'command_buffer/service/shader_translator_cache.cc',
+ 'command_buffer/service/stream_texture.h',
+ 'command_buffer/service/stream_texture_manager.h',
+ 'command_buffer/service/texture_manager.h',
+ 'command_buffer/service/texture_manager.cc',
+ 'command_buffer/service/transfer_buffer_manager.cc',
+ 'command_buffer/service/transfer_buffer_manager.h',
+ 'command_buffer/service/vertex_array_manager.h',
+ 'command_buffer/service/vertex_array_manager.cc',
+ 'command_buffer/service/vertex_attrib_manager.h',
+ 'command_buffer/service/vertex_attrib_manager.cc',
+ ],
+ 'conditions': [
+ ['toolkit_uses_gtk == 1', {
+ 'dependencies': [
+ '../build/linux/system.gyp:gtk',
+ ],
+ }],
+ ['ui_compositor_image_transport==1', {
+ 'include_dirs': [
+ '../third_party/khronos',
+ ],
+ }],
+ ['OS in ("win", "android") or (OS == "linux" and use_x11 == 1)', {
+ 'sources': [
+ 'command_buffer/service/async_pixel_transfer_manager_egl.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_egl.h',
+ ],
+ }]
+ ],
+}
diff --git a/chromium/gpu/config/DEPS b/chromium/gpu/config/DEPS
new file mode 100644
index 00000000000..39b325a88df
--- /dev/null
+++ b/chromium/gpu/config/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+third_party/libxml", # For parsing WinSAT results files.
+ "+third_party/libXNVCtrl", # For NV driver version query.
+]
diff --git a/chromium/gpu/config/OWNERS b/chromium/gpu/config/OWNERS
new file mode 100644
index 00000000000..92ac85812fe
--- /dev/null
+++ b/chromium/gpu/config/OWNERS
@@ -0,0 +1,4 @@
+apatrick@chromium.org
+kbr@chromium.org
+piman@chromium.org
+zmo@chromium.org
diff --git a/chromium/gpu/config/dx_diag_node.cc b/chromium/gpu/config/dx_diag_node.cc
new file mode 100644
index 00000000000..c1e84ae4088
--- /dev/null
+++ b/chromium/gpu/config/dx_diag_node.cc
@@ -0,0 +1,17 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/dx_diag_node.h"
+
+#if defined(OS_WIN)
+
+namespace gpu {
+
+DxDiagNode::DxDiagNode() {}
+
+DxDiagNode::~DxDiagNode() {}
+
+} // namespace gpu
+
+#endif // defined(OS_WIN)
diff --git a/chromium/gpu/config/dx_diag_node.h b/chromium/gpu/config/dx_diag_node.h
new file mode 100644
index 00000000000..45ffa6599c5
--- /dev/null
+++ b/chromium/gpu/config/dx_diag_node.h
@@ -0,0 +1,31 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// A tree of name value pairs that report contain DirectX diagnostic
+// information.
+
+#ifndef GPU_CONFIG_DX_DIAG_NODE_H_
+#define GPU_CONFIG_DX_DIAG_NODE_H_
+
+#if defined(OS_WIN)
+
+#include <map>
+#include <string>
+
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+struct GPU_EXPORT DxDiagNode {
+ DxDiagNode();
+ ~DxDiagNode();
+ std::map<std::string, std::string> values;
+ std::map<std::string, DxDiagNode> children;
+};
+
+} // namespace gpu
+
+#endif // defined(OS_WIN)
+
+#endif // GPU_CONFIG_DX_DIAG_NODE_H_
diff --git a/chromium/gpu/config/gpu_blacklist.cc b/chromium/gpu/config/gpu_blacklist.cc
new file mode 100644
index 00000000000..39946b072cd
--- /dev/null
+++ b/chromium/gpu/config/gpu_blacklist.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_blacklist.h"
+
+#include "gpu/config/gpu_feature_type.h"
+
+namespace gpu {
+
+GpuBlacklist::GpuBlacklist()
+ : GpuControlList() {
+}
+
+GpuBlacklist::~GpuBlacklist() {
+}
+
+// static
+GpuBlacklist* GpuBlacklist::Create() {
+ GpuBlacklist* list = new GpuBlacklist();
+ list->AddSupportedFeature("accelerated_2d_canvas",
+ GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS);
+ list->AddSupportedFeature("accelerated_compositing",
+ GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING);
+ list->AddSupportedFeature("webgl",
+ GPU_FEATURE_TYPE_WEBGL);
+ list->AddSupportedFeature("multisampling",
+ GPU_FEATURE_TYPE_MULTISAMPLING);
+ list->AddSupportedFeature("flash_3d",
+ GPU_FEATURE_TYPE_FLASH3D);
+ list->AddSupportedFeature("flash_stage3d",
+ GPU_FEATURE_TYPE_FLASH_STAGE3D);
+ list->AddSupportedFeature("flash_stage3d_baseline",
+ GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE);
+ list->AddSupportedFeature("texture_sharing",
+ GPU_FEATURE_TYPE_TEXTURE_SHARING);
+ list->AddSupportedFeature("accelerated_video_decode",
+ GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE);
+ list->AddSupportedFeature("3d_css",
+ GPU_FEATURE_TYPE_3D_CSS);
+ list->AddSupportedFeature("accelerated_video",
+ GPU_FEATURE_TYPE_ACCELERATED_VIDEO);
+ list->AddSupportedFeature("panel_fitting",
+ GPU_FEATURE_TYPE_PANEL_FITTING);
+ list->AddSupportedFeature("force_compositing_mode",
+ GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE);
+ list->set_supports_feature_type_all(true);
+ return list;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_blacklist.h b/chromium/gpu/config/gpu_blacklist.h
new file mode 100644
index 00000000000..4311212e0d2
--- /dev/null
+++ b/chromium/gpu/config/gpu_blacklist.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_BLACKLIST_H_
+#define GPU_CONFIG_GPU_BLACKLIST_H_
+
+#include <string>
+
+#include "gpu/config/gpu_control_list.h"
+
+namespace gpu {
+
+class GPU_EXPORT GpuBlacklist : public GpuControlList {
+ public:
+ virtual ~GpuBlacklist();
+
+ static GpuBlacklist* Create();
+
+ private:
+ GpuBlacklist();
+
+ DISALLOW_COPY_AND_ASSIGN(GpuBlacklist);
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_BLACKLIST_H_
diff --git a/chromium/gpu/config/gpu_blacklist_unittest.cc b/chromium/gpu/config/gpu_blacklist_unittest.cc
new file mode 100644
index 00000000000..3282437d6d3
--- /dev/null
+++ b/chromium/gpu/config/gpu_blacklist_unittest.cc
@@ -0,0 +1,143 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/config/gpu_blacklist.h"
+#include "gpu/config/gpu_control_list_jsons.h"
+#include "gpu/config/gpu_feature_type.h"
+#include "gpu/config/gpu_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const char kOsVersion[] = "10.6.4";
+
+namespace gpu {
+
+class GpuBlacklistTest : public testing::Test {
+ public:
+ GpuBlacklistTest() { }
+
+ virtual ~GpuBlacklistTest() { }
+
+ const GPUInfo& gpu_info() const {
+ return gpu_info_;
+ }
+
+ void RunFeatureTest(
+ const std::string feature_name, GpuFeatureType feature_type) {
+ const std::string json =
+ "{\n"
+ " \"name\": \"gpu blacklist\",\n"
+ " \"version\": \"0.1\",\n"
+ " \"entries\": [\n"
+ " {\n"
+ " \"id\": 1,\n"
+ " \"os\": {\n"
+ " \"type\": \"macosx\"\n"
+ " },\n"
+ " \"vendor_id\": \"0x10de\",\n"
+ " \"device_id\": [\"0x0640\"],\n"
+ " \"features\": [\n"
+ " \"" +
+ feature_name +
+ "\"\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}";
+
+ scoped_ptr<GpuBlacklist> blacklist(GpuBlacklist::Create());
+ EXPECT_TRUE(blacklist->LoadList(json, GpuBlacklist::kAllOs));
+ std::set<int> type = blacklist->MakeDecision(
+ GpuBlacklist::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_EQ(1u, type.size());
+ EXPECT_EQ(1u, type.count(feature_type));
+ }
+
+ protected:
+ virtual void SetUp() {
+ gpu_info_.gpu.vendor_id = 0x10de;
+ gpu_info_.gpu.device_id = 0x0640;
+ gpu_info_.driver_vendor = "NVIDIA";
+ gpu_info_.driver_version = "1.6.18";
+ gpu_info_.driver_date = "7-14-2009";
+ gpu_info_.machine_model = "MacBookPro 7.1";
+ gpu_info_.gl_vendor = "NVIDIA Corporation";
+ gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
+ gpu_info_.performance_stats.graphics = 5.0;
+ gpu_info_.performance_stats.gaming = 5.0;
+ gpu_info_.performance_stats.overall = 5.0;
+ }
+
+ virtual void TearDown() {
+ }
+
+ private:
+ GPUInfo gpu_info_;
+};
+
+TEST_F(GpuBlacklistTest, CurrentBlacklistValidation) {
+ scoped_ptr<GpuBlacklist> blacklist(GpuBlacklist::Create());
+ EXPECT_TRUE(blacklist->LoadList(
+ kSoftwareRenderingListJson, GpuBlacklist::kAllOs));
+ EXPECT_FALSE(blacklist->contains_unknown_fields());
+}
+
+#define GPU_BLACKLIST_FEATURE_TEST(test_name, feature_name, feature_type) \
+TEST_F(GpuBlacklistTest, test_name) { \
+ RunFeatureTest(feature_name, feature_type); \
+}
+
+GPU_BLACKLIST_FEATURE_TEST(Accelerated2DCanvas,
+ "accelerated_2d_canvas",
+ GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS)
+
+GPU_BLACKLIST_FEATURE_TEST(AcceleratedCompositing,
+ "accelerated_compositing",
+ GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING)
+
+GPU_BLACKLIST_FEATURE_TEST(WebGL,
+ "webgl",
+ GPU_FEATURE_TYPE_WEBGL)
+
+GPU_BLACKLIST_FEATURE_TEST(Multisampling,
+ "multisampling",
+ GPU_FEATURE_TYPE_MULTISAMPLING)
+
+GPU_BLACKLIST_FEATURE_TEST(Flash3D,
+ "flash_3d",
+ GPU_FEATURE_TYPE_FLASH3D)
+
+GPU_BLACKLIST_FEATURE_TEST(FlashStage3D,
+ "flash_stage3d",
+ GPU_FEATURE_TYPE_FLASH_STAGE3D)
+
+GPU_BLACKLIST_FEATURE_TEST(FlashStage3DBaseline,
+ "flash_stage3d_baseline",
+ GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE)
+
+GPU_BLACKLIST_FEATURE_TEST(TextureSharing,
+ "texture_sharing",
+ GPU_FEATURE_TYPE_TEXTURE_SHARING)
+
+GPU_BLACKLIST_FEATURE_TEST(AcceleratedVideoDecode,
+ "accelerated_video_decode",
+ GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE)
+
+GPU_BLACKLIST_FEATURE_TEST(Css3D,
+ "3d_css",
+ GPU_FEATURE_TYPE_3D_CSS)
+
+GPU_BLACKLIST_FEATURE_TEST(AcceleratedVideo,
+ "accelerated_video",
+ GPU_FEATURE_TYPE_ACCELERATED_VIDEO)
+
+GPU_BLACKLIST_FEATURE_TEST(PanelFitting,
+ "panel_fitting",
+ GPU_FEATURE_TYPE_PANEL_FITTING)
+
+GPU_BLACKLIST_FEATURE_TEST(ForceCompositingMode,
+ "force_compositing_mode",
+ GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE)
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_control_list.cc b/chromium/gpu/config/gpu_control_list.cc
new file mode 100644
index 00000000000..5eb09c489f1
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list.cc
@@ -0,0 +1,1450 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_control_list.h"
+
+#include "base/cpu.h"
+#include "base/json/json_reader.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/sys_info.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_util.h"
+
+namespace gpu {
+namespace {
+
+// Break a version string into segments. Return true if each segment is
+// a valid number.
+bool ProcessVersionString(const std::string& version_string,
+ char splitter,
+ std::vector<std::string>* version) {
+ DCHECK(version);
+ base::SplitString(version_string, splitter, version);
+ if (version->size() == 0)
+ return false;
+ // If the splitter is '-', we assume it's a date with format "mm-dd-yyyy";
+ // we split it into the order of "yyyy", "mm", "dd".
+ if (splitter == '-') {
+ std::string year = (*version)[version->size() - 1];
+ for (int i = version->size() - 1; i > 0; --i) {
+ (*version)[i] = (*version)[i - 1];
+ }
+ (*version)[0] = year;
+ }
+ for (size_t i = 0; i < version->size(); ++i) {
+ unsigned num = 0;
+ if (!base::StringToUint((*version)[i], &num))
+ return false;
+ }
+ return true;
+}
+
+// Compare two number strings using numerical ordering.
+// Return 0 if number = number_ref,
+// 1 if number > number_ref,
+// -1 if number < number_ref.
+int CompareNumericalNumberStrings(
+ const std::string& number, const std::string& number_ref) {
+ unsigned value1 = 0;
+ unsigned value2 = 0;
+ bool valid = base::StringToUint(number, &value1);
+ DCHECK(valid);
+ valid = base::StringToUint(number_ref, &value2);
+ DCHECK(valid);
+ if (value1 == value2)
+ return 0;
+ if (value1 > value2)
+ return 1;
+ return -1;
+}
+
+// Compare two number strings using lexical ordering.
+// Return 0 if number = number_ref,
+// 1 if number > number_ref,
+// -1 if number < number_ref.
+// We only compare as many digits as number_ref contains.
+// If number_ref is xxx, it's considered as xxx*
+// For example: CompareLexicalNumberStrings("121", "12") returns 0,
+// CompareLexicalNumberStrings("12", "121") returns -1.
+int CompareLexicalNumberStrings(
+ const std::string& number, const std::string& number_ref) {
+ for (size_t i = 0; i < number_ref.length(); ++i) {
+ unsigned value1 = 0;
+ if (i < number.length())
+ value1 = number[i] - '0';
+ unsigned value2 = number_ref[i] - '0';
+ if (value1 > value2)
+ return 1;
+ if (value1 < value2)
+ return -1;
+ }
+ return 0;
+}
+
+bool GpuUnmatched(uint32 vendor_id, const std::vector<uint32>& device_id_list,
+ const GPUInfo::GPUDevice& gpu) {
+ if (vendor_id == 0)
+ return false;
+ if (vendor_id != gpu.vendor_id)
+ return true;
+ bool device_specified = false;
+ for (size_t i = 0; i < device_id_list.size(); ++i) {
+ if (device_id_list[i] == 0)
+ continue;
+ if (device_id_list[i] == gpu.device_id)
+ return false;
+ device_specified = true;
+ }
+ return device_specified;
+}
+
+const char kMultiGpuStyleStringAMDSwitchable[] = "amd_switchable";
+const char kMultiGpuStyleStringOptimus[] = "optimus";
+
+const char kMultiGpuCategoryStringPrimary[] = "primary";
+const char kMultiGpuCategoryStringSecondary[] = "secondary";
+const char kMultiGpuCategoryStringAny[] = "any";
+
+const char kVersionStyleStringNumerical[] = "numerical";
+const char kVersionStyleStringLexical[] = "lexical";
+
+const char kOp[] = "op";
+
+} // namespace anonymous
+
+GpuControlList::VersionInfo::VersionInfo(
+ const std::string& version_op,
+ const std::string& version_style,
+ const std::string& version_string,
+ const std::string& version_string2)
+ : version_style_(kVersionStyleNumerical) {
+ op_ = StringToNumericOp(version_op);
+ if (op_ == kUnknown || op_ == kAny)
+ return;
+ version_style_ = StringToVersionStyle(version_style);
+ if (!ProcessVersionString(version_string, '.', &version_)) {
+ op_ = kUnknown;
+ return;
+ }
+ if (op_ == kBetween) {
+ if (!ProcessVersionString(version_string2, '.', &version2_))
+ op_ = kUnknown;
+ }
+}
+
+GpuControlList::VersionInfo::~VersionInfo() {
+}
+
+bool GpuControlList::VersionInfo::Contains(
+ const std::string& version_string) const {
+ return Contains(version_string, '.');
+}
+
+bool GpuControlList::VersionInfo::Contains(
+ const std::string& version_string, char splitter) const {
+ if (op_ == kUnknown)
+ return false;
+ if (op_ == kAny)
+ return true;
+ std::vector<std::string> version;
+ if (!ProcessVersionString(version_string, splitter, &version))
+ return false;
+ int relation = Compare(version, version_, version_style_);
+ if (op_ == kEQ)
+ return (relation == 0);
+ else if (op_ == kLT)
+ return (relation < 0);
+ else if (op_ == kLE)
+ return (relation <= 0);
+ else if (op_ == kGT)
+ return (relation > 0);
+ else if (op_ == kGE)
+ return (relation >= 0);
+ // op_ == kBetween
+ if (relation < 0)
+ return false;
+ return Compare(version, version2_, version_style_) <= 0;
+}
+
+bool GpuControlList::VersionInfo::IsValid() const {
+ return (op_ != kUnknown && version_style_ != kVersionStyleUnknown);
+}
+
+bool GpuControlList::VersionInfo::IsLexical() const {
+ return version_style_ == kVersionStyleLexical;
+}
+
+// static
+int GpuControlList::VersionInfo::Compare(
+ const std::vector<std::string>& version,
+ const std::vector<std::string>& version_ref,
+ VersionStyle version_style) {
+ DCHECK(version.size() > 0 && version_ref.size() > 0);
+ DCHECK(version_style != kVersionStyleUnknown);
+ for (size_t i = 0; i < version_ref.size(); ++i) {
+ if (i >= version.size())
+ return 0;
+ int ret = 0;
+ // We assume both versions are checked by ProcessVersionString().
+ if (i > 0 && version_style == kVersionStyleLexical)
+ ret = CompareLexicalNumberStrings(version[i], version_ref[i]);
+ else
+ ret = CompareNumericalNumberStrings(version[i], version_ref[i]);
+ if (ret != 0)
+ return ret;
+ }
+ return 0;
+}
+
+// static
+GpuControlList::VersionInfo::VersionStyle
+GpuControlList::VersionInfo::StringToVersionStyle(
+ const std::string& version_style) {
+ if (version_style.empty() || version_style == kVersionStyleStringNumerical)
+ return kVersionStyleNumerical;
+ if (version_style == kVersionStyleStringLexical)
+ return kVersionStyleLexical;
+ return kVersionStyleUnknown;
+}
+
+GpuControlList::OsInfo::OsInfo(const std::string& os,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2) {
+ type_ = StringToOsType(os);
+ if (type_ != kOsUnknown) {
+ version_info_.reset(new VersionInfo(
+ version_op, std::string(), version_string, version_string2));
+ }
+}
+
+GpuControlList::OsInfo::~OsInfo() {}
+
+bool GpuControlList::OsInfo::Contains(OsType type,
+ const std::string& version) const {
+ if (!IsValid())
+ return false;
+ if (type_ != type && type_ != kOsAny)
+ return false;
+ return version_info_->Contains(version);
+}
+
+bool GpuControlList::OsInfo::IsValid() const {
+ return type_ != kOsUnknown && version_info_->IsValid();
+}
+
+GpuControlList::OsType GpuControlList::OsInfo::type() const {
+ return type_;
+}
+
+GpuControlList::OsType GpuControlList::OsInfo::StringToOsType(
+ const std::string& os) {
+ if (os == "win")
+ return kOsWin;
+ else if (os == "macosx")
+ return kOsMacosx;
+ else if (os == "android")
+ return kOsAndroid;
+ else if (os == "linux")
+ return kOsLinux;
+ else if (os == "chromeos")
+ return kOsChromeOS;
+ else if (os == "any")
+ return kOsAny;
+ return kOsUnknown;
+}
+
+GpuControlList::MachineModelInfo::MachineModelInfo(
+ const std::string& name_op,
+ const std::string& name_value,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2) {
+ name_info_.reset(new StringInfo(name_op, name_value));
+ version_info_.reset(new VersionInfo(
+ version_op, std::string(), version_string, version_string2));
+}
+
+GpuControlList::MachineModelInfo::~MachineModelInfo() {}
+
+bool GpuControlList::MachineModelInfo::Contains(
+ const std::string& name, const std::string& version) const {
+ if (!IsValid())
+ return false;
+ if (!name_info_->Contains(name))
+ return false;
+ return version_info_->Contains(version);
+}
+
+bool GpuControlList::MachineModelInfo::IsValid() const {
+ return name_info_->IsValid() && version_info_->IsValid();
+}
+
+GpuControlList::StringInfo::StringInfo(const std::string& string_op,
+ const std::string& string_value) {
+ op_ = StringToOp(string_op);
+ value_ = StringToLowerASCII(string_value);
+}
+
+bool GpuControlList::StringInfo::Contains(const std::string& value) const {
+ std::string my_value = StringToLowerASCII(value);
+ switch (op_) {
+ case kContains:
+ return strstr(my_value.c_str(), value_.c_str()) != NULL;
+ case kBeginWith:
+ return StartsWithASCII(my_value, value_, false);
+ case kEndWith:
+ return EndsWith(my_value, value_, false);
+ case kEQ:
+ return value_ == my_value;
+ default:
+ return false;
+ }
+}
+
+bool GpuControlList::StringInfo::IsValid() const {
+ return op_ != kUnknown;
+}
+
+GpuControlList::StringInfo::Op GpuControlList::StringInfo::StringToOp(
+ const std::string& string_op) {
+ if (string_op == "=")
+ return kEQ;
+ else if (string_op == "contains")
+ return kContains;
+ else if (string_op == "beginwith")
+ return kBeginWith;
+ else if (string_op == "endwith")
+ return kEndWith;
+ return kUnknown;
+}
+
+GpuControlList::FloatInfo::FloatInfo(const std::string& float_op,
+ const std::string& float_value,
+ const std::string& float_value2)
+ : op_(kUnknown),
+ value_(0.f),
+ value2_(0.f) {
+ op_ = StringToNumericOp(float_op);
+ if (op_ == kAny)
+ return;
+ double dvalue = 0;
+ if (!base::StringToDouble(float_value, &dvalue)) {
+ op_ = kUnknown;
+ return;
+ }
+ value_ = static_cast<float>(dvalue);
+ if (op_ == kBetween) {
+ if (!base::StringToDouble(float_value2, &dvalue)) {
+ op_ = kUnknown;
+ return;
+ }
+ value2_ = static_cast<float>(dvalue);
+ }
+}
+
+bool GpuControlList::FloatInfo::Contains(float value) const {
+ if (op_ == kUnknown)
+ return false;
+ if (op_ == kAny)
+ return true;
+ if (op_ == kEQ)
+ return (value == value_);
+ if (op_ == kLT)
+ return (value < value_);
+ if (op_ == kLE)
+ return (value <= value_);
+ if (op_ == kGT)
+ return (value > value_);
+ if (op_ == kGE)
+ return (value >= value_);
+ DCHECK(op_ == kBetween);
+ return ((value_ <= value && value <= value2_) ||
+ (value2_ <= value && value <= value_));
+}
+
+bool GpuControlList::FloatInfo::IsValid() const {
+ return op_ != kUnknown;
+}
+
+GpuControlList::IntInfo::IntInfo(const std::string& int_op,
+ const std::string& int_value,
+ const std::string& int_value2)
+ : op_(kUnknown),
+ value_(0),
+ value2_(0) {
+ op_ = StringToNumericOp(int_op);
+ if (op_ == kAny)
+ return;
+ if (!base::StringToInt(int_value, &value_)) {
+ op_ = kUnknown;
+ return;
+ }
+ if (op_ == kBetween &&
+ !base::StringToInt(int_value2, &value2_))
+ op_ = kUnknown;
+}
+
+bool GpuControlList::IntInfo::Contains(int value) const {
+ if (op_ == kUnknown)
+ return false;
+ if (op_ == kAny)
+ return true;
+ if (op_ == kEQ)
+ return (value == value_);
+ if (op_ == kLT)
+ return (value < value_);
+ if (op_ == kLE)
+ return (value <= value_);
+ if (op_ == kGT)
+ return (value > value_);
+ if (op_ == kGE)
+ return (value >= value_);
+ DCHECK(op_ == kBetween);
+ return ((value_ <= value && value <= value2_) ||
+ (value2_ <= value && value <= value_));
+}
+
+bool GpuControlList::IntInfo::IsValid() const {
+ return op_ != kUnknown;
+}
+
+// static
+GpuControlList::ScopedGpuControlListEntry
+GpuControlList::GpuControlListEntry::GetEntryFromValue(
+ const base::DictionaryValue* value, bool top_level,
+ const FeatureMap& feature_map,
+ bool supports_feature_type_all) {
+ DCHECK(value);
+ ScopedGpuControlListEntry entry(new GpuControlListEntry());
+
+ size_t dictionary_entry_count = 0;
+
+ if (top_level) {
+ uint32 id;
+ if (!value->GetInteger("id", reinterpret_cast<int*>(&id)) ||
+ !entry->SetId(id)) {
+ LOG(WARNING) << "Malformed id entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+
+ bool disabled;
+ if (value->GetBoolean("disabled", &disabled)) {
+ entry->SetDisabled(disabled);
+ dictionary_entry_count++;
+ }
+ }
+
+ std::string description;
+ if (value->GetString("description", &description)) {
+ entry->description_ = description;
+ dictionary_entry_count++;
+ } else {
+ entry->description_ = "The GPU is unavailable for an unexplained reason.";
+ }
+
+ const base::ListValue* cr_bugs;
+ if (value->GetList("cr_bugs", &cr_bugs)) {
+ for (size_t i = 0; i < cr_bugs->GetSize(); ++i) {
+ int bug_id;
+ if (cr_bugs->GetInteger(i, &bug_id)) {
+ entry->cr_bugs_.push_back(bug_id);
+ } else {
+ LOG(WARNING) << "Malformed cr_bugs entry " << entry->id();
+ return NULL;
+ }
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::ListValue* webkit_bugs;
+ if (value->GetList("webkit_bugs", &webkit_bugs)) {
+ for (size_t i = 0; i < webkit_bugs->GetSize(); ++i) {
+ int bug_id;
+ if (webkit_bugs->GetInteger(i, &bug_id)) {
+ entry->webkit_bugs_.push_back(bug_id);
+ } else {
+ LOG(WARNING) << "Malformed webkit_bugs entry " << entry->id();
+ return NULL;
+ }
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* os_value = NULL;
+ if (value->GetDictionary("os", &os_value)) {
+ std::string os_type;
+ std::string os_version_op = "any";
+ std::string os_version_string;
+ std::string os_version_string2;
+ os_value->GetString("type", &os_type);
+ const base::DictionaryValue* os_version_value = NULL;
+ if (os_value->GetDictionary("version", &os_version_value)) {
+ os_version_value->GetString(kOp, &os_version_op);
+ os_version_value->GetString("number", &os_version_string);
+ os_version_value->GetString("number2", &os_version_string2);
+ }
+ if (!entry->SetOsInfo(os_type, os_version_op, os_version_string,
+ os_version_string2)) {
+ LOG(WARNING) << "Malformed os entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ std::string vendor_id;
+ if (value->GetString("vendor_id", &vendor_id)) {
+ if (!entry->SetVendorId(vendor_id)) {
+ LOG(WARNING) << "Malformed vendor_id entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::ListValue* device_id_list;
+ if (value->GetList("device_id", &device_id_list)) {
+ for (size_t i = 0; i < device_id_list->GetSize(); ++i) {
+ std::string device_id;
+ if (!device_id_list->GetString(i, &device_id) ||
+ !entry->AddDeviceId(device_id)) {
+ LOG(WARNING) << "Malformed device_id entry " << entry->id();
+ return NULL;
+ }
+ }
+ dictionary_entry_count++;
+ }
+
+ std::string multi_gpu_style;
+ if (value->GetString("multi_gpu_style", &multi_gpu_style)) {
+ if (!entry->SetMultiGpuStyle(multi_gpu_style)) {
+ LOG(WARNING) << "Malformed multi_gpu_style entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ std::string multi_gpu_category;
+ if (value->GetString("multi_gpu_category", &multi_gpu_category)) {
+ if (!entry->SetMultiGpuCategory(multi_gpu_category)) {
+ LOG(WARNING) << "Malformed multi_gpu_category entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* driver_vendor_value = NULL;
+ if (value->GetDictionary("driver_vendor", &driver_vendor_value)) {
+ std::string vendor_op;
+ std::string vendor_value;
+ driver_vendor_value->GetString(kOp, &vendor_op);
+ driver_vendor_value->GetString("value", &vendor_value);
+ if (!entry->SetDriverVendorInfo(vendor_op, vendor_value)) {
+ LOG(WARNING) << "Malformed driver_vendor entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* driver_version_value = NULL;
+ if (value->GetDictionary("driver_version", &driver_version_value)) {
+ std::string driver_version_op = "any";
+ std::string driver_version_style;
+ std::string driver_version_string;
+ std::string driver_version_string2;
+ driver_version_value->GetString(kOp, &driver_version_op);
+ driver_version_value->GetString("style", &driver_version_style);
+ driver_version_value->GetString("number", &driver_version_string);
+ driver_version_value->GetString("number2", &driver_version_string2);
+ if (!entry->SetDriverVersionInfo(driver_version_op,
+ driver_version_style,
+ driver_version_string,
+ driver_version_string2)) {
+ LOG(WARNING) << "Malformed driver_version entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* driver_date_value = NULL;
+ if (value->GetDictionary("driver_date", &driver_date_value)) {
+ std::string driver_date_op = "any";
+ std::string driver_date_string;
+ std::string driver_date_string2;
+ driver_date_value->GetString(kOp, &driver_date_op);
+ driver_date_value->GetString("number", &driver_date_string);
+ driver_date_value->GetString("number2", &driver_date_string2);
+ if (!entry->SetDriverDateInfo(driver_date_op, driver_date_string,
+ driver_date_string2)) {
+ LOG(WARNING) << "Malformed driver_date entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* gl_vendor_value = NULL;
+ if (value->GetDictionary("gl_vendor", &gl_vendor_value)) {
+ std::string vendor_op;
+ std::string vendor_value;
+ gl_vendor_value->GetString(kOp, &vendor_op);
+ gl_vendor_value->GetString("value", &vendor_value);
+ if (!entry->SetGLVendorInfo(vendor_op, vendor_value)) {
+ LOG(WARNING) << "Malformed gl_vendor entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* gl_renderer_value = NULL;
+ if (value->GetDictionary("gl_renderer", &gl_renderer_value)) {
+ std::string renderer_op;
+ std::string renderer_value;
+ gl_renderer_value->GetString(kOp, &renderer_op);
+ gl_renderer_value->GetString("value", &renderer_value);
+ if (!entry->SetGLRendererInfo(renderer_op, renderer_value)) {
+ LOG(WARNING) << "Malformed gl_renderer entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* gl_extensions_value = NULL;
+ if (value->GetDictionary("gl_extensions", &gl_extensions_value)) {
+ std::string extensions_op;
+ std::string extensions_value;
+ gl_extensions_value->GetString(kOp, &extensions_op);
+ gl_extensions_value->GetString("value", &extensions_value);
+ if (!entry->SetGLExtensionsInfo(extensions_op, extensions_value)) {
+ LOG(WARNING) << "Malformed gl_extensions entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* gl_reset_notification_strategy_value = NULL;
+ if (value->GetDictionary("gl_reset_notification_strategy",
+ &gl_reset_notification_strategy_value)) {
+ std::string op;
+ std::string int_value;
+ std::string int_value2;
+ gl_reset_notification_strategy_value->GetString(kOp, &op);
+ gl_reset_notification_strategy_value->GetString("value", &int_value);
+ gl_reset_notification_strategy_value->GetString("value2", &int_value2);
+ if (!entry->SetGLResetNotificationStrategyInfo(
+ op, int_value, int_value2)) {
+ LOG(WARNING) << "Malformed gl_reset_notification_strategy entry "
+ << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* cpu_brand_value = NULL;
+ if (value->GetDictionary("cpu_info", &cpu_brand_value)) {
+ std::string cpu_op;
+ std::string cpu_value;
+ cpu_brand_value->GetString(kOp, &cpu_op);
+ cpu_brand_value->GetString("value", &cpu_value);
+ if (!entry->SetCpuBrand(cpu_op, cpu_value)) {
+ LOG(WARNING) << "Malformed cpu_brand entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* perf_graphics_value = NULL;
+ if (value->GetDictionary("perf_graphics", &perf_graphics_value)) {
+ std::string op;
+ std::string float_value;
+ std::string float_value2;
+ perf_graphics_value->GetString(kOp, &op);
+ perf_graphics_value->GetString("value", &float_value);
+ perf_graphics_value->GetString("value2", &float_value2);
+ if (!entry->SetPerfGraphicsInfo(op, float_value, float_value2)) {
+ LOG(WARNING) << "Malformed perf_graphics entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* perf_gaming_value = NULL;
+ if (value->GetDictionary("perf_gaming", &perf_gaming_value)) {
+ std::string op;
+ std::string float_value;
+ std::string float_value2;
+ perf_gaming_value->GetString(kOp, &op);
+ perf_gaming_value->GetString("value", &float_value);
+ perf_gaming_value->GetString("value2", &float_value2);
+ if (!entry->SetPerfGamingInfo(op, float_value, float_value2)) {
+ LOG(WARNING) << "Malformed perf_gaming entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* perf_overall_value = NULL;
+ if (value->GetDictionary("perf_overall", &perf_overall_value)) {
+ std::string op;
+ std::string float_value;
+ std::string float_value2;
+ perf_overall_value->GetString(kOp, &op);
+ perf_overall_value->GetString("value", &float_value);
+ perf_overall_value->GetString("value2", &float_value2);
+ if (!entry->SetPerfOverallInfo(op, float_value, float_value2)) {
+ LOG(WARNING) << "Malformed perf_overall entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* machine_model_value = NULL;
+ if (value->GetDictionary("machine_model", &machine_model_value)) {
+ std::string name_op;
+ std::string name_value;
+ const base::DictionaryValue* name = NULL;
+ if (machine_model_value->GetDictionary("name", &name)) {
+ name->GetString(kOp, &name_op);
+ name->GetString("value", &name_value);
+ }
+
+ std::string version_op = "any";
+ std::string version_string;
+ std::string version_string2;
+ const base::DictionaryValue* version_value = NULL;
+ if (machine_model_value->GetDictionary("version", &version_value)) {
+ version_value->GetString(kOp, &version_op);
+ version_value->GetString("number", &version_string);
+ version_value->GetString("number2", &version_string2);
+ }
+ if (!entry->SetMachineModelInfo(
+ name_op, name_value, version_op, version_string, version_string2)) {
+ LOG(WARNING) << "Malformed machine_model entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* gpu_count_value = NULL;
+ if (value->GetDictionary("gpu_count", &gpu_count_value)) {
+ std::string op;
+ std::string int_value;
+ std::string int_value2;
+ gpu_count_value->GetString(kOp, &op);
+ gpu_count_value->GetString("value", &int_value);
+ gpu_count_value->GetString("value2", &int_value2);
+ if (!entry->SetGpuCountInfo(op, int_value, int_value2)) {
+ LOG(WARNING) << "Malformed gpu_count entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+
+ if (top_level) {
+ const base::ListValue* feature_value = NULL;
+ if (value->GetList("features", &feature_value)) {
+ std::vector<std::string> feature_list;
+ for (size_t i = 0; i < feature_value->GetSize(); ++i) {
+ std::string feature;
+ if (feature_value->GetString(i, &feature)) {
+ feature_list.push_back(feature);
+ } else {
+ LOG(WARNING) << "Malformed feature entry " << entry->id();
+ return NULL;
+ }
+ }
+ if (!entry->SetFeatures(
+ feature_list, feature_map, supports_feature_type_all)) {
+ LOG(WARNING) << "Malformed feature entry " << entry->id();
+ return NULL;
+ }
+ dictionary_entry_count++;
+ }
+ }
+
+ if (top_level) {
+ const base::ListValue* exception_list_value = NULL;
+ if (value->GetList("exceptions", &exception_list_value)) {
+ for (size_t i = 0; i < exception_list_value->GetSize(); ++i) {
+ const base::DictionaryValue* exception_value = NULL;
+ if (!exception_list_value->GetDictionary(i, &exception_value)) {
+ LOG(WARNING) << "Malformed exceptions entry " << entry->id();
+ return NULL;
+ }
+ ScopedGpuControlListEntry exception(GetEntryFromValue(
+ exception_value, false, feature_map, supports_feature_type_all));
+ if (exception.get() == NULL) {
+ LOG(WARNING) << "Malformed exceptions entry " << entry->id();
+ return NULL;
+ }
+ // Exception should inherit vendor_id from parent, otherwise if only
+ // device_ids are specified in Exception, the info will be incomplete.
+ if (exception->vendor_id_ == 0 && entry->vendor_id_ != 0)
+ exception->vendor_id_ = entry->vendor_id_;
+ if (exception->contains_unknown_fields_) {
+ LOG(WARNING) << "Exception with unknown fields " << entry->id();
+ entry->contains_unknown_fields_ = true;
+ } else {
+ entry->AddException(exception);
+ }
+ }
+ dictionary_entry_count++;
+ }
+
+ const base::DictionaryValue* browser_version_value = NULL;
+ // browser_version is processed in LoadGpuControlList().
+ if (value->GetDictionary("browser_version", &browser_version_value))
+ dictionary_entry_count++;
+ }
+
+ if (value->size() != dictionary_entry_count) {
+ LOG(WARNING) << "Entry with unknown fields " << entry->id();
+ entry->contains_unknown_fields_ = true;
+ }
+ return entry;
+}
+
+GpuControlList::GpuControlListEntry::GpuControlListEntry()
+ : id_(0),
+ disabled_(false),
+ vendor_id_(0),
+ multi_gpu_style_(kMultiGpuStyleNone),
+ multi_gpu_category_(kMultiGpuCategoryPrimary),
+ contains_unknown_fields_(false),
+ contains_unknown_features_(false) {
+}
+
+GpuControlList::GpuControlListEntry::~GpuControlListEntry() { }
+
+bool GpuControlList::GpuControlListEntry::SetId(uint32 id) {
+ if (id != 0) {
+ id_ = id;
+ return true;
+ }
+ return false;
+}
+
+void GpuControlList::GpuControlListEntry::SetDisabled(bool disabled) {
+ disabled_ = disabled;
+}
+
+bool GpuControlList::GpuControlListEntry::SetOsInfo(
+ const std::string& os,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2) {
+ os_info_.reset(new OsInfo(os, version_op, version_string, version_string2));
+ return os_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetVendorId(
+ const std::string& vendor_id_string) {
+ vendor_id_ = 0;
+ return base::HexStringToInt(vendor_id_string,
+ reinterpret_cast<int*>(&vendor_id_));
+}
+
+bool GpuControlList::GpuControlListEntry::AddDeviceId(
+ const std::string& device_id_string) {
+ uint32 device_id = 0;
+ if (base::HexStringToInt(device_id_string,
+ reinterpret_cast<int*>(&device_id))) {
+ device_id_list_.push_back(device_id);
+ return true;
+ }
+ return false;
+}
+
+bool GpuControlList::GpuControlListEntry::SetMultiGpuStyle(
+ const std::string& multi_gpu_style_string) {
+ MultiGpuStyle style = StringToMultiGpuStyle(multi_gpu_style_string);
+ if (style == kMultiGpuStyleNone)
+ return false;
+ multi_gpu_style_ = style;
+ return true;
+}
+
+bool GpuControlList::GpuControlListEntry::SetMultiGpuCategory(
+ const std::string& multi_gpu_category_string) {
+ MultiGpuCategory category =
+ StringToMultiGpuCategory(multi_gpu_category_string);
+ if (category == kMultiGpuCategoryNone)
+ return false;
+ multi_gpu_category_ = category;
+ return true;
+}
+
+bool GpuControlList::GpuControlListEntry::SetDriverVendorInfo(
+ const std::string& vendor_op,
+ const std::string& vendor_value) {
+ driver_vendor_info_.reset(new StringInfo(vendor_op, vendor_value));
+ return driver_vendor_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetDriverVersionInfo(
+ const std::string& version_op,
+ const std::string& version_style,
+ const std::string& version_string,
+ const std::string& version_string2) {
+ driver_version_info_.reset(new VersionInfo(
+ version_op, version_style, version_string, version_string2));
+ return driver_version_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetDriverDateInfo(
+ const std::string& date_op,
+ const std::string& date_string,
+ const std::string& date_string2) {
+ driver_date_info_.reset(
+ new VersionInfo(date_op, std::string(), date_string, date_string2));
+ return driver_date_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetGLVendorInfo(
+ const std::string& vendor_op,
+ const std::string& vendor_value) {
+ gl_vendor_info_.reset(new StringInfo(vendor_op, vendor_value));
+ return gl_vendor_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetGLRendererInfo(
+ const std::string& renderer_op,
+ const std::string& renderer_value) {
+ gl_renderer_info_.reset(new StringInfo(renderer_op, renderer_value));
+ return gl_renderer_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetGLExtensionsInfo(
+ const std::string& extensions_op,
+ const std::string& extensions_value) {
+ gl_extensions_info_.reset(new StringInfo(extensions_op, extensions_value));
+ return gl_extensions_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetGLResetNotificationStrategyInfo(
+ const std::string& op,
+ const std::string& int_string,
+ const std::string& int_string2) {
+ gl_reset_notification_strategy_info_.reset(
+ new IntInfo(op, int_string, int_string2));
+ return gl_reset_notification_strategy_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetCpuBrand(
+ const std::string& cpu_op,
+ const std::string& cpu_value) {
+ cpu_brand_.reset(new StringInfo(cpu_op, cpu_value));
+ return cpu_brand_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetPerfGraphicsInfo(
+ const std::string& op,
+ const std::string& float_string,
+ const std::string& float_string2) {
+ perf_graphics_info_.reset(new FloatInfo(op, float_string, float_string2));
+ return perf_graphics_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetPerfGamingInfo(
+ const std::string& op,
+ const std::string& float_string,
+ const std::string& float_string2) {
+ perf_gaming_info_.reset(new FloatInfo(op, float_string, float_string2));
+ return perf_gaming_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetPerfOverallInfo(
+ const std::string& op,
+ const std::string& float_string,
+ const std::string& float_string2) {
+ perf_overall_info_.reset(new FloatInfo(op, float_string, float_string2));
+ return perf_overall_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetMachineModelInfo(
+ const std::string& name_op,
+ const std::string& name_value,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2) {
+ machine_model_info_.reset(new MachineModelInfo(
+ name_op, name_value, version_op, version_string, version_string2));
+ return machine_model_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetGpuCountInfo(
+ const std::string& op,
+ const std::string& int_string,
+ const std::string& int_string2) {
+ gpu_count_info_.reset(new IntInfo(op, int_string, int_string2));
+ return gpu_count_info_->IsValid();
+}
+
+bool GpuControlList::GpuControlListEntry::SetFeatures(
+ const std::vector<std::string>& feature_strings,
+ const FeatureMap& feature_map,
+ bool supports_feature_type_all) {
+ size_t size = feature_strings.size();
+ if (size == 0)
+ return false;
+ features_.clear();
+ for (size_t i = 0; i < size; ++i) {
+ int feature = 0;
+ if (supports_feature_type_all && feature_strings[i] == "all") {
+ for (FeatureMap::const_iterator iter = feature_map.begin();
+ iter != feature_map.end(); ++iter)
+ features_.insert(iter->second);
+ continue;
+ }
+ if (StringToFeature(feature_strings[i], &feature, feature_map))
+ features_.insert(feature);
+ else
+ contains_unknown_features_ = true;
+ }
+ return true;
+}
+
+void GpuControlList::GpuControlListEntry::AddException(
+ ScopedGpuControlListEntry exception) {
+ exceptions_.push_back(exception);
+}
+
+// static
+GpuControlList::GpuControlListEntry::MultiGpuStyle
+GpuControlList::GpuControlListEntry::StringToMultiGpuStyle(
+ const std::string& style) {
+ if (style == kMultiGpuStyleStringOptimus)
+ return kMultiGpuStyleOptimus;
+ if (style == kMultiGpuStyleStringAMDSwitchable)
+ return kMultiGpuStyleAMDSwitchable;
+ return kMultiGpuStyleNone;
+}
+
+// static
+GpuControlList::GpuControlListEntry::MultiGpuCategory
+GpuControlList::GpuControlListEntry::StringToMultiGpuCategory(
+ const std::string& category) {
+ if (category == kMultiGpuCategoryStringPrimary)
+ return kMultiGpuCategoryPrimary;
+ if (category == kMultiGpuCategoryStringSecondary)
+ return kMultiGpuCategorySecondary;
+ if (category == kMultiGpuCategoryStringAny)
+ return kMultiGpuCategoryAny;
+ return kMultiGpuCategoryNone;
+}
+
+bool GpuControlList::GpuControlListEntry::Contains(
+ OsType os_type, const std::string& os_version,
+ const GPUInfo& gpu_info) const {
+ DCHECK(os_type != kOsAny);
+ if (os_info_.get() != NULL && !os_info_->Contains(os_type, os_version))
+ return false;
+ bool is_not_primary_gpu =
+ GpuUnmatched(vendor_id_, device_id_list_, gpu_info.gpu);
+ bool is_not_secondary_gpu = true;
+ for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) {
+ is_not_secondary_gpu = is_not_secondary_gpu &&
+ GpuUnmatched(vendor_id_, device_id_list_, gpu_info.secondary_gpus[i]);
+ }
+ switch (multi_gpu_category_) {
+ case kMultiGpuCategoryPrimary:
+ if (is_not_primary_gpu)
+ return false;
+ break;
+ case kMultiGpuCategorySecondary:
+ if (is_not_secondary_gpu)
+ return false;
+ break;
+ case kMultiGpuCategoryAny:
+ if (is_not_primary_gpu && is_not_secondary_gpu)
+ return false;
+ break;
+ case kMultiGpuCategoryNone:
+ break;
+ }
+ switch (multi_gpu_style_) {
+ case kMultiGpuStyleOptimus:
+ if (!gpu_info.optimus)
+ return false;
+ break;
+ case kMultiGpuStyleAMDSwitchable:
+ if (!gpu_info.amd_switchable)
+ return false;
+ break;
+ case kMultiGpuStyleNone:
+ break;
+ }
+ if (driver_vendor_info_.get() != NULL && !gpu_info.driver_vendor.empty() &&
+ !driver_vendor_info_->Contains(gpu_info.driver_vendor))
+ return false;
+ if (driver_version_info_.get() != NULL && !gpu_info.driver_version.empty()) {
+ if (!driver_version_info_->Contains(gpu_info.driver_version))
+ return false;
+ }
+ if (driver_date_info_.get() != NULL && !gpu_info.driver_date.empty()) {
+ if (!driver_date_info_->Contains(gpu_info.driver_date, '-'))
+ return false;
+ }
+ if (gl_vendor_info_.get() != NULL && !gpu_info.gl_vendor.empty() &&
+ !gl_vendor_info_->Contains(gpu_info.gl_vendor))
+ return false;
+ if (gl_renderer_info_.get() != NULL && !gpu_info.gl_renderer.empty() &&
+ !gl_renderer_info_->Contains(gpu_info.gl_renderer))
+ return false;
+ if (gl_extensions_info_.get() != NULL && !gpu_info.gl_extensions.empty() &&
+ !gl_extensions_info_->Contains(gpu_info.gl_extensions))
+ return false;
+ if (gl_reset_notification_strategy_info_.get() != NULL &&
+ !gl_reset_notification_strategy_info_->Contains(
+ gpu_info.gl_reset_notification_strategy))
+ return false;
+ if (perf_graphics_info_.get() != NULL &&
+ (gpu_info.performance_stats.graphics == 0.0 ||
+ !perf_graphics_info_->Contains(gpu_info.performance_stats.graphics)))
+ return false;
+ if (perf_gaming_info_.get() != NULL &&
+ (gpu_info.performance_stats.gaming == 0.0 ||
+ !perf_gaming_info_->Contains(gpu_info.performance_stats.gaming)))
+ return false;
+ if (perf_overall_info_.get() != NULL &&
+ (gpu_info.performance_stats.overall == 0.0 ||
+ !perf_overall_info_->Contains(gpu_info.performance_stats.overall)))
+ return false;
+ if (machine_model_info_.get() != NULL) {
+ std::vector<std::string> name_version;
+ base::SplitString(gpu_info.machine_model, ' ', &name_version);
+ if (name_version.size() == 2 &&
+ !machine_model_info_->Contains(name_version[0], name_version[1]))
+ return false;
+ }
+ if (gpu_count_info_.get() != NULL &&
+ !gpu_count_info_->Contains(gpu_info.secondary_gpus.size() + 1))
+ return false;
+ if (cpu_brand_.get() != NULL) {
+ base::CPU cpu_info;
+ if (!cpu_brand_->Contains(cpu_info.cpu_brand()))
+ return false;
+ }
+
+ for (size_t i = 0; i < exceptions_.size(); ++i) {
+ if (exceptions_[i]->Contains(os_type, os_version, gpu_info) &&
+ !exceptions_[i]->NeedsMoreInfo(gpu_info))
+ return false;
+ }
+ return true;
+}
+
+bool GpuControlList::GpuControlListEntry::NeedsMoreInfo(
+ const GPUInfo& gpu_info) const {
+ // We only check for missing info that might be collected with a gl context.
+ // If certain info is missing due to some error, say, we fail to collect
+ // vendor_id/device_id, then even if we launch GPU process and create a gl
+ // context, we won't gather such missing info, so we still return false.
+ if (driver_vendor_info_.get() && gpu_info.driver_vendor.empty())
+ return true;
+ if (driver_version_info_.get() && gpu_info.driver_version.empty())
+ return true;
+ if (gl_vendor_info_.get() && gpu_info.gl_vendor.empty())
+ return true;
+ if (gl_renderer_info_.get() && gpu_info.gl_renderer.empty())
+ return true;
+ for (size_t i = 0; i < exceptions_.size(); ++i) {
+ if (exceptions_[i]->NeedsMoreInfo(gpu_info))
+ return true;
+ }
+ return false;
+}
+
+GpuControlList::OsType GpuControlList::GpuControlListEntry::GetOsType() const {
+ if (os_info_.get() == NULL)
+ return kOsAny;
+ return os_info_->type();
+}
+
+uint32 GpuControlList::GpuControlListEntry::id() const {
+ return id_;
+}
+
+bool GpuControlList::GpuControlListEntry::disabled() const {
+ return disabled_;
+}
+
+const std::set<int>& GpuControlList::GpuControlListEntry::features() const {
+ return features_;
+}
+
+// static
+bool GpuControlList::GpuControlListEntry::StringToFeature(
+ const std::string& feature_name, int* feature_id,
+ const FeatureMap& feature_map) {
+ FeatureMap::const_iterator iter = feature_map.find(feature_name);
+ if (iter != feature_map.end()) {
+ *feature_id = iter->second;
+ return true;
+ }
+ return false;
+}
+
+GpuControlList::GpuControlList()
+ : max_entry_id_(0),
+ contains_unknown_fields_(false),
+ needs_more_info_(false),
+ supports_feature_type_all_(false) {
+}
+
+GpuControlList::~GpuControlList() {
+ Clear();
+}
+
+bool GpuControlList::LoadList(
+ const std::string& json_context, GpuControlList::OsFilter os_filter) {
+ const std::string browser_version_string = "0";
+ return LoadList(browser_version_string, json_context, os_filter);
+}
+
+bool GpuControlList::LoadList(
+ const std::string& browser_version_string,
+ const std::string& json_context,
+ GpuControlList::OsFilter os_filter) {
+ std::vector<std::string> pieces;
+ if (!ProcessVersionString(browser_version_string, '.', &pieces))
+ return false;
+ browser_version_ = browser_version_string;
+
+ scoped_ptr<base::Value> root;
+ root.reset(base::JSONReader::Read(json_context));
+ if (root.get() == NULL || !root->IsType(base::Value::TYPE_DICTIONARY))
+ return false;
+
+ base::DictionaryValue* root_dictionary =
+ static_cast<base::DictionaryValue*>(root.get());
+ DCHECK(root_dictionary);
+ return LoadList(*root_dictionary, os_filter);
+}
+
+bool GpuControlList::LoadList(const base::DictionaryValue& parsed_json,
+ GpuControlList::OsFilter os_filter) {
+ std::vector<ScopedGpuControlListEntry> entries;
+
+ parsed_json.GetString("version", &version_);
+ std::vector<std::string> pieces;
+ if (!ProcessVersionString(version_, '.', &pieces))
+ return false;
+
+ const base::ListValue* list = NULL;
+ if (!parsed_json.GetList("entries", &list))
+ return false;
+
+ uint32 max_entry_id = 0;
+ bool contains_unknown_fields = false;
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ const base::DictionaryValue* list_item = NULL;
+ bool valid = list->GetDictionary(i, &list_item);
+ if (!valid || list_item == NULL)
+ return false;
+ // Check browser version compatibility: if the entry is not for the
+ // current browser version, don't process it.
+ BrowserVersionSupport browser_version_support =
+ IsEntrySupportedByCurrentBrowserVersion(list_item);
+ if (browser_version_support == kMalformed)
+ return false;
+ if (browser_version_support == kUnsupported)
+ continue;
+ DCHECK(browser_version_support == kSupported);
+ ScopedGpuControlListEntry entry(GpuControlListEntry::GetEntryFromValue(
+ list_item, true, feature_map_, supports_feature_type_all_));
+ if (entry.get() == NULL)
+ return false;
+ if (entry->id() > max_entry_id)
+ max_entry_id = entry->id();
+ // If an unknown field is encountered, skip the entry; if an unknown
+ // feature is encountered, ignore the feature, but keep the entry.
+ if (entry->contains_unknown_fields()) {
+ contains_unknown_fields = true;
+ continue;
+ }
+ if (entry->contains_unknown_features())
+ contains_unknown_fields = true;
+ entries.push_back(entry);
+ }
+
+ Clear();
+ OsType my_os = GetOsType();
+ for (size_t i = 0; i < entries.size(); ++i) {
+ OsType entry_os = entries[i]->GetOsType();
+ if (os_filter == GpuControlList::kAllOs ||
+ entry_os == kOsAny || entry_os == my_os)
+ entries_.push_back(entries[i]);
+ }
+ max_entry_id_ = max_entry_id;
+ contains_unknown_fields_ = contains_unknown_fields;
+ return true;
+}
+
+std::set<int> GpuControlList::MakeDecision(
+ GpuControlList::OsType os,
+ std::string os_version,
+ const GPUInfo& gpu_info) {
+ active_entries_.clear();
+ std::set<int> features;
+
+ needs_more_info_ = false;
+ std::set<int> possible_features;
+
+ if (os == kOsAny)
+ os = GetOsType();
+ if (os_version.empty()) {
+ os_version = base::SysInfo::OperatingSystemVersion();
+ size_t pos = os_version.find_first_not_of("0123456789.");
+ if (pos != std::string::npos)
+ os_version = os_version.substr(0, pos);
+ }
+ std::vector<std::string> pieces;
+ if (!ProcessVersionString(os_version, '.', &pieces))
+ os_version = "0";
+
+ for (size_t i = 0; i < entries_.size(); ++i) {
+ if (entries_[i]->Contains(os, os_version, gpu_info)) {
+ if (!entries_[i]->disabled()) {
+ MergeFeatureSets(&possible_features, entries_[i]->features());
+ if (!entries_[i]->NeedsMoreInfo(gpu_info))
+ MergeFeatureSets(&features, entries_[i]->features());
+ }
+ active_entries_.push_back(entries_[i]);
+ }
+ }
+
+ if (possible_features.size() > features.size())
+ needs_more_info_ = true;
+
+ return features;
+}
+
+void GpuControlList::GetDecisionEntries(
+ std::vector<uint32>* entry_ids, bool disabled) const {
+ DCHECK(entry_ids);
+ entry_ids->clear();
+ for (size_t i = 0; i < active_entries_.size(); ++i) {
+ if (disabled == active_entries_[i]->disabled())
+ entry_ids->push_back(active_entries_[i]->id());
+ }
+}
+
+void GpuControlList::GetReasons(base::ListValue* problem_list) const {
+ DCHECK(problem_list);
+ for (size_t i = 0; i < active_entries_.size(); ++i) {
+ GpuControlListEntry* entry = active_entries_[i].get();
+ if (entry->disabled())
+ continue;
+ base::DictionaryValue* problem = new base::DictionaryValue();
+
+ problem->SetString("description", entry->description());
+
+ base::ListValue* cr_bugs = new base::ListValue();
+ for (size_t j = 0; j < entry->cr_bugs().size(); ++j)
+ cr_bugs->Append(new base::FundamentalValue(entry->cr_bugs()[j]));
+ problem->Set("crBugs", cr_bugs);
+
+ base::ListValue* webkit_bugs = new base::ListValue();
+ for (size_t j = 0; j < entry->webkit_bugs().size(); ++j) {
+ webkit_bugs->Append(new base::FundamentalValue(entry->webkit_bugs()[j]));
+ }
+ problem->Set("webkitBugs", webkit_bugs);
+
+ problem_list->Append(problem);
+ }
+}
+
+size_t GpuControlList::num_entries() const {
+ return entries_.size();
+}
+
+uint32 GpuControlList::max_entry_id() const {
+ return max_entry_id_;
+}
+
+std::string GpuControlList::version() const {
+ return version_;
+}
+
+GpuControlList::OsType GpuControlList::GetOsType() {
+#if defined(OS_CHROMEOS)
+ return kOsChromeOS;
+#elif defined(OS_WIN)
+ return kOsWin;
+#elif defined(OS_ANDROID)
+ return kOsAndroid;
+#elif defined(OS_LINUX) || defined(OS_OPENBSD)
+ return kOsLinux;
+#elif defined(OS_MACOSX)
+ return kOsMacosx;
+#else
+ return kOsUnknown;
+#endif
+}
+
+void GpuControlList::Clear() {
+ entries_.clear();
+ active_entries_.clear();
+ max_entry_id_ = 0;
+ contains_unknown_fields_ = false;
+}
+
+GpuControlList::BrowserVersionSupport
+GpuControlList::IsEntrySupportedByCurrentBrowserVersion(
+ const base::DictionaryValue* value) {
+ DCHECK(value);
+ const base::DictionaryValue* browser_version_value = NULL;
+ if (value->GetDictionary("browser_version", &browser_version_value)) {
+ std::string version_op = "any";
+ std::string version_string;
+ std::string version_string2;
+ browser_version_value->GetString(kOp, &version_op);
+ browser_version_value->GetString("number", &version_string);
+ browser_version_value->GetString("number2", &version_string2);
+ scoped_ptr<VersionInfo> browser_version_info;
+ browser_version_info.reset(new VersionInfo(
+ version_op, std::string(), version_string, version_string2));
+ if (!browser_version_info->IsValid())
+ return kMalformed;
+ if (browser_version_info->Contains(browser_version_))
+ return kSupported;
+ return kUnsupported;
+ }
+ return kSupported;
+}
+
+// static
+GpuControlList::NumericOp GpuControlList::StringToNumericOp(
+ const std::string& op) {
+ if (op == "=")
+ return kEQ;
+ if (op == "<")
+ return kLT;
+ if (op == "<=")
+ return kLE;
+ if (op == ">")
+ return kGT;
+ if (op == ">=")
+ return kGE;
+ if (op == "any")
+ return kAny;
+ if (op == "between")
+ return kBetween;
+ return kUnknown;
+}
+
+void GpuControlList::AddSupportedFeature(
+ const std::string& feature_name, int feature_id) {
+ feature_map_[feature_name] = feature_id;
+}
+
+void GpuControlList::set_supports_feature_type_all(bool supported) {
+ supports_feature_type_all_ = supported;
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list.h b/chromium/gpu/config/gpu_control_list.h
new file mode 100644
index 00000000000..62b66ec2782
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list.h
@@ -0,0 +1,503 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_CONTROL_LIST_H_
+#define GPU_CONFIG_GPU_CONTROL_LIST_H_
+
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/gtest_prod_util.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+struct GPUInfo;
+
+class GPU_EXPORT GpuControlList {
+ public:
+ enum OsType {
+ kOsLinux,
+ kOsMacosx,
+ kOsWin,
+ kOsChromeOS,
+ kOsAndroid,
+ kOsAny,
+ kOsUnknown
+ };
+
+ enum OsFilter {
+ // In loading, ignore all entries that belong to other OS.
+ kCurrentOsOnly,
+ // In loading, keep all entries. This is for testing only.
+ kAllOs
+ };
+
+ GpuControlList();
+ virtual ~GpuControlList();
+
+ // Loads control list information from a json file.
+ // If failed, the current GpuControlList is un-touched.
+ bool LoadList(const std::string& json_context, OsFilter os_filter);
+ bool LoadList(const std::string& browser_version_string,
+ const std::string& json_context, OsFilter os_filter);
+
+ // Collects system information and combines them with gpu_info and control
+ // list information to decide which entries are applied to the current
+ // system and returns the union of features specified in each entry.
+ // If os is kOsAny, use the current OS; if os_version is empty, use the
+ // current OS version.
+ std::set<int> MakeDecision(
+ OsType os, std::string os_version, const GPUInfo& gpu_info);
+
+ // Collects the active entries from the last MakeDecision() call.
+ // If disabled set to true, return entries that are disabled; otherwise,
+ // return enabled entries.
+ void GetDecisionEntries(std::vector<uint32>* entry_ids,
+ bool disabled) const;
+
+ // Returns the description and bugs from active entries from the last
+ // MakeDecision() call.
+ //
+ // Each problems has:
+ // {
+ // "description": "Your GPU is too old",
+ // "crBugs": [1234],
+ // "webkitBugs": []
+ // }
+ void GetReasons(base::ListValue* problem_list) const;
+
+ // Return the largest entry id. This is used for histogramming.
+ uint32 max_entry_id() const;
+
+ // Returns the version of the control list.
+ std::string version() const;
+
+ // Check if we need more gpu info to make the decisions.
+ // This is computed from the last MakeDecision() call.
+ // If yes, we should create a gl context and do a full gpu info collection.
+ bool needs_more_info() const { return needs_more_info_; }
+
+ // Check if any entries contain unknown fields. This is only for tests.
+ bool contains_unknown_fields() const { return contains_unknown_fields_; }
+
+ // Returns the number of entries. This is only for tests.
+ size_t num_entries() const;
+
+ // Register a feature to FeatureMap - used to construct a GpuControlList.
+ void AddSupportedFeature(const std::string& feature_name, int feature_id);
+ // Register whether "all" is recognized as all features.
+ void set_supports_feature_type_all(bool supported);
+
+ private:
+ friend class GpuControlListEntryTest;
+ friend class MachineModelInfoTest;
+ friend class NumberInfoTest;
+ friend class OsInfoTest;
+ friend class StringInfoTest;
+ friend class VersionInfoTest;
+
+ enum BrowserVersionSupport {
+ kSupported,
+ kUnsupported,
+ kMalformed
+ };
+
+ enum NumericOp {
+ kBetween, // <= * <=
+ kEQ, // =
+ kLT, // <
+ kLE, // <=
+ kGT, // >
+ kGE, // >=
+ kAny,
+ kUnknown // Indicates the data is invalid.
+ };
+
+ class GPU_EXPORT VersionInfo {
+ public:
+ // If version_style is empty, it defaults to kNumerical.
+ VersionInfo(const std::string& version_op,
+ const std::string& version_style,
+ const std::string& version_string,
+ const std::string& version_string2);
+ ~VersionInfo();
+
+ // Determines if a given version is included in the VersionInfo range.
+ // "splitter" divides version string into segments.
+ bool Contains(const std::string& version, char splitter) const;
+ // Same as above, using '.' as splitter.
+ bool Contains(const std::string& version) const;
+
+ // Determine if the version_style is lexical.
+ bool IsLexical() const;
+
+ // Determines if the VersionInfo contains valid information.
+ bool IsValid() const;
+
+ private:
+ enum VersionStyle {
+ kVersionStyleNumerical,
+ kVersionStyleLexical,
+ kVersionStyleUnknown
+ };
+
+ static VersionStyle StringToVersionStyle(const std::string& version_style);
+
+ // Compare two version strings.
+ // Return 1 if version > version_ref,
+ // 0 if version = version_ref,
+ // -1 if version < version_ref.
+ // Note that we only compare as many segments as both versions contain.
+ // For example: Compare("10.3.1", "10.3") returns 0,
+ // Compare("10.3", "10.3.1") returns 0.
+ // If "version_style" is Lexical, the first segment is compared
+ // numerically, all other segments are compared lexically.
+ // Lexical is used for AMD Linux driver versions only.
+ static int Compare(const std::vector<std::string>& version,
+ const std::vector<std::string>& version_ref,
+ VersionStyle version_style);
+
+ NumericOp op_;
+ VersionStyle version_style_;
+ std::vector<std::string> version_;
+ std::vector<std::string> version2_;
+ };
+
+ class GPU_EXPORT OsInfo {
+ public:
+ OsInfo(const std::string& os,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2);
+ ~OsInfo();
+
+ // Determines if a given os/version is included in the OsInfo set.
+ bool Contains(OsType type, const std::string& version) const;
+
+ // Determines if the VersionInfo contains valid information.
+ bool IsValid() const;
+
+ OsType type() const;
+
+ // Maps string to OsType; returns kOsUnknown if it's not a valid os.
+ static OsType StringToOsType(const std::string& os);
+
+ private:
+ OsType type_;
+ scoped_ptr<VersionInfo> version_info_;
+ };
+
+ class GPU_EXPORT StringInfo {
+ public:
+ StringInfo(const std::string& string_op, const std::string& string_value);
+
+ // Determines if a given string is included in the StringInfo.
+ bool Contains(const std::string& value) const;
+
+ // Determines if the StringInfo contains valid information.
+ bool IsValid() const;
+
+ private:
+ enum Op {
+ kContains,
+ kBeginWith,
+ kEndWith,
+ kEQ, // =
+ kUnknown // Indicates StringInfo data is invalid.
+ };
+
+ // Maps string to Op; returns kUnknown if it's not a valid Op.
+ static Op StringToOp(const std::string& string_op);
+
+ Op op_;
+ std::string value_;
+ };
+
+ class GPU_EXPORT FloatInfo {
+ public:
+ FloatInfo(const std::string& float_op,
+ const std::string& float_value,
+ const std::string& float_value2);
+
+ // Determines if a given float is included in the FloatInfo.
+ bool Contains(float value) const;
+
+ // Determines if the FloatInfo contains valid information.
+ bool IsValid() const;
+
+ private:
+ NumericOp op_;
+ float value_;
+ float value2_;
+ };
+
+ class GPU_EXPORT IntInfo {
+ public:
+ IntInfo(const std::string& int_op,
+ const std::string& int_value,
+ const std::string& int_value2);
+
+ // Determines if a given int is included in the IntInfo.
+ bool Contains(int value) const;
+
+ // Determines if the IntInfo contains valid information.
+ bool IsValid() const;
+
+ private:
+ NumericOp op_;
+ int value_;
+ int value2_;
+ };
+
+ class GPU_EXPORT MachineModelInfo {
+ public:
+ MachineModelInfo(const std::string& name_op,
+ const std::string& name_value,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2);
+ ~MachineModelInfo();
+
+ // Determines if a given name/version is included in the MachineModelInfo.
+ bool Contains(const std::string& name, const std::string& version) const;
+
+ // Determines if the MachineModelInfo contains valid information.
+ bool IsValid() const;
+
+ private:
+ scoped_ptr<StringInfo> name_info_;
+ scoped_ptr<VersionInfo> version_info_;
+ };
+
+ class GpuControlListEntry;
+ typedef scoped_refptr<GpuControlListEntry> ScopedGpuControlListEntry;
+
+ typedef base::hash_map<std::string, int> FeatureMap;
+
+ class GPU_EXPORT GpuControlListEntry
+ : public base::RefCounted<GpuControlListEntry> {
+ public:
+ // Constructs GpuControlListEntry from DictionaryValue loaded from json.
+ // Top-level entry must have an id number. Others are exceptions.
+ static ScopedGpuControlListEntry GetEntryFromValue(
+ const base::DictionaryValue* value, bool top_level,
+ const FeatureMap& feature_map,
+ bool supports_feature_type_all);
+
+ // Determines if a given os/gc/machine_model/driver is included in the
+ // Entry set.
+ bool Contains(OsType os_type, const std::string& os_version,
+ const GPUInfo& gpu_info) const;
+
+ // Determines whether we needs more gpu info to make the blacklisting
+ // decision. It should only be checked if Contains() returns true.
+ bool NeedsMoreInfo(const GPUInfo& gpu_info) const;
+
+ // Returns the OsType.
+ OsType GetOsType() const;
+
+ // Returns the entry's unique id. 0 is reserved.
+ uint32 id() const;
+
+ // Returns whether the entry is disabled.
+ bool disabled() const;
+
+ // Returns the description of the entry
+ const std::string& description() const { return description_; }
+
+ // Returns a list of Chromium and Webkit bugs applicable to this entry
+ const std::vector<int>& cr_bugs() const { return cr_bugs_; }
+ const std::vector<int>& webkit_bugs() const { return webkit_bugs_; }
+
+ // Returns the blacklisted features in this entry.
+ const std::set<int>& features() const;
+
+ // Returns true if an unknown field is encountered.
+ bool contains_unknown_fields() const {
+ return contains_unknown_fields_;
+ }
+ // Returns true if an unknown blacklist feature is encountered.
+ bool contains_unknown_features() const {
+ return contains_unknown_features_;
+ }
+
+ private:
+ friend class base::RefCounted<GpuControlListEntry>;
+
+ enum MultiGpuStyle {
+ kMultiGpuStyleOptimus,
+ kMultiGpuStyleAMDSwitchable,
+ kMultiGpuStyleNone
+ };
+
+ enum MultiGpuCategory {
+ kMultiGpuCategoryPrimary,
+ kMultiGpuCategorySecondary,
+ kMultiGpuCategoryAny,
+ kMultiGpuCategoryNone
+ };
+
+ GpuControlListEntry();
+ ~GpuControlListEntry();
+
+ bool SetId(uint32 id);
+
+ void SetDisabled(bool disabled);
+
+ bool SetOsInfo(const std::string& os,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2);
+
+ bool SetVendorId(const std::string& vendor_id_string);
+
+ bool AddDeviceId(const std::string& device_id_string);
+
+ bool SetMultiGpuStyle(const std::string& multi_gpu_style_string);
+
+ bool SetMultiGpuCategory(const std::string& multi_gpu_category_string);
+
+ bool SetDriverVendorInfo(const std::string& vendor_op,
+ const std::string& vendor_value);
+
+ bool SetDriverVersionInfo(const std::string& version_op,
+ const std::string& version_style,
+ const std::string& version_string,
+ const std::string& version_string2);
+
+ bool SetDriverDateInfo(const std::string& date_op,
+ const std::string& date_string,
+ const std::string& date_string2);
+
+ bool SetGLVendorInfo(const std::string& vendor_op,
+ const std::string& vendor_value);
+
+ bool SetGLRendererInfo(const std::string& renderer_op,
+ const std::string& renderer_value);
+
+ bool SetGLExtensionsInfo(const std::string& extensions_op,
+ const std::string& extensions_value);
+
+ bool SetGLResetNotificationStrategyInfo(const std::string& op,
+ const std::string& int_string,
+ const std::string& int_string2);
+
+ bool SetCpuBrand(const std::string& cpu_op,
+ const std::string& cpu_value);
+
+ bool SetPerfGraphicsInfo(const std::string& op,
+ const std::string& float_string,
+ const std::string& float_string2);
+
+ bool SetPerfGamingInfo(const std::string& op,
+ const std::string& float_string,
+ const std::string& float_string2);
+
+ bool SetPerfOverallInfo(const std::string& op,
+ const std::string& float_string,
+ const std::string& float_string2);
+
+ bool SetMachineModelInfo(const std::string& name_op,
+ const std::string& name_value,
+ const std::string& version_op,
+ const std::string& version_string,
+ const std::string& version_string2);
+
+ bool SetGpuCountInfo(const std::string& op,
+ const std::string& int_string,
+ const std::string& int_string2);
+
+ bool SetFeatures(const std::vector<std::string>& features,
+ const FeatureMap& feature_map,
+ bool supports_feature_type_all);
+
+ void AddException(ScopedGpuControlListEntry exception);
+
+ static MultiGpuStyle StringToMultiGpuStyle(const std::string& style);
+
+ static MultiGpuCategory StringToMultiGpuCategory(
+ const std::string& category);
+
+ // map a feature_name to feature_id. If the string is not a registered
+ // feature name, return false.
+ static bool StringToFeature(const std::string& feature_name,
+ int* feature_id,
+ const FeatureMap& feature_map);
+
+ uint32 id_;
+ bool disabled_;
+ std::string description_;
+ std::vector<int> cr_bugs_;
+ std::vector<int> webkit_bugs_;
+ scoped_ptr<OsInfo> os_info_;
+ uint32 vendor_id_;
+ std::vector<uint32> device_id_list_;
+ MultiGpuStyle multi_gpu_style_;
+ MultiGpuCategory multi_gpu_category_;
+ scoped_ptr<StringInfo> driver_vendor_info_;
+ scoped_ptr<VersionInfo> driver_version_info_;
+ scoped_ptr<VersionInfo> driver_date_info_;
+ scoped_ptr<StringInfo> gl_vendor_info_;
+ scoped_ptr<StringInfo> gl_renderer_info_;
+ scoped_ptr<StringInfo> gl_extensions_info_;
+ scoped_ptr<IntInfo> gl_reset_notification_strategy_info_;
+ scoped_ptr<StringInfo> cpu_brand_;
+ scoped_ptr<FloatInfo> perf_graphics_info_;
+ scoped_ptr<FloatInfo> perf_gaming_info_;
+ scoped_ptr<FloatInfo> perf_overall_info_;
+ scoped_ptr<MachineModelInfo> machine_model_info_;
+ scoped_ptr<IntInfo> gpu_count_info_;
+ std::set<int> features_;
+ std::vector<ScopedGpuControlListEntry> exceptions_;
+ bool contains_unknown_fields_;
+ bool contains_unknown_features_;
+ };
+
+ // Gets the current OS type.
+ static OsType GetOsType();
+
+ bool LoadList(const base::DictionaryValue& parsed_json, OsFilter os_filter);
+
+ void Clear();
+
+ // Check if the entry is supported by the current version of browser.
+ // By default, if there is no browser version information in the entry,
+ // return kSupported;
+ BrowserVersionSupport IsEntrySupportedByCurrentBrowserVersion(
+ const base::DictionaryValue* value);
+
+ static NumericOp StringToNumericOp(const std::string& op);
+
+ std::string version_;
+ std::vector<ScopedGpuControlListEntry> entries_;
+
+ std::string browser_version_;
+
+ // This records all the blacklist entries that are appliable to the current
+ // user machine. It is updated everytime MakeDecision() is called and is
+ // used later by GetDecisionEntries().
+ std::vector<ScopedGpuControlListEntry> active_entries_;
+
+ uint32 max_entry_id_;
+
+ bool contains_unknown_fields_;
+
+ bool needs_more_info_;
+
+ // The features a GpuControlList recognizes and handles.
+ FeatureMap feature_map_;
+ bool supports_feature_type_all_;
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_CONTROL_LIST_H_
+
diff --git a/chromium/gpu/config/gpu_control_list_entry_unittest.cc b/chromium/gpu/config/gpu_control_list_entry_unittest.cc
new file mode 100644
index 00000000000..8991334f17c
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_entry_unittest.cc
@@ -0,0 +1,745 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/json/json_reader.h"
+#include "gpu/config/gpu_control_list.h"
+#include "gpu/config/gpu_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+namespace gpu {
+
+enum TestFeatureType {
+ TEST_FEATURE_0 = 0,
+ TEST_FEATURE_1,
+ TEST_FEATURE_2
+};
+
+class GpuControlListEntryTest : public testing::Test {
+ public:
+ GpuControlListEntryTest() { }
+ virtual ~GpuControlListEntryTest() { }
+
+ const GPUInfo& gpu_info() const {
+ return gpu_info_;
+ }
+
+ typedef GpuControlList::ScopedGpuControlListEntry ScopedEntry;
+
+ static ScopedEntry GetEntryFromString(
+ const std::string& json, bool supports_feature_type_all) {
+ scoped_ptr<base::Value> root;
+ root.reset(base::JSONReader::Read(json));
+ DictionaryValue* value = NULL;
+ if (root.get() == NULL || !root->GetAsDictionary(&value))
+ return NULL;
+
+ GpuControlList::FeatureMap feature_map;
+ feature_map["test_feature_0"] = TEST_FEATURE_0;
+ feature_map["test_feature_1"] = TEST_FEATURE_1;
+ feature_map["test_feature_2"] = TEST_FEATURE_2;
+
+ return GpuControlList::GpuControlListEntry::GetEntryFromValue(
+ value, true, feature_map, supports_feature_type_all);
+ }
+
+ static ScopedEntry GetEntryFromString(const std::string& json) {
+ return GetEntryFromString(json, false);
+ }
+
+ virtual void SetUp() {
+ gpu_info_.gpu.vendor_id = 0x10de;
+ gpu_info_.gpu.device_id = 0x0640;
+ gpu_info_.driver_vendor = "NVIDIA";
+ gpu_info_.driver_version = "1.6.18";
+ gpu_info_.driver_date = "7-14-2009";
+ gpu_info_.machine_model = "MacBookPro 7.1";
+ gpu_info_.gl_vendor = "NVIDIA Corporation";
+ gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
+ gpu_info_.performance_stats.graphics = 5.0;
+ gpu_info_.performance_stats.gaming = 5.0;
+ gpu_info_.performance_stats.overall = 5.0;
+ }
+
+ private:
+ GPUInfo gpu_info_;
+};
+
+TEST_F(GpuControlListEntryTest, DetailedEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 5,
+ "description": "test entry",
+ "cr_bugs": [1024, 678],
+ "webkit_bugs": [1950],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "=",
+ "number": "10.6.4"
+ }
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0640"],
+ "driver_version": {
+ "op": "=",
+ "number": "1.6.18"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsMacosx, entry->GetOsType());
+ EXPECT_FALSE(entry->disabled());
+ EXPECT_EQ(5u, entry->id());
+ EXPECT_STREQ("test entry", entry->description().c_str());
+ EXPECT_EQ(2u, entry->cr_bugs().size());
+ EXPECT_EQ(1024, entry->cr_bugs()[0]);
+ EXPECT_EQ(678, entry->cr_bugs()[1]);
+ EXPECT_EQ(1u, entry->webkit_bugs().size());
+ EXPECT_EQ(1950, entry->webkit_bugs()[0]);
+ EXPECT_EQ(1u, entry->features().size());
+ EXPECT_EQ(1u, entry->features().count(TEST_FEATURE_0));
+ EXPECT_FALSE(entry->contains_unknown_fields());
+ EXPECT_FALSE(entry->contains_unknown_features());
+ EXPECT_FALSE(entry->NeedsMoreInfo(gpu_info()));
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsMacosx, "10.6.4", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, VendorOnAllOsEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "vendor_id": "0x10de",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsAny, entry->GetOsType());
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_TRUE(entry->Contains(os_type[i], "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, VendorOnLinuxEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x10de",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsLinux, entry->GetOsType());
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_FALSE(entry->Contains(os_type[i], "10.6", gpu_info()));
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsLinux, "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, AllExceptNVidiaOnLinuxEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "exceptions": [
+ {
+ "vendor_id": "0x10de"
+ }
+ ],
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsLinux, entry->GetOsType());
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_FALSE(entry->Contains(os_type[i], "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, AllExceptIntelOnLinuxEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "exceptions": [
+ {
+ "vendor_id": "0x8086"
+ }
+ ],
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsLinux, entry->GetOsType());
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_FALSE(entry->Contains(os_type[i], "10.6", gpu_info()));
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsLinux, "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, DateOnWindowsEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "win"
+ },
+ "driver_date": {
+ "op": "<",
+ "number": "2010.5.8"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsWin, entry->GetOsType());
+
+ GPUInfo gpu_info;
+ gpu_info.driver_date = "4-12-2010";
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsWin, "10.6", gpu_info));
+ gpu_info.driver_date = "5-8-2010";
+ EXPECT_FALSE(entry->Contains(
+ GpuControlList::kOsWin, "10.6", gpu_info));
+ gpu_info.driver_date = "5-9-2010";
+ EXPECT_FALSE(entry->Contains(
+ GpuControlList::kOsWin, "10.6", gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, MultipleDevicesEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "vendor_id": "0x10de",
+ "device_id": ["0x1023", "0x0640"],
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsAny, entry->GetOsType());
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_TRUE(entry->Contains(os_type[i], "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, ChromeOSEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "chromeos"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsChromeOS, entry->GetOsType());
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_FALSE(entry->Contains(os_type[i], "10.6", gpu_info()));
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsChromeOS, "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, MalformedVendor) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "vendor_id": "[0x10de]",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() == NULL);
+}
+
+TEST_F(GpuControlListEntryTest, UnknownFieldEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "unknown_field": 0,
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_TRUE(entry->contains_unknown_fields());
+ EXPECT_FALSE(entry->contains_unknown_features());
+}
+
+TEST_F(GpuControlListEntryTest, UnknownExceptionFieldEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 2,
+ "exceptions": [
+ {
+ "unknown_field": 0
+ }
+ ],
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_TRUE(entry->contains_unknown_fields());
+ EXPECT_FALSE(entry->contains_unknown_features());
+}
+
+TEST_F(GpuControlListEntryTest, UnknownFeatureEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "features": [
+ "some_unknown_feature",
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_FALSE(entry->contains_unknown_fields());
+ EXPECT_TRUE(entry->contains_unknown_features());
+ EXPECT_EQ(1u, entry->features().size());
+ EXPECT_EQ(1u, entry->features().count(TEST_FEATURE_0));
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_TRUE(entry->Contains(os_type[i], "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, GlVendorEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "NVIDIA"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_TRUE(entry->Contains(os_type[i], "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, GlRendererEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "gl_renderer": {
+ "op": "contains",
+ "value": "GeForce"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i)
+ EXPECT_TRUE(entry->Contains(os_type[i], "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, PerfGraphicsEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "perf_graphics": {
+ "op": "<",
+ "value": "6.0"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_TRUE(entry->Contains(GpuControlList::kOsWin, "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, PerfGamingEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "perf_graphics": {
+ "op": "<=",
+ "value": "4.0"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_FALSE(entry->Contains(GpuControlList::kOsWin, "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, PerfOverallEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "perf_overall": {
+ "op": "between",
+ "value": "1.0",
+ "value2": "9.0"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_TRUE(entry->Contains(GpuControlList::kOsWin, "10.6", gpu_info()));
+}
+
+TEST_F(GpuControlListEntryTest, DisabledEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "disabled": true,
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_TRUE(entry->disabled());
+}
+
+TEST_F(GpuControlListEntryTest, OptimusEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "multi_gpu_style": "optimus",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.optimus = true;
+
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsLinux, entry->GetOsType());
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsLinux, "10.6", gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, AMDSwitchableEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "macosx"
+ },
+ "multi_gpu_style": "amd_switchable",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.amd_switchable = true;
+
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsMacosx, entry->GetOsType());
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsMacosx, "10.6", gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, LexicalDriverVersionEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x1002",
+ "driver_version": {
+ "op": "=",
+ "style": "lexical",
+ "number": "8.76"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x1002;
+
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsLinux, entry->GetOsType());
+
+ gpu_info.driver_version = "8.76";
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsLinux, "10.6", gpu_info));
+
+ gpu_info.driver_version = "8.768";
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsLinux, "10.6", gpu_info));
+
+ gpu_info.driver_version = "8.76.8";
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsLinux, "10.6", gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, MultipleGPUsAnyEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0x0166"],
+ "multi_gpu_category": "any",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsMacosx, entry->GetOsType());
+
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x1976;
+ EXPECT_FALSE(entry->Contains(
+ GpuControlList::kOsMacosx, "10.6", gpu_info));
+
+ GPUInfo::GPUDevice gpu_device;
+ gpu_device.vendor_id = 0x8086;
+ gpu_device.device_id = 0x0166;
+ gpu_info.secondary_gpus.push_back(gpu_device);
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsMacosx, "10.6", gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, MultipleGPUsSecondaryEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0x0166"],
+ "multi_gpu_category": "secondary",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(GpuControlList::kOsMacosx, entry->GetOsType());
+
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x1976;
+ EXPECT_FALSE(entry->Contains(
+ GpuControlList::kOsMacosx, "10.6", gpu_info));
+
+ GPUInfo::GPUDevice gpu_device;
+ gpu_device.vendor_id = 0x8086;
+ gpu_device.device_id = 0x0166;
+ gpu_info.secondary_gpus.push_back(gpu_device);
+ EXPECT_TRUE(entry->Contains(
+ GpuControlList::kOsMacosx, "10.6", gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, NeedsMoreInfoEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "vendor_id": "0x8086",
+ "driver_version": {
+ "op": "<",
+ "number": "10.7"
+ },
+ "features": [
+ "test_feature_1"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x8086;
+ EXPECT_TRUE(entry->NeedsMoreInfo(gpu_info));
+
+ gpu_info.driver_version = "10.6";
+ EXPECT_FALSE(entry->NeedsMoreInfo(gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, NeedsMoreInfoForExceptionsEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "vendor_id": "0x8086",
+ "exceptions": [
+ {
+ "gl_renderer": {
+ "op": "contains",
+ "value": "mesa"
+ }
+ }
+ ],
+ "features": [
+ "test_feature_1"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json));
+ EXPECT_TRUE(entry.get() != NULL);
+
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x8086;
+ EXPECT_TRUE(entry->NeedsMoreInfo(gpu_info));
+
+ gpu_info.gl_renderer = "mesa";
+ EXPECT_FALSE(entry->NeedsMoreInfo(gpu_info));
+}
+
+TEST_F(GpuControlListEntryTest, FeatureTypeAllEntry) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "id": 1,
+ "features": [
+ "all"
+ ]
+ }
+ );
+ ScopedEntry entry(GetEntryFromString(json, true));
+ EXPECT_TRUE(entry.get() != NULL);
+ EXPECT_EQ(3u, entry->features().size());
+ EXPECT_EQ(1u, entry->features().count(TEST_FEATURE_0));
+ EXPECT_EQ(1u, entry->features().count(TEST_FEATURE_1));
+ EXPECT_EQ(1u, entry->features().count(TEST_FEATURE_2));
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list_jsons.h b/chromium/gpu/config/gpu_control_list_jsons.h
new file mode 100644
index 00000000000..671aa9edefa
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_jsons.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_CONTROL_LIST_JSONS_H_
+#define GPU_CONFIG_GPU_CONTROL_LIST_JSONS_H_
+
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+GPU_EXPORT extern const char kGpuDriverBugListJson[];
+GPU_EXPORT extern const char kGpuSwitchingListJson[];
+GPU_EXPORT extern const char kSoftwareRenderingListJson[];
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_CONTROL_LIST_JSONS_H_
+
diff --git a/chromium/gpu/config/gpu_control_list_machine_model_info_unittest.cc b/chromium/gpu/config/gpu_control_list_machine_model_info_unittest.cc
new file mode 100644
index 00000000000..9c681a9264f
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_machine_model_info_unittest.cc
@@ -0,0 +1,57 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_control_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class MachineModelInfoTest : public testing::Test {
+ public:
+ MachineModelInfoTest() { }
+ virtual ~MachineModelInfoTest() { }
+
+ typedef GpuControlList::MachineModelInfo MachineModelInfo;
+};
+
+TEST_F(MachineModelInfoTest, ValidModelInfo) {
+ const std::string name_op[] = {
+ "contains",
+ "beginwith",
+ "endwith",
+ "="
+ };
+ const std::string version_op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "any",
+ "between"
+ };
+ for (size_t i = 0; i < arraysize(name_op); ++i) {
+ for (size_t j = 0; j < arraysize(version_op); ++j) {
+ std::string version1;
+ std::string version2;
+ if (version_op[j] != "any")
+ version1 = "3.14";
+ if (version_op[j] == "between")
+ version2 = "5.4";
+ MachineModelInfo info(name_op[i], "model",
+ version_op[j], version1, version2);
+ EXPECT_TRUE(info.IsValid());
+ }
+ }
+}
+
+TEST_F(MachineModelInfoTest, ModelComparison) {
+ MachineModelInfo info("=", "model_a", ">", "3.4", std::string());
+ EXPECT_TRUE(info.Contains("model_a", "4"));
+ EXPECT_FALSE(info.Contains("model_b", "4"));
+ EXPECT_FALSE(info.Contains("model_a", "3.2"));
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list_number_info_unittest.cc b/chromium/gpu/config/gpu_control_list_number_info_unittest.cc
new file mode 100644
index 00000000000..5bd732cf91e
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_number_info_unittest.cc
@@ -0,0 +1,210 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_control_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class NumberInfoTest : public testing::Test {
+ public:
+ NumberInfoTest() { }
+ virtual ~NumberInfoTest() { }
+
+ typedef GpuControlList::FloatInfo FloatInfo;
+ typedef GpuControlList::IntInfo IntInfo;
+};
+
+TEST_F(NumberInfoTest, ValidFloatInfo) {
+ const std::string op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "any",
+ "between"
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ std::string value1;
+ std::string value2;
+ if (op[i] != "any")
+ value1 = "3.14";
+ if (op[i] == "between")
+ value2 = "4.21";
+ FloatInfo info(op[i], value1, value2);
+ EXPECT_TRUE(info.IsValid());
+ }
+
+ const std::string value[] = {
+ "1.0E12",
+ "1.0e12",
+ "2013",
+ "1.0e-12",
+ "2.1400",
+ "-2.14",
+ };
+ for (size_t i = 0; i < arraysize(value); ++i) {
+ FloatInfo info("=", value[i], std::string());
+ EXPECT_TRUE(info.IsValid());
+ }
+}
+
+TEST_F(NumberInfoTest, InvalidFloatInfo) {
+ const std::string op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ FloatInfo info(op[i], std::string(), std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ {
+ FloatInfo info("between", "3.14", std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ const std::string value[] = {
+ "1.0 E12",
+ "1.0e 12",
+ " 2013",
+ "2013 ",
+ "- 2.14",
+ };
+ for (size_t i = 0; i < arraysize(value); ++i) {
+ FloatInfo info("=", value[i], std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+}
+
+TEST_F(NumberInfoTest, FloatComparison) {
+ {
+ FloatInfo info("=", "3.14", std::string());
+ EXPECT_TRUE(info.Contains(3.14f));
+ EXPECT_TRUE(info.Contains(3.1400f));
+ EXPECT_FALSE(info.Contains(3.1f));
+ EXPECT_FALSE(info.Contains(3));
+ }
+ {
+ FloatInfo info(">", "3.14", std::string());
+ EXPECT_FALSE(info.Contains(3.14f));
+ EXPECT_TRUE(info.Contains(3.141f));
+ EXPECT_FALSE(info.Contains(3.1f));
+ }
+ {
+ FloatInfo info("<=", "3.14", std::string());
+ EXPECT_TRUE(info.Contains(3.14f));
+ EXPECT_FALSE(info.Contains(3.141f));
+ EXPECT_TRUE(info.Contains(3.1f));
+ }
+ {
+ FloatInfo info("any", std::string(), std::string());
+ EXPECT_TRUE(info.Contains(3.14f));
+ }
+ {
+ FloatInfo info("between", "3.14", "5.4");
+ EXPECT_TRUE(info.Contains(3.14f));
+ EXPECT_TRUE(info.Contains(5.4f));
+ EXPECT_TRUE(info.Contains(4));
+ EXPECT_FALSE(info.Contains(5.6f));
+ EXPECT_FALSE(info.Contains(3.12f));
+ }
+}
+
+TEST_F(NumberInfoTest, ValidIntInfo) {
+ const std::string op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "any",
+ "between"
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ std::string value1;
+ std::string value2;
+ if (op[i] != "any")
+ value1 = "3";
+ if (op[i] == "between")
+ value2 = "9";
+ IntInfo info(op[i], value1, value2);
+ EXPECT_TRUE(info.IsValid());
+ }
+
+ const std::string value[] = {
+ "12",
+ "-12",
+ };
+ for (size_t i = 0; i < arraysize(value); ++i) {
+ IntInfo info("=", value[i], std::string());
+ EXPECT_TRUE(info.IsValid());
+ }
+}
+
+TEST_F(NumberInfoTest, InvalidIntInfo) {
+ const std::string op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ IntInfo info(op[i], std::string(), std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ {
+ IntInfo info("between", "3", std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ const std::string value[] = {
+ " 12",
+ "12 ",
+ "- 12",
+ " -12",
+ "3.14"
+ };
+ for (size_t i = 0; i < arraysize(value); ++i) {
+ IntInfo info("=", value[i], std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+}
+
+TEST_F(NumberInfoTest, IntComparison) {
+ {
+ IntInfo info("=", "3", std::string());
+ EXPECT_TRUE(info.Contains(3));
+ EXPECT_FALSE(info.Contains(4));
+ }
+ {
+ IntInfo info(">", "3", std::string());
+ EXPECT_FALSE(info.Contains(2));
+ EXPECT_FALSE(info.Contains(3));
+ EXPECT_TRUE(info.Contains(4));
+ }
+ {
+ IntInfo info("<=", "3", std::string());
+ EXPECT_TRUE(info.Contains(2));
+ EXPECT_TRUE(info.Contains(3));
+ EXPECT_FALSE(info.Contains(4));
+ }
+ {
+ IntInfo info("any", std::string(), std::string());
+ EXPECT_TRUE(info.Contains(3));
+ }
+ {
+ IntInfo info("between", "3", "5");
+ EXPECT_TRUE(info.Contains(3));
+ EXPECT_TRUE(info.Contains(5));
+ EXPECT_TRUE(info.Contains(4));
+ EXPECT_FALSE(info.Contains(6));
+ EXPECT_FALSE(info.Contains(2));
+ }
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list_os_info_unittest.cc b/chromium/gpu/config/gpu_control_list_os_info_unittest.cc
new file mode 100644
index 00000000000..851f9917028
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_os_info_unittest.cc
@@ -0,0 +1,111 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_control_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class OsInfoTest : public testing::Test {
+ public:
+ OsInfoTest() { }
+ virtual ~OsInfoTest() { }
+
+ typedef GpuControlList::OsInfo OsInfo;
+};
+
+TEST_F(OsInfoTest, ValidOsInfo) {
+ const std::string os[] = {
+ "win",
+ "linux",
+ "macosx",
+ "chromeos",
+ "android",
+ "any"
+ };
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsWin,
+ GpuControlList::kOsLinux,
+ GpuControlList::kOsMacosx,
+ GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid,
+ GpuControlList::kOsAny
+ };
+ for (size_t i = 0; i < arraysize(os); ++i) {
+ OsInfo info(os[i], "=", "10.6", std::string());
+ EXPECT_TRUE(info.IsValid());
+ EXPECT_EQ(os_type[i], info.type());
+ }
+ {
+ OsInfo info("any", "any", std::string(), std::string());
+ EXPECT_TRUE(info.IsValid());
+ }
+}
+
+TEST_F(OsInfoTest, InvalidOsInfo) {
+ const std::string os[] = {
+ "win",
+ "linux",
+ "macosx",
+ "chromeos",
+ "android",
+ "any"
+ };
+ for (size_t i = 0; i < arraysize(os); ++i) {
+ {
+ OsInfo info(os[i], std::string(), std::string(), std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ {
+ OsInfo info(os[i], "=", std::string(), std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ {
+ OsInfo info(os[i], std::string(), "10.6", std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+ }
+ const std::string os_cap[] = {
+ "Win",
+ "Linux",
+ "MacOSX",
+ "ChromeOS",
+ "Android",
+ };
+ for (size_t i = 0; i < arraysize(os_cap); ++i) {
+ OsInfo info(os_cap[i], "=", "10.6", std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+}
+
+TEST_F(OsInfoTest, OsComparison) {
+ {
+ OsInfo info("any", "any", std::string(), std::string());
+ const GpuControlList::OsType os_type[] = {
+ GpuControlList::kOsWin, GpuControlList::kOsLinux,
+ GpuControlList::kOsMacosx, GpuControlList::kOsChromeOS,
+ GpuControlList::kOsAndroid,
+ };
+ for (size_t i = 0; i < arraysize(os_type); ++i) {
+ EXPECT_TRUE(info.Contains(os_type[i], std::string()));
+ EXPECT_TRUE(info.Contains(os_type[i], "7.8"));
+ }
+ }
+ {
+ OsInfo info("win", ">=", "6", std::string());
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsMacosx, "10.8.3"));
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsLinux, "10"));
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsChromeOS, "13"));
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsAndroid, "7"));
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsAny, "7"));
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsWin, std::string()));
+ EXPECT_TRUE(info.Contains(GpuControlList::kOsWin, "6"));
+ EXPECT_TRUE(info.Contains(GpuControlList::kOsWin, "6.1"));
+ EXPECT_TRUE(info.Contains(GpuControlList::kOsWin, "7"));
+ EXPECT_FALSE(info.Contains(GpuControlList::kOsWin, "5"));
+ }
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list_string_info_unittest.cc b/chromium/gpu/config/gpu_control_list_string_info_unittest.cc
new file mode 100644
index 00000000000..39e2f5800ce
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_string_info_unittest.cc
@@ -0,0 +1,98 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_control_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class StringInfoTest : public testing::Test {
+ public:
+ StringInfoTest() { }
+ virtual ~StringInfoTest() { }
+
+ typedef GpuControlList::StringInfo StringInfo;
+};
+
+TEST_F(StringInfoTest, ValidStringInfo) {
+ const std::string op[] = {
+ "contains",
+ "beginwith",
+ "endwith",
+ "="
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ {
+ StringInfo info(op[i], std::string());
+ EXPECT_TRUE(info.IsValid());
+ }
+ {
+ StringInfo info(op[i], "hello");
+ EXPECT_TRUE(info.IsValid());
+ }
+ }
+}
+
+TEST_F(StringInfoTest, InvalidStringInfo) {
+ const std::string op[] = {
+ "Contains",
+ "BeginWith",
+ "EndWith",
+ " =",
+ "= "
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ StringInfo info(op[i], "hello");
+ EXPECT_FALSE(info.IsValid());
+ }
+}
+
+TEST_F(StringInfoTest, StringComparison) {
+ {
+ StringInfo info("contains", "happy");
+ EXPECT_TRUE(info.Contains("unhappy"));
+ EXPECT_TRUE(info.Contains("happy1"));
+ EXPECT_TRUE(info.Contains("happy"));
+ EXPECT_TRUE(info.Contains("a happy dog"));
+ EXPECT_TRUE(info.Contains("Happy"));
+ EXPECT_TRUE(info.Contains("HAPPY"));
+ EXPECT_FALSE(info.Contains("ha-ppy"));
+ }
+ {
+ StringInfo info("beginwith", "happy");
+ EXPECT_FALSE(info.Contains("unhappy"));
+ EXPECT_TRUE(info.Contains("happy1"));
+ EXPECT_TRUE(info.Contains("happy"));
+ EXPECT_FALSE(info.Contains("a happy dog"));
+ EXPECT_TRUE(info.Contains("Happy"));
+ EXPECT_TRUE(info.Contains("HAPPY"));
+ EXPECT_FALSE(info.Contains("ha-ppy"));
+ }
+ {
+ StringInfo info("endwith", "happy");
+ EXPECT_TRUE(info.Contains("unhappy"));
+ EXPECT_FALSE(info.Contains("happy1"));
+ EXPECT_TRUE(info.Contains("happy"));
+ EXPECT_FALSE(info.Contains("a happy dog"));
+ EXPECT_TRUE(info.Contains("Happy"));
+ EXPECT_TRUE(info.Contains("HAPPY"));
+ EXPECT_FALSE(info.Contains("ha-ppy"));
+ }
+ {
+ StringInfo info("=", "happy");
+ EXPECT_FALSE(info.Contains("unhappy"));
+ EXPECT_FALSE(info.Contains("happy1"));
+ EXPECT_TRUE(info.Contains("happy"));
+ EXPECT_FALSE(info.Contains("a happy dog"));
+ EXPECT_TRUE(info.Contains("Happy"));
+ EXPECT_TRUE(info.Contains("HAPPY"));
+ EXPECT_FALSE(info.Contains("ha-ppy"));
+ EXPECT_FALSE(info.Contains("ha ppy"));
+ EXPECT_FALSE(info.Contains(" happy"));
+ EXPECT_FALSE(info.Contains("happy "));
+ }
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list_unittest.cc b/chromium/gpu/config/gpu_control_list_unittest.cc
new file mode 100644
index 00000000000..f20e9bb7634
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_unittest.cc
@@ -0,0 +1,497 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/config/gpu_control_list.h"
+#include "gpu/config/gpu_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const char kOsVersion[] = "10.6.4";
+const uint32 kIntelVendorId = 0x8086;
+const uint32 kIntelDeviceId = 0x0166; // 3rd Gen Core Graphics
+const uint32 kNvidiaVendorId = 0x10de;
+const uint32 kNvidiaDeviceId = 0x0fd5; // GeForce GT 650M
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+#define EXPECT_EMPTY_SET(feature_set) EXPECT_EQ(0u, feature_set.size())
+#define EXPECT_SINGLE_FEATURE(feature_set, feature) \
+ EXPECT_TRUE(feature_set.size() == 1 && feature_set.count(feature) == 1)
+
+namespace gpu {
+
+enum TestFeatureType {
+ TEST_FEATURE_0 = 1,
+ TEST_FEATURE_1 = 1 << 2,
+ TEST_FEATURE_2 = 1 << 3,
+};
+
+class GpuControlListTest : public testing::Test {
+ public:
+ GpuControlListTest() { }
+
+ virtual ~GpuControlListTest() { }
+
+ const GPUInfo& gpu_info() const {
+ return gpu_info_;
+ }
+
+ GpuControlList* Create() {
+ GpuControlList* rt = new GpuControlList();
+ rt->AddSupportedFeature("test_feature_0", TEST_FEATURE_0);
+ rt->AddSupportedFeature("test_feature_1", TEST_FEATURE_1);
+ rt->AddSupportedFeature("test_feature_2", TEST_FEATURE_2);
+ return rt;
+ }
+
+ protected:
+ virtual void SetUp() {
+ gpu_info_.gpu.vendor_id = kNvidiaVendorId;
+ gpu_info_.gpu.device_id = 0x0640;
+ gpu_info_.driver_vendor = "NVIDIA";
+ gpu_info_.driver_version = "1.6.18";
+ gpu_info_.driver_date = "7-14-2009";
+ gpu_info_.machine_model = "MacBookPro 7.1";
+ gpu_info_.gl_vendor = "NVIDIA Corporation";
+ gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
+ gpu_info_.performance_stats.graphics = 5.0;
+ gpu_info_.performance_stats.gaming = 5.0;
+ gpu_info_.performance_stats.overall = 5.0;
+ }
+
+ virtual void TearDown() {
+ }
+
+ private:
+ GPUInfo gpu_info_;
+};
+
+TEST_F(GpuControlListTest, DefaultControlListSettings) {
+ scoped_ptr<GpuControlList> control_list(Create());
+ // Default control list settings: all feature are allowed.
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_EMPTY_SET(features);
+}
+
+TEST_F(GpuControlListTest, EmptyControlList) {
+ // Empty list: all features are allowed.
+ const std::string empty_list_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "2.5",
+ "entries": [
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list(Create());
+
+ EXPECT_TRUE(control_list->LoadList(empty_list_json,
+ GpuControlList::kAllOs));
+ EXPECT_EQ("2.5", control_list->version());
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_EMPTY_SET(features);
+}
+
+TEST_F(GpuControlListTest, DetailedEntryAndInvalidJson) {
+ // exact setting.
+ const std::string exact_list_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 5,
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "=",
+ "number": "10.6.4"
+ }
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0640"],
+ "driver_version": {
+ "op": "=",
+ "number": "1.6.18"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list(Create());
+
+ EXPECT_TRUE(control_list->LoadList(exact_list_json, GpuControlList::kAllOs));
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+
+ // Invalid json input should not change the current control_list settings.
+ const std::string invalid_json = "invalid";
+
+ EXPECT_FALSE(control_list->LoadList(invalid_json, GpuControlList::kAllOs));
+ features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ std::vector<uint32> entries;
+ control_list->GetDecisionEntries(&entries, false);
+ ASSERT_EQ(1u, entries.size());
+ EXPECT_EQ(5u, entries[0]);
+ EXPECT_EQ(5u, control_list->max_entry_id());
+}
+
+TEST_F(GpuControlListTest, VendorOnAllOsEntry) {
+ // ControlList a vendor on all OS.
+ const std::string vendor_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "vendor_id": "0x10de",
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list(Create());
+
+ // ControlList entries won't be filtered to the current OS only upon loading.
+ EXPECT_TRUE(control_list->LoadList(vendor_json, GpuControlList::kAllOs));
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ features = control_list->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_MACOSX) || \
+ defined(OS_OPENBSD)
+ // ControlList entries will be filtered to the current OS only upon loading.
+ EXPECT_TRUE(control_list->LoadList(
+ vendor_json, GpuControlList::kCurrentOsOnly));
+ features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ features = control_list->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+#endif
+}
+
+TEST_F(GpuControlListTest, ChromeVersionEntry) {
+ const std::string browser_version_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "browser_version": {
+ "op": ">=",
+ "number": "10"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list9(Create());
+ EXPECT_TRUE(control_list9->LoadList(
+ "9.0", browser_version_json, GpuControlList::kAllOs));
+ std::set<int> features = control_list9->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_EMPTY_SET(features);
+
+ scoped_ptr<GpuControlList> control_list10(Create());
+ EXPECT_TRUE(control_list10->LoadList(
+ "10.0", browser_version_json, GpuControlList::kAllOs));
+ features = control_list10->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+}
+
+TEST_F(GpuControlListTest, UnknownField) {
+ const std::string unknown_field_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "unknown_field": 0,
+ "features": [
+ "test_feature_1"
+ ]
+ },
+ {
+ "id": 2,
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list(Create());
+
+ EXPECT_TRUE(control_list->LoadList(
+ unknown_field_json, GpuControlList::kAllOs));
+ EXPECT_EQ(1u, control_list->num_entries());
+ EXPECT_TRUE(control_list->contains_unknown_fields());
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+}
+
+TEST_F(GpuControlListTest, UnknownExceptionField) {
+ const std::string unknown_exception_field_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "unknown_field": 0,
+ "features": [
+ "test_feature_2"
+ ]
+ },
+ {
+ "id": 2,
+ "exceptions": [
+ {
+ "unknown_field": 0
+ }
+ ],
+ "features": [
+ "test_feature_1"
+ ]
+ },
+ {
+ "id": 3,
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list(Create());
+
+ EXPECT_TRUE(control_list->LoadList(
+ unknown_exception_field_json, GpuControlList::kAllOs));
+ EXPECT_EQ(1u, control_list->num_entries());
+ EXPECT_TRUE(control_list->contains_unknown_fields());
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+}
+
+TEST_F(GpuControlListTest, DisabledEntry) {
+ const std::string disabled_json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "disabled": true,
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuControlList> control_list(Create());
+ EXPECT_TRUE(control_list->LoadList(disabled_json, GpuControlList::kAllOs));
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_EMPTY_SET(features);
+ std::vector<uint32> flag_entries;
+ control_list->GetDecisionEntries(&flag_entries, false);
+ EXPECT_EQ(0u, flag_entries.size());
+ control_list->GetDecisionEntries(&flag_entries, true);
+ EXPECT_EQ(1u, flag_entries.size());
+}
+
+TEST_F(GpuControlListTest, NeedsMoreInfoForExceptions) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "exceptions": [
+ {
+ "gl_renderer": {
+ "op": "contains",
+ "value": "mesa"
+ }
+ }
+ ],
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = kIntelVendorId;
+
+ scoped_ptr<GpuControlList> control_list(Create());
+ EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs));
+
+ // The case this entry does not apply.
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info);
+ EXPECT_EMPTY_SET(features);
+ EXPECT_FALSE(control_list->needs_more_info());
+
+ // The case this entry might apply, but need more info.
+ features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info);
+ EXPECT_EMPTY_SET(features);
+ EXPECT_TRUE(control_list->needs_more_info());
+
+ // The case we have full info, and the exception applies (so the entry
+ // does not apply).
+ gpu_info.gl_renderer = "mesa";
+ features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info);
+ EXPECT_EMPTY_SET(features);
+ EXPECT_FALSE(control_list->needs_more_info());
+
+ // The case we have full info, and this entry applies.
+ gpu_info.gl_renderer = "my renderer";
+ features = control_list->MakeDecision(GpuControlList::kOsLinux, kOsVersion,
+ gpu_info);
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ EXPECT_FALSE(control_list->needs_more_info());
+}
+
+TEST_F(GpuControlListTest, IgnorableEntries) {
+ // If an entry will not change the control_list decisions, then it should not
+ // trigger the needs_more_info flag.
+ const std::string json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "test_feature_0"
+ ]
+ },
+ {
+ "id": 2,
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "driver_version": {
+ "op": "<",
+ "number": "10.7"
+ },
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = kIntelVendorId;
+
+ scoped_ptr<GpuControlList> control_list(Create());
+ EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs));
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info);
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+ EXPECT_FALSE(control_list->needs_more_info());
+}
+
+TEST_F(GpuControlListTest, ExceptionWithoutVendorId) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "name": "gpu control list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "exceptions": [
+ {
+ "device_id": ["0x2a06"],
+ "driver_version": {
+ "op": ">=",
+ "number": "8.1"
+ }
+ },
+ {
+ "device_id": ["0x2a02"],
+ "driver_version": {
+ "op": ">=",
+ "number": "9.1"
+ }
+ }
+ ],
+ "features": [
+ "test_feature_0"
+ ]
+ }
+ ]
+ }
+ );
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = kIntelVendorId;
+ gpu_info.gpu.device_id = 0x2a02;
+ gpu_info.driver_version = "9.1";
+
+ scoped_ptr<GpuControlList> control_list(Create());
+ EXPECT_TRUE(control_list->LoadList(json, GpuControlList::kAllOs));
+
+ std::set<int> features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info);
+ EXPECT_EMPTY_SET(features);
+
+ gpu_info.driver_version = "9.0";
+ features = control_list->MakeDecision(
+ GpuControlList::kOsLinux, kOsVersion, gpu_info);
+ EXPECT_SINGLE_FEATURE(features, TEST_FEATURE_0);
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_control_list_version_info_unittest.cc b/chromium/gpu/config/gpu_control_list_version_info_unittest.cc
new file mode 100644
index 00000000000..39814c87089
--- /dev/null
+++ b/chromium/gpu/config/gpu_control_list_version_info_unittest.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_control_list.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class VersionInfoTest : public testing::Test {
+ public:
+ VersionInfoTest() { }
+ virtual ~VersionInfoTest() { }
+
+ typedef GpuControlList::VersionInfo VersionInfo;
+};
+
+TEST_F(VersionInfoTest, ValidVersionInfo) {
+ const std::string op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "any",
+ "between"
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ std::string string1;
+ std::string string2;
+ if (op[i] != "any")
+ string1 = "8.9";
+ if (op[i] == "between")
+ string2 = "9.0";
+ VersionInfo info(op[i], std::string(), string1, string2);
+ EXPECT_TRUE(info.IsValid());
+ }
+
+ const std::string style[] = {
+ "lexical",
+ "numerical",
+ "" // Default, same as "numerical"
+ };
+ for (size_t i =0; i < arraysize(style); ++i) {
+ VersionInfo info("=", style[i], "8.9", std::string());
+ EXPECT_TRUE(info.IsValid());
+ if (style[i] == "lexical")
+ EXPECT_TRUE(info.IsLexical());
+ else
+ EXPECT_FALSE(info.IsLexical());
+ }
+
+ const std::string number[] = {
+ "10",
+ "10.9",
+ "10.0",
+ "10.0.9",
+ "0.8",
+ // Leading 0s are valid.
+ "10.09",
+ // Whitespaces are ignored.
+ " 10.9",
+ "10.9 ",
+ "10 .9",
+ "10. 9",
+ };
+ for (size_t i =0; i < arraysize(number); ++i) {
+ VersionInfo info("=", std::string(), number[i], std::string());
+ EXPECT_TRUE(info.IsValid());
+ }
+}
+
+TEST_F(VersionInfoTest, InvalidVersionInfo) {
+ const std::string op[] = {
+ "=",
+ "<",
+ "<=",
+ ">",
+ ">=",
+ "any",
+ "between"
+ };
+ for (size_t i = 0; i < arraysize(op); ++i) {
+ {
+ VersionInfo info(op[i], std::string(), "8.9", std::string());
+ if (op[i] == "between")
+ EXPECT_FALSE(info.IsValid());
+ else
+ EXPECT_TRUE(info.IsValid());
+ }
+ {
+ VersionInfo info(op[i], std::string(), std::string(), std::string());
+ if (op[i] == "any")
+ EXPECT_TRUE(info.IsValid());
+ else
+ EXPECT_FALSE(info.IsValid());
+ }
+ {
+ VersionInfo info(op[i], std::string(), "8.9", "9.0");
+ EXPECT_TRUE(info.IsValid());
+ }
+ }
+
+ const std::string number[] = {
+ "8.E",
+ "8-9",
+ };
+ for (size_t i = 0; i < arraysize(number); ++i) {
+ VersionInfo info("=", std::string(), number[i], std::string());
+ EXPECT_FALSE(info.IsValid());
+ }
+}
+
+TEST_F(VersionInfoTest, VersionComparison) {
+ {
+ VersionInfo info("any", std::string(), std::string(), std::string());
+ EXPECT_TRUE(info.Contains("0"));
+ EXPECT_TRUE(info.Contains("8.9"));
+ EXPECT_TRUE(info.Contains("100"));
+ }
+ {
+ VersionInfo info(">", std::string(), "8.9", std::string());
+ EXPECT_FALSE(info.Contains("7"));
+ EXPECT_FALSE(info.Contains("8.9"));
+ EXPECT_FALSE(info.Contains("8.9.1"));
+ EXPECT_TRUE(info.Contains("9"));
+ }
+ {
+ VersionInfo info(">=", std::string(), "8.9", std::string());
+ EXPECT_FALSE(info.Contains("7"));
+ EXPECT_TRUE(info.Contains("8.9"));
+ EXPECT_TRUE(info.Contains("8.9.1"));
+ EXPECT_TRUE(info.Contains("9"));
+ }
+ {
+ VersionInfo info("=", std::string(), "8.9", std::string());
+ EXPECT_FALSE(info.Contains("7"));
+ EXPECT_TRUE(info.Contains("8"));
+ EXPECT_TRUE(info.Contains("8.9"));
+ EXPECT_TRUE(info.Contains("8.9.1"));
+ EXPECT_FALSE(info.Contains("9"));
+ }
+ {
+ VersionInfo info("<", std::string(), "8.9", std::string());
+ EXPECT_TRUE(info.Contains("7"));
+ EXPECT_TRUE(info.Contains("8.8"));
+ EXPECT_FALSE(info.Contains("8"));
+ EXPECT_FALSE(info.Contains("8.9"));
+ EXPECT_FALSE(info.Contains("8.9.1"));
+ EXPECT_FALSE(info.Contains("9"));
+ }
+ {
+ VersionInfo info("<=", std::string(), "8.9", std::string());
+ EXPECT_TRUE(info.Contains("7"));
+ EXPECT_TRUE(info.Contains("8.8"));
+ EXPECT_TRUE(info.Contains("8"));
+ EXPECT_TRUE(info.Contains("8.9"));
+ EXPECT_TRUE(info.Contains("8.9.1"));
+ EXPECT_FALSE(info.Contains("9"));
+ }
+ {
+ VersionInfo info("between", std::string(), "8.9", "9.1");
+ EXPECT_FALSE(info.Contains("7"));
+ EXPECT_FALSE(info.Contains("8.8"));
+ EXPECT_TRUE(info.Contains("8"));
+ EXPECT_TRUE(info.Contains("8.9"));
+ EXPECT_TRUE(info.Contains("8.9.1"));
+ EXPECT_TRUE(info.Contains("9"));
+ EXPECT_TRUE(info.Contains("9.1"));
+ EXPECT_TRUE(info.Contains("9.1.9"));
+ EXPECT_FALSE(info.Contains("9.2"));
+ EXPECT_FALSE(info.Contains("10"));
+ }
+}
+
+TEST_F(VersionInfoTest, DateComparison) {
+ // When we use '-' as splitter, we assume a format of mm-dd-yyyy
+ // or mm-yyyy, i.e., a date.
+ {
+ VersionInfo info("=", std::string(), "1976.3.21", std::string());
+ EXPECT_TRUE(info.Contains("3-21-1976", '-'));
+ EXPECT_TRUE(info.Contains("3-1976", '-'));
+ EXPECT_TRUE(info.Contains("03-1976", '-'));
+ EXPECT_FALSE(info.Contains("21-3-1976", '-'));
+ }
+ {
+ VersionInfo info(">", std::string(), "1976.3.21", std::string());
+ EXPECT_TRUE(info.Contains("3-22-1976", '-'));
+ EXPECT_TRUE(info.Contains("4-1976", '-'));
+ EXPECT_TRUE(info.Contains("04-1976", '-'));
+ EXPECT_FALSE(info.Contains("3-1976", '-'));
+ EXPECT_FALSE(info.Contains("2-1976", '-'));
+ }
+ {
+ VersionInfo info("between", std::string(), "1976.3.21", "2012.12.25");
+ EXPECT_FALSE(info.Contains("3-20-1976", '-'));
+ EXPECT_TRUE(info.Contains("3-21-1976", '-'));
+ EXPECT_TRUE(info.Contains("3-22-1976", '-'));
+ EXPECT_TRUE(info.Contains("3-1976", '-'));
+ EXPECT_TRUE(info.Contains("4-1976", '-'));
+ EXPECT_TRUE(info.Contains("1-1-2000", '-'));
+ EXPECT_TRUE(info.Contains("1-2000", '-'));
+ EXPECT_TRUE(info.Contains("2000", '-'));
+ EXPECT_TRUE(info.Contains("11-2012", '-'));
+ EXPECT_TRUE(info.Contains("12-2012", '-'));
+ EXPECT_TRUE(info.Contains("12-24-2012", '-'));
+ EXPECT_TRUE(info.Contains("12-25-2012", '-'));
+ EXPECT_FALSE(info.Contains("12-26-2012", '-'));
+ EXPECT_FALSE(info.Contains("1-2013", '-'));
+ EXPECT_FALSE(info.Contains("2013", '-'));
+ }
+}
+
+TEST_F(VersionInfoTest, LexicalComparison) {
+ // When we use lexical style, we assume a format major.minor.*.
+ // We apply numerical comparison to major, lexical comparison to others.
+ {
+ VersionInfo info("<", "lexical", "8.201", std::string());
+ EXPECT_TRUE(info.Contains("8.001.100"));
+ EXPECT_TRUE(info.Contains("8.109"));
+ EXPECT_TRUE(info.Contains("8.10900"));
+ EXPECT_TRUE(info.Contains("8.109.100"));
+ EXPECT_TRUE(info.Contains("8.2"));
+ EXPECT_TRUE(info.Contains("8.20"));
+ EXPECT_TRUE(info.Contains("8.200"));
+ EXPECT_TRUE(info.Contains("8.20.100"));
+ EXPECT_FALSE(info.Contains("8.201"));
+ EXPECT_FALSE(info.Contains("8.2010"));
+ EXPECT_FALSE(info.Contains("8.21"));
+ EXPECT_FALSE(info.Contains("8.21.100"));
+ EXPECT_FALSE(info.Contains("9.002"));
+ EXPECT_FALSE(info.Contains("9.201"));
+ EXPECT_FALSE(info.Contains("12"));
+ EXPECT_FALSE(info.Contains("12.201"));
+ }
+ {
+ VersionInfo info("<", "lexical", "9.002", std::string());
+ EXPECT_TRUE(info.Contains("8.001.100"));
+ EXPECT_TRUE(info.Contains("8.109"));
+ EXPECT_TRUE(info.Contains("8.10900"));
+ EXPECT_TRUE(info.Contains("8.109.100"));
+ EXPECT_TRUE(info.Contains("8.2"));
+ EXPECT_TRUE(info.Contains("8.20"));
+ EXPECT_TRUE(info.Contains("8.200"));
+ EXPECT_TRUE(info.Contains("8.20.100"));
+ EXPECT_TRUE(info.Contains("8.201"));
+ EXPECT_TRUE(info.Contains("8.2010"));
+ EXPECT_TRUE(info.Contains("8.21"));
+ EXPECT_TRUE(info.Contains("8.21.100"));
+ EXPECT_FALSE(info.Contains("9.002"));
+ EXPECT_FALSE(info.Contains("9.201"));
+ EXPECT_FALSE(info.Contains("12"));
+ EXPECT_FALSE(info.Contains("12.201"));
+ }
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_driver_bug_list.cc b/chromium/gpu/config/gpu_driver_bug_list.cc
new file mode 100644
index 00000000000..d845c163043
--- /dev/null
+++ b/chromium/gpu/config/gpu_driver_bug_list.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_driver_bug_list.h"
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+
+namespace gpu {
+
+namespace {
+
+struct DriverBugInfo {
+ int feature_type;
+ std::string feature_name;
+};
+
+} // namespace anonymous
+
+GpuDriverBugList::GpuDriverBugList()
+ : GpuControlList() {
+}
+
+GpuDriverBugList::~GpuDriverBugList() {
+}
+
+// static
+GpuDriverBugList* GpuDriverBugList::Create() {
+ GpuDriverBugList* list = new GpuDriverBugList();
+
+ const DriverBugInfo kFeatureList[] = {
+#define GPU_OP(type, name) { type, #name },
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+ };
+ DCHECK_EQ(static_cast<int>(arraysize(kFeatureList)),
+ NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES);
+ for (int i = 0; i < NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES; ++i) {
+ list->AddSupportedFeature(kFeatureList[i].feature_name,
+ kFeatureList[i].feature_type);
+ }
+ return list;
+}
+
+std::string GpuDriverBugWorkaroundTypeToString(
+ GpuDriverBugWorkaroundType type) {
+ switch (type) {
+#define GPU_OP(type, name) case type: return #name;
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+ default:
+ return "unknown";
+ };
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_driver_bug_list.h b/chromium/gpu/config/gpu_driver_bug_list.h
new file mode 100644
index 00000000000..99432516389
--- /dev/null
+++ b/chromium/gpu/config/gpu_driver_bug_list.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_DRIVER_BUG_LIST_H_
+#define GPU_CONFIG_GPU_DRIVER_BUG_LIST_H_
+
+#include <string>
+
+#include "gpu/config/gpu_control_list.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class GPU_EXPORT GpuDriverBugList : public GpuControlList {
+ public:
+ virtual ~GpuDriverBugList();
+
+ static GpuDriverBugList* Create();
+
+ private:
+ GpuDriverBugList();
+
+ DISALLOW_COPY_AND_ASSIGN(GpuDriverBugList);
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_DRIVER_BUG_LIST_H_
+
diff --git a/chromium/gpu/config/gpu_driver_bug_list_json.cc b/chromium/gpu/config/gpu_driver_bug_list_json.cc
new file mode 100644
index 00000000000..423a723f838
--- /dev/null
+++ b/chromium/gpu/config/gpu_driver_bug_list_json.cc
@@ -0,0 +1,434 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Determines whether a certain driver bug exists in the current system.
+// A valid gpu_driver_bug_list.json file are in the format of
+// {
+// "version": "x.y",
+// "entries": [
+// { // entry 1
+// },
+// ...
+// { // entry n
+// }
+// ]
+// }
+//
+// Each entry contains the following fields (fields are optional unless
+// specifically described as mandatory below):
+// 1. "id" is an integer. 0 is reserved. This field is mandatory.
+// 2. "os" contains "type" and an optional "version". "type" could be "macosx",
+// "linux", "win", "chromeos", or "any". "any" is the same as not specifying
+// "os".
+// "version" is a VERSION structure (defined below).
+// 3. "vendor_id" is a string. 0 is reserved.
+// 4. "device_id" is an array of strings. 0 is reserved.
+// 5. "multi_gpu_style" is a string, valid values include "optimus", and
+// "amd_switchable".
+// 6. "multi_gpu_category" is a string, valid values include "any", "primary",
+// and "secondary". If unspecified, the default value is "primary".
+// 7. "driver_vendor" is a STRING structure (defined below).
+// 8. "driver_version" is a VERSION structure (defined below).
+// 9. "driver_date" is a VERSION structure (defined below).
+// The version is interpreted as "year.month.day".
+// 10. "gl_vendor" is a STRING structure (defined below).
+// 11. "gl_renderer" is a STRING structure (defined below).
+// 12. "gl_extensions" is a STRING structure (defined below).
+// 13. "perf_graphics" is a FLOAT structure (defined below).
+// 14. "perf_gaming" is a FLOAT structure (defined below).
+// 15. "perf_overall" is a FLOAT structure (defined below).
+// 16. "machine_model" contains "name" and an optional "version". "name" is a
+// STRING structure and "version" is a VERSION structure (defined below).
+// 17. "gpu_count" is a INT structure (defined below).
+// 18 "cpu_info" is a STRING structure (defined below).
+// 19. "exceptions" is a list of entries.
+// 20. "features" is a list of driver bug types. For a list of supported types,
+// see src/gpu/command_buffer/service/gpu_driver_bug_workaround_type.h
+// This field is mandatory.
+// 21. "description" has the description of the entry.
+// 22. "webkit_bugs" is an array of associated webkit bug numbers.
+// 23. "cr_bugs" is an array of associated chromium bug numbers.
+// 24. "browser_version" is a VERSION structure (defined below). If this
+// condition is not satisfied, the entry will be ignored. If it is not
+// present, then the entry applies to all versions of the browser.
+// 25. "disabled" is a boolean. If it is present, the entry will be skipped.
+// This can not be used in exceptions.
+//
+// VERSION includes "op", "style", "number", and "number2". "op" can be any of
+// the following values: "=", "<", "<=", ">", ">=", "any", "between". "style"
+// is optional and can be "lexical" or "numerical"; if it's not specified, it
+// defaults to "numerical". "number2" is only used if "op" is "between".
+// "between" is "number <= * <= number2".
+// "number" is used for all "op" values except "any". "number" and "number2"
+// are in the format of x, x.x, x.x.x, etc.
+// Only "driver_version" supports lexical style if the format is major.minor;
+// in that case, major is still numerical, but minor is lexical.
+//
+// STRING includes "op" and "value". "op" can be any of the following values:
+// "contains", "beginwith", "endwith", "=". "value" is a string.
+//
+// FLOAT includes "op" "value", and "value2". "op" can be any of the
+// following values: "=", "<", "<=", ">", ">=", "any", "between". "value2" is
+// only used if "op" is "between". "value" is used for all "op" values except
+// "any". "value" and "value2" are valid float numbers.
+// INT is very much like FLOAT, except that the values need to be integers.
+
+#include "gpu/config/gpu_control_list_jsons.h"
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+namespace gpu {
+
+const char kGpuDriverBugListJson[] = LONG_STRING_CONST(
+
+{
+ "name": "gpu driver bug list",
+ // Please update the version number whenever you change this file.
+ "version": "2.5",
+ "entries": [
+ {
+ "id": 1,
+ "description": "Imagination driver doesn't like uploading lots of buffer data constantly",
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "Imagination"
+ },
+ "features": [
+ "use_client_side_arrays_for_stream_buffers"
+ ]
+ },
+ {
+ "id": 2,
+ "description": "ARM driver doesn't like uploading lots of buffer data constantly",
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "ARM"
+ },
+ "features": [
+ "use_client_side_arrays_for_stream_buffers"
+ ]
+ },
+ {
+ "id": 3,
+ "features": [
+ "set_texture_filter_before_generating_mipmap"
+ ]
+ },
+ {
+ "id": 4,
+ "description": "Need to set the alpha to 255",
+ "features": [
+ "clear_alpha_in_readpixels"
+ ]
+ },
+ {
+ "id": 5,
+ "vendor_id": "0x10de",
+ "features": [
+ "use_current_program_after_successful_link"
+ ]
+ },
+ {
+ "id": 6,
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "Qualcomm"
+ },
+ "features": [
+ "restore_scissor_on_fbo_change",
+ "delete_instead_of_resize_fbo" // Only need this on the ICS driver.
+ ]
+ },
+ {
+ "id": 7,
+ "cr_bugs": [89557],
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x10de",
+ "features": [
+ "needs_offscreen_buffer_workaround"
+ ]
+ },
+ {
+ "id": 8,
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x1002",
+ "features": [
+ "needs_glsl_built_in_function_emulation"
+ ]
+ },
+ {
+ "id": 9,
+ "description": "Mac AMD drivers get gl_PointCoord backward on OSX 10.8 or earlier",
+ "cr_bugs": [256349],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.9"
+ }
+ },
+ "vendor_id": "0x1002",
+ "features": [
+ "reverse_point_sprite_coord_origin"
+ ]
+ },
+ {
+ "id": 10,
+ "description": "Mac Intel drivers get gl_PointCoord backward on OSX 10.8 or earlier",
+ "cr_bugs": [256349],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.9"
+ }
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "reverse_point_sprite_coord_origin"
+ ]
+ },
+ {
+ "id": 11,
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "max_texture_size_limit_4096"
+ ]
+ },
+ {
+ "id": 12,
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "max_cube_map_texture_size_limit_1024"
+ ]
+ },
+ {
+ "id": 13,
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.7.3"
+ }
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "max_cube_map_texture_size_limit_512"
+ ]
+ },
+ {
+ "id": 14,
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x1002",
+ "features": [
+ "max_texture_size_limit_4096",
+ "max_cube_map_texture_size_limit_4096"
+ ]
+ },
+ {
+ "id": 15,
+ "description": "Some Android Qualcomm drivers falsely report GL_ANGLE_framebuffer_multisample",
+ "cr_bugs": [165736],
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "Qualcomm"
+ },
+ "features": [
+ "disable_angle_framebuffer_multisample"
+ ]
+ },
+ {
+ "id": 16,
+ "description": "Intel drivers on Linux appear to be buggy",
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "disable_ext_occlusion_query"
+ ]
+ },
+ {
+ "id": 17,
+ "description": "Some drivers are unable to reset the D3D device in the GPU process sandbox",
+ "os": {
+ "type": "win"
+ },
+ "features": [
+ "exit_on_context_lost"
+ ]
+ },
+ {
+ "id": 18,
+ "description": "Everything except async + NPOT + multiple-of-8 textures are brutally slow for Imagination drivers",
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "Imagination"
+ },
+ "features": [
+ "enable_chromium_fast_npot_mo8_textures"
+ ]
+ },
+ {
+ "id": 19,
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "Qualcomm"
+ },
+ "features": [
+ "disable_depth_texture"
+ ]
+ },
+ {
+ "id": 20,
+ "description": "Disable EXT_draw_buffers on GeForce GT 650M on Mac OS X due to driver bugs.",
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0fd5"],
+ "multi_gpu_category": "any",
+ "features": [
+ "disable_ext_draw_buffers"
+ ]
+ },
+ {
+ "id": 21,
+ "description": "Vivante GPUs are buggy with context switching.",
+ "cr_bugs": [179250, 235935],
+ "os": {
+ "type": "android"
+ },
+ "gl_extensions": {
+ "op": "contains",
+ "value": "GL_VIV_shader_binary"
+ },
+ "features": [
+ "unbind_fbo_on_context_switch"
+ ]
+ },
+ {
+ "id": 22,
+ "description": "Imagination drivers are buggy with context switching.",
+ "cr_bugs": [230896],
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "Imagination"
+ },
+ "features": [
+ "unbind_fbo_on_context_switch"
+ ]
+ },
+ {
+ "id": 23,
+ "cr_bugs": [243038],
+ "description": "Disable OES_standard_derivative on Intel Pineview M Gallium drivers.",
+ "os": {
+ "type": "chromeos"
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0xa011", "0xa012"],
+ "features": [
+ "disable_oes_standard_derivatives"
+ ]
+ },
+ {
+ "id": 24,
+ "cr_bugs": [231082],
+ "description": "Mali-400 drivers throw an error when a buffer object's size is set to 0.",
+ "os": {
+ "type": "android"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "ARM"
+ },
+ "gl_renderer": {
+ "op": "contains",
+ "value": "Mali-400"
+ },
+ "features": [
+ "use_non_zero_size_for_client_side_stream_buffers"
+ ]
+ },
+ {
+ "id": 25,
+ "cr_bugs": [152225],
+ "description":
+ "PBO + Readpixels + intel gpu doesn't work on OSX 10.7.",
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.8"
+ }
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "disable_async_readpixels"
+ ]
+ },
+ {
+ "id": 26,
+ "description": "Disable use of Direct3D 11 on Windows",
+ "os": {
+ "type": "win"
+ },
+ "features": [
+ "disable_d3d11"
+ ]
+ },
+ {
+ "id": 27,
+ "cr_bugs": [265115],
+ "description": "Async Readpixels with GL_BGRA format is broken on Haswell chipset on Mac.",
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0x0402", "0x0406", "0x040a", "0x0412", "0x0416", "0x041a",
+ "0x0a04", "0x0a16", "0x0a22", "0x0a26", "0x0a2a"],
+ "features": [
+ "swizzle_rgba_for_async_readpixels"
+ ]
+ }
+ ]
+}
+
+); // LONG_STRING_CONST macro
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_driver_bug_list_unittest.cc b/chromium/gpu/config/gpu_driver_bug_list_unittest.cc
new file mode 100644
index 00000000000..60bc3392c8f
--- /dev/null
+++ b/chromium/gpu/config/gpu_driver_bug_list_unittest.cc
@@ -0,0 +1,81 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/config/gpu_control_list_jsons.h"
+#include "gpu/config/gpu_driver_bug_list.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
+#include "gpu/config/gpu_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+const char kOsVersion[] = "10.6.4";
+
+namespace gpu {
+
+class GpuDriverBugListTest : public testing::Test {
+ public:
+ GpuDriverBugListTest() { }
+
+ virtual ~GpuDriverBugListTest() { }
+
+ const GPUInfo& gpu_info() const {
+ return gpu_info_;
+ }
+
+ protected:
+ virtual void SetUp() {
+ gpu_info_.gpu.vendor_id = 0x10de;
+ gpu_info_.gpu.device_id = 0x0640;
+ gpu_info_.driver_vendor = "NVIDIA";
+ gpu_info_.driver_version = "1.6.18";
+ gpu_info_.driver_date = "7-14-2009";
+ gpu_info_.machine_model = "MacBookPro 7.1";
+ gpu_info_.gl_vendor = "NVIDIA Corporation";
+ gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
+ gpu_info_.performance_stats.graphics = 5.0;
+ gpu_info_.performance_stats.gaming = 5.0;
+ gpu_info_.performance_stats.overall = 5.0;
+ }
+
+ virtual void TearDown() {
+ }
+
+ private:
+ GPUInfo gpu_info_;
+};
+
+TEST_F(GpuDriverBugListTest, CurrentDriverBugListValidation) {
+ scoped_ptr<GpuDriverBugList> list(GpuDriverBugList::Create());
+ std::string json;
+ EXPECT_TRUE(list->LoadList(kGpuDriverBugListJson, GpuControlList::kAllOs));
+ EXPECT_FALSE(list->contains_unknown_fields());
+}
+
+TEST_F(GpuDriverBugListTest, CurrentListForARM) {
+ scoped_ptr<GpuDriverBugList> list(GpuDriverBugList::Create());
+ EXPECT_TRUE(list->LoadList(kGpuDriverBugListJson, GpuControlList::kAllOs));
+
+ GPUInfo gpu_info;
+ gpu_info.gl_vendor = "ARM";
+ gpu_info.gl_renderer = "MALi_T604";
+ std::set<int> bugs = list->MakeDecision(
+ GpuControlList::kOsAndroid, "4.1", gpu_info);
+ EXPECT_EQ(1u, bugs.count(USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS));
+}
+
+TEST_F(GpuDriverBugListTest, CurrentListForImagination) {
+ scoped_ptr<GpuDriverBugList> list(GpuDriverBugList::Create());
+ EXPECT_TRUE(list->LoadList(kGpuDriverBugListJson, GpuControlList::kAllOs));
+
+ GPUInfo gpu_info;
+ gpu_info.gl_vendor = "Imagination Technologies";
+ gpu_info.gl_renderer = "PowerVR SGX 540";
+ std::set<int> bugs = list->MakeDecision(
+ GpuControlList::kOsAndroid, "4.1", gpu_info);
+ EXPECT_EQ(1u, bugs.count(USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS));
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_driver_bug_workaround_type.h b/chromium/gpu/config/gpu_driver_bug_workaround_type.h
new file mode 100644
index 00000000000..20198dacd1a
--- /dev/null
+++ b/chromium/gpu/config/gpu_driver_bug_workaround_type.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_DRIVER_BUG_WORKAROUND_TYPE_H_
+#define GPU_CONFIG_GPU_DRIVER_BUG_WORKAROUND_TYPE_H_
+
+#include <string>
+
+#include "gpu/gpu_export.h"
+
+#define GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP) \
+ GPU_OP(CLEAR_ALPHA_IN_READPIXELS, \
+ clear_alpha_in_readpixels) \
+ GPU_OP(CLEAR_UNIFORMS_BEFORE_PROGRAM_USE, \
+ clear_uniforms_before_program_use) \
+ GPU_OP(DELETE_INSTEAD_OF_RESIZE_FBO, \
+ delete_instead_of_resize_fbo) \
+ GPU_OP(DISABLE_ANGLE_FRAMEBUFFER_MULTISAMPLE, \
+ disable_angle_framebuffer_multisample) \
+ GPU_OP(DISABLE_DEPTH_TEXTURE, \
+ disable_depth_texture) \
+ GPU_OP(DISABLE_EXT_DRAW_BUFFERS, \
+ disable_ext_draw_buffers) \
+ GPU_OP(DISABLE_EXT_OCCLUSION_QUERY, \
+ disable_ext_occlusion_query) \
+ GPU_OP(DISABLE_OES_STANDARD_DERIVATIVES, \
+ disable_oes_standard_derivatives) \
+ GPU_OP(ENABLE_CHROMIUM_FAST_NPOT_MO8_TEXTURES, \
+ enable_chromium_fast_npot_mo8_textures) \
+ GPU_OP(EXIT_ON_CONTEXT_LOST, \
+ exit_on_context_lost) \
+ GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_1024, \
+ max_cube_map_texture_size_limit_1024) \
+ GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_4096, \
+ max_cube_map_texture_size_limit_4096) \
+ GPU_OP(MAX_CUBE_MAP_TEXTURE_SIZE_LIMIT_512, \
+ max_cube_map_texture_size_limit_512) \
+ GPU_OP(MAX_TEXTURE_SIZE_LIMIT_4096, \
+ max_texture_size_limit_4096) \
+ GPU_OP(NEEDS_GLSL_BUILT_IN_FUNCTION_EMULATION, \
+ needs_glsl_built_in_function_emulation) \
+ GPU_OP(NEEDS_OFFSCREEN_BUFFER_WORKAROUND, \
+ needs_offscreen_buffer_workaround) \
+ GPU_OP(RESTORE_SCISSOR_ON_FBO_CHANGE, \
+ restore_scissor_on_fbo_change) \
+ GPU_OP(REVERSE_POINT_SPRITE_COORD_ORIGIN, \
+ reverse_point_sprite_coord_origin) \
+ GPU_OP(SET_TEXTURE_FILTER_BEFORE_GENERATING_MIPMAP, \
+ set_texture_filter_before_generating_mipmap) \
+ GPU_OP(UNBIND_FBO_ON_CONTEXT_SWITCH, \
+ unbind_fbo_on_context_switch) \
+ GPU_OP(USE_CLIENT_SIDE_ARRAYS_FOR_STREAM_BUFFERS, \
+ use_client_side_arrays_for_stream_buffers) \
+ GPU_OP(USE_CURRENT_PROGRAM_AFTER_SUCCESSFUL_LINK, \
+ use_current_program_after_successful_link) \
+ GPU_OP(USE_NON_ZERO_SIZE_FOR_CLIENT_SIDE_STREAM_BUFFERS, \
+ use_non_zero_size_for_client_side_stream_buffers) \
+ GPU_OP(DISABLE_ASYNC_READPIXELS, \
+ disable_async_readpixels) \
+ GPU_OP(DISABLE_D3D11, \
+ disable_d3d11) \
+ GPU_OP(SWIZZLE_RGBA_FOR_ASYNC_READPIXELS, \
+ swizzle_rgba_for_async_readpixels) \
+
+namespace gpu {
+
+// Provides all types of GPU driver bug workarounds.
+enum GPU_EXPORT GpuDriverBugWorkaroundType {
+#define GPU_OP(type, name) type,
+ GPU_DRIVER_BUG_WORKAROUNDS(GPU_OP)
+#undef GPU_OP
+ NUMBER_OF_GPU_DRIVER_BUG_WORKAROUND_TYPES
+};
+
+GPU_EXPORT std::string GpuDriverBugWorkaroundTypeToString(
+ GpuDriverBugWorkaroundType type);
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_DRIVER_BUG_WORKAROUND_TYPE_H_
diff --git a/chromium/gpu/config/gpu_dx_diagnostics_win.cc b/chromium/gpu/config/gpu_dx_diagnostics_win.cc
new file mode 100644
index 00000000000..023e351d82c
--- /dev/null
+++ b/chromium/gpu/config/gpu_dx_diagnostics_win.cc
@@ -0,0 +1,135 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// Functions to enumerate the Dx Diagnostic Tool hierarchy and build up
+// a tree of nodes with name / value properties.
+
+#define INITGUID
+#include <dxdiag.h>
+#include <windows.h>
+
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/scoped_com_initializer.h"
+#include "gpu/config/gpu_info_collector.h"
+
+namespace gpu {
+
+namespace {
+
+// Traverses the IDxDiagContainer tree and populates a tree of DxDiagNode
+// structures that contains property name / value pairs and subtrees of DirectX
+// diagnostic information.
+void RecurseDiagnosticTree(DxDiagNode* output,
+ IDxDiagContainer* container,
+ int depth) {
+ HRESULT hr;
+
+ VARIANT variant;
+ VariantInit(&variant);
+
+ DWORD prop_count;
+ hr = container->GetNumberOfProps(&prop_count);
+ if (SUCCEEDED(hr)) {
+ for (DWORD i = 0; i < prop_count; i++) {
+ WCHAR prop_name16[256];
+ hr = container->EnumPropNames(i, prop_name16, arraysize(prop_name16));
+ if (SUCCEEDED(hr)) {
+ std::string prop_name8 = WideToUTF8(prop_name16);
+
+ hr = container->GetProp(prop_name16, &variant);
+ if (SUCCEEDED(hr)) {
+ switch (variant.vt) {
+ case VT_UI4:
+ output->values[prop_name8] = base::UintToString(variant.ulVal);
+ break;
+ case VT_I4:
+ output->values[prop_name8] = base::IntToString(variant.lVal);
+ break;
+ case VT_BOOL:
+ output->values[prop_name8] = variant.boolVal ? "true" : "false";
+ break;
+ case VT_BSTR:
+ output->values[prop_name8] = WideToUTF8(variant.bstrVal);
+ break;
+ default:
+ break;
+ }
+
+ // Clear the variant (this is needed to free BSTR memory).
+ VariantClear(&variant);
+ }
+ }
+ }
+ }
+
+ if (depth > 0) {
+ DWORD child_count;
+ hr = container->GetNumberOfChildContainers(&child_count);
+ if (SUCCEEDED(hr)) {
+ for (DWORD i = 0; i < child_count; i++) {
+ WCHAR child_name16[256];
+ hr = container->EnumChildContainerNames(i,
+ child_name16,
+ arraysize(child_name16));
+ if (SUCCEEDED(hr)) {
+ std::string child_name8 = WideToUTF8(child_name16);
+ DxDiagNode* output_child = &output->children[child_name8];
+
+ IDxDiagContainer* child_container = NULL;
+ hr = container->GetChildContainer(child_name16, &child_container);
+ if (SUCCEEDED(hr)) {
+ RecurseDiagnosticTree(output_child, child_container, depth - 1);
+
+ child_container->Release();
+ }
+ }
+ }
+ }
+ }
+}
+} // namespace anonymous
+
+bool GetDxDiagnostics(DxDiagNode* output) {
+ HRESULT hr;
+ bool success = false;
+ base::win::ScopedCOMInitializer com_initializer;
+
+ IDxDiagProvider* provider = NULL;
+ hr = CoCreateInstance(CLSID_DxDiagProvider,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IDxDiagProvider,
+ reinterpret_cast<void**>(&provider));
+ if (SUCCEEDED(hr)) {
+ DXDIAG_INIT_PARAMS params = { sizeof(params) };
+ params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION;
+ params.bAllowWHQLChecks = FALSE;
+ params.pReserved = NULL;
+
+ hr = provider->Initialize(&params);
+ if (SUCCEEDED(hr)) {
+ IDxDiagContainer* root = NULL;
+ hr = provider->GetRootContainer(&root);
+ if (SUCCEEDED(hr)) {
+ // Limit to the DisplayDevices subtree. The tree in its entirity is
+ // enormous and only this branch contains useful information.
+ IDxDiagContainer* display_devices = NULL;
+ hr = root->GetChildContainer(L"DxDiag_DisplayDevices",
+ &display_devices);
+ if (SUCCEEDED(hr)) {
+ RecurseDiagnosticTree(output, display_devices, 1);
+ success = true;
+ display_devices->Release();
+ }
+
+ root->Release();
+ }
+ }
+ provider->Release();
+ }
+
+ return success;
+}
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_feature_type.h b/chromium/gpu/config/gpu_feature_type.h
new file mode 100644
index 00000000000..b082d7884c4
--- /dev/null
+++ b/chromium/gpu/config/gpu_feature_type.h
@@ -0,0 +1,32 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_FEATURE_TYPE_H_
+#define GPU_CONFIG_GPU_FEATURE_TYPE_H_
+
+namespace gpu {
+
+// Provides flags indicating which gpu features are blacklisted for the system
+// on which chrome is currently running.
+// If a bit is set to 1, corresponding feature is blacklisted.
+enum GpuFeatureType {
+ GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS = 0,
+ GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING,
+ GPU_FEATURE_TYPE_WEBGL,
+ GPU_FEATURE_TYPE_MULTISAMPLING,
+ GPU_FEATURE_TYPE_FLASH3D,
+ GPU_FEATURE_TYPE_FLASH_STAGE3D,
+ GPU_FEATURE_TYPE_TEXTURE_SHARING,
+ GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE,
+ GPU_FEATURE_TYPE_3D_CSS,
+ GPU_FEATURE_TYPE_ACCELERATED_VIDEO,
+ GPU_FEATURE_TYPE_PANEL_FITTING,
+ GPU_FEATURE_TYPE_FORCE_COMPOSITING_MODE,
+ GPU_FEATURE_TYPE_FLASH_STAGE3D_BASELINE,
+ NUMBER_OF_GPU_FEATURE_TYPES
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_FEATURE_TYPE_H_
diff --git a/chromium/gpu/config/gpu_info.cc b/chromium/gpu/config/gpu_info.cc
new file mode 100644
index 00000000000..827c76c17ce
--- /dev/null
+++ b/chromium/gpu/config/gpu_info.cc
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info.h"
+
+namespace gpu {
+
+GPUInfo::GPUDevice::GPUDevice()
+ : vendor_id(0),
+ device_id(0) {
+}
+
+GPUInfo::GPUDevice::~GPUDevice() { }
+
+GPUInfo::GPUInfo()
+ : finalized(false),
+ optimus(false),
+ amd_switchable(false),
+ lenovo_dcute(false),
+ adapter_luid(0),
+ gl_reset_notification_strategy(0),
+ can_lose_context(false),
+ software_rendering(false),
+ sandboxed(false) {
+}
+
+GPUInfo::~GPUInfo() { }
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_info.h b/chromium/gpu/config/gpu_info.h
new file mode 100644
index 00000000000..98ab80ca300
--- /dev/null
+++ b/chromium/gpu/config/gpu_info.h
@@ -0,0 +1,147 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_INFO_H_
+#define GPU_CONFIG_GPU_INFO_H_
+
+// Provides access to the GPU information for the system
+// on which chrome is currently running.
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time/time.h"
+#include "base/version.h"
+#include "build/build_config.h"
+#include "gpu/config/dx_diag_node.h"
+#include "gpu/config/gpu_performance_stats.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+struct GPU_EXPORT GPUInfo {
+ struct GPU_EXPORT GPUDevice {
+ GPUDevice();
+ ~GPUDevice();
+
+ // The DWORD (uint32) representing the graphics card vendor id.
+ uint32 vendor_id;
+
+ // The DWORD (uint32) representing the graphics card device id.
+ // Device ids are unique to vendor, not to one another.
+ uint32 device_id;
+
+ // The strings that describe the GPU.
+ // In Linux these strings are obtained through libpci.
+ // In Win/MacOSX, these two strings are not filled at the moment.
+ std::string vendor_string;
+ std::string device_string;
+ };
+
+ GPUInfo();
+ ~GPUInfo();
+
+ // Whether more GPUInfo fields might be collected in the future.
+ bool finalized;
+
+ // The amount of time taken to get from the process starting to the message
+ // loop being pumped.
+ base::TimeDelta initialization_time;
+
+ // Computer has NVIDIA Optimus
+ bool optimus;
+
+ // Computer has AMD Dynamic Switchable Graphics
+ bool amd_switchable;
+
+ // Lenovo dCute is installed. http://crbug.com/181665.
+ bool lenovo_dcute;
+
+ // Version of DisplayLink driver installed. Zero if not installed.
+ // http://crbug.com/177611.
+ Version display_link_version;
+
+ // Primary GPU, for exmaple, the discrete GPU in a dual GPU machine.
+ GPUDevice gpu;
+
+ // Secondary GPUs, for example, the integrated GPU in a dual GPU machine.
+ std::vector<GPUDevice> secondary_gpus;
+
+ // On Windows, the unique identifier of the adapter the GPU process uses.
+ // The default is zero, which makes the browser process create its D3D device
+ // on the primary adapter. Note that the primary adapter can change at any
+ // time so it is better to specify a particular LUID. Note that valid LUIDs
+ // are always non-zero.
+ uint64 adapter_luid;
+
+ // The vendor of the graphics driver currently installed.
+ std::string driver_vendor;
+
+ // The version of the graphics driver currently installed.
+ std::string driver_version;
+
+ // The date of the graphics driver currently installed.
+ std::string driver_date;
+
+ // The version of the pixel/fragment shader used by the gpu.
+ std::string pixel_shader_version;
+
+ // The version of the vertex shader used by the gpu.
+ std::string vertex_shader_version;
+
+ // The machine model identifier with format "name major.minor".
+ // Name should not contain any whitespaces.
+ std::string machine_model;
+
+ // The version of OpenGL we are using.
+ // TODO(zmo): should be able to tell if it's GL or GLES.
+ std::string gl_version;
+
+ // The GL_VERSION string. "" if we are not using OpenGL.
+ std::string gl_version_string;
+
+ // The GL_VENDOR string. "" if we are not using OpenGL.
+ std::string gl_vendor;
+
+ // The GL_RENDERER string. "" if we are not using OpenGL.
+ std::string gl_renderer;
+
+ // The GL_EXTENSIONS string. "" if we are not using OpenGL.
+ std::string gl_extensions;
+
+ // GL window system binding vendor. "" if not available.
+ std::string gl_ws_vendor;
+
+ // GL window system binding version. "" if not available.
+ std::string gl_ws_version;
+
+ // GL window system binding extensions. "" if not available.
+ std::string gl_ws_extensions;
+
+ // GL reset notification strategy as defined by GL_ARB_robustness. 0 if GPU
+ // reset detection or notification not available.
+ uint32 gl_reset_notification_strategy;
+
+ // The device semantics, i.e. whether the Vista and Windows 7 specific
+ // semantics are available.
+ bool can_lose_context;
+
+ // By default all values are 0.
+ GpuPerformanceStats performance_stats;
+
+ bool software_rendering;
+
+ // Whether the gpu process is running in a sandbox.
+ bool sandboxed;
+
+#if defined(OS_WIN)
+ // The information returned by the DirectX Diagnostics Tool.
+ DxDiagNode dx_diagnostics;
+#endif
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_INFO_H_
diff --git a/chromium/gpu/config/gpu_info_collector.cc b/chromium/gpu/config/gpu_info_collector.cc
new file mode 100644
index 00000000000..0bb83dd04f7
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector.cc
@@ -0,0 +1,161 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info_collector.h"
+
+#include <string>
+#include <vector>
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+
+namespace {
+
+scoped_refptr<gfx::GLSurface> InitializeGLSurface() {
+ scoped_refptr<gfx::GLSurface> surface(
+ gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(1, 1)));
+ if (!surface.get()) {
+ LOG(ERROR) << "gfx::GLContext::CreateOffscreenGLSurface failed";
+ return NULL;
+ }
+
+ return surface;
+}
+
+scoped_refptr<gfx::GLContext> InitializeGLContext(gfx::GLSurface* surface) {
+
+ scoped_refptr<gfx::GLContext> context(
+ gfx::GLContext::CreateGLContext(NULL,
+ surface,
+ gfx::PreferIntegratedGpu));
+ if (!context.get()) {
+ LOG(ERROR) << "gfx::GLContext::CreateGLContext failed";
+ return NULL;
+ }
+
+ if (!context->MakeCurrent(surface)) {
+ LOG(ERROR) << "gfx::GLContext::MakeCurrent() failed";
+ return NULL;
+ }
+
+ return context;
+}
+
+std::string GetGLString(unsigned int pname) {
+ const char* gl_string =
+ reinterpret_cast<const char*>(glGetString(pname));
+ if (gl_string)
+ return std::string(gl_string);
+ return std::string();
+}
+
+// Return a version string in the format of "major.minor".
+std::string GetVersionFromString(const std::string& version_string) {
+ size_t begin = version_string.find_first_of("0123456789");
+ if (begin != std::string::npos) {
+ size_t end = version_string.find_first_not_of("01234567890.", begin);
+ std::string sub_string;
+ if (end != std::string::npos)
+ sub_string = version_string.substr(begin, end - begin);
+ else
+ sub_string = version_string.substr(begin);
+ std::vector<std::string> pieces;
+ base::SplitString(sub_string, '.', &pieces);
+ if (pieces.size() >= 2)
+ return pieces[0] + "." + pieces[1];
+ }
+ return std::string();
+}
+
+} // namespace anonymous
+
+namespace gpu {
+
+bool CollectGraphicsInfoGL(GPUInfo* gpu_info) {
+ TRACE_EVENT0("startup", "gpu_info_collector::CollectGraphicsInfoGL");
+ if (!gfx::GLSurface::InitializeOneOff()) {
+ LOG(ERROR) << "gfx::GLSurface::InitializeOneOff() failed";
+ return false;
+ }
+
+ scoped_refptr<gfx::GLSurface> surface(InitializeGLSurface());
+ if (!surface.get())
+ return false;
+
+ scoped_refptr<gfx::GLContext> context(InitializeGLContext(surface.get()));
+ if (!context.get())
+ return false;
+
+ gpu_info->gl_renderer = GetGLString(GL_RENDERER);
+ gpu_info->gl_vendor = GetGLString(GL_VENDOR);
+ gpu_info->gl_extensions = GetGLString(GL_EXTENSIONS);
+ gpu_info->gl_version_string = GetGLString(GL_VERSION);
+ std::string glsl_version_string = GetGLString(GL_SHADING_LANGUAGE_VERSION);
+
+ gfx::GLWindowSystemBindingInfo window_system_binding_info;
+ if (GetGLWindowSystemBindingInfo(&window_system_binding_info)) {
+ gpu_info->gl_ws_vendor = window_system_binding_info.vendor;
+ gpu_info->gl_ws_version = window_system_binding_info.version;
+ gpu_info->gl_ws_extensions = window_system_binding_info.extensions;
+ }
+
+ bool supports_robustness =
+ gpu_info->gl_extensions.find("GL_EXT_robustness") != std::string::npos ||
+ gpu_info->gl_extensions.find("GL_ARB_robustness") != std::string::npos;
+ if (supports_robustness) {
+ glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_ARB,
+ reinterpret_cast<GLint*>(&gpu_info->gl_reset_notification_strategy));
+ }
+
+ // TODO(kbr): remove once the destruction of a current context automatically
+ // clears the current context.
+ context->ReleaseCurrent(surface.get());
+
+ gpu_info->gl_version = GetVersionFromString(gpu_info->gl_version_string);
+ std::string glsl_version = GetVersionFromString(glsl_version_string);
+ gpu_info->pixel_shader_version = glsl_version;
+ gpu_info->vertex_shader_version = glsl_version;
+
+ return CollectDriverInfoGL(gpu_info);
+}
+
+void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info) {
+ DCHECK(basic_gpu_info);
+ basic_gpu_info->gl_renderer = context_gpu_info.gl_renderer;
+ basic_gpu_info->gl_vendor = context_gpu_info.gl_vendor;
+ basic_gpu_info->gl_version_string = context_gpu_info.gl_version_string;
+ basic_gpu_info->gl_extensions = context_gpu_info.gl_extensions;
+ basic_gpu_info->gl_version = context_gpu_info.gl_version;
+ basic_gpu_info->pixel_shader_version =
+ context_gpu_info.pixel_shader_version;
+ basic_gpu_info->vertex_shader_version =
+ context_gpu_info.vertex_shader_version;
+ basic_gpu_info->gl_ws_vendor = context_gpu_info.gl_ws_vendor;
+ basic_gpu_info->gl_ws_version = context_gpu_info.gl_ws_version;
+ basic_gpu_info->gl_ws_extensions = context_gpu_info.gl_ws_extensions;
+ basic_gpu_info->gl_reset_notification_strategy =
+ context_gpu_info.gl_reset_notification_strategy;
+
+ if (!context_gpu_info.driver_vendor.empty())
+ basic_gpu_info->driver_vendor = context_gpu_info.driver_vendor;
+ if (!context_gpu_info.driver_version.empty())
+ basic_gpu_info->driver_version = context_gpu_info.driver_version;
+
+ basic_gpu_info->can_lose_context = context_gpu_info.can_lose_context;
+ basic_gpu_info->sandboxed = context_gpu_info.sandboxed;
+ basic_gpu_info->finalized = context_gpu_info.finalized;
+ basic_gpu_info->initialization_time = context_gpu_info.initialization_time;
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_info_collector.h b/chromium/gpu/config/gpu_info_collector.h
new file mode 100644
index 00000000000..e89535a08eb
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector.h
@@ -0,0 +1,67 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_INFO_COLLECTOR_H_
+#define GPU_CONFIG_GPU_INFO_COLLECTOR_H_
+
+#include "base/basictypes.h"
+#include "build/build_config.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+enum GpuIDResult {
+ kGpuIDFailure,
+ kGpuIDSuccess,
+ kGpuIDNotSupported
+};
+
+// Collect GPU vendor_id and device ID.
+GPU_EXPORT GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id);
+
+// Collects basic GPU info without creating a GL/DirectX context (and without
+// the danger of crashing), including vendor_id and device_id.
+// This is called at browser process startup time.
+// The subset each platform collects may be different.
+GPU_EXPORT bool CollectBasicGraphicsInfo(GPUInfo* gpu_info);
+
+// Create a GL/DirectX context and collect related info.
+// This is called at GPU process startup time.
+// Returns true on success.
+GPU_EXPORT bool CollectContextGraphicsInfo(GPUInfo* gpu_info);
+
+#if defined(OS_WIN)
+// Collect the DirectX Disagnostics information about the attached displays.
+GPU_EXPORT bool GetDxDiagnostics(DxDiagNode* output);
+#endif // OS_WIN
+
+// Create a GL context and collect GL strings and versions.
+GPU_EXPORT bool CollectGraphicsInfoGL(GPUInfo* gpu_info);
+
+// Each platform stores the driver version on the GL_VERSION string differently
+GPU_EXPORT bool CollectDriverInfoGL(GPUInfo* gpu_info);
+
+// Merge GPUInfo from CollectContextGraphicsInfo into basic GPUInfo.
+// This is platform specific, depending on which info are collected at which
+// stage.
+GPU_EXPORT void MergeGPUInfo(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info);
+
+// MergeGPUInfo() when GL driver is used.
+GPU_EXPORT void MergeGPUInfoGL(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info);
+
+// Advanced Micro Devices has interesting configurations on laptops were
+// there are two videocards that can alternatively a given process output.
+enum AMDVideoCardType {
+ UNKNOWN,
+ STANDALONE,
+ INTEGRATED,
+ SWITCHABLE
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_INFO_COLLECTOR_H_
diff --git a/chromium/gpu/config/gpu_info_collector_android.cc b/chromium/gpu/config/gpu_info_collector_android.cc
new file mode 100644
index 00000000000..a26606af18a
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector_android.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info_collector.h"
+
+#include "base/android/build_info.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+
+namespace {
+
+std::string GetDriverVersionFromString(const std::string& version_string) {
+ // Extract driver version from the second number in a string like:
+ // "OpenGL ES 2.0 V@6.0 AU@ (CL@2946718)"
+
+ // Exclude first "2.0".
+ size_t begin = version_string.find_first_of("0123456789");
+ if (begin == std::string::npos)
+ return "0";
+ size_t end = version_string.find_first_not_of("01234567890.", begin);
+
+ // Extract number of the form "%d.%d"
+ begin = version_string.find_first_of("0123456789", end);
+ if (begin == std::string::npos)
+ return "0";
+ end = version_string.find_first_not_of("01234567890.", begin);
+ std::string sub_string;
+ if (end != std::string::npos)
+ sub_string = version_string.substr(begin, end - begin);
+ else
+ sub_string = version_string.substr(begin);
+ std::vector<std::string> pieces;
+ base::SplitString(sub_string, '.', &pieces);
+ if (pieces.size() < 2)
+ return "0";
+ return pieces[0] + "." + pieces[1];
+}
+
+}
+
+namespace gpu {
+
+bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
+ return CollectBasicGraphicsInfo(gpu_info);
+}
+
+GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
+ DCHECK(vendor_id && device_id);
+ *vendor_id = 0;
+ *device_id = 0;
+ return kGpuIDNotSupported;
+}
+
+bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
+ gpu_info->can_lose_context = false;
+ gpu_info->finalized = true;
+
+ gpu_info->machine_model = base::android::BuildInfo::GetInstance()->model();
+
+ // Create a short-lived context on the UI thread to collect the GL strings.
+ return CollectGraphicsInfoGL(gpu_info);
+}
+
+bool CollectDriverInfoGL(GPUInfo* gpu_info) {
+ gpu_info->driver_version = GetDriverVersionFromString(
+ gpu_info->gl_version_string);
+ return true;
+}
+
+void MergeGPUInfo(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info) {
+ MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_info_collector_mac.mm b/chromium/gpu/config/gpu_info_collector_mac.mm
new file mode 100644
index 00000000000..1f7fad1ad20
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector_mac.mm
@@ -0,0 +1,220 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info_collector.h"
+
+#include <vector>
+
+#include "base/debug/trace_event.h"
+#include "base/logging.h"
+#include "base/mac/mac_util.h"
+#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_util.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_interface.h"
+
+#import <Cocoa/Cocoa.h>
+#import <Foundation/Foundation.h>
+#import <IOKit/IOKitLib.h>
+
+namespace gpu {
+
+namespace {
+
+const UInt32 kVendorIDIntel = 0x8086;
+const UInt32 kVendorIDNVidia = 0x10de;
+const UInt32 kVendorIDAMD = 0x1002;
+
+// Return 0 if we couldn't find the property.
+// The property values we use should not be 0, so it's OK to use 0 as failure.
+UInt32 GetEntryProperty(io_registry_entry_t entry, CFStringRef property_name) {
+ base::ScopedCFTypeRef<CFDataRef> data_ref(
+ static_cast<CFDataRef>(IORegistryEntrySearchCFProperty(
+ entry,
+ kIOServicePlane,
+ property_name,
+ kCFAllocatorDefault,
+ kIORegistryIterateRecursively | kIORegistryIterateParents)));
+ if (!data_ref)
+ return 0;
+
+ UInt32 value = 0;
+ const UInt32* value_pointer =
+ reinterpret_cast<const UInt32*>(CFDataGetBytePtr(data_ref));
+ if (value_pointer != NULL)
+ value = *value_pointer;
+ return value;
+}
+
+// Find the info of the current GPU.
+GPUInfo::GPUDevice GetActiveGPU() {
+ GPUInfo::GPUDevice gpu;
+ io_registry_entry_t dsp_port = CGDisplayIOServicePort(kCGDirectMainDisplay);
+ gpu.vendor_id = GetEntryProperty(dsp_port, CFSTR("vendor-id"));
+ gpu.device_id = GetEntryProperty(dsp_port, CFSTR("device-id"));
+ return gpu;
+}
+
+// Scan IO registry for PCI video cards.
+bool CollectPCIVideoCardInfo(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ // Collect all GPUs' info.
+ // match_dictionary will be consumed by IOServiceGetMatchingServices, no need
+ // to release it.
+ CFMutableDictionaryRef match_dictionary = IOServiceMatching("IOPCIDevice");
+ io_iterator_t entry_iterator;
+ std::vector<GPUInfo::GPUDevice> gpu_list;
+ if (IOServiceGetMatchingServices(kIOMasterPortDefault,
+ match_dictionary,
+ &entry_iterator) == kIOReturnSuccess) {
+ io_registry_entry_t entry;
+ while ((entry = IOIteratorNext(entry_iterator))) {
+ GPUInfo::GPUDevice gpu;
+ if (GetEntryProperty(entry, CFSTR("class-code")) != 0x30000) {
+ // 0x30000 : DISPLAY_VGA
+ continue;
+ }
+ gpu.vendor_id = GetEntryProperty(entry, CFSTR("vendor-id"));
+ gpu.device_id = GetEntryProperty(entry, CFSTR("device-id"));
+ if (gpu.vendor_id && gpu.device_id)
+ gpu_list.push_back(gpu);
+ }
+ IOObjectRelease(entry_iterator);
+ }
+
+ switch (gpu_list.size()) {
+ case 0:
+ return false;
+ case 1:
+ gpu_info->gpu = gpu_list[0];
+ break;
+ case 2:
+ {
+ int integrated = -1;
+ int discrete = -1;
+ if (gpu_list[0].vendor_id == kVendorIDIntel)
+ integrated = 0;
+ else if (gpu_list[1].vendor_id == kVendorIDIntel)
+ integrated = 1;
+ if (integrated >= 0) {
+ switch (gpu_list[1 - integrated].vendor_id) {
+ case kVendorIDAMD:
+ gpu_info->amd_switchable = true;
+ discrete = 1 - integrated;
+ break;
+ case kVendorIDNVidia:
+ gpu_info->optimus = true;
+ discrete = 1 - integrated;
+ break;
+ default:
+ break;
+ }
+ }
+ if (integrated >= 0 && discrete >= 0) {
+ // We always put discrete GPU as primary for blacklisting purpose.
+ gpu_info->gpu = gpu_list[discrete];
+ gpu_info->secondary_gpus.push_back(gpu_list[integrated]);
+ break;
+ }
+ // If it's not optimus or amd_switchable, we put the current GPU as
+ // primary. Fall through to default.
+ }
+ default:
+ {
+ GPUInfo::GPUDevice active_gpu = GetActiveGPU();
+ size_t current = gpu_list.size();
+ if (active_gpu.vendor_id && active_gpu.device_id) {
+ for (size_t i = 0; i < gpu_list.size(); ++i) {
+ if (gpu_list[i].vendor_id == active_gpu.vendor_id &&
+ gpu_list[i].device_id == active_gpu.device_id) {
+ current = i;
+ break;
+ }
+ }
+ }
+ if (current == gpu_list.size()) {
+ // If we fail to identify the current GPU, select any one as primary.
+ current = 0;
+ }
+ for (size_t i = 0; i < gpu_list.size(); ++i) {
+ if (i == current)
+ gpu_info->gpu = gpu_list[i];
+ else
+ gpu_info->secondary_gpus.push_back(gpu_list[i]);
+ }
+ }
+ break;
+ }
+ return (gpu_info->gpu.vendor_id && gpu_info->gpu.device_id);
+}
+
+} // namespace anonymous
+
+bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo");
+
+ gpu_info->can_lose_context =
+ (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
+ gpu_info->finalized = true;
+ return CollectGraphicsInfoGL(gpu_info);
+}
+
+GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
+ DCHECK(vendor_id && device_id);
+ *vendor_id = 0;
+ *device_id = 0;
+
+ GPUInfo gpu_info;
+ if (CollectPCIVideoCardInfo(&gpu_info)) {
+ *vendor_id = gpu_info.gpu.vendor_id;
+ *device_id = gpu_info.gpu.device_id;
+ return kGpuIDSuccess;
+ }
+ return kGpuIDFailure;
+}
+
+bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ std::string model_name;
+ int32 model_major = 0, model_minor = 0;
+ base::mac::ParseModelIdentifier(base::mac::GetModelIdentifier(),
+ &model_name, &model_major, &model_minor);
+ ReplaceChars(model_name, " ", "_", &gpu_info->machine_model);
+ gpu_info->machine_model += " " + base::IntToString(model_major) +
+ "." + base::IntToString(model_minor);
+
+ return CollectPCIVideoCardInfo(gpu_info);
+}
+
+bool CollectDriverInfoGL(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ // Extract the OpenGL driver version string from the GL_VERSION string.
+ // Mac OpenGL drivers have the driver version
+ // at the end of the gl version string preceded by a dash.
+ // Use some jiggery-pokery to turn that utf8 string into a std::wstring.
+ std::string gl_version_string = gpu_info->gl_version_string;
+ size_t pos = gl_version_string.find_last_of('-');
+ if (pos == std::string::npos)
+ return false;
+ gpu_info->driver_version = gl_version_string.substr(pos + 1);
+ return true;
+}
+
+void MergeGPUInfo(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info) {
+ MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_info_collector_ozone.cc b/chromium/gpu/config/gpu_info_collector_ozone.cc
new file mode 100644
index 00000000000..acef6ae74f6
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector_ozone.cc
@@ -0,0 +1,37 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info_collector.h"
+
+#include "base/logging.h"
+
+namespace gpu {
+
+bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
+ return CollectBasicGraphicsInfo(gpu_info);
+}
+
+GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
+ DCHECK(vendor_id && device_id);
+ *vendor_id = 0;
+ *device_id = 0;
+ return kGpuIDNotSupported;
+}
+
+bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
+ gpu_info->can_lose_context = false;
+ return true;
+}
+
+bool CollectDriverInfoGL(GPUInfo* gpu_info) {
+ NOTIMPLEMENTED();
+ return false;
+}
+
+void MergeGPUInfo(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info) {
+ MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
+}
+
+} // namespace gpu_info_collector
diff --git a/chromium/gpu/config/gpu_info_collector_unittest.cc b/chromium/gpu/config/gpu_info_collector_unittest.cc
new file mode 100644
index 00000000000..5e61ee27e12
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector_unittest.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::Return;
+
+namespace gpu {
+
+class GPUInfoCollectorTest : public testing::Test {
+ public:
+ GPUInfoCollectorTest() {}
+ virtual ~GPUInfoCollectorTest() { }
+
+ virtual void SetUp() {
+ // TODO(kbr): make this setup robust in the case where
+ // GLSurface::InitializeOneOff() has already been called by
+ // another unit test. http://crbug.com/100285
+ gfx::InitializeGLBindings(gfx::kGLImplementationMockGL);
+ gl_.reset(new ::testing::StrictMock< ::gfx::MockGLInterface>());
+ ::gfx::GLInterface::SetGLInterface(gl_.get());
+#if defined(OS_WIN)
+ const uint32 vendor_id = 0x10de;
+ const uint32 device_id = 0x0658;
+ const char* driver_vendor = ""; // not implemented
+ const char* driver_version = "";
+ const char* shader_version = "1.40";
+ const char* gl_version = "3.1";
+ const char* gl_renderer = "Quadro FX 380/PCI/SSE2";
+ const char* gl_vendor = "NVIDIA Corporation";
+ const char* gl_version_string = "3.1.0";
+ const char* gl_shading_language_version = "1.40 NVIDIA via Cg compiler";
+ const char* gl_extensions =
+ "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
+ "GL_EXT_read_format_bgra";
+#elif defined(OS_MACOSX)
+ const uint32 vendor_id = 0x10de;
+ const uint32 device_id = 0x0640;
+ const char* driver_vendor = ""; // not implemented
+ const char* driver_version = "1.6.18";
+ const char* shader_version = "1.20";
+ const char* gl_version = "2.1";
+ const char* gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
+ const char* gl_vendor = "NVIDIA Corporation";
+ const char* gl_version_string = "2.1 NVIDIA-1.6.18";
+ const char* gl_shading_language_version = "1.20 ";
+ const char* gl_extensions =
+ "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
+ "GL_EXT_read_format_bgra";
+#else // defined (OS_LINUX)
+ const uint32 vendor_id = 0x10de;
+ const uint32 device_id = 0x0658;
+ const char* driver_vendor = "NVIDIA";
+ const char* driver_version = "195.36.24";
+ const char* shader_version = "1.50";
+ const char* gl_version = "3.2";
+ const char* gl_renderer = "Quadro FX 380/PCI/SSE2";
+ const char* gl_vendor = "NVIDIA Corporation";
+ const char* gl_version_string = "3.2.0 NVIDIA 195.36.24";
+ const char* gl_shading_language_version = "1.50 NVIDIA via Cg compiler";
+ const char* gl_extensions =
+ "GL_OES_packed_depth_stencil GL_EXT_texture_format_BGRA8888 "
+ "GL_EXT_read_format_bgra";
+#endif
+ test_values_.gpu.vendor_id = vendor_id;
+ test_values_.gpu.device_id = device_id;
+ test_values_.driver_vendor = driver_vendor;
+ test_values_.driver_version =driver_version;
+ test_values_.pixel_shader_version = shader_version;
+ test_values_.vertex_shader_version = shader_version;
+ test_values_.gl_version = gl_version;
+ test_values_.gl_renderer = gl_renderer;
+ test_values_.gl_vendor = gl_vendor;
+ test_values_.gl_version_string = gl_version_string;
+ test_values_.gl_extensions = gl_extensions;
+ test_values_.can_lose_context = false;
+
+ EXPECT_CALL(*gl_, GetString(GL_EXTENSIONS))
+ .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
+ gl_extensions)));
+ EXPECT_CALL(*gl_, GetString(GL_SHADING_LANGUAGE_VERSION))
+ .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
+ gl_shading_language_version)));
+ EXPECT_CALL(*gl_, GetString(GL_VERSION))
+ .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
+ gl_version_string)));
+ EXPECT_CALL(*gl_, GetString(GL_VENDOR))
+ .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
+ gl_vendor)));
+ EXPECT_CALL(*gl_, GetString(GL_RENDERER))
+ .WillRepeatedly(Return(reinterpret_cast<const GLubyte*>(
+ gl_renderer)));
+ }
+
+ virtual void TearDown() {
+ ::gfx::GLInterface::SetGLInterface(NULL);
+ gl_.reset();
+ }
+
+ public:
+ // Use StrictMock to make 100% sure we know how GL will be called.
+ scoped_ptr< ::testing::StrictMock< ::gfx::MockGLInterface> > gl_;
+ GPUInfo test_values_;
+};
+
+// TODO(rlp): Test the vendor and device id collection if deemed necessary as
+// it involves several complicated mocks for each platform.
+
+// TODO(kbr): re-enable these tests; see http://crbug.com/100285 .
+
+TEST_F(GPUInfoCollectorTest, DISABLED_DriverVendorGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.driver_vendor,
+ gpu_info.driver_vendor);
+}
+
+// Skip Windows because the driver version is obtained from bot registry.
+#if !defined(OS_WIN)
+TEST_F(GPUInfoCollectorTest, DISABLED_DriverVersionGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.driver_version,
+ gpu_info.driver_version);
+}
+#endif
+
+TEST_F(GPUInfoCollectorTest, DISABLED_PixelShaderVersionGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.pixel_shader_version,
+ gpu_info.pixel_shader_version);
+}
+
+TEST_F(GPUInfoCollectorTest, DISABLED_VertexShaderVersionGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.vertex_shader_version,
+ gpu_info.vertex_shader_version);
+}
+
+TEST_F(GPUInfoCollectorTest, DISABLED_GLVersionGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.gl_version,
+ gpu_info.gl_version);
+}
+
+TEST_F(GPUInfoCollectorTest, DISABLED_GLVersionStringGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.gl_version_string,
+ gpu_info.gl_version_string);
+}
+
+TEST_F(GPUInfoCollectorTest, DISABLED_GLRendererGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.gl_renderer,
+ gpu_info.gl_renderer);
+}
+
+TEST_F(GPUInfoCollectorTest, DISABLED_GLVendorGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.gl_vendor,
+ gpu_info.gl_vendor);
+}
+
+TEST_F(GPUInfoCollectorTest, DISABLED_GLExtensionsGL) {
+ GPUInfo gpu_info;
+ CollectGraphicsInfoGL(&gpu_info);
+ EXPECT_EQ(test_values_.gl_extensions,
+ gpu_info.gl_extensions);
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_info_collector_win.cc b/chromium/gpu/config/gpu_info_collector_win.cc
new file mode 100644
index 00000000000..898863d1cf3
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector_win.cc
@@ -0,0 +1,653 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info_collector.h"
+
+// This has to be included before windows.h.
+#include "third_party/re2/re2/re2.h"
+
+#include <windows.h>
+#include <d3d9.h>
+#include <d3d11.h>
+#include <dxgi.h>
+#include <setupapi.h>
+
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/field_trial.h"
+#include "base/metrics/histogram.h"
+#include "base/scoped_native_library.h"
+#include "base/strings/string16.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+#include "base/threading/thread.h"
+#include "base/threading/worker_pool.h"
+#include "base/win/registry.h"
+#include "base/win/scoped_com_initializer.h"
+#include "base/win/scoped_comptr.h"
+#include "base/win/windows_version.h"
+#include "third_party/libxml/chromium/libxml_utils.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface_egl.h"
+
+namespace gpu {
+
+namespace {
+
+// This must be kept in sync with histograms.xml.
+enum DisplayLinkInstallationStatus {
+ DISPLAY_LINK_NOT_INSTALLED,
+ DISPLAY_LINK_7_1_OR_EARLIER,
+ DISPLAY_LINK_7_2_OR_LATER,
+ DISPLAY_LINK_INSTALLATION_STATUS_MAX
+};
+
+float ReadXMLFloatValue(XmlReader* reader) {
+ std::string score_string;
+ if (!reader->ReadElementContent(&score_string))
+ return 0.0;
+
+ double score;
+ if (!base::StringToDouble(score_string, &score))
+ return 0.0;
+
+ return static_cast<float>(score);
+}
+
+GpuPerformanceStats RetrieveGpuPerformanceStats() {
+ TRACE_EVENT0("gpu", "RetrieveGpuPerformanceStats");
+
+ // If the user re-runs the assessment without restarting, the COM API
+ // returns WINSAT_ASSESSMENT_STATE_NOT_AVAILABLE. Because of that and
+ // http://crbug.com/124325, read the assessment result files directly.
+ GpuPerformanceStats stats;
+
+ // Get path to WinSAT results files.
+ wchar_t winsat_results_path[MAX_PATH];
+ DWORD size = ExpandEnvironmentStrings(
+ L"%WinDir%\\Performance\\WinSAT\\DataStore\\",
+ winsat_results_path, MAX_PATH);
+ if (size == 0 || size > MAX_PATH) {
+ LOG(ERROR) << "The path to the WinSAT results is too long: "
+ << size << " chars.";
+ return stats;
+ }
+
+ // Find most recent formal assessment results.
+ base::FileEnumerator file_enumerator(
+ base::FilePath(winsat_results_path),
+ false, // not recursive
+ base::FileEnumerator::FILES,
+ FILE_PATH_LITERAL("* * Formal.Assessment (*).WinSAT.xml"));
+
+ base::FilePath current_results;
+ for (base::FilePath results = file_enumerator.Next(); !results.empty();
+ results = file_enumerator.Next()) {
+ // The filenames start with the date and time as yyyy-mm-dd hh.mm.ss.xxx,
+ // so the greatest file lexicographically is also the most recent file.
+ if (base::FilePath::CompareLessIgnoreCase(current_results.value(),
+ results.value()))
+ current_results = results;
+ }
+
+ std::string current_results_string = current_results.MaybeAsASCII();
+ if (current_results_string.empty()) {
+ LOG(ERROR) << "Can't retrieve a valid WinSAT assessment.";
+ return stats;
+ }
+
+ // Get relevant scores from results file. XML schema at:
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/aa969210.aspx
+ XmlReader reader;
+ if (!reader.LoadFile(current_results_string)) {
+ LOG(ERROR) << "Could not open WinSAT results file.";
+ return stats;
+ }
+ // Descend into <WinSAT> root element.
+ if (!reader.SkipToElement() || !reader.Read()) {
+ LOG(ERROR) << "Could not read WinSAT results file.";
+ return stats;
+ }
+
+ // Search for <WinSPR> element containing the results.
+ do {
+ if (reader.NodeName() == "WinSPR")
+ break;
+ } while (reader.Next());
+ // Descend into <WinSPR> element.
+ if (!reader.Read()) {
+ LOG(ERROR) << "Could not find WinSPR element in results file.";
+ return stats;
+ }
+
+ // Read scores.
+ for (int depth = reader.Depth(); reader.Depth() == depth; reader.Next()) {
+ std::string node_name = reader.NodeName();
+ if (node_name == "SystemScore")
+ stats.overall = ReadXMLFloatValue(&reader);
+ else if (node_name == "GraphicsScore")
+ stats.graphics = ReadXMLFloatValue(&reader);
+ else if (node_name == "GamingScore")
+ stats.gaming = ReadXMLFloatValue(&reader);
+ }
+
+ if (stats.overall == 0.0)
+ LOG(ERROR) << "Could not read overall score from assessment results.";
+ if (stats.graphics == 0.0)
+ LOG(ERROR) << "Could not read graphics score from assessment results.";
+ if (stats.gaming == 0.0)
+ LOG(ERROR) << "Could not read gaming score from assessment results.";
+
+ return stats;
+}
+
+GpuPerformanceStats RetrieveGpuPerformanceStatsWithHistograms() {
+ base::TimeTicks start_time = base::TimeTicks::Now();
+
+ GpuPerformanceStats stats = RetrieveGpuPerformanceStats();
+
+ UMA_HISTOGRAM_TIMES("GPU.WinSAT.ReadResultsFileTime",
+ base::TimeTicks::Now() - start_time);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.OverallScore2",
+ stats.overall * 10, 10, 200, 50);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.GraphicsScore2",
+ stats.graphics * 10, 10, 200, 50);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("GPU.WinSAT.GamingScore2",
+ stats.gaming * 10, 10, 200, 50);
+ UMA_HISTOGRAM_BOOLEAN(
+ "GPU.WinSAT.HasResults",
+ stats.overall != 0.0 && stats.graphics != 0.0 && stats.gaming != 0.0);
+
+ return stats;
+}
+
+// Returns the display link driver version or an invalid version if it is
+// not installed.
+Version DisplayLinkVersion() {
+ base::win::RegKey key;
+
+ if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY))
+ return Version();
+
+ if (key.OpenKey(L"DisplayLink", KEY_READ | KEY_WOW64_64KEY))
+ return Version();
+
+ if (key.OpenKey(L"Core", KEY_READ | KEY_WOW64_64KEY))
+ return Version();
+
+ string16 version;
+ if (key.ReadValue(L"Version", &version))
+ return Version();
+
+ return Version(WideToASCII(version));
+}
+
+// Returns whether Lenovo dCute is installed.
+bool IsLenovoDCuteInstalled() {
+ base::win::RegKey key;
+
+ if (key.Open(HKEY_LOCAL_MACHINE, L"SOFTWARE", KEY_READ | KEY_WOW64_64KEY))
+ return false;
+
+ if (key.OpenKey(L"Lenovo", KEY_READ | KEY_WOW64_64KEY))
+ return false;
+
+ if (key.OpenKey(L"Lenovo dCute", KEY_READ | KEY_WOW64_64KEY))
+ return false;
+
+ return true;
+}
+
+// Determines whether D3D11 won't work, either because it is not supported on
+// the machine or because it is known it is likely to crash.
+bool D3D11ShouldWork(const GPUInfo& gpu_info) {
+ // TODO(apatrick): This is a temporary change to see what impact disabling
+ // D3D11 stats collection has on Canary.
+ return false;
+
+ // Windows XP never supports D3D11. It seems to be less stable that D3D9 on
+ // Vista.
+ if (base::win::GetVersion() <= base::win::VERSION_VISTA)
+ return false;
+
+ // http://crbug.com/175525.
+ if (gpu_info.display_link_version.IsValid())
+ return false;
+
+ return true;
+}
+
+// Collects information about the level of D3D11 support and records it in
+// the UMA stats. Records no stats when D3D11 in not supported at all.
+void CollectD3D11SupportOnWorkerThread() {
+ TRACE_EVENT0("gpu", "CollectD3D11Support");
+
+ typedef HRESULT (WINAPI *D3D11CreateDeviceFunc)(
+ IDXGIAdapter* adapter,
+ D3D_DRIVER_TYPE driver_type,
+ HMODULE software,
+ UINT flags,
+ const D3D_FEATURE_LEVEL* feature_levels,
+ UINT num_feature_levels,
+ UINT sdk_version,
+ ID3D11Device** device,
+ D3D_FEATURE_LEVEL* feature_level,
+ ID3D11DeviceContext** immediate_context);
+
+ // This enumeration must be kept in sync with histograms.xml. Do not reorder
+ // the members; always add to the end.
+ enum FeatureLevel {
+ FEATURE_LEVEL_UNKNOWN,
+ FEATURE_LEVEL_NO_D3D11_DLL,
+ FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT,
+ FEATURE_LEVEL_DEVICE_CREATION_FAILED,
+ FEATURE_LEVEL_9_1,
+ FEATURE_LEVEL_9_2,
+ FEATURE_LEVEL_9_3,
+ FEATURE_LEVEL_10_0,
+ FEATURE_LEVEL_10_1,
+ FEATURE_LEVEL_11_0,
+ NUM_FEATURE_LEVELS
+ };
+
+ FeatureLevel feature_level = FEATURE_LEVEL_UNKNOWN;
+ UINT bgra_support = 0;
+
+ // This module is leaked in case it is hooked by third party software.
+ base::NativeLibrary d3d11_module = base::LoadNativeLibrary(
+ base::FilePath(L"d3d11.dll"),
+ NULL);
+
+ if (!d3d11_module) {
+ feature_level = FEATURE_LEVEL_NO_D3D11_DLL;
+ } else {
+ D3D11CreateDeviceFunc create_func =
+ reinterpret_cast<D3D11CreateDeviceFunc>(
+ base::GetFunctionPointerFromNativeLibrary(d3d11_module,
+ "D3D11CreateDevice"));
+ if (!create_func) {
+ feature_level = FEATURE_LEVEL_NO_CREATE_DEVICE_ENTRY_POINT;
+ } else {
+ static const D3D_FEATURE_LEVEL d3d_feature_levels[] = {
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1
+ };
+
+ base::win::ScopedComPtr<ID3D11Device> device;
+ D3D_FEATURE_LEVEL d3d_feature_level;
+ base::win::ScopedComPtr<ID3D11DeviceContext> device_context;
+ HRESULT hr = create_func(NULL,
+ D3D_DRIVER_TYPE_HARDWARE,
+ NULL,
+ 0,
+ d3d_feature_levels,
+ arraysize(d3d_feature_levels),
+ D3D11_SDK_VERSION,
+ device.Receive(),
+ &d3d_feature_level,
+ device_context.Receive());
+ if (FAILED(hr)) {
+ feature_level = FEATURE_LEVEL_DEVICE_CREATION_FAILED;
+ } else {
+ switch (d3d_feature_level) {
+ case D3D_FEATURE_LEVEL_11_0:
+ feature_level = FEATURE_LEVEL_11_0;
+ break;
+ case D3D_FEATURE_LEVEL_10_1:
+ feature_level = FEATURE_LEVEL_10_1;
+ break;
+ case D3D_FEATURE_LEVEL_10_0:
+ feature_level = FEATURE_LEVEL_10_0;
+ break;
+ case D3D_FEATURE_LEVEL_9_3:
+ feature_level = FEATURE_LEVEL_9_3;
+ break;
+ case D3D_FEATURE_LEVEL_9_2:
+ feature_level = FEATURE_LEVEL_9_2;
+ break;
+ case D3D_FEATURE_LEVEL_9_1:
+ feature_level = FEATURE_LEVEL_9_1;
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ hr = device->CheckFormatSupport(DXGI_FORMAT_B8G8R8A8_UNORM,
+ &bgra_support);
+ DCHECK(SUCCEEDED(hr));
+ }
+ }
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("GPU.D3D11_FeatureLevel",
+ feature_level,
+ NUM_FEATURE_LEVELS);
+
+ // ANGLE requires at least feature level 10.0. Do not record any further
+ // stats if ANGLE would not work anyway.
+ if (feature_level < FEATURE_LEVEL_10_0)
+ return;
+
+ UMA_HISTOGRAM_BOOLEAN(
+ "GPU.D3D11_B8G8R8A8_Texture2DSupport",
+ (bgra_support & D3D11_FORMAT_SUPPORT_TEXTURE2D) != 0);
+ UMA_HISTOGRAM_BOOLEAN(
+ "GPU.D3D11_B8G8R8A8_RenderTargetSupport",
+ (bgra_support & D3D11_FORMAT_SUPPORT_RENDER_TARGET) != 0);
+}
+
+// Collects information about the level of D3D11 support and records it in
+// the UMA stats. Records no stats when D3D11 in not supported at all.
+void CollectD3D11Support() {
+ // D3D11 takes about 50ms to initialize so do this on a worker thread.
+ base::WorkerPool::PostTask(
+ FROM_HERE,
+ base::Bind(CollectD3D11SupportOnWorkerThread),
+ false);
+}
+} // namespace anonymous
+
+#if !defined(GOOGLE_CHROME_BUILD)
+AMDVideoCardType GetAMDVideocardType() {
+ return STANDALONE;
+}
+#else
+// This function has a real implementation for official builds that can
+// be found in src/third_party/amd.
+AMDVideoCardType GetAMDVideocardType();
+#endif
+
+bool CollectDriverInfoD3D(const std::wstring& device_id,
+ GPUInfo* gpu_info) {
+ TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
+
+ // create device info for the display device
+ HDEVINFO device_info = SetupDiGetClassDevsW(
+ NULL, device_id.c_str(), NULL,
+ DIGCF_PRESENT | DIGCF_PROFILE | DIGCF_ALLCLASSES);
+ if (device_info == INVALID_HANDLE_VALUE) {
+ LOG(ERROR) << "Creating device info failed";
+ return false;
+ }
+
+ DWORD index = 0;
+ bool found = false;
+ SP_DEVINFO_DATA device_info_data;
+ device_info_data.cbSize = sizeof(device_info_data);
+ while (SetupDiEnumDeviceInfo(device_info, index++, &device_info_data)) {
+ WCHAR value[255];
+ if (SetupDiGetDeviceRegistryPropertyW(device_info,
+ &device_info_data,
+ SPDRP_DRIVER,
+ NULL,
+ reinterpret_cast<PBYTE>(value),
+ sizeof(value),
+ NULL)) {
+ HKEY key;
+ std::wstring driver_key = L"System\\CurrentControlSet\\Control\\Class\\";
+ driver_key += value;
+ LONG result = RegOpenKeyExW(
+ HKEY_LOCAL_MACHINE, driver_key.c_str(), 0, KEY_QUERY_VALUE, &key);
+ if (result == ERROR_SUCCESS) {
+ DWORD dwcb_data = sizeof(value);
+ std::string driver_version;
+ result = RegQueryValueExW(
+ key, L"DriverVersion", NULL, NULL,
+ reinterpret_cast<LPBYTE>(value), &dwcb_data);
+ if (result == ERROR_SUCCESS)
+ driver_version = WideToASCII(std::wstring(value));
+
+ std::string driver_date;
+ dwcb_data = sizeof(value);
+ result = RegQueryValueExW(
+ key, L"DriverDate", NULL, NULL,
+ reinterpret_cast<LPBYTE>(value), &dwcb_data);
+ if (result == ERROR_SUCCESS)
+ driver_date = WideToASCII(std::wstring(value));
+
+ std::string driver_vendor;
+ dwcb_data = sizeof(value);
+ result = RegQueryValueExW(
+ key, L"ProviderName", NULL, NULL,
+ reinterpret_cast<LPBYTE>(value), &dwcb_data);
+ if (result == ERROR_SUCCESS) {
+ driver_vendor = WideToASCII(std::wstring(value));
+ if (driver_vendor == "Advanced Micro Devices, Inc." ||
+ driver_vendor == "ATI Technologies Inc.") {
+ // We are conservative and assume that in the absence of a clear
+ // signal the videocard is assumed to be switchable. Additionally,
+ // some switchable systems with Intel GPUs aren't correctly
+ // detected, so always count them.
+ AMDVideoCardType amd_card_type = GetAMDVideocardType();
+ gpu_info->amd_switchable = (gpu_info->gpu.vendor_id == 0x8086) ||
+ (amd_card_type != STANDALONE);
+ }
+ }
+
+ gpu_info->driver_vendor = driver_vendor;
+ gpu_info->driver_version = driver_version;
+ gpu_info->driver_date = driver_date;
+ found = true;
+ RegCloseKey(key);
+ break;
+ }
+ }
+ }
+ SetupDiDestroyDeviceInfoList(device_info);
+ return found;
+}
+
+bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
+ TRACE_EVENT0("gpu", "CollectGraphicsInfo");
+
+ DCHECK(gpu_info);
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kUseGL)) {
+ std::string requested_implementation_name =
+ CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kUseGL);
+ if (requested_implementation_name == "swiftshader") {
+ gpu_info->software_rendering = true;
+ return false;
+ }
+ }
+
+ if (!CollectGraphicsInfoGL(gpu_info))
+ return false;
+
+ // ANGLE's renderer strings are of the form:
+ // ANGLE (<adapter_identifier> Direct3D<version> vs_x_x ps_x_x)
+ std::string direct3d_version;
+ int vertex_shader_major_version = 0;
+ int vertex_shader_minor_version = 0;
+ int pixel_shader_major_version = 0;
+ int pixel_shader_minor_version = 0;
+ gpu_info->adapter_luid = 0;
+ if (RE2::FullMatch(gpu_info->gl_renderer,
+ "ANGLE \\(.*\\)") &&
+ RE2::PartialMatch(gpu_info->gl_renderer,
+ " Direct3D(\\w+)",
+ &direct3d_version) &&
+ RE2::PartialMatch(gpu_info->gl_renderer,
+ " vs_(\\d+)_(\\d+)",
+ &vertex_shader_major_version,
+ &vertex_shader_minor_version) &&
+ RE2::PartialMatch(gpu_info->gl_renderer,
+ " ps_(\\d+)_(\\d+)",
+ &pixel_shader_major_version,
+ &pixel_shader_minor_version)) {
+ gpu_info->can_lose_context = direct3d_version == "9";
+ gpu_info->vertex_shader_version =
+ base::StringPrintf("%d.%d",
+ vertex_shader_major_version,
+ vertex_shader_minor_version);
+ gpu_info->pixel_shader_version =
+ base::StringPrintf("%d.%d",
+ pixel_shader_major_version,
+ pixel_shader_minor_version);
+
+ // ANGLE's EGL vendor strings are of the form:
+ // Google, Inc. (adapter LUID: 0123456789ABCDEF)
+ // The LUID is optional and identifies the GPU adapter ANGLE is using.
+ const char* egl_vendor = eglQueryString(
+ gfx::GLSurfaceEGL::GetHardwareDisplay(),
+ EGL_VENDOR);
+ RE2::PartialMatch(egl_vendor,
+ " \\(adapter LUID: ([0-9A-Fa-f]{16})\\)",
+ RE2::Hex(&gpu_info->adapter_luid));
+
+ // DirectX diagnostics are collected asynchronously because it takes a
+ // couple of seconds. Do not mark gpu_info as complete until that is done.
+ gpu_info->finalized = false;
+ } else {
+ gpu_info->finalized = true;
+ }
+
+ return true;
+}
+
+GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
+ DCHECK(vendor_id && device_id);
+ *vendor_id = 0;
+ *device_id = 0;
+
+ // Taken from http://developer.nvidia.com/object/device_ids.html
+ DISPLAY_DEVICE dd;
+ dd.cb = sizeof(DISPLAY_DEVICE);
+ std::wstring id;
+ for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
+ if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
+ id = dd.DeviceID;
+ break;
+ }
+ }
+
+ if (id.length() > 20) {
+ int vendor = 0, device = 0;
+ std::wstring vendor_string = id.substr(8, 4);
+ std::wstring device_string = id.substr(17, 4);
+ base::HexStringToInt(WideToASCII(vendor_string), &vendor);
+ base::HexStringToInt(WideToASCII(device_string), &device);
+ *vendor_id = vendor;
+ *device_id = device;
+ return kGpuIDSuccess;
+ }
+ return kGpuIDFailure;
+}
+
+bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
+ TRACE_EVENT0("gpu", "CollectPreliminaryGraphicsInfo");
+
+ DCHECK(gpu_info);
+
+ gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms();
+
+ // nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
+ HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
+ gpu_info->optimus = nvd3d9wrap != NULL;
+
+ gpu_info->lenovo_dcute = IsLenovoDCuteInstalled();
+
+ gpu_info->display_link_version = DisplayLinkVersion();
+
+ if (!gpu_info->display_link_version .IsValid()) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
+ DISPLAY_LINK_NOT_INSTALLED,
+ DISPLAY_LINK_INSTALLATION_STATUS_MAX);
+ } else if (gpu_info->display_link_version.IsOlderThan("7.2")) {
+ UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
+ DISPLAY_LINK_7_1_OR_EARLIER,
+ DISPLAY_LINK_INSTALLATION_STATUS_MAX);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("GPU.DisplayLinkInstallationStatus",
+ DISPLAY_LINK_7_2_OR_LATER,
+ DISPLAY_LINK_INSTALLATION_STATUS_MAX);
+ }
+
+ // Taken from http://developer.nvidia.com/object/device_ids.html
+ DISPLAY_DEVICE dd;
+ dd.cb = sizeof(DISPLAY_DEVICE);
+ std::wstring id;
+ for (int i = 0; EnumDisplayDevices(NULL, i, &dd, 0); ++i) {
+ if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) {
+ id = dd.DeviceID;
+ break;
+ }
+ }
+
+ if (id.length() <= 20)
+ return false;
+
+ int vendor_id = 0, device_id = 0;
+ string16 vendor_id_string = id.substr(8, 4);
+ string16 device_id_string = id.substr(17, 4);
+ base::HexStringToInt(WideToASCII(vendor_id_string), &vendor_id);
+ base::HexStringToInt(WideToASCII(device_id_string), &device_id);
+ gpu_info->gpu.vendor_id = vendor_id;
+ gpu_info->gpu.device_id = device_id;
+ // TODO(zmo): we only need to call CollectDriverInfoD3D() if we use ANGLE.
+ if (!CollectDriverInfoD3D(id, gpu_info))
+ return false;
+
+ // Collect basic information about supported D3D11 features. Delay for 45
+ // seconds so as not to regress performance tests.
+ if (D3D11ShouldWork(*gpu_info)) {
+ // This is on a field trial so we can turn it off easily if it blows up
+ // again in stable channel.
+ scoped_refptr<base::FieldTrial> trial(
+ base::FieldTrialList::FactoryGetFieldTrial(
+ "D3D11Experiment", 100, "Disabled", 2015, 7, 8,
+ base::FieldTrial::SESSION_RANDOMIZED, NULL));
+ const int enabled_group =
+ trial->AppendGroup("Enabled", 0);
+
+ if (trial->group() == enabled_group) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&CollectD3D11Support),
+ base::TimeDelta::FromSeconds(45));
+ }
+ }
+
+ return true;
+}
+
+bool CollectDriverInfoGL(GPUInfo* gpu_info) {
+ TRACE_EVENT0("gpu", "CollectDriverInfoGL");
+
+ if (!gpu_info->driver_version.empty())
+ return true;
+
+ std::string gl_version_string = gpu_info->gl_version_string;
+
+ return RE2::PartialMatch(gl_version_string,
+ "([\\d\\.]+)$",
+ &gpu_info->driver_version);
+}
+
+void MergeGPUInfo(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info) {
+ DCHECK(basic_gpu_info);
+
+ if (context_gpu_info.software_rendering) {
+ basic_gpu_info->software_rendering = true;
+ return;
+ }
+
+ MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
+
+ basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics;
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_info_collector_x11.cc b/chromium/gpu/config/gpu_info_collector_x11.cc
new file mode 100644
index 00000000000..a19ef9cd9ea
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_collector_x11.cc
@@ -0,0 +1,274 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info_collector.h"
+
+#include <X11/Xlib.h>
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/debug/trace_event.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "library_loaders/libpci.h"
+#include "third_party/libXNVCtrl/NVCtrl.h"
+#include "third_party/libXNVCtrl/NVCtrlLib.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_switches.h"
+
+namespace gpu {
+
+namespace {
+
+// This checks if a system supports PCI bus.
+// We check the existence of /sys/bus/pci or /sys/bug/pci_express.
+bool IsPciSupported() {
+ const base::FilePath pci_path("/sys/bus/pci/");
+ const base::FilePath pcie_path("/sys/bus/pci_express/");
+ return (base::PathExists(pci_path) ||
+ base::PathExists(pcie_path));
+}
+
+// Scan /etc/ati/amdpcsdb.default for "ReleaseVersion".
+// Return empty string on failing.
+std::string CollectDriverVersionATI() {
+ const base::FilePath::CharType kATIFileName[] =
+ FILE_PATH_LITERAL("/etc/ati/amdpcsdb.default");
+ base::FilePath ati_file_path(kATIFileName);
+ if (!base::PathExists(ati_file_path))
+ return std::string();
+ std::string contents;
+ if (!file_util::ReadFileToString(ati_file_path, &contents))
+ return std::string();
+ base::StringTokenizer t(contents, "\r\n");
+ while (t.GetNext()) {
+ std::string line = t.token();
+ if (StartsWithASCII(line, "ReleaseVersion=", true)) {
+ size_t begin = line.find_first_of("0123456789");
+ if (begin != std::string::npos) {
+ size_t end = line.find_first_not_of("0123456789.", begin);
+ if (end == std::string::npos)
+ return line.substr(begin);
+ else
+ return line.substr(begin, end - begin);
+ }
+ }
+ }
+ return std::string();
+}
+
+// Use NVCtrl extention to query NV driver version.
+// Return empty string on failing.
+std::string CollectDriverVersionNVidia() {
+ Display* display = base::MessagePumpForUI::GetDefaultXDisplay();
+ if (!display) {
+ LOG(ERROR) << "XOpenDisplay failed.";
+ return std::string();
+ }
+ int event_base = 0, error_base = 0;
+ if (!XNVCTRLQueryExtension(display, &event_base, &error_base)) {
+ LOG(INFO) << "NVCtrl extension does not exist.";
+ return std::string();
+ }
+ int screen_count = ScreenCount(display);
+ for (int screen = 0; screen < screen_count; ++screen) {
+ char* buffer = NULL;
+ if (XNVCTRLIsNvScreen(display, screen) &&
+ XNVCTRLQueryStringAttribute(display, screen, 0,
+ NV_CTRL_STRING_NVIDIA_DRIVER_VERSION,
+ &buffer)) {
+ std::string driver_version(buffer);
+ XFree(buffer);
+ return driver_version;
+ }
+ }
+ return std::string();
+}
+
+const uint32 kVendorIDIntel = 0x8086;
+const uint32 kVendorIDNVidia = 0x10de;
+const uint32 kVendorIDAMD = 0x1002;
+
+bool CollectPCIVideoCardInfo(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ if (IsPciSupported() == false) {
+ VLOG(1) << "PCI bus scanning is not supported";
+ return false;
+ }
+
+ // TODO(zmo): be more flexible about library name.
+ LibPciLoader libpci_loader;
+ if (!libpci_loader.Load("libpci.so.3") &&
+ !libpci_loader.Load("libpci.so")) {
+ VLOG(1) << "Failed to locate libpci";
+ return false;
+ }
+
+ pci_access* access = (libpci_loader.pci_alloc)();
+ DCHECK(access != NULL);
+ (libpci_loader.pci_init)(access);
+ (libpci_loader.pci_scan_bus)(access);
+ bool primary_gpu_identified = false;
+ for (pci_dev* device = access->devices;
+ device != NULL; device = device->next) {
+ // Fill the IDs and class fields.
+ (libpci_loader.pci_fill_info)(device, 33);
+ // TODO(zmo): there might be other classes that qualify as display devices.
+ if (device->device_class != 0x0300) // Device class is DISPLAY_VGA.
+ continue;
+
+ GPUInfo::GPUDevice gpu;
+ gpu.vendor_id = device->vendor_id;
+ gpu.device_id = device->device_id;
+
+ if (!primary_gpu_identified) {
+ primary_gpu_identified = true;
+ gpu_info->gpu = gpu;
+ } else {
+ // TODO(zmo): if there are multiple GPUs, we assume the non Intel
+ // one is primary. Revisit this logic because we actually don't know
+ // which GPU we are using at this point.
+ if (gpu_info->gpu.vendor_id == kVendorIDIntel &&
+ gpu.vendor_id != kVendorIDIntel) {
+ gpu_info->secondary_gpus.push_back(gpu_info->gpu);
+ gpu_info->gpu = gpu;
+ } else {
+ gpu_info->secondary_gpus.push_back(gpu);
+ }
+ }
+ }
+
+ // Detect Optimus or AMD Switchable GPU.
+ if (gpu_info->secondary_gpus.size() == 1 &&
+ gpu_info->secondary_gpus[0].vendor_id == kVendorIDIntel) {
+ if (gpu_info->gpu.vendor_id == kVendorIDNVidia)
+ gpu_info->optimus = true;
+ if (gpu_info->gpu.vendor_id == kVendorIDAMD)
+ gpu_info->amd_switchable = true;
+ }
+
+ (libpci_loader.pci_cleanup)(access);
+ return (primary_gpu_identified);
+}
+
+} // namespace anonymous
+
+bool CollectContextGraphicsInfo(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ TRACE_EVENT0("gpu", "gpu_info_collector::CollectGraphicsInfo");
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kGpuNoContextLost)) {
+ gpu_info->can_lose_context = false;
+ } else {
+#if defined(OS_CHROMEOS)
+ gpu_info->can_lose_context = false;
+#else
+ // TODO(zmo): need to consider the case where we are running on top
+ // of desktop GL and GL_ARB_robustness extension is available.
+ gpu_info->can_lose_context =
+ (gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2);
+#endif
+ }
+
+ gpu_info->finalized = true;
+ bool rt = CollectGraphicsInfoGL(gpu_info);
+
+ return rt;
+}
+
+GpuIDResult CollectGpuID(uint32* vendor_id, uint32* device_id) {
+ DCHECK(vendor_id && device_id);
+ *vendor_id = 0;
+ *device_id = 0;
+
+ GPUInfo gpu_info;
+ if (CollectPCIVideoCardInfo(&gpu_info)) {
+ *vendor_id = gpu_info.gpu.vendor_id;
+ *device_id = gpu_info.gpu.device_id;
+ return kGpuIDSuccess;
+ }
+ return kGpuIDFailure;
+}
+
+bool CollectBasicGraphicsInfo(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ bool rt = CollectPCIVideoCardInfo(gpu_info);
+
+ std::string driver_version;
+ switch (gpu_info->gpu.vendor_id) {
+ case kVendorIDAMD:
+ driver_version = CollectDriverVersionATI();
+ if (!driver_version.empty()) {
+ gpu_info->driver_vendor = "ATI / AMD";
+ gpu_info->driver_version = driver_version;
+ }
+ break;
+ case kVendorIDNVidia:
+ driver_version = CollectDriverVersionNVidia();
+ if (!driver_version.empty()) {
+ gpu_info->driver_vendor = "NVIDIA";
+ gpu_info->driver_version = driver_version;
+ }
+ break;
+ case kVendorIDIntel:
+ // In dual-GPU cases, sometimes PCI scan only gives us the
+ // integrated GPU (i.e., the Intel one).
+ driver_version = CollectDriverVersionNVidia();
+ if (!driver_version.empty()) {
+ gpu_info->driver_vendor = "NVIDIA";
+ gpu_info->driver_version = driver_version;
+ // Machines with more than two GPUs are not handled.
+ if (gpu_info->secondary_gpus.size() <= 1)
+ gpu_info->optimus = true;
+ }
+ break;
+ }
+
+ return rt;
+}
+
+bool CollectDriverInfoGL(GPUInfo* gpu_info) {
+ DCHECK(gpu_info);
+
+ std::string gl_version_string = gpu_info->gl_version_string;
+ if (StartsWithASCII(gl_version_string, "OpenGL ES", true))
+ gl_version_string = gl_version_string.substr(10);
+ std::vector<std::string> pieces;
+ base::SplitStringAlongWhitespace(gl_version_string, &pieces);
+ // In linux, the gl version string might be in the format of
+ // GLVersion DriverVendor DriverVersion
+ if (pieces.size() < 3)
+ return false;
+
+ std::string driver_version = pieces[2];
+ size_t pos = driver_version.find_first_not_of("0123456789.");
+ if (pos == 0)
+ return false;
+ if (pos != std::string::npos)
+ driver_version = driver_version.substr(0, pos);
+
+ gpu_info->driver_vendor = pieces[1];
+ gpu_info->driver_version = driver_version;
+ return true;
+}
+
+void MergeGPUInfo(GPUInfo* basic_gpu_info,
+ const GPUInfo& context_gpu_info) {
+ MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_info_unittest.cc b/chromium/gpu/config/gpu_info_unittest.cc
new file mode 100644
index 00000000000..42cbd3c7091
--- /dev/null
+++ b/chromium/gpu/config/gpu_info_unittest.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+// Test that an empty GPUInfo has valid members
+TEST(GPUInfoBasicTest, EmptyGPUInfo) {
+ GPUInfo gpu_info;
+ EXPECT_EQ(gpu_info.finalized, false);
+ EXPECT_EQ(gpu_info.initialization_time.ToInternalValue(), 0);
+ EXPECT_EQ(gpu_info.gpu.vendor_id, 0u);
+ EXPECT_EQ(gpu_info.gpu.device_id, 0u);
+ EXPECT_EQ(gpu_info.secondary_gpus.size(), 0u);
+ EXPECT_EQ(gpu_info.driver_vendor, "");
+ EXPECT_EQ(gpu_info.driver_version, "");
+ EXPECT_EQ(gpu_info.driver_date, "");
+ EXPECT_EQ(gpu_info.pixel_shader_version, "");
+ EXPECT_EQ(gpu_info.vertex_shader_version, "");
+ EXPECT_EQ(gpu_info.gl_version, "");
+ EXPECT_EQ(gpu_info.gl_version_string, "");
+ EXPECT_EQ(gpu_info.gl_vendor, "");
+ EXPECT_EQ(gpu_info.gl_renderer, "");
+ EXPECT_EQ(gpu_info.gl_extensions, "");
+ EXPECT_EQ(gpu_info.gl_ws_vendor, "");
+ EXPECT_EQ(gpu_info.gl_ws_version, "");
+ EXPECT_EQ(gpu_info.gl_ws_extensions, "");
+ EXPECT_EQ(gpu_info.can_lose_context, false);
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_performance_stats.h b/chromium/gpu/config/gpu_performance_stats.h
new file mode 100644
index 00000000000..2ade8bfac97
--- /dev/null
+++ b/chromium/gpu/config/gpu_performance_stats.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_PERFORMANCE_STATS_H_
+#define GPU_CONFIG_GPU_PERFORMANCE_STATS_H_
+
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+struct GPU_EXPORT GpuPerformanceStats {
+ GpuPerformanceStats() : graphics(0.f), gaming(0.f), overall(0.f) {}
+
+ float graphics;
+ float gaming;
+ float overall;
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_PERFORMANCE_STATS_H_
+
diff --git a/chromium/gpu/config/gpu_switching_list.cc b/chromium/gpu/config/gpu_switching_list.cc
new file mode 100644
index 00000000000..b87dfb2e3f4
--- /dev/null
+++ b/chromium/gpu/config/gpu_switching_list.cc
@@ -0,0 +1,29 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_switching_list.h"
+
+#include "gpu/config/gpu_switching_option.h"
+
+namespace gpu {
+
+GpuSwitchingList::GpuSwitchingList()
+ : GpuControlList() {
+}
+
+GpuSwitchingList::~GpuSwitchingList() {
+}
+
+// static
+GpuSwitchingList* GpuSwitchingList::Create() {
+ GpuSwitchingList* list = new GpuSwitchingList();
+ list->AddSupportedFeature("force_integrated",
+ GPU_SWITCHING_OPTION_FORCE_INTEGRATED);
+ list->AddSupportedFeature("force_discrete",
+ GPU_SWITCHING_OPTION_FORCE_DISCRETE);
+ return list;
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_switching_list.h b/chromium/gpu/config/gpu_switching_list.h
new file mode 100644
index 00000000000..095597a36ea
--- /dev/null
+++ b/chromium/gpu/config/gpu_switching_list.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_SWITCHING_LIST_H_
+#define GPU_CONFIG_GPU_SWITCHING_LIST_H_
+
+#include <string>
+
+#include "gpu/config/gpu_control_list.h"
+
+namespace gpu {
+
+class GPU_EXPORT GpuSwitchingList : public GpuControlList {
+ public:
+ virtual ~GpuSwitchingList();
+
+ static GpuSwitchingList* Create();
+
+ private:
+ GpuSwitchingList();
+
+ DISALLOW_COPY_AND_ASSIGN(GpuSwitchingList);
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_SWITCHING_LIST_H_
+
diff --git a/chromium/gpu/config/gpu_switching_list_json.cc b/chromium/gpu/config/gpu_switching_list_json.cc
new file mode 100644
index 00000000000..9916b020cbb
--- /dev/null
+++ b/chromium/gpu/config/gpu_switching_list_json.cc
@@ -0,0 +1,125 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Determines whether a certain gpu is prefered in a dual-gpu situation.
+// A valid gpu_switching_list.json file are in the format of
+// {
+// "version": "x.y",
+// "entries": [
+// { // entry 1
+// },
+// ...
+// { // entry n
+// }
+// ]
+// }
+//
+// Each entry contains the following fields (fields are optional unless
+// specifically described as mandatory below):
+// 1. "id" is an integer. 0 is reserved. This field is mandatory.
+// 2. "os" contains "type" and an optional "version". "type" could be "macosx",
+// "linux", "win", "chromeos", or "any". "any" is the same as not specifying
+// "os".
+// "version" is a VERSION structure (defined below).
+// 3. "vendor_id" is a string. 0 is reserved.
+// 4. "device_id" is an array of strings. 0 is reserved.
+// 5. "multi_gpu_style" is a string, valid values include "optimus", and
+// "amd_switchable".
+// 6. "multi_gpu_category" is a string, valid values include "any", "primary",
+// and "secondary". If unspecified, the default value is "primary".
+// 7. "driver_vendor" is a STRING structure (defined below).
+// 8. "driver_version" is a VERSION structure (defined below).
+// 9. "driver_date" is a VERSION structure (defined below).
+// The version is interpreted as "year.month.day".
+// 10. "gl_vendor" is a STRING structure (defined below).
+// 11. "gl_renderer" is a STRING structure (defined below).
+// 12. "gl_extensions" is a STRING structure (defined below).
+// 13. "perf_graphics" is a FLOAT structure (defined below).
+// 14. "perf_gaming" is a FLOAT structure (defined below).
+// 15. "perf_overall" is a FLOAT structure (defined below).
+// 16. "machine_model" contais "name" and an optional "version". "name" is a
+// STRING structure and "version" is a VERSION structure (defined below).
+// 17. "gpu_count" is a INT structure (defined below).
+// 18 "cpu_info" is a STRING structure (defined below).
+// 19. "exceptions" is a list of entries.
+// 20. "features" is a list of gpu switching options, including
+// "force_discrete" and "force_integrated".
+// This field is mandatory.
+// 21. "description" has the description of the entry.
+// 22. "webkit_bugs" is an array of associated webkit bug numbers.
+// 23. "cr_bugs" is an array of associated webkit bug numbers.
+// 24. "browser_version" is a VERSION structure (defined below). If this
+// condition is not satisfied, the entry will be ignored. If it is not
+// present, then the entry applies to all versions of the browser.
+// 25. "disabled" is a boolean. If it is present, the entry will be skipped.
+// This can not be used in exceptions.
+//
+// VERSION includes "op", "style", "number", and "number2". "op" can be any of
+// the following values: "=", "<", "<=", ">", ">=", "any", "between". "style"
+// is optional and can be "lexical" or "numerical"; if it's not specified, it
+// defaults to "numerical". "number2" is only used if "op" is "between".
+// "between" is "number <= * <= number2".
+// "number" is used for all "op" values except "any". "number" and "number2"
+// are in the format of x, x.x, x.x.x, etc.
+// Only "driver_version" supports lexical style if the format is major.minor;
+// in that case, major is still numerical, but minor is lexical.
+//
+// STRING includes "op" and "value". "op" can be any of the following values:
+// "contains", "beginwith", "endwith", "=". "value" is a string.
+//
+// FLOAT includes "op" "value", and "value2". "op" can be any of the
+// following values: "=", "<", "<=", ">", ">=", "any", "between". "value2" is
+// only used if "op" is "between". "value" is used for all "op" values except
+// "any". "value" and "value2" are valid float numbers.
+// INT is very much like FLOAT, except that the values need to be integers.
+
+#include "gpu/config/gpu_control_list_jsons.h"
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+namespace gpu {
+
+const char kGpuSwitchingListJson[] = LONG_STRING_CONST(
+
+{
+ "name": "gpu switching list",
+ // Please update the version number whenever you change this file.
+ "version": "2.0",
+ "entries": [
+ {
+ "id": 1,
+ "description": "Force to use discrete GPU on older MacBookPro models.",
+ "cr_bugs": [113703],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": ">=",
+ "number": "10.7"
+ }
+ },
+ "machine_model": {
+ "name": {
+ "op": "=",
+ "value": "MacBookPro"
+ },
+ "version": {
+ "op": "<",
+ "number": "8"
+ }
+ },
+ "gpu_count": {
+ "op": "=",
+ "value": "2"
+ },
+ "features": [
+ "force_discrete"
+ ]
+ }
+ ]
+}
+
+); // LONG_STRING_CONST macro
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_switching_list_unittest.cc b/chromium/gpu/config/gpu_switching_list_unittest.cc
new file mode 100644
index 00000000000..78dc74d93f4
--- /dev/null
+++ b/chromium/gpu/config/gpu_switching_list_unittest.cc
@@ -0,0 +1,109 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <vector>
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/config/gpu_control_list_jsons.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_switching_list.h"
+#include "gpu/config/gpu_switching_option.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+const char kOsVersion[] = "10.6.4";
+
+namespace gpu {
+
+class GpuSwitchingListTest : public testing::Test {
+ public:
+ GpuSwitchingListTest() { }
+
+ virtual ~GpuSwitchingListTest() { }
+
+ const GPUInfo& gpu_info() const {
+ return gpu_info_;
+ }
+
+ protected:
+ virtual void SetUp() {
+ gpu_info_.gpu.vendor_id = 0x10de;
+ gpu_info_.gpu.device_id = 0x0640;
+ gpu_info_.driver_vendor = "NVIDIA";
+ gpu_info_.driver_version = "1.6.18";
+ gpu_info_.driver_date = "7-14-2009";
+ gpu_info_.machine_model = "MacBookPro 7.1";
+ gpu_info_.gl_vendor = "NVIDIA Corporation";
+ gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
+ gpu_info_.performance_stats.graphics = 5.0;
+ gpu_info_.performance_stats.gaming = 5.0;
+ gpu_info_.performance_stats.overall = 5.0;
+ }
+
+ virtual void TearDown() {
+ }
+
+ private:
+ GPUInfo gpu_info_;
+};
+
+TEST_F(GpuSwitchingListTest, CurrentSwitchingListValidation) {
+ scoped_ptr<GpuSwitchingList> switching_list(GpuSwitchingList::Create());
+ EXPECT_TRUE(switching_list->LoadList(
+ kGpuSwitchingListJson, GpuControlList::kAllOs));
+ EXPECT_FALSE(switching_list->contains_unknown_fields());
+}
+
+TEST_F(GpuSwitchingListTest, GpuSwitching) {
+ const std::string json = LONG_STRING_CONST(
+ {
+ "name": "gpu switching list",
+ "version": "0.1",
+ "entries": [
+ {
+ "id": 1,
+ "os": {
+ "type": "macosx"
+ },
+ "features": [
+ "force_discrete"
+ ]
+ },
+ {
+ "id": 2,
+ "os": {
+ "type": "win"
+ },
+ "features": [
+ "force_integrated"
+ ]
+ }
+ ]
+ }
+ );
+ scoped_ptr<GpuSwitchingList> switching_list(GpuSwitchingList::Create());
+ EXPECT_TRUE(switching_list->LoadList(json, GpuControlList::kAllOs));
+ std::set<int> switching = switching_list->MakeDecision(
+ GpuControlList::kOsMacosx, kOsVersion, gpu_info());
+ EXPECT_EQ(1u, switching.size());
+ EXPECT_EQ(1u, switching.count(GPU_SWITCHING_OPTION_FORCE_DISCRETE));
+ std::vector<uint32> entries;
+ switching_list->GetDecisionEntries(&entries, false);
+ ASSERT_EQ(1u, entries.size());
+ EXPECT_EQ(1u, entries[0]);
+
+ switching_list.reset(GpuSwitchingList::Create());
+ EXPECT_TRUE(switching_list->LoadList(json, GpuControlList::kAllOs));
+ switching = switching_list->MakeDecision(
+ GpuControlList::kOsWin, kOsVersion, gpu_info());
+ EXPECT_EQ(1u, switching.size());
+ EXPECT_EQ(1u, switching.count(GPU_SWITCHING_OPTION_FORCE_INTEGRATED));
+ switching_list->GetDecisionEntries(&entries, false);
+ ASSERT_EQ(1u, entries.size());
+ EXPECT_EQ(2u, entries[0]);
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_switching_option.h b/chromium/gpu/config/gpu_switching_option.h
new file mode 100644
index 00000000000..036c15f4e41
--- /dev/null
+++ b/chromium/gpu/config/gpu_switching_option.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_SWITCHING_OPTION_H_
+#define GPU_CONFIG_GPU_SWITCHING_OPTION_H_
+
+//#include "build/build_config.h"
+
+namespace gpu {
+
+enum GpuSwitchingOption {
+ GPU_SWITCHING_OPTION_AUTOMATIC,
+ GPU_SWITCHING_OPTION_FORCE_INTEGRATED,
+ GPU_SWITCHING_OPTION_FORCE_DISCRETE,
+ GPU_SWITCHING_OPTION_UNKNOWN
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_SWITCHING_OPTION_H_
+
diff --git a/chromium/gpu/config/gpu_test_config.cc b/chromium/gpu/config/gpu_test_config.cc
new file mode 100644
index 00000000000..ffb6e5f2149
--- /dev/null
+++ b/chromium/gpu/config/gpu_test_config.cc
@@ -0,0 +1,272 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_test_config.h"
+
+#include "base/logging.h"
+#include "base/sys_info.h"
+#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "gpu/config/gpu_test_expectations_parser.h"
+
+namespace gpu {
+
+namespace {
+
+GPUTestConfig::OS GetCurrentOS() {
+#if defined(OS_CHROMEOS)
+ return GPUTestConfig::kOsChromeOS;
+#elif defined(OS_LINUX) || defined(OS_OPENBSD)
+ return GPUTestConfig::kOsLinux;
+#elif defined(OS_WIN)
+ int32 major_version = 0;
+ int32 minor_version = 0;
+ int32 bugfix_version = 0;
+ base::SysInfo::OperatingSystemVersionNumbers(
+ &major_version, &minor_version, &bugfix_version);
+ if (major_version == 5)
+ return GPUTestConfig::kOsWinXP;
+ if (major_version == 6 && minor_version == 0)
+ return GPUTestConfig::kOsWinVista;
+ if (major_version == 6 && minor_version == 1)
+ return GPUTestConfig::kOsWin7;
+ if (major_version == 6 && minor_version == 2)
+ return GPUTestConfig::kOsWin8;
+#elif defined(OS_MACOSX)
+ int32 major_version = 0;
+ int32 minor_version = 0;
+ int32 bugfix_version = 0;
+ base::SysInfo::OperatingSystemVersionNumbers(
+ &major_version, &minor_version, &bugfix_version);
+ if (major_version == 10) {
+ switch (minor_version) {
+ case 5:
+ return GPUTestConfig::kOsMacLeopard;
+ case 6:
+ return GPUTestConfig::kOsMacSnowLeopard;
+ case 7:
+ return GPUTestConfig::kOsMacLion;
+ case 8:
+ return GPUTestConfig::kOsMacMountainLion;
+ }
+ }
+#elif defined(OS_ANDROID)
+ return GPUTestConfig::kOsAndroid;
+#endif
+ return GPUTestConfig::kOsUnknown;
+}
+
+} // namespace anonymous
+
+GPUTestConfig::GPUTestConfig()
+ : validate_gpu_info_(true),
+ os_(kOsUnknown),
+ gpu_device_id_(0),
+ build_type_(kBuildTypeUnknown) {
+}
+
+GPUTestConfig::~GPUTestConfig() {
+}
+
+void GPUTestConfig::set_os(int32 os) {
+ DCHECK_EQ(0, os & ~(kOsAndroid | kOsWin | kOsMac | kOsLinux | kOsChromeOS));
+ os_ = os;
+}
+
+void GPUTestConfig::AddGPUVendor(uint32 gpu_vendor) {
+ DCHECK_NE(0u, gpu_vendor);
+ for (size_t i = 0; i < gpu_vendor_.size(); ++i)
+ DCHECK_NE(gpu_vendor_[i], gpu_vendor);
+ gpu_vendor_.push_back(gpu_vendor);
+}
+
+void GPUTestConfig::set_gpu_device_id(uint32 id) {
+ gpu_device_id_ = id;
+}
+
+void GPUTestConfig::set_build_type(int32 build_type) {
+ DCHECK_EQ(0, build_type & ~(kBuildTypeRelease | kBuildTypeDebug));
+ build_type_ = build_type;
+}
+
+bool GPUTestConfig::IsValid() const {
+ if (!validate_gpu_info_)
+ return true;
+ if (gpu_device_id_ != 0 && (gpu_vendor_.size() != 1 || gpu_vendor_[0] == 0))
+ return false;
+ return true;
+}
+
+bool GPUTestConfig::OverlapsWith(const GPUTestConfig& config) const {
+ DCHECK(IsValid());
+ DCHECK(config.IsValid());
+ if (config.os_ != kOsUnknown && os_ != kOsUnknown &&
+ (os_ & config.os_) == 0)
+ return false;
+ if (config.gpu_vendor_.size() > 0 && gpu_vendor_.size() > 0) {
+ bool shared = false;
+ for (size_t i = 0; i < config.gpu_vendor_.size() && !shared; ++i) {
+ for (size_t j = 0; j < gpu_vendor_.size(); ++j) {
+ if (config.gpu_vendor_[i] == gpu_vendor_[j]) {
+ shared = true;
+ break;
+ }
+ }
+ }
+ if (!shared)
+ return false;
+ }
+ if (config.gpu_device_id_ != 0 && gpu_device_id_ != 0 &&
+ gpu_device_id_ != config.gpu_device_id_)
+ return false;
+ if (config.build_type_ != kBuildTypeUnknown &&
+ build_type_ != kBuildTypeUnknown &&
+ (build_type_ & config.build_type_) == 0)
+ return false;
+ return true;
+}
+
+void GPUTestConfig::DisableGPUInfoValidation() {
+ validate_gpu_info_ = false;
+}
+
+void GPUTestConfig::ClearGPUVendor() {
+ gpu_vendor_.clear();
+}
+
+GPUTestBotConfig::~GPUTestBotConfig() {
+}
+
+void GPUTestBotConfig::AddGPUVendor(uint32 gpu_vendor) {
+ DCHECK_EQ(0u, GPUTestConfig::gpu_vendor().size());
+ GPUTestConfig::AddGPUVendor(gpu_vendor);
+}
+
+bool GPUTestBotConfig::SetGPUInfo(const GPUInfo& gpu_info) {
+ DCHECK(validate_gpu_info_);
+ if (gpu_info.gpu.device_id == 0 || gpu_info.gpu.vendor_id == 0)
+ return false;
+ ClearGPUVendor();
+ AddGPUVendor(gpu_info.gpu.vendor_id);
+ set_gpu_device_id(gpu_info.gpu.device_id);
+ return true;
+}
+
+bool GPUTestBotConfig::IsValid() const {
+ switch (os()) {
+ case kOsWinXP:
+ case kOsWinVista:
+ case kOsWin7:
+ case kOsWin8:
+ case kOsMacLeopard:
+ case kOsMacSnowLeopard:
+ case kOsMacLion:
+ case kOsMacMountainLion:
+ case kOsLinux:
+ case kOsChromeOS:
+ case kOsAndroid:
+ break;
+ default:
+ return false;
+ }
+ if (validate_gpu_info_) {
+ if (gpu_vendor().size() != 1 || gpu_vendor()[0] == 0)
+ return false;
+ if (gpu_device_id() == 0)
+ return false;
+ }
+ switch (build_type()) {
+ case kBuildTypeRelease:
+ case kBuildTypeDebug:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+bool GPUTestBotConfig::Matches(const GPUTestConfig& config) const {
+ DCHECK(IsValid());
+ DCHECK(config.IsValid());
+ if (config.os() != kOsUnknown && (os() & config.os()) == 0)
+ return false;
+ if (config.gpu_vendor().size() > 0) {
+ bool contained = false;
+ for (size_t i = 0; i < config.gpu_vendor().size(); ++i) {
+ if (config.gpu_vendor()[i] == gpu_vendor()[0]) {
+ contained = true;
+ break;
+ }
+ }
+ if (!contained)
+ return false;
+ }
+ if (config.gpu_device_id() != 0 &&
+ gpu_device_id() != config.gpu_device_id())
+ return false;
+ if (config.build_type() != kBuildTypeUnknown &&
+ (build_type() & config.build_type()) == 0)
+ return false;
+ return true;
+}
+
+bool GPUTestBotConfig::Matches(const std::string& config_data) const {
+ GPUTestExpectationsParser parser;
+ GPUTestConfig config;
+
+ if (!parser.ParseConfig(config_data, &config))
+ return false;
+ return Matches(config);
+}
+
+bool GPUTestBotConfig::LoadCurrentConfig(const GPUInfo* gpu_info) {
+ bool rt;
+ if (gpu_info == NULL) {
+ GPUInfo my_gpu_info;
+ GpuIDResult result;
+ result = CollectGpuID(&my_gpu_info.gpu.vendor_id,
+ &my_gpu_info.gpu.device_id);
+ if (result == kGpuIDNotSupported) {
+ DisableGPUInfoValidation();
+ rt = true;
+ } else {
+ rt = SetGPUInfo(my_gpu_info);
+ }
+ } else {
+ rt = SetGPUInfo(*gpu_info);
+ }
+ set_os(GetCurrentOS());
+ if (os() == kOsUnknown)
+ rt = false;
+#if defined(NDEBUG)
+ set_build_type(kBuildTypeRelease);
+#else
+ set_build_type(kBuildTypeDebug);
+#endif
+ return rt;
+}
+
+// static
+bool GPUTestBotConfig::CurrentConfigMatches(const std::string& config_data) {
+ GPUTestBotConfig my_config;
+ if (!my_config.LoadCurrentConfig(NULL))
+ return false;
+ return my_config.Matches(config_data);
+}
+
+// static
+bool GPUTestBotConfig::CurrentConfigMatches(
+ const std::vector<std::string>& configs) {
+ GPUTestBotConfig my_config;
+ if (!my_config.LoadCurrentConfig(NULL))
+ return false;
+ for (size_t i = 0 ; i < configs.size(); ++i) {
+ if (my_config.Matches(configs[i]))
+ return true;
+ }
+ return false;
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_test_config.h b/chromium/gpu/config/gpu_test_config.h
new file mode 100644
index 00000000000..3c7b038567f
--- /dev/null
+++ b/chromium/gpu/config/gpu_test_config.h
@@ -0,0 +1,124 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_TEST_CONFIG_H_
+#define GPU_CONFIG_GPU_TEST_CONFIG_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+struct GPUInfo;
+
+class GPU_EXPORT GPUTestConfig {
+ public:
+ enum OS {
+ kOsUnknown = 0,
+ kOsWinXP = 1 << 0,
+ kOsWinVista = 1 << 1,
+ kOsWin7 = 1 << 2,
+ kOsWin8 = 1 << 3,
+ kOsWin = kOsWinXP | kOsWinVista | kOsWin7 | kOsWin8,
+ kOsMacLeopard = 1 << 4,
+ kOsMacSnowLeopard = 1 << 5,
+ kOsMacLion = 1 << 6,
+ kOsMacMountainLion = 1 << 7,
+ kOsMac = kOsMacLeopard | kOsMacSnowLeopard | kOsMacLion |
+ kOsMacMountainLion,
+ kOsLinux = 1 << 8,
+ kOsChromeOS = 1 << 9,
+ kOsAndroid = 1 << 10,
+ };
+
+ enum BuildType {
+ kBuildTypeUnknown = 0,
+ kBuildTypeRelease = 1 << 0,
+ kBuildTypeDebug = 1 << 1,
+ };
+
+ GPUTestConfig();
+ virtual ~GPUTestConfig();
+
+ void set_os(int32 os);
+ void set_gpu_device_id(uint32 id);
+ void set_build_type(int32 build_type);
+
+ virtual void AddGPUVendor(uint32 gpu_vendor);
+
+ int32 os() const { return os_; }
+ const std::vector<uint32>& gpu_vendor() const { return gpu_vendor_; }
+ uint32 gpu_device_id() const { return gpu_device_id_; }
+ int32 build_type() const { return build_type_; }
+
+ // Check if the config is valid. For example, if gpu_device_id_ is set, but
+ // gpu_vendor_ is unknown, then it's invalid.
+ virtual bool IsValid() const;
+
+ // Check if two configs overlap, i.e., if there exists a config that matches
+ // both configs.
+ bool OverlapsWith(const GPUTestConfig& config) const;
+
+ // Disable validation of GPU vendor and device ids.
+ void DisableGPUInfoValidation();
+
+ protected:
+ void ClearGPUVendor();
+
+ // Indicates that the OS has the notion of a numeric GPU vendor and device id
+ // and this data should be validated.
+ bool validate_gpu_info_;
+
+ private:
+ // operating system.
+ int32 os_;
+
+ // GPU vendor.
+ std::vector<uint32> gpu_vendor_;
+
+ // GPU device id (unique to each vendor).
+ uint32 gpu_device_id_;
+
+ // Release or Debug.
+ int32 build_type_;
+};
+
+class GPU_EXPORT GPUTestBotConfig : public GPUTestConfig {
+ public:
+ GPUTestBotConfig() { }
+ virtual ~GPUTestBotConfig();
+
+ // This should only be called when no gpu_vendor is added.
+ virtual void AddGPUVendor(uint32 gpu_vendor) OVERRIDE;
+
+ // Return false if gpu_info does not have valid vendor_id and device_id.
+ bool SetGPUInfo(const GPUInfo& gpu_info);
+
+ // Check if the bot config is valid, i.e., if it is one valid test-bot
+ // environment. For example, if a field is unknown, or if OS is not one
+ // fully defined OS, then it's valid.
+ virtual bool IsValid() const OVERRIDE;
+
+ // Check if a bot config matches a test config, i.e., the test config is a
+ // superset of the bot config.
+ bool Matches(const GPUTestConfig& config) const;
+ bool Matches(const std::string& config_data) const;
+
+ // Setup the config with the current gpu testing environment.
+ // If gpu_info is NULL, collect GPUInfo first.
+ bool LoadCurrentConfig(const GPUInfo* gpu_info);
+
+ // Check if this bot's config matches |config_data| or any of the |configs|.
+ static bool CurrentConfigMatches(const std::string& config_data);
+ static bool CurrentConfigMatches(const std::vector<std::string>& configs);
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_TEST_CONFIG_H_
+
diff --git a/chromium/gpu/config/gpu_test_config_unittest.cc b/chromium/gpu/config/gpu_test_config_unittest.cc
new file mode 100644
index 00000000000..b9411dc52ad
--- /dev/null
+++ b/chromium/gpu/config/gpu_test_config_unittest.cc
@@ -0,0 +1,255 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_info.h"
+#include "gpu/config/gpu_test_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class GPUTestConfigTest : public testing::Test {
+ public:
+ GPUTestConfigTest() { }
+
+ virtual ~GPUTestConfigTest() { }
+
+ protected:
+ virtual void SetUp() { }
+
+ virtual void TearDown() { }
+};
+
+TEST_F(GPUTestConfigTest, EmptyValues) {
+ GPUTestConfig config;
+ EXPECT_EQ(GPUTestConfig::kOsUnknown, config.os());
+ EXPECT_EQ(0u, config.gpu_vendor().size());
+ EXPECT_EQ(0u, config.gpu_device_id());
+ EXPECT_EQ(GPUTestConfig::kBuildTypeUnknown, config.build_type());
+}
+
+TEST_F(GPUTestConfigTest, SetGPUInfo) {
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x0640;
+ GPUTestBotConfig config;
+ EXPECT_TRUE(config.SetGPUInfo(gpu_info));
+ EXPECT_EQ(1u, config.gpu_vendor().size());
+ EXPECT_EQ(gpu_info.gpu.vendor_id, config.gpu_vendor()[0]);
+ EXPECT_EQ(gpu_info.gpu.device_id, config.gpu_device_id());
+
+ gpu_info.gpu.vendor_id = 0x8086;
+ gpu_info.gpu.device_id = 0x0046;
+ EXPECT_TRUE(config.SetGPUInfo(gpu_info));
+ EXPECT_EQ(1u, config.gpu_vendor().size());
+ EXPECT_EQ(gpu_info.gpu.vendor_id, config.gpu_vendor()[0]);
+ EXPECT_EQ(gpu_info.gpu.device_id, config.gpu_device_id());
+}
+
+TEST_F(GPUTestConfigTest, IsValid) {
+ {
+ GPUTestConfig config;
+ config.set_gpu_device_id(0x0640);
+ EXPECT_FALSE(config.IsValid());
+ config.AddGPUVendor(0x10de);
+ EXPECT_TRUE(config.IsValid());
+ }
+
+ {
+ GPUTestBotConfig config;
+ config.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ config.set_os(GPUTestConfig::kOsWin7);
+ config.set_gpu_device_id(0x0640);
+ EXPECT_FALSE(config.IsValid());
+ config.AddGPUVendor(0x10de);
+ EXPECT_TRUE(config.IsValid());
+
+ config.set_gpu_device_id(0);
+ EXPECT_FALSE(config.IsValid());
+ config.set_gpu_device_id(0x0640);
+ EXPECT_TRUE(config.IsValid());
+
+ config.set_os(GPUTestConfig::kOsWin);
+ EXPECT_FALSE(config.IsValid());
+ config.set_os(GPUTestConfig::kOsWin7 | GPUTestConfig::kOsWinXP);
+ EXPECT_FALSE(config.IsValid());
+ config.set_os(GPUTestConfig::kOsWin7);
+ EXPECT_TRUE(config.IsValid());
+
+ config.set_build_type(GPUTestConfig::kBuildTypeUnknown);
+ EXPECT_FALSE(config.IsValid());
+ config.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ EXPECT_TRUE(config.IsValid());
+ }
+}
+
+TEST_F(GPUTestConfigTest, Matches) {
+ GPUTestBotConfig config;
+ config.set_os(GPUTestConfig::kOsWin7);
+ config.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ config.AddGPUVendor(0x10de);
+ config.set_gpu_device_id(0x0640);
+ EXPECT_TRUE(config.IsValid());
+
+ { // os matching
+ GPUTestConfig config2;
+ EXPECT_TRUE(config.Matches(config2));
+ config2.set_os(GPUTestConfig::kOsWin);
+ EXPECT_TRUE(config.Matches(config2));
+ config2.set_os(GPUTestConfig::kOsWin7);
+ EXPECT_TRUE(config.Matches(config2));
+ config2.set_os(GPUTestConfig::kOsMac);
+ EXPECT_FALSE(config.Matches(config2));
+ config2.set_os(GPUTestConfig::kOsWin7 | GPUTestConfig::kOsLinux);
+ EXPECT_TRUE(config.Matches(config2));
+ }
+
+ { // gpu vendor matching
+ {
+ GPUTestConfig config2;
+ config2.AddGPUVendor(0x10de);
+ EXPECT_TRUE(config.Matches(config2));
+ config2.AddGPUVendor(0x1004);
+ EXPECT_TRUE(config.Matches(config2));
+ }
+ {
+ GPUTestConfig config2;
+ config2.AddGPUVendor(0x8086);
+ EXPECT_FALSE(config.Matches(config2));
+ }
+ }
+
+ { // build type matching
+ GPUTestConfig config2;
+ config2.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ EXPECT_TRUE(config.Matches(config2));
+ config2.set_build_type(GPUTestConfig::kBuildTypeRelease |
+ GPUTestConfig::kBuildTypeDebug);
+ EXPECT_TRUE(config.Matches(config2));
+ config2.set_build_type(GPUTestConfig::kBuildTypeDebug);
+ EXPECT_FALSE(config.Matches(config2));
+ }
+
+ { // exact matching
+ GPUTestConfig config2;
+ config2.set_os(GPUTestConfig::kOsWin7);
+ config2.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ config2.AddGPUVendor(0x10de);
+ config2.set_gpu_device_id(0x0640);
+ EXPECT_TRUE(config.Matches(config2));
+ config2.set_gpu_device_id(0x0641);
+ EXPECT_FALSE(config.Matches(config2));
+ }
+}
+
+TEST_F(GPUTestConfigTest, StringMatches) {
+ GPUTestBotConfig config;
+ config.set_os(GPUTestConfig::kOsWin7);
+ config.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ config.AddGPUVendor(0x10de);
+ config.set_gpu_device_id(0x0640);
+ EXPECT_TRUE(config.IsValid());
+
+ EXPECT_TRUE(config.Matches(std::string()));
+
+ // os matching
+ EXPECT_TRUE(config.Matches("WIN"));
+ EXPECT_TRUE(config.Matches("WIN7"));
+ EXPECT_FALSE(config.Matches("MAC"));
+ EXPECT_TRUE(config.Matches("WIN7 LINUX"));
+
+ // gpu vendor matching
+ EXPECT_TRUE(config.Matches("NVIDIA"));
+ EXPECT_TRUE(config.Matches("NVIDIA AMD"));
+ EXPECT_FALSE(config.Matches("INTEL"));
+
+ // build type matching
+ EXPECT_TRUE(config.Matches("RELEASE"));
+ EXPECT_TRUE(config.Matches("RELEASE DEBUG"));
+ EXPECT_FALSE(config.Matches("DEBUG"));
+
+ // exact matching
+ EXPECT_TRUE(config.Matches("WIN7 RELEASE NVIDIA 0X0640"));
+ EXPECT_FALSE(config.Matches("WIN7 RELEASE NVIDIA 0X0641"));
+}
+
+TEST_F(GPUTestConfigTest, OverlapsWith) {
+ { // os
+ // win vs win7
+ GPUTestConfig config;
+ config.set_os(GPUTestConfig::kOsWin);
+ GPUTestConfig config2;
+ config2.set_os(GPUTestConfig::kOsWin7);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ // win vs win7+linux
+ config2.set_os(GPUTestConfig::kOsWin7 | GPUTestConfig::kOsLinux);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ // win vs mac
+ config2.set_os(GPUTestConfig::kOsMac);
+ EXPECT_FALSE(config.OverlapsWith(config2));
+ EXPECT_FALSE(config2.OverlapsWith(config));
+ // win vs unknown
+ config2.set_os(GPUTestConfig::kOsUnknown);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ }
+
+ { // gpu vendor
+ GPUTestConfig config;
+ config.AddGPUVendor(0x10de);
+ // nvidia vs unknown
+ GPUTestConfig config2;
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ // nvidia vs intel
+ config2.AddGPUVendor(0x1086);
+ EXPECT_FALSE(config.OverlapsWith(config2));
+ EXPECT_FALSE(config2.OverlapsWith(config));
+ // nvidia vs nvidia+intel
+ config2.AddGPUVendor(0x10de);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ }
+
+ { // build type
+ // release vs debug
+ GPUTestConfig config;
+ config.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ GPUTestConfig config2;
+ config2.set_build_type(GPUTestConfig::kBuildTypeDebug);
+ EXPECT_FALSE(config.OverlapsWith(config2));
+ EXPECT_FALSE(config2.OverlapsWith(config));
+ // release vs release+debug
+ config2.set_build_type(GPUTestConfig::kBuildTypeRelease |
+ GPUTestConfig::kBuildTypeDebug);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ // release vs unknown
+ config2.set_build_type(GPUTestConfig::kBuildTypeUnknown);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ }
+
+ { // win7 vs nvidia
+ GPUTestConfig config;
+ config.set_os(GPUTestConfig::kOsWin7);
+ GPUTestConfig config2;
+ config2.AddGPUVendor(0x10de);
+ EXPECT_TRUE(config.OverlapsWith(config2));
+ EXPECT_TRUE(config2.OverlapsWith(config));
+ }
+}
+
+TEST_F(GPUTestConfigTest, LoadCurrentConfig) {
+ GPUTestBotConfig config;
+ GPUInfo gpu_info;
+ gpu_info.gpu.vendor_id = 0x10de;
+ gpu_info.gpu.device_id = 0x0640;
+ EXPECT_TRUE(config.LoadCurrentConfig(&gpu_info));
+ EXPECT_TRUE(config.IsValid());
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_test_expectations_parser.cc b/chromium/gpu/config/gpu_test_expectations_parser.cc
new file mode 100644
index 00000000000..c746bed89c8
--- /dev/null
+++ b/chromium/gpu/config/gpu_test_expectations_parser.cc
@@ -0,0 +1,503 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_test_expectations_parser.h"
+
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/strings/stringprintf.h"
+
+namespace gpu {
+
+namespace {
+
+enum LineParserStage {
+ kLineParserBegin = 0,
+ kLineParserBugID,
+ kLineParserConfigs,
+ kLineParserColon,
+ kLineParserTestName,
+ kLineParserEqual,
+ kLineParserExpectations,
+};
+
+enum Token {
+ // os
+ kConfigWinXP = 0,
+ kConfigWinVista,
+ kConfigWin7,
+ kConfigWin8,
+ kConfigWin,
+ kConfigMacLeopard,
+ kConfigMacSnowLeopard,
+ kConfigMacLion,
+ kConfigMacMountainLion,
+ kConfigMac,
+ kConfigLinux,
+ kConfigChromeOS,
+ kConfigAndroid,
+ // gpu vendor
+ kConfigNVidia,
+ kConfigAMD,
+ kConfigIntel,
+ kConfigVMWare,
+ // build type
+ kConfigRelease,
+ kConfigDebug,
+ // expectation
+ kExpectationPass,
+ kExpectationFail,
+ kExpectationFlaky,
+ kExpectationTimeout,
+ kExpectationSkip,
+ // separator
+ kSeparatorColon,
+ kSeparatorEqual,
+
+ kNumberOfExactMatchTokens,
+
+ // others
+ kConfigGPUDeviceID,
+ kTokenComment,
+ kTokenWord,
+};
+
+struct TokenInfo {
+ const char* name;
+ int32 flag;
+};
+
+const TokenInfo kTokenData[] = {
+ { "xp", GPUTestConfig::kOsWinXP },
+ { "vista", GPUTestConfig::kOsWinVista },
+ { "win7", GPUTestConfig::kOsWin7 },
+ { "win8", GPUTestConfig::kOsWin8 },
+ { "win", GPUTestConfig::kOsWin },
+ { "leopard", GPUTestConfig::kOsMacLeopard },
+ { "snowleopard", GPUTestConfig::kOsMacSnowLeopard },
+ { "lion", GPUTestConfig::kOsMacLion },
+ { "mountainlion", GPUTestConfig::kOsMacMountainLion },
+ { "mac", GPUTestConfig::kOsMac },
+ { "linux", GPUTestConfig::kOsLinux },
+ { "chromeos", GPUTestConfig::kOsChromeOS },
+ { "android", GPUTestConfig::kOsAndroid },
+ { "nvidia", 0x10DE },
+ { "amd", 0x1002 },
+ { "intel", 0x8086 },
+ { "vmware", 0x15ad },
+ { "release", GPUTestConfig::kBuildTypeRelease },
+ { "debug", GPUTestConfig::kBuildTypeDebug },
+ { "pass", GPUTestExpectationsParser::kGpuTestPass },
+ { "fail", GPUTestExpectationsParser::kGpuTestFail },
+ { "flaky", GPUTestExpectationsParser::kGpuTestFlaky },
+ { "timeout", GPUTestExpectationsParser::kGpuTestTimeout },
+ { "skip", GPUTestExpectationsParser::kGpuTestSkip },
+ { ":", 0 },
+ { "=", 0 },
+};
+
+enum ErrorType {
+ kErrorFileIO = 0,
+ kErrorIllegalEntry,
+ kErrorInvalidEntry,
+ kErrorEntryWithOsConflicts,
+ kErrorEntryWithGpuVendorConflicts,
+ kErrorEntryWithBuildTypeConflicts,
+ kErrorEntryWithGpuDeviceIdConflicts,
+ kErrorEntryWithExpectationConflicts,
+ kErrorEntriesOverlap,
+
+ kNumberOfErrors,
+};
+
+const char* kErrorMessage[] = {
+ "file IO failed",
+ "entry with wrong format",
+ "entry invalid, likely wrong modifiers combination",
+ "entry with OS modifier conflicts",
+ "entry with GPU vendor modifier conflicts",
+ "entry with GPU build type conflicts",
+ "entry with GPU device id conflicts or malformat",
+ "entry with expectation modifier conflicts",
+ "two entries's configs overlap",
+};
+
+Token ParseToken(const std::string& word) {
+ if (StartsWithASCII(word, "//", false))
+ return kTokenComment;
+ if (StartsWithASCII(word, "0x", false))
+ return kConfigGPUDeviceID;
+
+ for (int32 i = 0; i < kNumberOfExactMatchTokens; ++i) {
+ if (LowerCaseEqualsASCII(word, kTokenData[i].name))
+ return static_cast<Token>(i);
+ }
+ return kTokenWord;
+}
+
+// reference name can have the last character as *.
+bool NamesMatching(const std::string& ref, const std::string& test_name) {
+ size_t len = ref.length();
+ if (len == 0)
+ return false;
+ if (ref[len - 1] == '*') {
+ if (test_name.length() > len -1 &&
+ ref.compare(0, len - 1, test_name, 0, len - 1) == 0)
+ return true;
+ return false;
+ }
+ return (ref == test_name);
+}
+
+} // namespace anonymous
+
+GPUTestExpectationsParser::GPUTestExpectationsParser() {
+ // Some sanity check.
+ DCHECK_EQ(static_cast<unsigned int>(kNumberOfExactMatchTokens),
+ sizeof(kTokenData) / sizeof(kTokenData[0]));
+ DCHECK_EQ(static_cast<unsigned int>(kNumberOfErrors),
+ sizeof(kErrorMessage) / sizeof(kErrorMessage[0]));
+}
+
+GPUTestExpectationsParser::~GPUTestExpectationsParser() {
+}
+
+bool GPUTestExpectationsParser::LoadTestExpectations(const std::string& data) {
+ entries_.clear();
+ error_messages_.clear();
+
+ std::vector<std::string> lines;
+ base::SplitString(data, '\n', &lines);
+ bool rt = true;
+ for (size_t i = 0; i < lines.size(); ++i) {
+ if (!ParseLine(lines[i], i + 1))
+ rt = false;
+ }
+ if (DetectConflictsBetweenEntries()) {
+ entries_.clear();
+ rt = false;
+ }
+
+ return rt;
+}
+
+bool GPUTestExpectationsParser::LoadTestExpectations(
+ const base::FilePath& path) {
+ entries_.clear();
+ error_messages_.clear();
+
+ std::string data;
+ if (!file_util::ReadFileToString(path, &data)) {
+ error_messages_.push_back(kErrorMessage[kErrorFileIO]);
+ return false;
+ }
+ return LoadTestExpectations(data);
+}
+
+int32 GPUTestExpectationsParser::GetTestExpectation(
+ const std::string& test_name,
+ const GPUTestBotConfig& bot_config) const {
+ for (size_t i = 0; i < entries_.size(); ++i) {
+ if (NamesMatching(entries_[i].test_name, test_name) &&
+ bot_config.Matches(entries_[i].test_config))
+ return entries_[i].test_expectation;
+ }
+ return kGpuTestPass;
+}
+
+const std::vector<std::string>&
+GPUTestExpectationsParser::GetErrorMessages() const {
+ return error_messages_;
+}
+
+bool GPUTestExpectationsParser::ParseConfig(
+ const std::string& config_data, GPUTestConfig* config) {
+ DCHECK(config);
+ std::vector<std::string> tokens;
+ base::SplitStringAlongWhitespace(config_data, &tokens);
+
+ for (size_t i = 0; i < tokens.size(); ++i) {
+ Token token = ParseToken(tokens[i]);
+ switch (token) {
+ case kConfigWinXP:
+ case kConfigWinVista:
+ case kConfigWin7:
+ case kConfigWin8:
+ case kConfigWin:
+ case kConfigMacLeopard:
+ case kConfigMacSnowLeopard:
+ case kConfigMacLion:
+ case kConfigMacMountainLion:
+ case kConfigMac:
+ case kConfigLinux:
+ case kConfigChromeOS:
+ case kConfigAndroid:
+ case kConfigNVidia:
+ case kConfigAMD:
+ case kConfigIntel:
+ case kConfigVMWare:
+ case kConfigRelease:
+ case kConfigDebug:
+ case kConfigGPUDeviceID:
+ if (token == kConfigGPUDeviceID) {
+ if (!UpdateTestConfig(config, tokens[i], 0))
+ return false;
+ } else {
+ if (!UpdateTestConfig(config, token, 0))
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool GPUTestExpectationsParser::ParseLine(
+ const std::string& line_data, size_t line_number) {
+ std::vector<std::string> tokens;
+ base::SplitStringAlongWhitespace(line_data, &tokens);
+ int32 stage = kLineParserBegin;
+ GPUTestExpectationEntry entry;
+ entry.line_number = line_number;
+ GPUTestConfig& config = entry.test_config;
+ bool comments_encountered = false;
+ for (size_t i = 0; i < tokens.size() && !comments_encountered; ++i) {
+ Token token = ParseToken(tokens[i]);
+ switch (token) {
+ case kTokenComment:
+ comments_encountered = true;
+ break;
+ case kConfigWinXP:
+ case kConfigWinVista:
+ case kConfigWin7:
+ case kConfigWin8:
+ case kConfigWin:
+ case kConfigMacLeopard:
+ case kConfigMacSnowLeopard:
+ case kConfigMacLion:
+ case kConfigMacMountainLion:
+ case kConfigMac:
+ case kConfigLinux:
+ case kConfigChromeOS:
+ case kConfigAndroid:
+ case kConfigNVidia:
+ case kConfigAMD:
+ case kConfigIntel:
+ case kConfigVMWare:
+ case kConfigRelease:
+ case kConfigDebug:
+ case kConfigGPUDeviceID:
+ // MODIFIERS, could be in any order, need at least one.
+ if (stage != kLineParserConfigs && stage != kLineParserBugID) {
+ PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
+ line_number);
+ return false;
+ }
+ if (token == kConfigGPUDeviceID) {
+ if (!UpdateTestConfig(&config, tokens[i], line_number))
+ return false;
+ } else {
+ if (!UpdateTestConfig(&config, token, line_number))
+ return false;
+ }
+ if (stage == kLineParserBugID)
+ stage++;
+ break;
+ case kSeparatorColon:
+ // :
+ if (stage != kLineParserConfigs) {
+ PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
+ line_number);
+ return false;
+ }
+ stage++;
+ break;
+ case kSeparatorEqual:
+ // =
+ if (stage != kLineParserTestName) {
+ PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
+ line_number);
+ return false;
+ }
+ stage++;
+ break;
+ case kTokenWord:
+ // BUG_ID or TEST_NAME
+ if (stage == kLineParserBegin) {
+ // Bug ID is not used for anything; ignore it.
+ } else if (stage == kLineParserColon) {
+ entry.test_name = tokens[i];
+ } else {
+ PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
+ line_number);
+ return false;
+ }
+ stage++;
+ break;
+ case kExpectationPass:
+ case kExpectationFail:
+ case kExpectationFlaky:
+ case kExpectationTimeout:
+ case kExpectationSkip:
+ // TEST_EXPECTATIONS
+ if (stage != kLineParserEqual && stage != kLineParserExpectations) {
+ PushErrorMessage(kErrorMessage[kErrorIllegalEntry],
+ line_number);
+ return false;
+ }
+ if ((kTokenData[token].flag & entry.test_expectation) != 0) {
+ PushErrorMessage(kErrorMessage[kErrorEntryWithExpectationConflicts],
+ line_number);
+ return false;
+ }
+ entry.test_expectation =
+ (kTokenData[token].flag | entry.test_expectation);
+ if (stage == kLineParserEqual)
+ stage++;
+ break;
+ default:
+ DCHECK(false);
+ break;
+ }
+ }
+ if (stage == kLineParserBegin) {
+ // The whole line is empty or all comments
+ return true;
+ }
+ if (stage == kLineParserExpectations) {
+ if (!config.IsValid()) {
+ PushErrorMessage(kErrorMessage[kErrorInvalidEntry], line_number);
+ return false;
+ }
+ entries_.push_back(entry);
+ return true;
+ }
+ PushErrorMessage(kErrorMessage[kErrorIllegalEntry], line_number);
+ return false;
+}
+
+bool GPUTestExpectationsParser::UpdateTestConfig(
+ GPUTestConfig* config, int32 token, size_t line_number) {
+ DCHECK(config);
+ switch (token) {
+ case kConfigWinXP:
+ case kConfigWinVista:
+ case kConfigWin7:
+ case kConfigWin8:
+ case kConfigWin:
+ case kConfigMacLeopard:
+ case kConfigMacSnowLeopard:
+ case kConfigMacLion:
+ case kConfigMacMountainLion:
+ case kConfigMac:
+ case kConfigLinux:
+ case kConfigChromeOS:
+ case kConfigAndroid:
+ if ((config->os() & kTokenData[token].flag) != 0) {
+ PushErrorMessage(kErrorMessage[kErrorEntryWithOsConflicts],
+ line_number);
+ return false;
+ }
+ config->set_os(config->os() | kTokenData[token].flag);
+ break;
+ case kConfigNVidia:
+ case kConfigAMD:
+ case kConfigIntel:
+ case kConfigVMWare:
+ {
+ uint32 gpu_vendor =
+ static_cast<uint32>(kTokenData[token].flag);
+ for (size_t i = 0; i < config->gpu_vendor().size(); ++i) {
+ if (config->gpu_vendor()[i] == gpu_vendor) {
+ PushErrorMessage(
+ kErrorMessage[kErrorEntryWithGpuVendorConflicts],
+ line_number);
+ return false;
+ }
+ }
+ config->AddGPUVendor(gpu_vendor);
+ }
+ break;
+ case kConfigRelease:
+ case kConfigDebug:
+ if ((config->build_type() & kTokenData[token].flag) != 0) {
+ PushErrorMessage(
+ kErrorMessage[kErrorEntryWithBuildTypeConflicts],
+ line_number);
+ return false;
+ }
+ config->set_build_type(
+ config->build_type() | kTokenData[token].flag);
+ break;
+ default:
+ DCHECK(false);
+ break;
+ }
+ return true;
+}
+
+bool GPUTestExpectationsParser::UpdateTestConfig(
+ GPUTestConfig* config,
+ const std::string& gpu_device_id,
+ size_t line_number) {
+ DCHECK(config);
+ uint32 device_id = 0;
+ if (config->gpu_device_id() != 0 ||
+ !base::HexStringToInt(gpu_device_id,
+ reinterpret_cast<int*>(&device_id)) ||
+ device_id == 0) {
+ PushErrorMessage(kErrorMessage[kErrorEntryWithGpuDeviceIdConflicts],
+ line_number);
+ return false;
+ }
+ config->set_gpu_device_id(device_id);
+ return true;
+}
+
+bool GPUTestExpectationsParser::DetectConflictsBetweenEntries() {
+ bool rt = false;
+ for (size_t i = 0; i < entries_.size(); ++i) {
+ for (size_t j = i + 1; j < entries_.size(); ++j) {
+ if (entries_[i].test_name == entries_[j].test_name &&
+ entries_[i].test_config.OverlapsWith(entries_[j].test_config)) {
+ PushErrorMessage(kErrorMessage[kErrorEntriesOverlap],
+ entries_[i].line_number,
+ entries_[j].line_number);
+ rt = true;
+ }
+ }
+ }
+ return rt;
+}
+
+void GPUTestExpectationsParser::PushErrorMessage(
+ const std::string& message, size_t line_number) {
+ error_messages_.push_back(
+ base::StringPrintf("Line %d : %s",
+ static_cast<int>(line_number), message.c_str()));
+}
+
+void GPUTestExpectationsParser::PushErrorMessage(
+ const std::string& message,
+ size_t entry1_line_number,
+ size_t entry2_line_number) {
+ error_messages_.push_back(
+ base::StringPrintf("Line %d and %d : %s",
+ static_cast<int>(entry1_line_number),
+ static_cast<int>(entry2_line_number),
+ message.c_str()));
+}
+
+GPUTestExpectationsParser:: GPUTestExpectationEntry::GPUTestExpectationEntry()
+ : test_expectation(0),
+ line_number(0) {
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_test_expectations_parser.h b/chromium/gpu/config/gpu_test_expectations_parser.h
new file mode 100644
index 00000000000..a69f7e96e32
--- /dev/null
+++ b/chromium/gpu/config/gpu_test_expectations_parser.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_TEST_EXPECTATIONS_PARSER_H_
+#define GPU_CONFIG_GPU_TEST_EXPECTATIONS_PARSER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "gpu/config/gpu_test_config.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+class GPU_EXPORT GPUTestExpectationsParser {
+ public:
+ enum GPUTestExpectation {
+ kGpuTestPass = 1 << 0,
+ kGpuTestFail = 1 << 1,
+ kGpuTestFlaky = 1 << 2,
+ kGpuTestTimeout = 1 << 3,
+ kGpuTestSkip = 1 << 4,
+ };
+
+ GPUTestExpectationsParser();
+ ~GPUTestExpectationsParser();
+
+ // Parse the text expectations, and if no error is encountered,
+ // save all the entries. Otherwise, generate error messages.
+ // Return true if parsing succeeds.
+ bool LoadTestExpectations(const std::string& data);
+ bool LoadTestExpectations(const base::FilePath& path);
+
+ // Query error messages from the last LoadTestExpectations() call.
+ const std::vector<std::string>& GetErrorMessages() const;
+
+ // Get the test expectation of a given test on a given bot.
+ int32 GetTestExpectation(const std::string& test_name,
+ const GPUTestBotConfig& bot_config) const;
+
+ // Parse a list of config modifiers. If we have a valid entry with no
+ // conflicts, | config | stores it, and the function returns true.
+ bool ParseConfig(const std::string& config_data, GPUTestConfig* config);
+
+ private:
+ struct GPUTestExpectationEntry {
+ GPUTestExpectationEntry();
+
+ std::string test_name;
+ GPUTestConfig test_config;
+ int32 test_expectation;
+ size_t line_number;
+ };
+
+ // Parse a line of text. If we have a valid entry, save it; otherwise,
+ // generate error messages.
+ bool ParseLine(const std::string& line_data, size_t line_number);
+
+ // Update OS/GPUVendor/BuildType modifiers. May generate an error message.
+ bool UpdateTestConfig(
+ GPUTestConfig* config, int32 token, size_t line_number);
+
+ // Update GPUDeviceID modifier. May generate an error message.
+ bool UpdateTestConfig(GPUTestConfig* config,
+ const std::string & gpu_device_id,
+ size_t line_number);
+
+ // Check if two entries' config overlap with each other. May generate an
+ // error message.
+ bool DetectConflictsBetweenEntries();
+
+ // Save an error message, which can be queried later.
+ void PushErrorMessage(const std::string& message, size_t line_number);
+ void PushErrorMessage(const std::string& message,
+ size_t entry1_line_number,
+ size_t entry2_line_number);
+
+ std::vector<GPUTestExpectationEntry> entries_;
+ std::vector<std::string> error_messages_;
+};
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_TEST_EXPECTATIONS_PARSER_H_
+
diff --git a/chromium/gpu/config/gpu_test_expectations_parser_unittest.cc b/chromium/gpu/config/gpu_test_expectations_parser_unittest.cc
new file mode 100644
index 00000000000..79c169c1a85
--- /dev/null
+++ b/chromium/gpu/config/gpu_test_expectations_parser_unittest.cc
@@ -0,0 +1,245 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "gpu/config/gpu_test_expectations_parser.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+class GPUTestExpectationsParserTest : public testing::Test {
+ public:
+ GPUTestExpectationsParserTest() { }
+
+ virtual ~GPUTestExpectationsParserTest() { }
+
+ const GPUTestBotConfig& bot_config() const {
+ return bot_config_;
+ }
+
+ protected:
+ virtual void SetUp() {
+ bot_config_.set_os(GPUTestConfig::kOsWin7);
+ bot_config_.set_build_type(GPUTestConfig::kBuildTypeRelease);
+ bot_config_.AddGPUVendor(0x10de);
+ bot_config_.set_gpu_device_id(0x0640);
+ ASSERT_TRUE(bot_config_.IsValid());
+ }
+
+ virtual void TearDown() { }
+
+ private:
+ GPUTestBotConfig bot_config_;
+};
+
+TEST_F(GPUTestExpectationsParserTest, CommentOnly) {
+ const std::string text =
+ " \n"
+ "// This is just some comment\n"
+ "";
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestPass,
+ parser.GetTestExpectation("some_test", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, ValidFullEntry) {
+ const std::string text =
+ "BUG12345 WIN7 RELEASE NVIDIA 0x0640 : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestFail,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, ValidPartialEntry) {
+ const std::string text =
+ "BUG12345 WIN NVIDIA : MyTest = TIMEOUT";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestTimeout,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, ValidUnrelatedOsEntry) {
+ const std::string text =
+ "BUG12345 LEOPARD : MyTest = TIMEOUT";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestPass,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, ValidUnrelatedTestEntry) {
+ const std::string text =
+ "BUG12345 WIN7 RELEASE NVIDIA 0x0640 : AnotherTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestPass,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, AllModifiers) {
+ const std::string text =
+ "BUG12345 XP VISTA WIN7 WIN8 LEOPARD SNOWLEOPARD LION MOUNTAINLION "
+ "LINUX CHROMEOS ANDROID "
+ "NVIDIA INTEL AMD VMWARE RELEASE DEBUG : MyTest = "
+ "PASS FAIL FLAKY TIMEOUT SKIP";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestPass |
+ GPUTestExpectationsParser::kGpuTestFail |
+ GPUTestExpectationsParser::kGpuTestFlaky |
+ GPUTestExpectationsParser::kGpuTestTimeout |
+ GPUTestExpectationsParser::kGpuTestSkip,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, DuplicateModifiers) {
+ const std::string text =
+ "BUG12345 WIN7 WIN7 RELEASE NVIDIA 0x0640 : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, AllModifiersLowerCase) {
+ const std::string text =
+ "BUG12345 xp vista win7 leopard snowleopard lion linux chromeos android "
+ "nvidia intel amd vmware release debug : MyTest = "
+ "pass fail flaky timeout skip";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestPass |
+ GPUTestExpectationsParser::kGpuTestFail |
+ GPUTestExpectationsParser::kGpuTestFlaky |
+ GPUTestExpectationsParser::kGpuTestTimeout |
+ GPUTestExpectationsParser::kGpuTestSkip,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, MissingColon) {
+ const std::string text =
+ "BUG12345 XP MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, MissingEqual) {
+ const std::string text =
+ "BUG12345 XP : MyTest FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, IllegalModifier) {
+ const std::string text =
+ "BUG12345 XP XXX : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, OsConflicts) {
+ const std::string text =
+ "BUG12345 XP WIN : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, InvalidModifierCombination) {
+ const std::string text =
+ "BUG12345 XP NVIDIA INTEL 0x0640 : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, BadGpuDeviceID) {
+ const std::string text =
+ "BUG12345 XP NVIDIA 0xU07X : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, MoreThanOneGpuDeviceID) {
+ const std::string text =
+ "BUG12345 XP NVIDIA 0x0640 0x0641 : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, MultipleEntriesConflicts) {
+ const std::string text =
+ "BUG12345 WIN7 RELEASE NVIDIA 0x0640 : MyTest = FAIL\n"
+ "BUG12345 WIN : MyTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_FALSE(parser.LoadTestExpectations(text));
+ EXPECT_NE(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, MultipleTests) {
+ const std::string text =
+ "BUG12345 WIN7 RELEASE NVIDIA 0x0640 : MyTest = FAIL\n"
+ "BUG12345 WIN : AnotherTest = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+}
+
+TEST_F(GPUTestExpectationsParserTest, ValidMultipleEntries) {
+ const std::string text =
+ "BUG12345 WIN7 RELEASE NVIDIA 0x0640 : MyTest = FAIL\n"
+ "BUG12345 LINUX : MyTest = TIMEOUT";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestFail,
+ parser.GetTestExpectation("MyTest", bot_config()));
+}
+
+TEST_F(GPUTestExpectationsParserTest, StarMatching) {
+ const std::string text =
+ "BUG12345 WIN7 RELEASE NVIDIA 0x0640 : MyTest* = FAIL";
+
+ GPUTestExpectationsParser parser;
+ EXPECT_TRUE(parser.LoadTestExpectations(text));
+ EXPECT_EQ(0u, parser.GetErrorMessages().size());
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestFail,
+ parser.GetTestExpectation("MyTest0", bot_config()));
+ EXPECT_EQ(GPUTestExpectationsParser::kGpuTestPass,
+ parser.GetTestExpectation("OtherTest", bot_config()));
+}
+
+} // namespace gpu
+
diff --git a/chromium/gpu/config/gpu_util.cc b/chromium/gpu/config/gpu_util.cc
new file mode 100644
index 00000000000..7fae88a5216
--- /dev/null
+++ b/chromium/gpu/config/gpu_util.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_util.h"
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_control_list_jsons.h"
+#include "gpu/config/gpu_driver_bug_list.h"
+#include "gpu/config/gpu_info_collector.h"
+#include "ui/gl/gl_switches.h"
+
+namespace gpu {
+
+namespace {
+
+// Combine the integers into a string, seperated by ','.
+std::string IntSetToString(const std::set<int>& list) {
+ std::string rt;
+ for (std::set<int>::const_iterator it = list.begin();
+ it != list.end(); ++it) {
+ if (!rt.empty())
+ rt += ",";
+ rt += base::IntToString(*it);
+ }
+ return rt;
+}
+
+} // namespace anonymous
+
+GpuSwitchingOption StringToGpuSwitchingOption(
+ const std::string& switching_string) {
+ if (switching_string == switches::kGpuSwitchingOptionNameAutomatic)
+ return GPU_SWITCHING_OPTION_AUTOMATIC;
+ if (switching_string == switches::kGpuSwitchingOptionNameForceIntegrated)
+ return GPU_SWITCHING_OPTION_FORCE_INTEGRATED;
+ if (switching_string == switches::kGpuSwitchingOptionNameForceDiscrete)
+ return GPU_SWITCHING_OPTION_FORCE_DISCRETE;
+ return GPU_SWITCHING_OPTION_UNKNOWN;
+}
+
+std::string GpuSwitchingOptionToString(GpuSwitchingOption option) {
+ switch (option) {
+ case GPU_SWITCHING_OPTION_AUTOMATIC:
+ return switches::kGpuSwitchingOptionNameAutomatic;
+ case GPU_SWITCHING_OPTION_FORCE_INTEGRATED:
+ return switches::kGpuSwitchingOptionNameForceIntegrated;
+ case GPU_SWITCHING_OPTION_FORCE_DISCRETE:
+ return switches::kGpuSwitchingOptionNameForceDiscrete;
+ default:
+ return "unknown";
+ }
+}
+
+void MergeFeatureSets(std::set<int>* dst, const std::set<int>& src) {
+ DCHECK(dst);
+ if (src.empty())
+ return;
+ dst->insert(src.begin(), src.end());
+}
+
+void ApplyGpuDriverBugWorkarounds(CommandLine* command_line) {
+ GPUInfo gpu_info;
+ CollectBasicGraphicsInfo(&gpu_info);
+
+ GpuDriverBugList* list = GpuDriverBugList::Create();
+ list->LoadList("0", kGpuDriverBugListJson,
+ GpuControlList::kCurrentOsOnly);
+ std::set<int> workarounds = list->MakeDecision(
+ GpuControlList::kOsAny, std::string(), gpu_info);
+ if (!workarounds.empty()) {
+ command_line->AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
+ IntSetToString(workarounds));
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/gpu_util.h b/chromium/gpu/config/gpu_util.h
new file mode 100644
index 00000000000..6d6800e3923
--- /dev/null
+++ b/chromium/gpu/config/gpu_util.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_CONFIG_GPU_UTIL_H_
+#define GPU_CONFIG_GPU_UTIL_H_
+
+#include <set>
+#include <string>
+
+#include "build/build_config.h"
+#include "gpu/config/gpu_switching_option.h"
+#include "gpu/gpu_export.h"
+
+class CommandLine;
+
+namespace gpu {
+
+// Maps string to GpuSwitchingOption; returns GPU_SWITCHING_UNKNOWN if an
+// unknown name is input (case-sensitive).
+GPU_EXPORT GpuSwitchingOption StringToGpuSwitchingOption(
+ const std::string& switching_string);
+
+// Gets a string version of a GpuSwitchingOption.
+GPU_EXPORT std::string GpuSwitchingOptionToString(GpuSwitchingOption option);
+
+// Merge features in src into dst.
+GPU_EXPORT void MergeFeatureSets(
+ std::set<int>* dst, const std::set<int>& src);
+
+// Collect basic GPUInfo, compute the driver bug workarounds for the current
+// system, and append the |command_line|.
+GPU_EXPORT void ApplyGpuDriverBugWorkarounds(CommandLine* command_line);
+
+} // namespace gpu
+
+#endif // GPU_CONFIG_GPU_UTIL_H_
+
diff --git a/chromium/gpu/config/gpu_util_unittest.cc b/chromium/gpu/config/gpu_util_unittest.cc
new file mode 100644
index 00000000000..f3e3f8f73a0
--- /dev/null
+++ b/chromium/gpu/config/gpu_util_unittest.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/config/gpu_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_switches.h"
+
+namespace gpu {
+
+TEST(GpuUtilTest, GpuSwitchingOptionFromString) {
+ // Test StringToGpuSwitchingOption.
+ EXPECT_EQ(StringToGpuSwitchingOption(
+ switches::kGpuSwitchingOptionNameAutomatic),
+ GPU_SWITCHING_OPTION_AUTOMATIC);
+ EXPECT_EQ(StringToGpuSwitchingOption(
+ switches::kGpuSwitchingOptionNameForceDiscrete),
+ GPU_SWITCHING_OPTION_FORCE_DISCRETE);
+ EXPECT_EQ(StringToGpuSwitchingOption(
+ switches::kGpuSwitchingOptionNameForceIntegrated),
+ GPU_SWITCHING_OPTION_FORCE_INTEGRATED);
+ EXPECT_EQ(StringToGpuSwitchingOption("xxx"), GPU_SWITCHING_OPTION_UNKNOWN);
+}
+
+TEST(GpuUtilTest, GpuSwitchingOptionToString) {
+ // Test GpuSwitchingOptionToString.
+ EXPECT_STREQ(
+ GpuSwitchingOptionToString(GPU_SWITCHING_OPTION_AUTOMATIC).c_str(),
+ switches::kGpuSwitchingOptionNameAutomatic);
+ EXPECT_STREQ(
+ GpuSwitchingOptionToString(GPU_SWITCHING_OPTION_FORCE_DISCRETE).c_str(),
+ switches::kGpuSwitchingOptionNameForceDiscrete);
+ EXPECT_STREQ(
+ GpuSwitchingOptionToString(GPU_SWITCHING_OPTION_FORCE_INTEGRATED).c_str(),
+ switches::kGpuSwitchingOptionNameForceIntegrated);
+}
+
+TEST(GpuUtilTest, MergeFeatureSets) {
+ {
+ // Merge two empty sets.
+ std::set<int> src;
+ std::set<int> dst;
+ EXPECT_TRUE(dst.empty());
+ MergeFeatureSets(&dst, src);
+ EXPECT_TRUE(dst.empty());
+ }
+ {
+ // Merge an empty set into a set with elements.
+ std::set<int> src;
+ std::set<int> dst;
+ dst.insert(1);
+ EXPECT_EQ(1u, dst.size());
+ MergeFeatureSets(&dst, src);
+ EXPECT_EQ(1u, dst.size());
+ }
+ {
+ // Merge two sets where the source elements are already in the target set.
+ std::set<int> src;
+ std::set<int> dst;
+ src.insert(1);
+ dst.insert(1);
+ EXPECT_EQ(1u, dst.size());
+ MergeFeatureSets(&dst, src);
+ EXPECT_EQ(1u, dst.size());
+ }
+ {
+ // Merge two sets with different elements.
+ std::set<int> src;
+ std::set<int> dst;
+ src.insert(1);
+ dst.insert(2);
+ EXPECT_EQ(1u, dst.size());
+ MergeFeatureSets(&dst, src);
+ EXPECT_EQ(2u, dst.size());
+ }
+}
+
+} // namespace gpu
diff --git a/chromium/gpu/config/software_rendering_list_json.cc b/chromium/gpu/config/software_rendering_list_json.cc
new file mode 100644
index 00000000000..b7c5c539801
--- /dev/null
+++ b/chromium/gpu/config/software_rendering_list_json.cc
@@ -0,0 +1,1170 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Determines whether certain gpu-related features are blacklisted or not.
+// A valid software_rendering_list.json file are in the format of
+// {
+// "version": "x.y",
+// "entries": [
+// { // entry 1
+// },
+// ...
+// { // entry n
+// }
+// ]
+// }
+//
+// Each entry contains the following fields (fields are optional unless
+// specifically described as mandatory below):
+// 1. "id" is an integer. 0 is reserved. This field is mandatory.
+// 2. "os" contains "type" and an optional "version". "type" could be "macosx",
+// "linux", "win", "chromeos", or "any". "any" is the same as not specifying
+// "os".
+// "version" is a VERSION structure (defined below).
+// 3. "vendor_id" is a string. 0 is reserved.
+// 4. "device_id" is an array of strings. 0 is reserved.
+// 5. "multi_gpu_style" is a string, valid values include "optimus", and
+// "amd_switchable".
+// 6. "multi_gpu_category" is a string, valid values include "any", "primary",
+// and "secondary". If unspecified, the default value is "primary".
+// 7. "driver_vendor" is a STRING structure (defined below).
+// 8. "driver_version" is a VERSION structure (defined below).
+// 9. "driver_date" is a VERSION structure (defined below).
+// The version is interpreted as "year.month.day".
+// 10. "gl_vendor" is a STRING structure (defined below).
+// 11. "gl_renderer" is a STRING structure (defined below).
+// 12. "gl_extensions" is a STRING structure (defined below).
+// 13. "gl_reset_notification_strategy" is an INT structure (defined below).
+// 14. "perf_graphics" is a FLOAT structure (defined below).
+// 15. "perf_gaming" is a FLOAT structure (defined below).
+// 16. "perf_overall" is a FLOAT structure (defined below).
+// 17. "machine_model" contais "name" and an optional "version". "name" is a
+// STRING structure and "version" is a VERSION structure (defined below).
+// 18. "gpu_count" is a INT structure (defined below).
+// 19 "cpu_info" is a STRING structure (defined below).
+// 20. "exceptions" is a list of entries.
+// 21. "features" is a list of gpu feature strings, valid values include
+// "accelerated_2d_canvas", "accelerated_compositing", "webgl",
+// "multisampling", "flash_3d", "flash_stage3d", "texture_sharing",
+// "accelerated_video", "accelerated_video_decode", "panel_fitting",
+// "force_compositing_mode", and "all".
+// This field is mandatory.
+// 22. "description" has the description of the entry.
+// 23. "webkit_bugs" is an array of associated webkit bug numbers.
+// 24. "cr_bugs" is an array of associated webkit bug numbers.
+// 25. "browser_version" is a VERSION structure (defined below). If this
+// condition is not satisfied, the entry will be ignored. If it is not
+// present, then the entry applies to all versions of the browser.
+// 26. "disabled" is a boolean. If it is present, the entry will be skipped.
+// This can not be used in exceptions.
+//
+// VERSION includes "op", "style", "number", and "number2". "op" can be any of
+// the following values: "=", "<", "<=", ">", ">=", "any", "between". "style"
+// is optional and can be "lexical" or "numerical"; if it's not specified, it
+// defaults to "numerical". "number2" is only used if "op" is "between".
+// "between" is "number <= * <= number2".
+// "number" is used for all "op" values except "any". "number" and "number2"
+// are in the format of x, x.x, x.x.x, etc.
+// Only "driver_version" supports lexical style if the format is major.minor;
+// in that case, major is still numerical, but minor is lexical.
+//
+// STRING includes "op" and "value". "op" can be any of the following values:
+// "contains", "beginwith", "endwith", "=". "value" is a string.
+//
+// FLOAT includes "op" "value", and "value2". "op" can be any of the
+// following values: "=", "<", "<=", ">", ">=", "any", "between". "value2" is
+// only used if "op" is "between". "value" is used for all "op" values except
+// "any". "value" and "value2" are valid float numbers.
+// INT is very much like FLOAT, except that the values need to be integers.
+
+#include "gpu/config/gpu_control_list_jsons.h"
+
+#define LONG_STRING_CONST(...) #__VA_ARGS__
+
+namespace gpu {
+
+const char kSoftwareRenderingListJson[] = LONG_STRING_CONST(
+
+{
+ "name": "software rendering list",
+ // Please update the version number whenever you change this file.
+ "version": "6.5",
+ "entries": [
+ {
+ "id": 1,
+ "description": "ATI Radeon X1900 is not compatible with WebGL on the Mac.",
+ "webkit_bugs": [47028],
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x1002",
+ "device_id": ["0x7249"],
+ "features": [
+ "webgl",
+ "flash_3d",
+ "flash_stage3d"
+ ]
+ },
+ {
+ "id": 3,
+ "description": "GL driver is software rendered. Accelerated compositing is disabled.",
+ "cr_bugs": [59302],
+ "os": {
+ "type": "linux"
+ },
+ "gl_renderer": {
+ "op": "contains",
+ "value": "software"
+ },
+ "features": [
+ "accelerated_compositing"
+ ]
+ },
+ {
+ "id": 4,
+ "description": "The Intel Mobile 945 Express family of chipsets is not compatible with WebGL.",
+ "cr_bugs": [232035],
+ "os": {
+ "type": "any"
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0x27AE", "0x27A2"],
+ "features": [
+ "webgl",
+ "flash_3d",
+ "flash_stage3d",
+ "accelerated_2d_canvas"
+ ]
+ },
+ {
+ "id": 5,
+ "description": "ATI/AMD cards with older or third-party drivers in Linux are crash-prone.",
+ "cr_bugs": [71381, 76428, 73910, 101225, 136240],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x1002",
+ "exceptions": [
+ {
+ "driver_vendor": {
+ "op": "contains",
+ "value": "AMD"
+ },
+ "driver_version": {
+ "op": ">=",
+ "style": "lexical",
+ "number": "8.98"
+ }
+ }
+ ],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 8,
+ "description": "NVIDIA GeForce FX Go5200 is assumed to be buggy.",
+ "cr_bugs": [72938],
+ "os": {
+ "type": "any"
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0324"],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 10,
+ "description": "NVIDIA GeForce 7300 GT on Mac does not support WebGL.",
+ "cr_bugs": [73794],
+ "os": {
+ "type": "macosx"
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0393"],
+ "features": [
+ "webgl",
+ "flash_3d",
+ "flash_stage3d"
+ ]
+ },
+ {
+ "id": 12,
+ "description": "Drivers older than 2009-01 on Windows are possibly unreliable.",
+ "cr_bugs": [72979, 89802],
+ "os": {
+ "type": "win"
+ },
+ "driver_date": {
+ "op": "<",
+ "number": "2009.1"
+ },
+ "exceptions": [
+ {
+ "vendor_id": "0x8086",
+ "device_id": ["0x29a2"],
+ "driver_version": {
+ "op": ">=",
+ "number": "7.15.10.1624"
+ }
+ }
+ ],
+ "features": [
+ "accelerated_2d_canvas",
+ "accelerated_video",
+ "accelerated_video_decode",
+ "3d_css",
+ "multisampling",
+ "flash_3d",
+ "force_compositing_mode"
+ ]
+ },
+ {
+ "id": 13,
+ "description": "ATI drivers older than 10.6 on Windows XP are possibly unreliable.",
+ "cr_bugs": [74212],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "vendor_id": "0x1002",
+ "driver_version": {
+ "op": "<",
+ "number": "8.741"
+ },
+ "features": [
+ "accelerated_video",
+ "accelerated_video_decode",
+ "3d_css",
+ "multisampling",
+ "flash_3d",
+ "force_compositing_mode"
+ ]
+ },
+ {
+ "id": 14,
+ "description": "NVIDIA drivers older than 257.21 on Windows XP are possibly unreliable.",
+ "cr_bugs": [74212],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "vendor_id": "0x10de",
+ "driver_version": {
+ "op": "<",
+ "number": "6.14.12.5721"
+ },
+ "features": [
+ "accelerated_video",
+ "accelerated_video_decode",
+ "3d_css",
+ "multisampling",
+ "flash_3d",
+ "force_compositing_mode"
+ ]
+ },
+ {
+ "id": 15,
+ "description": "Intel drivers older than 14.42.7.5294 on Windows XP are possibly unreliable.",
+ "cr_bugs": [74212],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "vendor_id": "0x8086",
+ "driver_version": {
+ "op": "<",
+ "number": "6.14.10.5294"
+ },
+ "features": [
+ "accelerated_video",
+ "accelerated_video_decode",
+ "3d_css",
+ "multisampling",
+ "flash_3d",
+ "force_compositing_mode"
+ ]
+ },
+ {
+ "id": 16,
+ "description": "Multisampling is buggy in ATI cards on older MacOSX.",
+ "cr_bugs": [67752, 83153],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.7.2"
+ }
+ },
+ "vendor_id": "0x1002",
+ "features": [
+ "multisampling"
+ ]
+ },
+ {
+ "id": 17,
+ "description": "Intel mesa drivers are crash-prone.",
+ "cr_bugs": [76703, 164555, 225200],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "exceptions": [
+ {
+ "device_id": ["0x0102", "0x0106", "0x0112", "0x0116", "0x0122", "0x0126", "0x010a", "0x0152", "0x0156", "0x015a", "0x0162", "0x0166"],
+ "driver_version": {
+ "op": ">=",
+ "number": "8.0"
+ }
+ },
+ {
+ "device_id": ["0xa001", "0xa002", "0xa011", "0xa012", "0x29a2", "0x2992", "0x2982", "0x2972", "0x2a12", "0x2a42", "0x2e02", "0x2e12", "0x2e22", "0x2e32", "0x2e42", "0x2e92"],
+ "driver_version": {
+ "op": ">",
+ "number": "8.0.2"
+ }
+ },
+ {
+ "device_id": ["0x0042", "0x0046"],
+ "driver_version": {
+ "op": ">",
+ "number": "8.0.4"
+ }
+ },
+ {
+ "device_id": ["0x2a02"],
+ "driver_version": {
+ "op": ">=",
+ "number": "9.1"
+ }
+ }
+ ],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 18,
+ "description": "NVIDIA Quadro FX 1500 is buggy.",
+ "cr_bugs": [84701],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x029e"],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 19,
+ "description": "GPU acceleration is no longer supported in Leopard.",
+ "cr_bugs": [87157, 130495],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "=",
+ "number": "10.5"
+ }
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 23,
+ "description": "Mesa drivers in linux older than 7.11 are assumed to be buggy.",
+ "os": {
+ "type": "linux"
+ },
+ "driver_vendor": {
+ "op": "=",
+ "value": "Mesa"
+ },
+ "driver_version": {
+ "op": "<",
+ "number": "7.11"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 24,
+ "description": "Accelerated 2d canvas is unstable in Linux at the moment.",
+ "os": {
+ "type": "linux"
+ },
+ "features": [
+ "accelerated_2d_canvas"
+ ]
+ },
+ {
+ "id": 27,
+ "description": "ATI/AMD cards with older drivers in Linux are crash-prone.",
+ "cr_bugs": [95934, 94973, 136240],
+ "os": {
+ "type": "linux"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "ATI"
+ },
+ "exceptions": [
+ {
+ "driver_vendor": {
+ "op": "contains",
+ "value": "AMD"
+ },
+ "driver_version": {
+ "op": ">=",
+ "style": "lexical",
+ "number": "8.98"
+ }
+ }
+ ],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 28,
+ "description": "ATI/AMD cards with third-party drivers in Linux are crash-prone.",
+ "cr_bugs": [95934, 94973],
+ "os": {
+ "type": "linux"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "X.Org"
+ },
+ "gl_renderer": {
+ "op": "contains",
+ "value": "AMD"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 29,
+ "description": "ATI/AMD cards with third-party drivers in Linux are crash-prone.",
+ "cr_bugs": [95934, 94973],
+ "os": {
+ "type": "linux"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "X.Org"
+ },
+ "gl_renderer": {
+ "op": "contains",
+ "value": "ATI"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 30,
+ "description": "NVIDIA cards with nouveau drivers in Linux are crash-prone.",
+ "cr_bugs": [94103],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x10de",
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "nouveau"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 32,
+ "description": "Accelerated 2d canvas is disabled on Windows systems with low perf stats.",
+ "cr_bugs": [116350, 151500],
+ "os": {
+ "type": "win"
+ },
+ "perf_overall": {
+ "op": "<",
+ "value": "3.5"
+ },
+ "exceptions": [
+ {
+ "perf_gaming": {
+ "op": ">",
+ "value": "3.5"
+ }
+ },
+ {
+ "cpu_info": {
+ "op": "contains",
+ "value": "Atom"
+ }
+ }
+ ],
+ "features": [
+ "accelerated_2d_canvas"
+ ]
+ },
+ {
+ "id": 33,
+ "description": "Multisampling is buggy in Intel IvyBridge.",
+ "cr_bugs": [116370],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0x0152", "0x0156", "0x015a", "0x0162", "0x0166"],
+ "features": [
+ "multisampling"
+ ]
+ },
+ {
+ "id": 34,
+ "description": "S3 Trio (used in Virtual PC) is not compatible.",
+ "cr_bugs": [119948],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x5333",
+ "device_id": ["0x8811"],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 35,
+ "description": "Stage3D is not supported on Linux.",
+ "cr_bugs": [129848],
+ "os": {
+ "type": "linux"
+ },
+ "features": [
+ "flash_stage3d"
+ ]
+ },
+ {
+ "id": 37,
+ "description": "Drivers are unreliable for Optimus on Linux.",
+ "cr_bugs": [131308],
+ "os": {
+ "type": "linux"
+ },
+ "multi_gpu_style": "optimus",
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 38,
+ "description": "Accelerated 2D canvas is unstable for NVidia GeForce 9400M on Lion.",
+ "cr_bugs": [130495],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "=",
+ "number": "10.7"
+ }
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0863"],
+ "features": [
+ "accelerated_2d_canvas"
+ ]
+ },
+ {
+ "id": 41,
+ "description": "Disable 3D (but not Stage3D) in Flash on XP",
+ "cr_bugs": [134885],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "features": [
+ "flash_3d"
+ ]
+ },
+ {
+ "id": 42,
+ "description": "AMD Radeon HD 6490M on Snow Leopard is buggy.",
+ "cr_bugs": [137307],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "=",
+ "number": "10.6"
+ }
+ },
+ "vendor_id": "0x1002",
+ "device_id": ["0x6760"],
+ "features": [
+ "webgl"
+ ]
+ },
+ {
+ "id": 43,
+ "description": "Intel driver version 8.15.10.1749 has problems sharing textures.",
+ "cr_bugs": [133924],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x8086",
+ "driver_version": {
+ "op": "=",
+ "number": "8.15.10.1749"
+ },
+ "features": [
+ "texture_sharing"
+ ]
+ },
+ {
+ "id": 44,
+ "description": "Intel HD 4000 causes kernel panic on Lion.",
+ "cr_bugs": [134015],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "between",
+ "number": "10.7.0",
+ "number2": "10.7.4"
+ }
+ },
+ "vendor_id": "0x8086",
+ "device_id": ["0x0166"],
+ "multi_gpu_category": "any",
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 45,
+ "description": "Parallels drivers older than 7 are buggy.",
+ "cr_bugs": [138105],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x1ab8",
+ "driver_version": {
+ "op": "<",
+ "number": "7"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 46,
+ "description": "ATI FireMV 2400 cards on Windows are buggy.",
+ "cr_bugs": [124152],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x1002",
+ "device_id": ["0x3151"],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 47,
+ "description": "NVIDIA linux drivers older than 295.* are assumed to be buggy.",
+ "cr_bugs": [78497],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x10de",
+ "driver_vendor": {
+ "op": "=",
+ "value": "NVIDIA"
+ },
+ "driver_version": {
+ "op": "<",
+ "number": "295"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 48,
+ // Please keep in sync with content/test/content_browser_test.cc.
+ "description": "Accelerated video decode is unavailable on Mac and Linux.",
+ "cr_bugs": [137247, 133828],
+ "exceptions": [
+ {
+ "os": {
+ "type": "chromeos"
+ }
+ },
+ {
+ "os": {
+ "type": "win"
+ }
+ }
+ ],
+ "features": [
+ "accelerated_video_decode"
+ ]
+ },
+ {
+ "id": 49,
+ "description": "NVidia GeForce GT 650M can cause the system to hang with flash 3D.",
+ "cr_bugs": [140175],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "between",
+ "number": "10.8.0",
+ "number2": "10.8.1"
+ }
+ },
+ "multi_gpu_style": "optimus",
+ "vendor_id": "0x10de",
+ "device_id": ["0x0fd5"],
+ "features": [
+ "flash_3d",
+ "flash_stage3d"
+ ]
+ },
+ {
+ "id": 50,
+ "description": "Disable VMware software renderer.",
+ "cr_bugs": [145531],
+ "os": {
+ "type": "linux"
+ },
+ "gl_vendor": {
+ "op": "beginwith",
+ "value": "VMware"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 51,
+ "description": "NVIDIA drivers 6.14.11.9621 is buggy on Windows XP.",
+ "cr_bugs": [152096],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "vendor_id": "0x10de",
+ "driver_version": {
+ "op": "=",
+ "number": "6.14.11.9621"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 52,
+ "description": "NVIDIA drivers 6.14.11.8267 is buggy on Windows XP.",
+ "cr_bugs": [152096],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "vendor_id": "0x10de",
+ "driver_version": {
+ "op": "=",
+ "number": "6.14.11.8267"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 53,
+ "description": "The Intel GMA500 is too slow for Stage3D.",
+ "cr_bugs": [152096],
+ "vendor_id": "0x8086",
+ "device_id": ["0x8108", "0x8109"],
+ "features": [
+ "flash_stage3d"
+ ]
+ },
+ {
+ "id": 55,
+ "description": "Drivers older than 2007-01 on Windows are assumed to be buggy.",
+ "cr_bugs": [72979, 89802],
+ "os": {
+ "type": "win"
+ },
+ "driver_date": {
+ "op": "<",
+ "number": "2007.1"
+ },
+ "exceptions": [
+ {
+ "vendor_id": "0x8086",
+ "device_id": ["0x29a2"],
+ "driver_version": {
+ "op": ">=",
+ "number": "7.15.10.1624"
+ }
+ }
+ ],
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 56,
+ "description": "NVIDIA linux drivers are unstable when using multiple Open GL contexts and with low memory.",
+ "cr_bugs": [145600],
+ "os": {
+ "type": "linux"
+ },
+ "vendor_id": "0x10de",
+ "driver_vendor": {
+ "op": "=",
+ "value": "NVIDIA"
+ },
+ "features": [
+ "accelerated_video",
+ "accelerated_video_decode",
+ "flash_3d",
+ "flash_stage3d"
+ ]
+ },
+ {
+ // Panel fitting is only used with OS_CHROMEOS. To avoid displaying an
+ // error in chrome:gpu on every other platform, this blacklist entry needs
+ // to only match on chromeos. The drawback is that panel_fitting will not
+ // appear to be blacklisted if accidentally queried on non-chromeos.
+ "id": 57,
+ "description": "Chrome OS panel fitting is only supported for Intel IVB and SNB Graphics Controllers.",
+ "os": {
+ "type": "chromeos"
+ },
+ "exceptions": [
+ {
+ "vendor_id": "0x8086",
+ "device_id": ["0x0106", "0x0116", "0x0166"]
+ }
+ ],
+ "features": [
+ "panel_fitting"
+ ]
+ },
+ {
+ "id": 59,
+ "description": "NVidia driver 8.15.11.8593 is crashy on Windows.",
+ "cr_bugs": [155749],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x10de",
+ "driver_version": {
+ "op": "=",
+ "number": "8.15.11.8593"
+ },
+ "features": [
+ "accelerated_video_decode"
+ ]
+ },
+ {
+ "id": 60,
+ "description": "Multisampling is buggy on Mac with NVIDIA gpu prior to 10.8.3.",
+ "cr_bugs": [137303],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.8.3"
+ }
+ },
+ "vendor_id": "0x10de",
+ "features": [
+ "multisampling"
+ ]
+ },
+ {
+ "id": 61,
+ "description": "Multisampling is buggy on Mac with Intel gpu prior to 10.8.3.",
+ "cr_bugs": [137303],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.8.3"
+ }
+ },
+ "vendor_id": "0x8086",
+ "features": [
+ "multisampling"
+ ]
+ },
+ {
+ "id": 62,
+ "description": "Accelerated 2D canvas buggy on old Qualcomm Adreno.",
+ "cr_bugs": [161575],
+ "os": {
+ "type": "android"
+ },
+ "gl_renderer": {
+ "op": "contains",
+ "value": "Adreno"
+ },
+ "driver_version": {
+ "op": "<",
+ "number": "4.1"
+ },
+ "features": [
+ "accelerated_2d_canvas"
+ ]
+ },
+ {
+ "id": 63,
+ "description": "Multisampling is buggy on Mac with AMD gpu prior to 10.8.3.",
+ "cr_bugs": [162466],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.8.3"
+ }
+ },
+ "vendor_id": "0x1002",
+ "features": [
+ "multisampling"
+ ]
+ },
+ {
+ "id": 64,
+ "description": "Hardware video decode is only supported in win7+.",
+ "cr_bugs": [159458],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "<",
+ "number": "6.1"
+ }
+ },
+ "features": [
+ "accelerated_video_decode"
+ ]
+ },
+ {
+ "id": 65,
+ "description": "Force compositing mode is unstable in Win Vista.",
+ "cr_bugs": [170421],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "6.0"
+ }
+ },
+ "features": [
+ "force_compositing_mode"
+ ]
+ },
+ {
+ "id": 66,
+ "description": "Force compositing mode is unstable in MacOSX earlier than 10.8.",
+ "cr_bugs": [174101],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.8"
+ }
+ },
+ "features": [
+ "force_compositing_mode"
+ ]
+ },
+ {
+ "id": 67,
+ "description": "Accelerated 2D Canvas is not supported on WinXP.",
+ "cr_bugs": [175149],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": "=",
+ "number": "5"
+ }
+ },
+ "features": [
+ "accelerated_2d_canvas"
+ ]
+ },
+ {
+ "id": 68,
+ "description": "VMware Fusion 4 has corrupt rendering with Win Vista+.",
+ "cr_bugs": [169470],
+ "os": {
+ "type": "win",
+ "version": {
+ "op": ">=",
+ "number": "6.0"
+ }
+ },
+ "vendor_id": "0x15ad",
+ "driver_version": {
+ "op": "<=",
+ "number": "7.14.1.1134"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 69,
+ "description": "NVIDIA driver 8.17.11.9621 is buggy with Stage3D baseline mode.",
+ "cr_bugs": [172771],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x10de",
+ "driver_version": {
+ "op": "=",
+ "number": "8.17.11.9621"
+ },
+ "features": [
+ "flash_stage3d_baseline"
+ ]
+ },
+ {
+ "id": 70,
+ "description": "NVIDIA driver 8.17.11.8267 is buggy with Stage3D baseline mode.",
+ "cr_bugs": [172771],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x10de",
+ "driver_version": {
+ "op": "=",
+ "number": "8.17.11.8267"
+ },
+ "features": [
+ "flash_stage3d_baseline"
+ ]
+ },
+ {
+ "id": 71,
+ "description": "All Intel drivers before 8.15.10.2021 are buggy with Stage3D baseline mode.",
+ "cr_bugs": [172771],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x8086",
+ "driver_version": {
+ "op": "<",
+ "number": "8.15.10.2021"
+ },
+ "features": [
+ "flash_stage3d_baseline"
+ ]
+ },
+ {
+ "id": 72,
+ "description": "NVIDIA GeForce 6200 LE is buggy with WebGL.",
+ "cr_bugs": [232529],
+ "os": {
+ "type": "win"
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0163"],
+ "features": [
+ "webgl"
+ ]
+ },
+ {
+ "id": 73,
+ "description": "WebGL is buggy with the NVIDIA GeForce GT 330M, 9400, and 9400M on MacOSX earlier than 10.8",
+ "cr_bugs": [233523],
+ "os": {
+ "type": "macosx",
+ "version": {
+ "op": "<",
+ "number": "10.8"
+ }
+ },
+ "vendor_id": "0x10de",
+ "device_id": ["0x0a29", "0x0861", "0x0863"],
+ "features": [
+ "webgl"
+ ]
+ },
+ {
+ "id": 74,
+ "description": "GPU access is blocked if users don't have proper graphics driver installed after Windows installation",
+ "cr_bugs": [248178],
+ "os": {
+ "type": "win"
+ },
+ "driver_vendor": {
+ "op": "=",
+ "value": "Microsoft"
+ },
+ "features": [
+ "all"
+ ]
+ },
+ {
+ "id": 75,
+ "description": "Texture sharing not supported on AMD Switchable GPUs due to driver issues",
+ "cr_bugs": [117371],
+ "os": {
+ "type": "win"
+ },
+ "multi_gpu_style": "amd_switchable",
+ "features": [
+ "texture_sharing"
+ ]
+ },
+) // String split to avoid MSVC char limit.
+LONG_STRING_CONST(
+ {
+ "id": 76,
+ "description": "WebGL is disabled on Android unless GPU reset notification is supported",
+ "os": {
+ "type": "android"
+ },
+ "exceptions": [
+ {
+ "gl_reset_notification_strategy": {
+ "op": "=",
+ "value": "33362"
+ }
+ }
+ ],
+ "features": [
+ "webgl"
+ ]
+ }
+ ]
+}
+
+); // LONG_STRING_CONST macro
+
+} // namespace gpu
+
diff --git a/chromium/gpu/gles2_cmd_helper.gypi b/chromium/gpu/gles2_cmd_helper.gypi
new file mode 100644
index 00000000000..523a7614bbb
--- /dev/null
+++ b/chromium/gpu/gles2_cmd_helper.gypi
@@ -0,0 +1,12 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ # Library helps make GLES2 command buffers.
+ 'sources': [
+ 'command_buffer/client/gles2_cmd_helper.cc',
+ 'command_buffer/client/gles2_cmd_helper.h',
+ 'command_buffer/client/gles2_cmd_helper_autogen.h',
+ ],
+}
diff --git a/chromium/gpu/gles2_conform_support/DEPS b/chromium/gpu/gles2_conform_support/DEPS
new file mode 100644
index 00000000000..45eed75282e
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/DEPS
@@ -0,0 +1,3 @@
+include_rules = [
+ "+third_party/gles2_conform",
+]
diff --git a/chromium/gpu/gles2_conform_support/egl/config.cc b/chromium/gpu/gles2_conform_support/egl/config.cc
new file mode 100644
index 00000000000..6c914be905a
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/config.cc
@@ -0,0 +1,152 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/gles2_conform_support/egl/config.h"
+
+namespace egl {
+
+Config::Config()
+ : buffer_size_(0),
+ red_size_(0),
+ green_size_(0),
+ blue_size_(0),
+ luminance_size_(0),
+ alpha_size_(0),
+ alpha_mask_size_(0),
+ bind_to_texture_rgb_(EGL_DONT_CARE),
+ bind_to_texture_rgba_(EGL_DONT_CARE),
+ color_buffer_type_(EGL_RGB_BUFFER),
+ config_caveat_(EGL_DONT_CARE),
+ config_id_(EGL_DONT_CARE),
+ conformant_(EGL_OPENGL_ES2_BIT),
+ depth_size_(0),
+ level_(0),
+ max_pbuffer_width_(0),
+ max_pbuffer_height_(0),
+ max_pbuffer_pixels_(0),
+ min_swap_interval_(EGL_DONT_CARE),
+ max_swap_interval_(EGL_DONT_CARE),
+ native_renderable_(EGL_DONT_CARE),
+ native_visual_id_(0),
+ native_visual_type_(EGL_DONT_CARE),
+ renderable_type_(EGL_OPENGL_ES2_BIT),
+ sample_buffers_(0),
+ samples_(0),
+ stencil_size_(0),
+ surface_type_(EGL_WINDOW_BIT),
+ transparent_type_(EGL_NONE),
+ transparent_red_value_(EGL_DONT_CARE),
+ transparent_green_value_(EGL_DONT_CARE),
+ transparent_blue_value_(EGL_DONT_CARE) {
+}
+
+Config::~Config() {
+}
+
+bool Config::GetAttrib(EGLint attribute, EGLint* value) const {
+ // TODO(alokp): Find out how to get correct values.
+ switch (attribute) {
+ case EGL_BUFFER_SIZE:
+ *value = buffer_size_;
+ break;
+ case EGL_RED_SIZE:
+ *value = red_size_;
+ break;
+ case EGL_GREEN_SIZE:
+ *value = green_size_;
+ break;
+ case EGL_BLUE_SIZE:
+ *value = blue_size_;
+ break;
+ case EGL_LUMINANCE_SIZE:
+ *value = luminance_size_;
+ break;
+ case EGL_ALPHA_SIZE:
+ *value = alpha_size_;
+ break;
+ case EGL_ALPHA_MASK_SIZE:
+ *value = alpha_mask_size_;
+ break;
+ case EGL_BIND_TO_TEXTURE_RGB:
+ *value = bind_to_texture_rgb_;
+ break;
+ case EGL_BIND_TO_TEXTURE_RGBA:
+ *value = bind_to_texture_rgba_;
+ break;
+ case EGL_COLOR_BUFFER_TYPE:
+ *value = color_buffer_type_;
+ break;
+ case EGL_CONFIG_CAVEAT:
+ *value = config_caveat_;
+ break;
+ case EGL_CONFIG_ID:
+ *value = config_id_;
+ break;
+ case EGL_CONFORMANT:
+ *value = conformant_;
+ break;
+ case EGL_DEPTH_SIZE:
+ *value = depth_size_;
+ break;
+ case EGL_LEVEL:
+ *value = level_;
+ break;
+ case EGL_MAX_PBUFFER_WIDTH:
+ *value = max_pbuffer_width_;
+ break;
+ case EGL_MAX_PBUFFER_HEIGHT:
+ *value = max_pbuffer_height_;
+ break;
+ case EGL_MAX_PBUFFER_PIXELS:
+ *value = max_pbuffer_pixels_;
+ break;
+ case EGL_MIN_SWAP_INTERVAL:
+ *value = min_swap_interval_;
+ break;
+ case EGL_MAX_SWAP_INTERVAL:
+ *value = max_swap_interval_;
+ break;
+ case EGL_NATIVE_RENDERABLE:
+ *value = native_renderable_;
+ break;
+ case EGL_NATIVE_VISUAL_ID:
+ *value = native_visual_id_;
+ break;
+ case EGL_NATIVE_VISUAL_TYPE:
+ *value = native_visual_type_;
+ break;
+ case EGL_RENDERABLE_TYPE:
+ *value = renderable_type_;
+ break;
+ case EGL_SAMPLE_BUFFERS:
+ *value = sample_buffers_;
+ break;
+ case EGL_SAMPLES:
+ *value = samples_;
+ break;
+ case EGL_STENCIL_SIZE:
+ *value = stencil_size_;
+ break;
+ case EGL_SURFACE_TYPE:
+ *value = surface_type_;
+ break;
+ case EGL_TRANSPARENT_TYPE:
+ *value = transparent_type_;
+ break;
+ case EGL_TRANSPARENT_RED_VALUE:
+ *value = transparent_red_value_;
+ break;
+ case EGL_TRANSPARENT_GREEN_VALUE:
+ *value = transparent_green_value_;
+ break;
+ case EGL_TRANSPARENT_BLUE_VALUE:
+ *value = transparent_blue_value_;
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+} // namespace egl
diff --git a/chromium/gpu/gles2_conform_support/egl/config.h b/chromium/gpu/gles2_conform_support/egl/config.h
new file mode 100644
index 00000000000..ef2ae1dcb9e
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/config.h
@@ -0,0 +1,92 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_GLES2_CONFORM_TEST_CONFIG_H_
+#define GPU_GLES2_CONFORM_TEST_CONFIG_H_
+
+#include <EGL/egl.h>
+
+#include "base/basictypes.h"
+
+namespace egl {
+
+class Config {
+ public:
+ Config();
+ ~Config();
+
+ bool GetAttrib(EGLint attribute, EGLint* value) const;
+
+ private:
+ // Total color component bits in the color buffer.
+ EGLint buffer_size_;
+ // Bits of Red in the color buffer.
+ EGLint red_size_;
+ // Bits of Green in the color buffer.
+ EGLint green_size_;
+ // Bits of Blue in the color buffer.
+ EGLint blue_size_;
+ // Bits of Luminance in the color buffer.
+ EGLint luminance_size_;
+ // Bits of Alpha in the color buffer.
+ EGLint alpha_size_;
+ // Bits of Alpha Mask in the mask buffer.
+ EGLint alpha_mask_size_;
+ // True if bindable to RGB textures.
+ EGLBoolean bind_to_texture_rgb_;
+ // True if bindable to RGBA textures.
+ EGLBoolean bind_to_texture_rgba_;
+ // Color buffer type.
+ EGLenum color_buffer_type_;
+ // Any caveats for the configuration.
+ EGLenum config_caveat_;
+ // Unique EGLConfig identifier.
+ EGLint config_id_;
+ // Whether contexts created with this config are conformant.
+ EGLint conformant_;
+ // Bits of Z in the depth buffer.
+ EGLint depth_size_;
+ // Frame buffer level.
+ EGLint level_;
+ // Maximum width of pbuffer.
+ EGLint max_pbuffer_width_;
+ // Maximum height of pbuffer.
+ EGLint max_pbuffer_height_;
+ // Maximum size of pbuffer.
+ EGLint max_pbuffer_pixels_;
+ // Minimum swap interval.
+ EGLint min_swap_interval_;
+ // Maximum swap interval.
+ EGLint max_swap_interval_;
+ // True if native rendering APIs can render to surface.
+ EGLBoolean native_renderable_;
+ // Handle of corresponding native visual.
+ EGLint native_visual_id_;
+ // Native visual type of the associated visual.
+ EGLint native_visual_type_;
+ // Which client rendering APIs are supported.
+ EGLint renderable_type_;
+ // Number of multisample buffers.
+ EGLint sample_buffers_;
+ // Number of samples per pixel.
+ EGLint samples_;
+ // Bits of Stencil in the stencil buffer.
+ EGLint stencil_size_;
+ // Which types of EGL surfaces are supported.
+ EGLint surface_type_;
+ // Type of transparency supported
+ EGLenum transparent_type_;
+ // Transparent red value
+ EGLint transparent_red_value_;
+ // Transparent green value
+ EGLint transparent_green_value_;
+ // Transparent blue value
+ EGLint transparent_blue_value_;
+
+ DISALLOW_COPY_AND_ASSIGN(Config);
+};
+
+} // namespace egl
+
+#endif // GPU_GLES2_CONFORM_TEST_CONFIG_H_
diff --git a/chromium/gpu/gles2_conform_support/egl/display.cc b/chromium/gpu/gles2_conform_support/egl/display.cc
new file mode 100644
index 00000000000..66934bb9010
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/display.cc
@@ -0,0 +1,265 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/gles2_conform_support/egl/display.h"
+
+#include <vector>
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "gpu/command_buffer/client/gles2_implementation.h"
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/command_buffer/client/transfer_buffer.h"
+#include "gpu/command_buffer/service/context_group.h"
+#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/gles2_conform_support/egl/config.h"
+#include "gpu/gles2_conform_support/egl/surface.h"
+
+namespace {
+const int32 kCommandBufferSize = 1024 * 1024;
+const int32 kTransferBufferSize = 512 * 1024;
+}
+
+namespace egl {
+
+Display::Display(EGLNativeDisplayType display_id)
+ : display_id_(display_id),
+ is_initialized_(false),
+ create_offscreen_(false),
+ create_offscreen_width_(0),
+ create_offscreen_height_(0) {
+}
+
+Display::~Display() {
+ gles2::Terminate();
+}
+
+bool Display::Initialize() {
+ gles2::Initialize();
+ is_initialized_ = true;
+ return true;
+}
+
+bool Display::IsValidConfig(EGLConfig config) {
+ return (config != NULL) && (config == config_.get());
+}
+
+bool Display::ChooseConfigs(EGLConfig* configs,
+ EGLint config_size,
+ EGLint* num_config) {
+ // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
+ // does not support finding or choosing configs.
+ *num_config = 1;
+ if (configs != NULL) {
+ if (config_ == NULL) {
+ config_.reset(new Config);
+ }
+ configs[0] = config_.get();
+ }
+ return true;
+}
+
+bool Display::GetConfigs(EGLConfig* configs,
+ EGLint config_size,
+ EGLint* num_config) {
+ // TODO(alokp): Find out a way to find all configs. CommandBuffer currently
+ // does not support finding or choosing configs.
+ *num_config = 1;
+ if (configs != NULL) {
+ if (config_ == NULL) {
+ config_.reset(new Config);
+ }
+ configs[0] = config_.get();
+ }
+ return true;
+}
+
+bool Display::GetConfigAttrib(EGLConfig config,
+ EGLint attribute,
+ EGLint* value) {
+ const egl::Config* cfg = static_cast<egl::Config*>(config);
+ return cfg->GetAttrib(attribute, value);
+}
+
+bool Display::IsValidNativeWindow(EGLNativeWindowType win) {
+#if defined OS_WIN
+ return ::IsWindow(win) != FALSE;
+#else
+ // TODO(alokp): Validate window handle.
+ return true;
+#endif // OS_WIN
+}
+
+bool Display::IsValidSurface(EGLSurface surface) {
+ return (surface != NULL) && (surface == surface_.get());
+}
+
+EGLSurface Display::CreateWindowSurface(EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint* attrib_list) {
+ if (surface_ != NULL) {
+ // We do not support more than one window surface.
+ return EGL_NO_SURFACE;
+ }
+
+ {
+ gpu::TransferBufferManager* manager = new gpu::TransferBufferManager();
+ transfer_buffer_manager_.reset(manager);
+ manager->Initialize();
+ }
+ scoped_ptr<gpu::CommandBufferService> command_buffer(
+ new gpu::CommandBufferService(transfer_buffer_manager_.get()));
+ if (!command_buffer->Initialize())
+ return NULL;
+
+ scoped_refptr<gpu::gles2::ContextGroup> group(
+ new gpu::gles2::ContextGroup(NULL, NULL, NULL, NULL, true));
+
+ decoder_.reset(gpu::gles2::GLES2Decoder::Create(group.get()));
+ if (!decoder_.get())
+ return EGL_NO_SURFACE;
+
+ gpu_scheduler_.reset(new gpu::GpuScheduler(command_buffer.get(),
+ decoder_.get(),
+ NULL));
+
+ decoder_->set_engine(gpu_scheduler_.get());
+ gfx::Size size(create_offscreen_width_, create_offscreen_height_);
+ if (create_offscreen_) {
+ gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size);
+ create_offscreen_ = false;
+ create_offscreen_width_ = 0;
+ create_offscreen_height_ = 0;
+ } else {
+ gl_surface_ = gfx::GLSurface::CreateViewGLSurface(win);
+ }
+ if (!gl_surface_.get())
+ return EGL_NO_SURFACE;
+
+ gl_context_ = gfx::GLContext::CreateGLContext(NULL,
+ gl_surface_.get(),
+ gfx::PreferDiscreteGpu);
+ if (!gl_context_.get())
+ return EGL_NO_SURFACE;
+
+ gl_context_->MakeCurrent(gl_surface_.get());
+
+ EGLint depth_size = 0;
+ EGLint alpha_size = 0;
+ EGLint stencil_size = 0;
+ GetConfigAttrib(config, EGL_DEPTH_SIZE, &depth_size);
+ GetConfigAttrib(config, EGL_ALPHA_SIZE, &alpha_size);
+ GetConfigAttrib(config, EGL_STENCIL_SIZE, &stencil_size);
+ std::vector<int32> attribs;
+ attribs.push_back(EGL_DEPTH_SIZE);
+ attribs.push_back(depth_size);
+ attribs.push_back(EGL_ALPHA_SIZE);
+ attribs.push_back(alpha_size);
+ attribs.push_back(EGL_STENCIL_SIZE);
+ attribs.push_back(stencil_size);
+ // TODO(gman): Insert attrib_list. Although ES 1.1 says it must be null
+ attribs.push_back(EGL_NONE);
+
+ if (!decoder_->Initialize(gl_surface_.get(),
+ gl_context_.get(),
+ gl_surface_->IsOffscreen(),
+ size,
+ gpu::gles2::DisallowedFeatures(),
+ NULL,
+ attribs)) {
+ return EGL_NO_SURFACE;
+ }
+
+ command_buffer->SetPutOffsetChangeCallback(
+ base::Bind(&gpu::GpuScheduler::PutChanged,
+ base::Unretained(gpu_scheduler_.get())));
+ command_buffer->SetGetBufferChangeCallback(
+ base::Bind(&gpu::GpuScheduler::SetGetBuffer,
+ base::Unretained(gpu_scheduler_.get())));
+
+ scoped_ptr<gpu::gles2::GLES2CmdHelper> cmd_helper(
+ new gpu::gles2::GLES2CmdHelper(command_buffer.get()));
+ if (!cmd_helper->Initialize(kCommandBufferSize))
+ return NULL;
+
+ scoped_ptr<gpu::TransferBuffer> transfer_buffer(new gpu::TransferBuffer(
+ cmd_helper.get()));
+
+ command_buffer_.reset(command_buffer.release());
+ transfer_buffer_.reset(transfer_buffer.release());
+ gles2_cmd_helper_.reset(cmd_helper.release());
+ surface_.reset(new Surface(win));
+
+ return surface_.get();
+}
+
+void Display::DestroySurface(EGLSurface surface) {
+ DCHECK(IsValidSurface(surface));
+ gpu_scheduler_.reset();
+ if (decoder_.get()) {
+ decoder_->Destroy(true);
+ }
+ decoder_.reset();
+ gl_surface_ = NULL;
+ gl_context_ = NULL;
+ surface_.reset();
+}
+
+void Display::SwapBuffers(EGLSurface surface) {
+ DCHECK(IsValidSurface(surface));
+ context_->SwapBuffers();
+}
+
+bool Display::IsValidContext(EGLContext ctx) {
+ return (ctx != NULL) && (ctx == context_.get());
+}
+
+EGLContext Display::CreateContext(EGLConfig config,
+ EGLContext share_ctx,
+ const EGLint* attrib_list) {
+ DCHECK(IsValidConfig(config));
+ // TODO(alokp): Add support for shared contexts.
+ if (share_ctx != NULL)
+ return EGL_NO_CONTEXT;
+
+ DCHECK(command_buffer_ != NULL);
+ DCHECK(transfer_buffer_.get());
+ context_.reset(new gpu::gles2::GLES2Implementation(
+ gles2_cmd_helper_.get(),
+ NULL,
+ transfer_buffer_.get(),
+ true,
+ NULL));
+
+ if (!context_->Initialize(
+ kTransferBufferSize,
+ kTransferBufferSize / 2,
+ kTransferBufferSize * 2)) {
+ return EGL_NO_CONTEXT;
+ }
+
+ context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets");
+ context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs");
+
+ return context_.get();
+}
+
+void Display::DestroyContext(EGLContext ctx) {
+ DCHECK(IsValidContext(ctx));
+ context_.reset();
+ transfer_buffer_.reset();
+}
+
+bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) {
+ if (ctx == EGL_NO_CONTEXT) {
+ gles2::SetGLContext(NULL);
+ } else {
+ DCHECK(IsValidSurface(draw));
+ DCHECK(IsValidSurface(read));
+ DCHECK(IsValidContext(ctx));
+ gles2::SetGLContext(context_.get());
+ }
+ return true;
+}
+
+} // namespace egl
diff --git a/chromium/gpu/gles2_conform_support/egl/display.h b/chromium/gpu/gles2_conform_support/egl/display.h
new file mode 100644
index 00000000000..251904c5028
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/display.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_GLES2_CONFORM_SUPPORT_EGL_DISPLAY_H_
+#define GPU_GLES2_CONFORM_SUPPORT_EGL_DISPLAY_H_
+
+#include <EGL/egl.h>
+
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/client/gles2_cmd_helper.h"
+#include "gpu/command_buffer/service/command_buffer_service.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+#include "gpu/command_buffer/service/gpu_scheduler.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
+
+namespace gpu {
+class CommandBufferService;
+class GpuScheduler;
+class TransferBuffer;
+class TransferBufferManagerInterface;
+
+namespace gles2 {
+class GLES2CmdHelper;
+class GLES2Implementation;
+} // namespace gles2
+} // namespace gpu
+
+namespace egl {
+
+class Config;
+class Surface;
+
+class Display {
+ public:
+ explicit Display(EGLNativeDisplayType display_id);
+ virtual ~Display();
+
+ void SetCreateOffscreen(int width, int height) {
+ create_offscreen_ = true;
+ create_offscreen_width_ = width;
+ create_offscreen_height_ = height;
+ }
+
+ bool is_initialized() const { return is_initialized_; }
+ bool Initialize();
+
+ // Config routines.
+ bool IsValidConfig(EGLConfig config);
+ bool ChooseConfigs(
+ EGLConfig* configs, EGLint config_size, EGLint* num_config);
+ bool GetConfigs(EGLConfig* configs, EGLint config_size, EGLint* num_config);
+ bool GetConfigAttrib(EGLConfig config, EGLint attribute, EGLint* value);
+
+ // Surface routines.
+ bool IsValidNativeWindow(EGLNativeWindowType win);
+ bool IsValidSurface(EGLSurface surface);
+ EGLSurface CreateWindowSurface(EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint* attrib_list);
+ void DestroySurface(EGLSurface surface);
+ void SwapBuffers(EGLSurface surface);
+
+ // Context routines.
+ bool IsValidContext(EGLContext ctx);
+ EGLContext CreateContext(EGLConfig config,
+ EGLContext share_ctx,
+ const EGLint* attrib_list);
+ void DestroyContext(EGLContext ctx);
+ bool MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx);
+
+ private:
+ EGLNativeDisplayType display_id_;
+
+ bool is_initialized_;
+ bool create_offscreen_;
+ int create_offscreen_width_;
+ int create_offscreen_height_;
+
+ scoped_ptr<gpu::TransferBufferManagerInterface> transfer_buffer_manager_;
+ scoped_ptr<gpu::CommandBufferService> command_buffer_;
+ scoped_ptr<gpu::GpuScheduler> gpu_scheduler_;
+ scoped_ptr<gpu::gles2::GLES2Decoder> decoder_;
+ scoped_refptr<gfx::GLContext> gl_context_;
+ scoped_refptr<gfx::GLSurface> gl_surface_;
+ scoped_ptr<gpu::gles2::GLES2CmdHelper> gles2_cmd_helper_;
+ scoped_ptr<gpu::TransferBuffer> transfer_buffer_;
+
+ // TODO(alokp): Support more than one config, surface, and context.
+ scoped_ptr<Config> config_;
+ scoped_ptr<Surface> surface_;
+ scoped_ptr<gpu::gles2::GLES2Implementation> context_;
+
+ DISALLOW_COPY_AND_ASSIGN(Display);
+};
+
+} // namespace egl
+
+#endif // GPU_GLES2_CONFORM_SUPPORT_EGL_DISPLAY_H_
diff --git a/chromium/gpu/gles2_conform_support/egl/egl.cc b/chromium/gpu/gles2_conform_support/egl/egl.cc
new file mode 100644
index 00000000000..3827229c45a
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/egl.cc
@@ -0,0 +1,404 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <EGL/egl.h>
+
+#include "base/command_line.h"
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/gles2_conform_support/egl/display.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_surface.h"
+
+#if REGAL_STATIC_EGL
+extern "C" {
+
+typedef EGLContext RegalSystemContext;
+#define REGAL_DECL
+REGAL_DECL void RegalMakeCurrent( RegalSystemContext ctx );
+
+} // extern "C"
+#endif
+
+namespace {
+void SetCurrentError(EGLint error_code) {
+}
+
+template<typename T>
+T EglError(EGLint error_code, T return_value) {
+ SetCurrentError(error_code);
+ return return_value;
+}
+
+template<typename T>
+T EglSuccess(T return_value) {
+ SetCurrentError(EGL_SUCCESS);
+ return return_value;
+}
+
+EGLint ValidateDisplay(EGLDisplay dpy) {
+ if (dpy == EGL_NO_DISPLAY)
+ return EGL_BAD_DISPLAY;
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->is_initialized())
+ return EGL_NOT_INITIALIZED;
+
+ return EGL_SUCCESS;
+}
+
+EGLint ValidateDisplayConfig(EGLDisplay dpy, EGLConfig config) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return error_code;
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->IsValidConfig(config))
+ return EGL_BAD_CONFIG;
+
+ return EGL_SUCCESS;
+}
+
+EGLint ValidateDisplaySurface(EGLDisplay dpy, EGLSurface surface) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return error_code;
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->IsValidSurface(surface))
+ return EGL_BAD_SURFACE;
+
+ return EGL_SUCCESS;
+}
+
+EGLint ValidateDisplayContext(EGLDisplay dpy, EGLContext context) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return error_code;
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->IsValidContext(context))
+ return EGL_BAD_CONTEXT;
+
+ return EGL_SUCCESS;
+}
+} // namespace
+
+extern "C" {
+EGLint eglGetError() {
+ // TODO(alokp): Fix me.
+ return EGL_SUCCESS;
+}
+
+EGLDisplay eglGetDisplay(EGLNativeDisplayType display_id) {
+ return new egl::Display(display_id);
+}
+
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+ if (dpy == EGL_NO_DISPLAY)
+ return EglError(EGL_BAD_DISPLAY, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->Initialize())
+ return EglError(EGL_NOT_INITIALIZED, EGL_FALSE);
+
+ int argc = 1;
+ const char* const argv[] = {
+ "dummy"
+ };
+ CommandLine::Init(argc, argv);
+ gfx::GLSurface::InitializeOneOff();
+
+ *major = 1;
+ *minor = 4;
+ return EglSuccess(EGL_TRUE);
+}
+
+EGLBoolean eglTerminate(EGLDisplay dpy) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ delete display;
+
+ return EglSuccess(EGL_TRUE);
+}
+
+const char* eglQueryString(EGLDisplay dpy, EGLint name) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, static_cast<const char*>(NULL));
+
+ switch (name) {
+ case EGL_CLIENT_APIS:
+ return EglSuccess("OpenGL_ES");
+ case EGL_EXTENSIONS:
+ return EglSuccess("");
+ case EGL_VENDOR:
+ return EglSuccess("Google Inc.");
+ case EGL_VERSION:
+ return EglSuccess("1.4");
+ default:
+ return EglError(EGL_BAD_PARAMETER, static_cast<const char*>(NULL));
+ }
+}
+
+EGLBoolean eglChooseConfig(EGLDisplay dpy,
+ const EGLint* attrib_list,
+ EGLConfig* configs,
+ EGLint config_size,
+ EGLint* num_config) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ if (num_config == NULL)
+ return EglError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->ChooseConfigs(configs, config_size, num_config))
+ return EglError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+
+ return EglSuccess(EGL_TRUE);
+}
+
+EGLBoolean eglGetConfigs(EGLDisplay dpy,
+ EGLConfig* configs,
+ EGLint config_size,
+ EGLint* num_config) {
+ EGLint error_code = ValidateDisplay(dpy);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ if (num_config == NULL)
+ return EglError(EGL_BAD_PARAMETER, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->GetConfigs(configs, config_size, num_config))
+ return EglError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+
+ return EglSuccess(EGL_TRUE);
+}
+
+EGLBoolean eglGetConfigAttrib(EGLDisplay dpy,
+ EGLConfig config,
+ EGLint attribute,
+ EGLint* value) {
+ EGLint error_code = ValidateDisplayConfig(dpy, config);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->GetConfigAttrib(config, attribute, value))
+ return EglError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
+
+ return EglSuccess(EGL_TRUE);
+}
+
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
+ EGLConfig config,
+ EGLNativeWindowType win,
+ const EGLint* attrib_list) {
+ EGLint error_code = ValidateDisplayConfig(dpy, config);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_NO_SURFACE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->IsValidNativeWindow(win))
+ return EglError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+
+ EGLSurface surface = display->CreateWindowSurface(config, win, attrib_list);
+ if (surface == EGL_NO_SURFACE)
+ return EglError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
+
+ return EglSuccess(surface);
+}
+
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy,
+ EGLConfig config,
+ const EGLint* attrib_list) {
+ return EGL_NO_SURFACE;
+}
+
+EGLSurface eglCreatePixmapSurface(EGLDisplay dpy,
+ EGLConfig config,
+ EGLNativePixmapType pixmap,
+ const EGLint* attrib_list) {
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglDestroySurface(EGLDisplay dpy,
+ EGLSurface surface) {
+ EGLint error_code = ValidateDisplaySurface(dpy, surface);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ display->DestroySurface(surface);
+ return EglSuccess(EGL_TRUE);
+}
+
+EGLBoolean eglQuerySurface(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint attribute,
+ EGLint* value) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglBindAPI(EGLenum api) {
+ return EGL_FALSE;
+}
+
+EGLenum eglQueryAPI() {
+ return EGL_OPENGL_ES_API;
+}
+
+EGLBoolean eglWaitClient(void) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglReleaseThread(void) {
+ return EGL_FALSE;
+}
+
+EGLSurface eglCreatePbufferFromClientBuffer(EGLDisplay dpy,
+ EGLenum buftype,
+ EGLClientBuffer buffer,
+ EGLConfig config,
+ const EGLint* attrib_list) {
+ return EGL_NO_SURFACE;
+}
+
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint attribute,
+ EGLint value) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglBindTexImage(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint buffer) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglReleaseTexImage(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint buffer) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval) {
+ return EGL_FALSE;
+}
+
+EGLContext eglCreateContext(EGLDisplay dpy,
+ EGLConfig config,
+ EGLContext share_context,
+ const EGLint* attrib_list) {
+ EGLint error_code = ValidateDisplayConfig(dpy, config);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_NO_CONTEXT);
+
+ if (share_context != EGL_NO_CONTEXT) {
+ error_code = ValidateDisplayContext(dpy, share_context);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_NO_CONTEXT);
+ }
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ EGLContext context = display->CreateContext(
+ config, share_context, attrib_list);
+ if (context == EGL_NO_CONTEXT)
+ return EglError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
+
+ return EglSuccess(context);
+}
+
+EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
+ EGLint error_code = ValidateDisplayContext(dpy, ctx);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ display->DestroyContext(ctx);
+ return EGL_TRUE;
+}
+
+EGLBoolean eglMakeCurrent(EGLDisplay dpy,
+ EGLSurface draw,
+ EGLSurface read,
+ EGLContext ctx) {
+ if (ctx != EGL_NO_CONTEXT) {
+ EGLint error_code = ValidateDisplaySurface(dpy, draw);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+ error_code = ValidateDisplaySurface(dpy, read);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+ error_code = ValidateDisplayContext(dpy, ctx);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+ }
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ if (!display->MakeCurrent(draw, read, ctx))
+ return EglError(EGL_CONTEXT_LOST, EGL_FALSE);
+
+#if REGAL_STATIC_EGL
+ RegalMakeCurrent(ctx);
+#endif
+
+ return EGL_TRUE;
+}
+
+EGLContext eglGetCurrentContext() {
+ return EGL_NO_CONTEXT;
+}
+
+EGLSurface eglGetCurrentSurface(EGLint readdraw) {
+ return EGL_NO_SURFACE;
+}
+
+EGLDisplay eglGetCurrentDisplay() {
+ return EGL_NO_DISPLAY;
+}
+
+EGLBoolean eglQueryContext(EGLDisplay dpy,
+ EGLContext ctx,
+ EGLint attribute,
+ EGLint* value) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglWaitGL() {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglWaitNative(EGLint engine) {
+ return EGL_FALSE;
+}
+
+EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) {
+ EGLint error_code = ValidateDisplaySurface(dpy, surface);
+ if (error_code != EGL_SUCCESS)
+ return EglError(error_code, EGL_FALSE);
+
+ egl::Display* display = static_cast<egl::Display*>(dpy);
+ display->SwapBuffers(surface);
+ return EglSuccess(EGL_TRUE);
+}
+
+EGLBoolean eglCopyBuffers(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLNativePixmapType target) {
+ return EGL_FALSE;
+}
+
+/* Now, define eglGetProcAddress using the generic function ptr. type */
+__eglMustCastToProperFunctionPointerType
+eglGetProcAddress(const char* procname) {
+ return gles2::GetGLFunctionPointer(procname);
+}
+} // extern "C"
diff --git a/chromium/gpu/gles2_conform_support/egl/surface.cc b/chromium/gpu/gles2_conform_support/egl/surface.cc
new file mode 100644
index 00000000000..423fe2756f6
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/surface.cc
@@ -0,0 +1,15 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/gles2_conform_support/egl/surface.h"
+
+namespace egl {
+
+Surface::Surface(EGLNativeWindowType win) : window_(win) {
+}
+
+Surface::~Surface() {
+}
+
+} // namespace egl
diff --git a/chromium/gpu/gles2_conform_support/egl/surface.h b/chromium/gpu/gles2_conform_support/egl/surface.h
new file mode 100644
index 00000000000..3b66de082c7
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/egl/surface.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_GLES2_CONFORM_TEST_SURFACE_H_
+#define GPU_GLES2_CONFORM_TEST_SURFACE_H_
+
+#include <EGL/egl.h>
+
+#include "base/basictypes.h"
+
+namespace egl {
+
+class Surface {
+ public:
+ explicit Surface(EGLNativeWindowType win);
+ ~Surface();
+
+ EGLNativeWindowType window() { return window_; }
+
+ private:
+ EGLNativeWindowType window_;
+
+ DISALLOW_COPY_AND_ASSIGN(Surface);
+};
+
+} // namespace egl
+
+#endif // GPU_GLES2_CONFORM_TEST_SURFACE_H_
diff --git a/chromium/gpu/gles2_conform_support/gles2_conform_support.c b/chromium/gpu/gles2_conform_support/gles2_conform_support.c
new file mode 100644
index 00000000000..db0e8c0bc2c
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/gles2_conform_support.c
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A small sample just to make sure we can actually compile and link
+// our OpenGL ES 2.0 conformance test support code.
+
+#include <EGL/egl.h>
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+
+// Note: This code is not intended to run, only compile and link.
+int GTFMain(int argc, char** argv) {
+ EGLint major, minor;
+ EGLDisplay eglDisplay;
+ EGLNativeDisplayType nativeDisplay = EGL_DEFAULT_DISPLAY;
+
+ eglDisplay = eglGetDisplay(nativeDisplay);
+ eglInitialize(eglDisplay, &major, &minor);
+
+ return 0;
+}
+
+
diff --git a/chromium/gpu/gles2_conform_support/gles2_conform_support.gyp b/chromium/gpu/gles2_conform_support/gles2_conform_support.gyp
new file mode 100644
index 00000000000..6564ea1e57b
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/gles2_conform_support.gyp
@@ -0,0 +1,140 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ # These are defined here because we want to be able to compile them on
+ # the buildbots without needed the OpenGL ES 2.0 conformance tests
+ # which are not open source.
+ 'bootstrap_sources_native': [
+ 'native/main.cc',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'bootstrap_sources_native': [
+ 'native/egl_native_aura.cc',
+ 'native/egl_native.cc',
+ 'native/egl_native_gtk.cc',
+ 'native/egl_native_x11.cc',
+ ],
+ }],
+ ['OS=="win"', {
+ 'bootstrap_sources_native': [
+ 'native/egl_native.cc',
+ 'native/egl_native_win.cc',
+ ],
+ }],
+ ],
+
+ },
+ 'targets': [
+ {
+ 'target_name': 'egl_native',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../gpu/gpu.gyp:gpu',
+ '../../gpu/gpu.gyp:gles2_implementation_client_side_arrays_no_check',
+ '../../gpu/gpu.gyp:command_buffer_service',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ '../../ui/gl/gl.gyp:gl',
+ '../../ui/ui.gyp:ui',
+ ],
+ 'sources': [
+ 'egl/config.cc',
+ 'egl/config.h',
+ 'egl/display.cc',
+ 'egl/display.h',
+ 'egl/egl.cc',
+ 'egl/surface.cc',
+ 'egl/surface.h',
+ ],
+ 'defines': [
+ 'EGLAPI=',
+ 'EGLAPIENTRY=',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
+ 'target_name': 'egl_main_native',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'egl_native',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'conditions': [
+ ['toolkit_uses_gtk == 1', {
+ 'dependencies': ['../../build/linux/system.gyp:gtk'],
+ }],
+ ],
+ 'sources': [
+ '<@(bootstrap_sources_native)',
+ ],
+ 'defines': [
+ 'GLES2_CONFORM_SUPPORT_ONLY',
+ 'GTF_GLES20',
+ 'EGLAPI=',
+ 'EGLAPIENTRY=',
+ ],
+ },
+ {
+ 'target_name': 'egl_main_windowless',
+ 'type': 'static_library',
+ 'dependencies': [
+ 'egl_native',
+ '../../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'conditions': [
+ ['toolkit_uses_gtk == 1', {
+ 'dependencies': ['../../build/linux/system.gyp:gtk'],
+ }],
+ ],
+ 'sources': [
+ 'native/main.cc',
+ 'native/egl_native.cc',
+ 'native/egl_native_windowless.cc',
+ '<@(bootstrap_sources_native)',
+ ],
+ 'defines': [
+ 'GLES2_CONFORM_SUPPORT_ONLY',
+ 'GTF_GLES20',
+ 'EGLAPI=',
+ 'EGLAPIENTRY=',
+ ],
+ },
+ {
+ 'target_name': 'gles2_conform_support',
+ 'type': 'executable',
+ 'dependencies': [
+ 'egl_native',
+ '../../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../../gpu/gpu.gyp:gles2_c_lib_nocheck',
+ '../../third_party/expat/expat.gyp:expat',
+ ],
+ 'conditions': [
+ ['toolkit_uses_gtk == 1', {
+ 'dependencies': ['../../build/linux/system.gyp:gtk'],
+ }],
+ # See http://crbug.com/162998#c4 for why this is needed.
+ ['OS=="linux" and linux_use_tcmalloc==1', {
+ 'dependencies': [
+ '../../base/allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ],
+ 'defines': [
+ 'GLES2_CONFORM_SUPPORT_ONLY',
+ 'GTF_GLES20',
+ 'EGLAPI=',
+ 'EGLAPIENTRY=',
+ ],
+ 'sources': [
+ '<@(bootstrap_sources_native)',
+ 'gles2_conform_support.c'
+ ],
+ },
+ ],
+}
diff --git a/chromium/gpu/gles2_conform_support/gtf/gtf_stubs.h b/chromium/gpu/gles2_conform_support/gtf/gtf_stubs.h
new file mode 100644
index 00000000000..23bb362bbe0
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/gtf/gtf_stubs.h
@@ -0,0 +1,23 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A few stubs so we don't need the actual OpenGL ES 2.0 conformance tests
+// to compile the support for them.
+
+#ifndef GPU_GLES2_CONFORM_SUPPORT_GTF_GTF_STUBS_H_
+#define GPU_GLES2_CONFORM_SUPPORT_GTF_GTF_STUBS_H_
+
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+typedef unsigned char GTFbool;
+#define GTFfalse 0
+#define GTFtrue 1
+
+int GTFMain(int argc, char** argv);
+
+#endif // GPU_GLES2_CONFORM_SUPPORT_GTF_GTF_STUBS_H_
+
+
diff --git a/chromium/gpu/gles2_conform_support/native/egl_native.cc b/chromium/gpu/gles2_conform_support/native/egl_native.cc
new file mode 100644
index 00000000000..bf8c7719b96
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/egl_native.cc
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" {
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h"
+#endif
+
+GTFbool GTFNativeCreatePixmap(EGLNativeDisplayType nativeDisplay,
+ EGLDisplay eglDisplay, EGLConfig eglConfig,
+ const char *title, int width, int height,
+ EGLNativePixmapType *pNativePixmap) {
+ return GTFtrue;
+}
+
+void GTFNativeDestroyPixmap(EGLNativeDisplayType nativeDisplay,
+ EGLNativePixmapType nativePixmap) {
+}
+
+EGLImageKHR GTFCreateEGLImageExternal(
+ int width, int height, int format,
+ float r, float g, float b, float a, void** resource) {
+ return (EGLImageKHR)0;
+}
+
+void GTFDestroyEGLImageExternal(EGLImageKHR image, void* resource) {
+}
+
+const int* GTFQueryFormatsEGLImageExternal(void) {
+ return 0;
+}
+
+GTFbool GTFIsAlphaFormatEGLImageExternal(int format) {
+ return GTFfalse;
+}
+
+} // extern "C"
+
+
diff --git a/chromium/gpu/gles2_conform_support/native/egl_native_aura.cc b/chromium/gpu/gles2_conform_support/native/egl_native_aura.cc
new file mode 100644
index 00000000000..f3eea4726c3
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/egl_native_aura.cc
@@ -0,0 +1,42 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is just a compile fix. If this is really needed when using aura, the
+// methods below should be filled out.
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "base/logging.h"
+
+extern "C" {
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h"
+#endif
+
+GTFbool GTFNativeCreateDisplay(EGLNativeDisplayType *pNativeDisplay) {
+ NOTIMPLEMENTED();
+ return GTFfalse;
+}
+
+void GTFNativeDestroyDisplay(EGLNativeDisplayType nativeDisplay) {
+ NOTIMPLEMENTED();
+}
+
+void GTFNativeDestroyWindow(EGLNativeDisplayType nativeDisplay,
+ EGLNativeWindowType nativeWindow) {
+ NOTIMPLEMENTED();
+}
+
+GTFbool GTFNativeCreateWindow(EGLNativeDisplayType nativeDisplay,
+ EGLDisplay eglDisplay, EGLConfig eglConfig,
+ const char* title, int width, int height,
+ EGLNativeWindowType *pNativeWindow) {
+ NOTIMPLEMENTED();
+ return GTFfalse;
+}
+
+} // extern "C"
diff --git a/chromium/gpu/gles2_conform_support/native/egl_native_gtk.cc b/chromium/gpu/gles2_conform_support/native/egl_native_gtk.cc
new file mode 100644
index 00000000000..e3ae0cbf9e6
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/egl_native_gtk.cc
@@ -0,0 +1,63 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+extern "C" {
+
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h"
+#endif
+
+GTFbool GTFNativeCreateDisplay(EGLNativeDisplayType *pNativeDisplay) {
+ int argc = 0;
+ char **argv = NULL;
+ gtk_init(&argc, &argv);
+ *pNativeDisplay = GDK_DISPLAY();;
+ return *pNativeDisplay ? GTFtrue : GTFfalse;
+}
+
+void GTFNativeDestroyDisplay(EGLNativeDisplayType nativeDisplay) {
+ gtk_exit(0);
+}
+
+void GTFNativeDestroyWindow(EGLNativeDisplayType nativeDisplay,
+ EGLNativeWindowType nativeWindow) {
+ GdkWindow* window = gdk_window_lookup(nativeWindow);
+ gpointer widget = NULL;
+ gdk_window_get_user_data(window, &widget);
+ gtk_widget_destroy(GTK_WIDGET(widget));
+}
+
+GTFbool GTFNativeCreateWindow(EGLNativeDisplayType nativeDisplay,
+ EGLDisplay eglDisplay, EGLConfig eglConfig,
+ const char* title, int width, int height,
+ EGLNativeWindowType *pNativeWindow) {
+#ifdef CHROMEOS_GLES2_CONFORMANCE
+ // Due to the behavior of ChromeOS window manager, which always resize the
+ // top level window etc, we had to create a popup window.
+ GtkWidget* hwnd = gtk_window_new(GTK_WINDOW_POPUP);
+#else
+ GtkWidget* hwnd = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+#endif
+
+ gtk_window_set_title(GTK_WINDOW(hwnd), title);
+ gtk_window_set_default_size(GTK_WINDOW(hwnd), width, height);
+ gtk_widget_set_double_buffered(hwnd, FALSE);
+ gtk_widget_set_app_paintable(hwnd, TRUE);
+
+ // We had to enter gtk main loop to realize the window on ChromeOS.
+ gtk_widget_show_now(hwnd);
+
+ *pNativeWindow = GDK_WINDOW_XWINDOW(hwnd->window);
+
+ return GTFtrue;
+}
+
+} // extern "C"
diff --git a/chromium/gpu/gles2_conform_support/native/egl_native_win.cc b/chromium/gpu/gles2_conform_support/native/egl_native_win.cc
new file mode 100644
index 00000000000..acb286db61d
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/egl_native_win.cc
@@ -0,0 +1,117 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+extern "C" {
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h"
+#endif
+}
+
+#include <string>
+
+namespace {
+LPCTSTR kWindowClassName = TEXT("ES2CONFORM");
+
+LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg,
+ WPARAM w_param, LPARAM l_param) {
+ LRESULT result = 0;
+ switch (msg) {
+ case WM_CLOSE:
+ ::DestroyWindow(hwnd);
+ break;
+ case WM_DESTROY:
+ ::PostQuitMessage(0);
+ break;
+ case WM_ERASEBKGND:
+ // Return a non-zero value to indicate that the background has been
+ // erased.
+ result = 1;
+ break;
+ default:
+ result = ::DefWindowProc(hwnd, msg, w_param, l_param);
+ break;
+ }
+ return result;
+}
+} // namespace.
+
+extern "C" {
+
+GTFbool GTFNativeCreateDisplay(EGLNativeDisplayType *pNativeDisplay) {
+ *pNativeDisplay = EGL_DEFAULT_DISPLAY;
+ return GTFtrue;
+}
+
+void GTFNativeDestroyDisplay(EGLNativeDisplayType nativeDisplay) {
+ // Nothing to destroy since we are using EGL_DEFAULT_DISPLAY
+}
+
+GTFbool GTFNativeCreateWindow(EGLNativeDisplayType nativeDisplay,
+ EGLDisplay eglDisplay, EGLConfig eglConfig,
+ const char* title, int width, int height,
+ EGLNativeWindowType *pNativeWindow) {
+ WNDCLASS wnd_class = {0};
+ HINSTANCE instance = GetModuleHandle(NULL);
+ wnd_class.style = CS_OWNDC;
+ wnd_class.lpfnWndProc = WindowProc;
+ wnd_class.hInstance = instance;
+ wnd_class.hbrBackground =
+ reinterpret_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
+ wnd_class.lpszClassName = kWindowClassName;
+ if (!RegisterClass(&wnd_class))
+ return GTFfalse;
+
+ DWORD wnd_style = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
+ RECT wnd_rect;
+ wnd_rect.left = 0;
+ wnd_rect.top = 0;
+ wnd_rect.right = width;
+ wnd_rect.bottom = height;
+ if (!AdjustWindowRect(&wnd_rect, wnd_style, FALSE))
+ return GTFfalse;
+
+#ifdef UNICODE
+ // Convert ascii string to wide string.
+ const std::wstring wnd_title(title, title + strlen(title));
+#else
+ const std::string wnd_title = title;
+#endif // UNICODE
+
+ HWND hwnd = CreateWindow(
+ wnd_class.lpszClassName,
+ wnd_title.c_str(),
+ wnd_style,
+ 0,
+ 0,
+ wnd_rect.right - wnd_rect.left,
+ wnd_rect.bottom - wnd_rect.top,
+ NULL,
+ NULL,
+ instance,
+ NULL);
+ if (hwnd == NULL)
+ return GTFfalse;
+
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ *pNativeWindow = hwnd;
+ return GTFtrue;
+}
+
+void GTFNativeDestroyWindow(EGLNativeDisplayType nativeDisplay,
+ EGLNativeWindowType nativeWindow) {
+ DestroyWindow(nativeWindow);
+ UnregisterClass(kWindowClassName, GetModuleHandle(NULL));
+}
+
+EGLImageKHR GTFCreateEGLImage(int width, int height,
+ GLenum format, GLenum type) {
+ return (EGLImageKHR)NULL;
+}
+
+void GTFDestroyEGLImage(EGLImageKHR image) {
+}
+
+} // extern "C"
diff --git a/chromium/gpu/gles2_conform_support/native/egl_native_windowless.cc b/chromium/gpu/gles2_conform_support/native/egl_native_windowless.cc
new file mode 100644
index 00000000000..14172cfea1e
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/egl_native_windowless.cc
@@ -0,0 +1,45 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/gles2_conform_support/egl/display.h"
+
+extern "C" {
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h"
+#endif
+
+GTFbool GTFNativeCreateDisplay(EGLNativeDisplayType *pNativeDisplay) {
+ *pNativeDisplay = EGL_DEFAULT_DISPLAY;
+ return GTFtrue;
+}
+
+void GTFNativeDestroyDisplay(EGLNativeDisplayType nativeDisplay) {
+ // Nothing to destroy since we are using EGL_DEFAULT_DISPLAY
+}
+
+GTFbool GTFNativeCreateWindow(EGLNativeDisplayType nativeDisplay,
+ EGLDisplay eglDisplay, EGLConfig eglConfig,
+ const char* title, int width, int height,
+ EGLNativeWindowType *pNativeWindow) {
+ egl::Display* display = static_cast<egl::Display*>(eglDisplay);
+ display->SetCreateOffscreen(width, height);
+ return GTFtrue;
+}
+
+void GTFNativeDestroyWindow(EGLNativeDisplayType nativeDisplay,
+ EGLNativeWindowType nativeWindow) {
+}
+
+EGLImageKHR GTFCreateEGLImage(int width, int height,
+ GLenum format, GLenum type) {
+ return (EGLImageKHR)NULL;
+}
+
+void GTFDestroyEGLImage(EGLImageKHR image) {
+}
+
+} // extern "C"
+
diff --git a/chromium/gpu/gles2_conform_support/native/egl_native_x11.cc b/chromium/gpu/gles2_conform_support/native/egl_native_x11.cc
new file mode 100644
index 00000000000..3cb6895c880
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/egl_native_x11.cc
@@ -0,0 +1,74 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+extern "C" {
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/eglNative.h"
+#endif
+
+EGLImageKHR GTFCreateEGLImage(int width, int height,
+ GLenum format, GLenum type) {
+ PFNEGLCREATEIMAGEKHRPROC egl_create_image_khr_;
+ egl_create_image_khr_ = reinterpret_cast<PFNEGLCREATEIMAGEKHRPROC>
+ (eglGetProcAddress("eglCreateImageKHR"));
+
+ static const EGLint attrib[] = {
+ EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ EGL_GL_TEXTURE_LEVEL_KHR, 0,
+ EGL_NONE
+ };
+
+ if (format != GL_RGBA && format != GL_RGB)
+ return static_cast<EGLImageKHR>(NULL);
+
+ if (type != GL_UNSIGNED_BYTE)
+ return static_cast<EGLImageKHR>(NULL);
+
+ GLuint texture;
+ glGenTextures(1, &texture);
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ format,
+ width,
+ height,
+ 0,
+ format,
+ type,
+ NULL);
+
+ // Disable mip-maps because we do not require it.
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ if(glGetError() != GL_NO_ERROR)
+ return static_cast<EGLImageKHR>(NULL);
+
+ EGLImageKHR egl_image =
+ egl_create_image_khr_(eglGetCurrentDisplay(),
+ eglGetCurrentContext(),
+ EGL_GL_TEXTURE_2D_KHR,
+ reinterpret_cast<EGLClientBuffer>(texture),
+ attrib);
+
+ if (eglGetError() == EGL_SUCCESS)
+ return egl_image;
+ else
+ return static_cast<EGLImageKHR>(NULL);
+}
+
+void GTFDestroyEGLImage(EGLImageKHR image) {
+ PFNEGLDESTROYIMAGEKHRPROC egl_destroy_image_khr_;
+ egl_destroy_image_khr_ = reinterpret_cast<PFNEGLDESTROYIMAGEKHRPROC>
+ (eglGetProcAddress("eglDestroyImageKHR"));
+
+ egl_destroy_image_khr_(eglGetCurrentDisplay(), image);
+}
+
+} // extern "C"
diff --git a/chromium/gpu/gles2_conform_support/native/main.cc b/chromium/gpu/gles2_conform_support/native/main.cc
new file mode 100644
index 00000000000..cb5617ad1eb
--- /dev/null
+++ b/chromium/gpu/gles2_conform_support/native/main.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#if defined(OS_MACOSX)
+#include "base/mac/scoped_nsautorelease_pool.h"
+#endif
+#include "ui/gl/gl_surface.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/gfx/gtk_util.h"
+#endif
+
+extern "C" {
+#if defined(GLES2_CONFORM_SUPPORT_ONLY)
+#include "gpu/gles2_conform_support/gtf/gtf_stubs.h"
+#else
+#include "third_party/gles2_conform/GTF_ES/glsl/GTF/Source/GTFMain.h"
+#endif
+}
+
+int main(int argc, char *argv[]) {
+ base::AtExitManager at_exit;
+ CommandLine::Init(argc, argv);
+ base::MessageLoopForUI message_loop;
+
+#if defined(OS_MACOSX)
+ base::mac::ScopedNSAutoreleasePool pool;
+#endif
+#if defined(TOOLKIT_GTK)
+ gfx::GtkInitFromCommandLine(*CommandLine::ForCurrentProcess());
+#endif
+
+ GTFMain(argc, argv);
+
+ return 0;
+}
+
diff --git a/chromium/gpu/gpu.gyp b/chromium/gpu/gpu.gyp
new file mode 100644
index 00000000000..316aa914422
--- /dev/null
+++ b/chromium/gpu/gpu.gyp
@@ -0,0 +1,551 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'nacl_win64_target': 0,
+ },
+ 'includes': [
+ 'gpu_common.gypi',
+ ],
+ 'targets': [
+ {
+ # Library emulates GLES2 using command_buffers.
+ 'target_name': 'gles2_implementation',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ '../ui/gl/gl.gyp:gl',
+ '../ui/ui.gyp:ui',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'gles2_cmd_helper',
+ ],
+ 'defines': [
+ 'GLES2_IMPL_IMPLEMENTATION',
+ ],
+ 'sources': [
+ '<@(gles2_implementation_source_files)',
+ 'command_buffer/client/gl_in_process_context.h',
+ 'command_buffer/client/gl_in_process_context.cc',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ # Library emulates GLES2 using command_buffers.
+ 'target_name': 'gles2_implementation_client_side_arrays',
+ 'type': '<(component)',
+ 'defines': [
+ 'GLES2_IMPL_IMPLEMENTATION',
+ 'GLES2_SUPPORT_CLIENT_SIDE_ARRAYS=1',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ '../ui/gl/gl.gyp:gl',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'gles2_cmd_helper',
+ ],
+ 'sources': [
+ '<@(gles2_implementation_source_files)',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
+ # Library emulates GLES2 using command_buffers.
+ 'target_name': 'gles2_implementation_client_side_arrays_no_check',
+ 'type': '<(component)',
+ 'defines': [
+ 'GLES2_IMPL_IMPLEMENTATION',
+ 'GLES2_SUPPORT_CLIENT_SIDE_ARRAYS=1',
+ 'GLES2_CONFORMANCE_TESTS=1',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'gles2_cmd_helper',
+ ],
+ 'sources': [
+ '<@(gles2_implementation_source_files)',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
+ # Stub to expose gles2_implemenation in C instead of C++.
+ # so GLES2 C programs can work with no changes.
+ 'target_name': 'gles2_c_lib',
+ 'type': '<(component)',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'command_buffer_client',
+ 'gles2_implementation',
+ ],
+ 'defines': [
+ 'GLES2_C_LIB_IMPLEMENTATION',
+ ],
+ 'sources': [
+ '<@(gles2_c_lib_source_files)',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ # Same as gles2_c_lib except with no parameter checking. Required for
+ # OpenGL ES 2.0 conformance tests.
+ 'target_name': 'gles2_c_lib_nocheck',
+ 'type': '<(component)',
+ 'defines': [
+ 'GLES2_C_LIB_IMPLEMENTATION',
+ 'GLES2_CONFORMANCE_TESTS=1',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'command_buffer_client',
+ 'gles2_implementation_client_side_arrays_no_check',
+ ],
+ 'sources': [
+ '<@(gles2_c_lib_source_files)',
+ ],
+ },
+ {
+ 'target_name': 'gpu_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ '../third_party/angle_dx11/src/build_angle.gyp:translator_glsl',
+ '../ui/gl/gl.gyp:gl',
+ '../ui/ui.gyp:ui',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'command_buffer_client',
+ 'command_buffer_common',
+ 'command_buffer_service',
+ 'gpu',
+ 'gpu_unittest_utils',
+ 'gles2_implementation_client_side_arrays',
+ 'gles2_cmd_helper',
+ ],
+ 'defines': [
+ 'GLES2_C_LIB_IMPLEMENTATION',
+ ],
+ 'sources': [
+ '<@(gles2_c_lib_source_files)',
+ 'command_buffer/client/buffer_tracker_unittest.cc',
+ 'command_buffer/client/client_test_helper.cc',
+ 'command_buffer/client/client_test_helper.h',
+ 'command_buffer/client/cmd_buffer_helper_test.cc',
+ 'command_buffer/client/fenced_allocator_test.cc',
+ 'command_buffer/client/gles2_interface_stub.cc',
+ 'command_buffer/client/gles2_interface_stub.h',
+ 'command_buffer/client/gles2_implementation_unittest.cc',
+ 'command_buffer/client/mapped_memory_unittest.cc',
+ 'command_buffer/client/query_tracker_unittest.cc',
+ 'command_buffer/client/program_info_manager_unittest.cc',
+ 'command_buffer/client/ring_buffer_test.cc',
+ 'command_buffer/client/transfer_buffer_unittest.cc',
+ 'command_buffer/client/vertex_array_object_manager_unittest.cc',
+ 'command_buffer/common/bitfield_helpers_test.cc',
+ 'command_buffer/common/command_buffer_mock.cc',
+ 'command_buffer/common/command_buffer_mock.h',
+ 'command_buffer/common/command_buffer_shared_test.cc',
+ 'command_buffer/common/debug_marker_manager_unittest.cc',
+ 'command_buffer/common/gles2_cmd_format_test.cc',
+ 'command_buffer/common/gles2_cmd_format_test_autogen.h',
+ 'command_buffer/common/gles2_cmd_utils_unittest.cc',
+ 'command_buffer/common/id_allocator_test.cc',
+ 'command_buffer/common/trace_event.h',
+ 'command_buffer/common/unittest_main.cc',
+ 'command_buffer/service/async_pixel_transfer_delegate_mock.h',
+ 'command_buffer/service/async_pixel_transfer_delegate_mock.cc',
+ 'command_buffer/service/async_pixel_transfer_manager_mock.h',
+ 'command_buffer/service/async_pixel_transfer_manager_mock.cc',
+ 'command_buffer/service/buffer_manager_unittest.cc',
+ 'command_buffer/service/cmd_parser_test.cc',
+ 'command_buffer/service/command_buffer_service_unittest.cc',
+ 'command_buffer/service/common_decoder_unittest.cc',
+ 'command_buffer/service/context_group_unittest.cc',
+ 'command_buffer/service/feature_info_unittest.cc',
+ 'command_buffer/service/framebuffer_manager_unittest.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_1.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_2.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_3.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_base.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_base.h',
+ 'command_buffer/service/gl_surface_mock.cc',
+ 'command_buffer/service/gl_surface_mock.h',
+ 'command_buffer/service/gpu_scheduler_unittest.cc',
+ 'command_buffer/service/id_manager_unittest.cc',
+ 'command_buffer/service/mailbox_manager_unittest.cc',
+ 'command_buffer/service/memory_program_cache_unittest.cc',
+ 'command_buffer/service/mocks.cc',
+ 'command_buffer/service/mocks.h',
+ 'command_buffer/service/program_manager_unittest.cc',
+ 'command_buffer/service/query_manager_unittest.cc',
+ 'command_buffer/service/renderbuffer_manager_unittest.cc',
+ 'command_buffer/service/program_cache_unittest.cc',
+ 'command_buffer/service/shader_manager_unittest.cc',
+ 'command_buffer/service/shader_translator_unittest.cc',
+ 'command_buffer/service/stream_texture_mock.cc',
+ 'command_buffer/service/stream_texture_mock.h',
+ 'command_buffer/service/stream_texture_manager_mock.cc',
+ 'command_buffer/service/stream_texture_manager_mock.h',
+ 'command_buffer/service/test_helper.cc',
+ 'command_buffer/service/test_helper.h',
+ 'command_buffer/service/texture_manager_unittest.cc',
+ 'command_buffer/service/transfer_buffer_manager_unittest.cc',
+ 'command_buffer/service/vertex_attrib_manager_unittest.cc',
+ 'command_buffer/service/vertex_array_manager_unittest.cc',
+ 'config/gpu_blacklist_unittest.cc',
+ 'config/gpu_control_list_entry_unittest.cc',
+ 'config/gpu_control_list_machine_model_info_unittest.cc',
+ 'config/gpu_control_list_number_info_unittest.cc',
+ 'config/gpu_control_list_os_info_unittest.cc',
+ 'config/gpu_control_list_string_info_unittest.cc',
+ 'config/gpu_control_list_unittest.cc',
+ 'config/gpu_control_list_version_info_unittest.cc',
+ 'config/gpu_driver_bug_list_unittest.cc',
+ 'config/gpu_info_collector_unittest.cc',
+ 'config/gpu_info_unittest.cc',
+ 'config/gpu_switching_list_unittest.cc',
+ 'config/gpu_test_config_unittest.cc',
+ 'config/gpu_test_expectations_parser_unittest.cc',
+ 'config/gpu_util_unittest.cc',
+ ],
+ 'conditions': [
+ ['OS == "android" and gtest_target_type == "shared_library"', {
+ 'dependencies': [
+ '../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ # See http://crbug.com/162998#c4 for why this is needed.
+ ['OS=="linux" and linux_use_tcmalloc==1', {
+ 'dependencies': [
+ '../base/allocator/allocator.gyp:allocator',
+ ],
+ }],
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
+ 'target_name': 'gl_tests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ '../third_party/angle_dx11/src/build_angle.gyp:translator_glsl',
+ '../ui/ui.gyp:ui',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'command_buffer_client',
+ 'command_buffer_common',
+ 'command_buffer_service',
+ 'gpu',
+ 'gpu_unittest_utils',
+ 'gles2_implementation_client_side_arrays',
+ 'gles2_cmd_helper',
+ #'gl_unittests',
+ ],
+ 'defines': [
+ 'GLES2_C_LIB_IMPLEMENTATION',
+ 'GL_GLEXT_PROTOTYPES',
+ ],
+ 'sources': [
+ '<@(gles2_c_lib_source_files)',
+ 'command_buffer/tests/compressed_texture_test.cc',
+ 'command_buffer/tests/gl_bind_uniform_location_unittest.cc',
+ 'command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc',
+ 'command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc',
+ 'command_buffer/tests/gl_depth_texture_unittest.cc',
+ 'command_buffer/tests/gl_gpu_memory_buffer_unittests.cc',
+ 'command_buffer/tests/gl_lose_context_chromium_unittests.cc',
+ 'command_buffer/tests/gl_manager.cc',
+ 'command_buffer/tests/gl_manager.h',
+ 'command_buffer/tests/gl_pointcoord_unittest.cc',
+ 'command_buffer/tests/gl_program_unittests.cc',
+ 'command_buffer/tests/gl_query_unittests.cc',
+ 'command_buffer/tests/gl_readback_unittests.cc',
+ 'command_buffer/tests/gl_shared_resources_unittests.cc',
+ 'command_buffer/tests/gl_stream_draw_unittests.cc',
+ 'command_buffer/tests/gl_test_utils.cc',
+ 'command_buffer/tests/gl_test_utils.h',
+ 'command_buffer/tests/gl_tests_main.cc',
+ 'command_buffer/tests/gl_texture_mailbox_unittests.cc',
+ 'command_buffer/tests/gl_texture_storage_unittests.cc',
+ 'command_buffer/tests/gl_unittests.cc',
+ 'command_buffer/tests/gl_unittests_android.cc',
+ 'command_buffer/tests/gl_virtual_contexts_unittests.cc',
+ 'command_buffer/tests/occlusion_query_unittests.cc',
+ ],
+ 'conditions': [
+ ['OS == "android" and gtest_target_type == "shared_library"', {
+ 'dependencies': [
+ '../testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
+ 'target_name': 'gpu_unittest_utils',
+ 'type': 'static_library',
+ 'dependencies': [
+ '../testing/gmock.gyp:gmock',
+ '../testing/gtest.gyp:gtest',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ '../ui/gl/gl.gyp:gl_unittest_utils',
+ 'gpu',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'command_buffer/service/gles2_cmd_decoder_mock.cc',
+ 'command_buffer/service/error_state_mock.cc',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['component=="static_library"', {
+ 'targets': [
+ {
+ 'target_name': 'disk_cache_proto',
+ 'type': 'static_library',
+ 'sources': [ 'command_buffer/service/disk_cache_proto.proto' ],
+ 'variables': {
+ 'proto_in_dir': 'command_buffer/service',
+ 'proto_out_dir': 'gpu/command_buffer/service',
+ },
+ 'includes': [ '../build/protoc.gypi' ],
+ },
+ {
+ 'target_name': 'gpu',
+ 'type': 'none',
+ 'dependencies': [
+ 'command_buffer_client',
+ 'command_buffer_common',
+ 'command_buffer_service',
+ 'gles2_cmd_helper',
+ 'gpu_config',
+ 'gpu_ipc',
+ ],
+ 'sources': [
+ 'gpu_export.h',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ 'target_name': 'command_buffer_common',
+ 'type': 'static_library',
+ 'includes': [
+ 'command_buffer_common.gypi',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ ],
+ 'export_dependent_settings': [
+ '../base/base.gyp:base',
+ ],
+ },
+ {
+ # Library helps make GLES2 command buffers.
+ 'target_name': 'gles2_cmd_helper',
+ 'type': 'static_library',
+ 'includes': [
+ 'gles2_cmd_helper.gypi',
+ ],
+ 'dependencies': [
+ 'command_buffer_client',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ 'target_name': 'command_buffer_client',
+ 'type': 'static_library',
+ 'includes': [
+ 'command_buffer_client.gypi',
+ ],
+ 'dependencies': [
+ 'command_buffer_common',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ 'target_name': 'command_buffer_service',
+ 'type': 'static_library',
+ 'includes': [
+ 'command_buffer_service.gypi',
+ ],
+ 'dependencies': [
+ 'command_buffer_common',
+ 'disk_cache_proto',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ 'target_name': 'gpu_ipc',
+ 'type': 'static_library',
+ 'includes': [
+ 'gpu_ipc.gypi',
+ ],
+ 'dependencies': [
+ 'command_buffer_common',
+ ],
+ },
+ {
+ 'target_name': 'gpu_config',
+ 'type': 'static_library',
+ 'includes': [
+ 'gpu_config.gypi',
+ ],
+ },
+ ],
+ },
+ { # component != static_library
+ 'targets': [
+ {
+ 'target_name': 'disk_cache_proto',
+ 'type': 'static_library',
+ 'sources': [ 'command_buffer/service/disk_cache_proto.proto' ],
+ 'variables': {
+ 'proto_in_dir': 'command_buffer/service',
+ 'proto_out_dir': 'gpu/command_buffer/service',
+ },
+ 'includes': [ '../build/protoc.gypi' ],
+ },
+ {
+ 'target_name': 'gpu',
+ 'type': 'shared_library',
+ 'includes': [
+ 'command_buffer_client.gypi',
+ 'command_buffer_common.gypi',
+ 'command_buffer_service.gypi',
+ 'gles2_cmd_helper.gypi',
+ 'gpu_config.gypi',
+ 'gpu_ipc.gypi',
+ ],
+ 'defines': [
+ 'GPU_IMPLEMENTATION',
+ ],
+ 'sources': [
+ 'gpu_export.h',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base',
+ 'command_buffer/command_buffer.gyp:gles2_utils',
+ 'disk_cache_proto',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ 'target_name': 'command_buffer_common',
+ 'type': 'none',
+ 'dependencies': [
+ 'gpu',
+ ],
+ },
+ {
+ # Library helps make GLES2 command buffers.
+ 'target_name': 'gles2_cmd_helper',
+ 'type': 'none',
+ 'dependencies': [
+ 'gpu',
+ ],
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [4267, ],
+ },
+ {
+ 'target_name': 'command_buffer_client',
+ 'type': 'none',
+ 'dependencies': [
+ 'gpu',
+ ],
+ },
+ {
+ 'target_name': 'command_buffer_service',
+ 'type': 'none',
+ 'dependencies': [
+ 'gpu',
+ ],
+ },
+ {
+ 'target_name': 'gpu_ipc',
+ 'type': 'none',
+ 'dependencies': [
+ 'gpu',
+ ],
+ },
+ ],
+ }],
+ ['disable_nacl!=1 and OS=="win" and target_arch=="ia32"', {
+ 'targets': [
+ {
+ 'target_name': 'gpu_ipc_win64',
+ 'type': 'static_library',
+ 'variables': {
+ 'nacl_win64_target': 1,
+ },
+ 'includes': [
+ 'gpu_ipc.gypi',
+ ],
+ 'dependencies': [
+ '../base/base.gyp:base_nacl_win64',
+ '../ipc/ipc.gyp:ipc_win64',
+ ],
+ 'defines': [
+ '<@(nacl_win64_defines)',
+ 'GPU_IMPLEMENTATION',
+ ],
+ 'configurations': {
+ 'Common_Base': {
+ 'msvs_target_platform': 'x64',
+ },
+ },
+ },
+ ],
+ }],
+ ['OS == "android" and gtest_target_type == "shared_library"', {
+ 'targets': [
+ {
+ 'target_name': 'gl_tests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'gl_tests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'gl_tests',
+ 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)gl_tests<(SHARED_LIB_SUFFIX)',
+ },
+ 'includes': [
+ '../build/apk_test.gypi',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/gpu/gpu_common.gypi b/chromium/gpu/gpu_common.gypi
new file mode 100644
index 00000000000..da2be68476b
--- /dev/null
+++ b/chromium/gpu/gpu_common.gypi
@@ -0,0 +1,73 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ # These are defined here because we need to build this library twice. Once
+ # with extra parameter checking. Once with no parameter checking to be 100%
+ # OpenGL ES 2.0 compliant for the conformance tests.
+ 'gles2_c_lib_source_files': [
+ 'command_buffer/client/gles2_c_lib.cc',
+ 'command_buffer/client/gles2_c_lib_autogen.h',
+ 'command_buffer/client/gles2_c_lib_export.h',
+ 'command_buffer/client/gles2_lib.h',
+ 'command_buffer/client/gles2_lib.cc',
+ ],
+ # These are defined here because we need to build this library twice. Once
+ # with without support for client side arrays and once with for pepper and
+ # the OpenGL ES 2.0 compliant for the conformance tests.
+ 'gles2_implementation_source_files': [
+ 'command_buffer/client/buffer_tracker.cc',
+ 'command_buffer/client/buffer_tracker.h',
+ 'command_buffer/client/client_context_state.h',
+ 'command_buffer/client/client_context_state.cc',
+ 'command_buffer/client/client_context_state_autogen.h',
+ 'command_buffer/client/client_context_state_impl_autogen.h',
+ 'command_buffer/client/gles2_impl_export.h',
+ 'command_buffer/client/gles2_implementation_autogen.h',
+ 'command_buffer/client/gles2_implementation.cc',
+ 'command_buffer/client/gles2_implementation.h',
+ 'command_buffer/client/gles2_implementation_impl_autogen.h',
+ 'command_buffer/client/gles2_interface.h',
+ 'command_buffer/client/gles2_interface.cc',
+ 'command_buffer/client/gles2_trace_implementation_autogen.h',
+ 'command_buffer/client/gles2_trace_implementation.cc',
+ 'command_buffer/client/gles2_trace_implementation.h',
+ 'command_buffer/client/gles2_trace_implementation_impl_autogen.h',
+ 'command_buffer/client/gpu_memory_buffer_factory.h',
+ 'command_buffer/client/gpu_memory_buffer_tracker.cc',
+ 'command_buffer/client/gpu_memory_buffer_tracker.h',
+ 'command_buffer/client/image_factory.h',
+ 'command_buffer/client/program_info_manager.cc',
+ 'command_buffer/client/program_info_manager.h',
+ 'command_buffer/client/query_tracker.cc',
+ 'command_buffer/client/query_tracker.h',
+ 'command_buffer/client/share_group.cc',
+ 'command_buffer/client/share_group.h',
+ 'command_buffer/client/vertex_array_object_manager.cc',
+ 'command_buffer/client/vertex_array_object_manager.h',
+ ]
+ },
+ 'conditions': [
+ # Special target to wrap a gtest_target_type==shared_library
+ # gpu_unittests into an android apk for execution.
+ ['OS == "android" and gtest_target_type == "shared_library"', {
+ 'targets': [
+ {
+ 'target_name': 'gpu_unittests_apk',
+ 'type': 'none',
+ 'dependencies': [
+ 'gpu_unittests',
+ ],
+ 'variables': {
+ 'test_suite_name': 'gpu_unittests',
+ 'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)gpu_unittests<(SHARED_LIB_SUFFIX)',
+ },
+ 'includes': [ '../build/apk_test.gypi' ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/gpu/gpu_config.gypi b/chromium/gpu/gpu_config.gypi
new file mode 100644
index 00000000000..c95605b2713
--- /dev/null
+++ b/chromium/gpu/gpu_config.gypi
@@ -0,0 +1,77 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'dependencies': [
+ '../base/base.gyp:base',
+ '../third_party/re2/re2.gyp:re2',
+ '../ui/gl/gl.gyp:gl',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'config/dx_diag_node.cc',
+ 'config/dx_diag_node.h',
+ 'config/gpu_blacklist.cc',
+ 'config/gpu_blacklist.h',
+ 'config/gpu_control_list_jsons.h',
+ 'config/gpu_control_list.cc',
+ 'config/gpu_control_list.h',
+ 'config/gpu_driver_bug_list_json.cc',
+ 'config/gpu_driver_bug_list.cc',
+ 'config/gpu_driver_bug_list.h',
+ 'config/gpu_driver_bug_workaround_type.h',
+ 'config/gpu_dx_diagnostics_win.cc',
+ 'config/gpu_feature_type.h',
+ 'config/gpu_info.cc',
+ 'config/gpu_info.h',
+ 'config/gpu_info_collector_android.cc',
+ 'config/gpu_info_collector_mac.mm',
+ 'config/gpu_info_collector_ozone.cc',
+ 'config/gpu_info_collector_win.cc',
+ 'config/gpu_info_collector_x11.cc',
+ 'config/gpu_info_collector.cc',
+ 'config/gpu_info_collector.h',
+ 'config/gpu_performance_stats.h',
+ 'config/gpu_switching_list_json.cc',
+ 'config/gpu_switching_list.cc',
+ 'config/gpu_switching_list.h',
+ 'config/gpu_switching_option.h',
+ 'config/gpu_test_config.cc',
+ 'config/gpu_test_config.h',
+ 'config/gpu_test_expectations_parser.cc',
+ 'config/gpu_test_expectations_parser.h',
+ 'config/gpu_util.cc',
+ 'config/gpu_util.h',
+ 'config/software_rendering_list_json.cc',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'dependencies': [
+ '../third_party/libxml/libxml.gyp:libxml',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '-ldxguid.lib',
+ '-lsetupapi.lib',
+ ],
+ },
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ 'msvs_disabled_warnings': [ 4267, ],
+ }],
+ ['OS=="win" and branding=="Chrome"', {
+ 'sources': [
+ '../third_party/amd/AmdCfxPxExt.h',
+ '../third_party/amd/amd_videocard_info_win.cc',
+ ],
+ }],
+ ['OS=="linux" and use_x11==1', {
+ 'dependencies': [
+ '../build/linux/system.gyp:libpci',
+ '../third_party/libXNVCtrl/libXNVCtrl.gyp:libXNVCtrl',
+ ],
+ }],
+ ],
+}
diff --git a/chromium/gpu/gpu_export.h b/chromium/gpu/gpu_export.h
new file mode 100644
index 00000000000..69aea7b9305
--- /dev/null
+++ b/chromium/gpu/gpu_export.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_GPU_EXPORT_H_
+#define GPU_GPU_EXPORT_H_
+
+#if defined(COMPONENT_BUILD) && !defined(NACL_WIN64)
+#if defined(WIN32)
+
+#if defined(GPU_IMPLEMENTATION)
+#define GPU_EXPORT __declspec(dllexport)
+#else
+#define GPU_EXPORT __declspec(dllimport)
+#endif // defined(GPU_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(GPU_IMPLEMENTATION)
+#define GPU_EXPORT __attribute__((visibility("default")))
+#else
+#define GPU_EXPORT
+#endif
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define GPU_EXPORT
+#endif
+
+#endif // GPU_GPU_EXPORT_H_
diff --git a/chromium/gpu/gpu_ipc.gypi b/chromium/gpu/gpu_ipc.gypi
new file mode 100644
index 00000000000..2777e963b0c
--- /dev/null
+++ b/chromium/gpu/gpu_ipc.gypi
@@ -0,0 +1,35 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'dependencies': [
+ '../ipc/ipc.gyp:ipc',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ ],
+ 'include_dirs': [
+ '..',
+ ],
+ 'sources': [
+ 'ipc/command_buffer_proxy.h',
+ 'ipc/command_buffer_proxy.cc',
+ 'ipc/gpu_command_buffer_traits.cc',
+ 'ipc/gpu_command_buffer_traits.h',
+ ],
+ 'conditions': [
+ # This section applies to gpu_ipc_win64, used by the NaCl Win64 helper
+ # (nacl64.exe).
+ ['nacl_win64_target==1', {
+ # gpu_ipc_win64 must only link against the 64-bit ipc target.
+ 'dependencies!': [
+ '../ipc/ipc.gyp:ipc',
+ ],
+ # The NaCl Win64 build only needs the ParamTraits, so we exclude
+ # command_buffer_proxy.*.
+ 'sources!': [
+ 'ipc/command_buffer_proxy.h',
+ 'ipc/command_buffer_proxy.cc',
+ ],
+ }],
+ ],
+}
diff --git a/chromium/gpu/gpu_untrusted.gyp b/chromium/gpu/gpu_untrusted.gyp
new file mode 100644
index 00000000000..a1f755cc89b
--- /dev/null
+++ b/chromium/gpu/gpu_untrusted.gyp
@@ -0,0 +1,121 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ # nacl_win64_target is for building the trusted Win64 NaCl broker.
+ 'nacl_win64_target': 0,
+ },
+ 'includes': [
+ '../build/common_untrusted.gypi',
+ 'gpu_common.gypi',
+ ],
+ 'conditions': [
+ ['disable_nacl==0 and disable_nacl_untrusted==0', {
+ 'targets': [
+ {
+ 'target_name': 'gles2_implementation_untrusted',
+ 'type': 'none',
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libgles2_implementation_untrusted.a',
+ 'build_glibc': 0,
+ 'build_newlib': 1,
+ 'build_irt': 1,
+ },
+ 'defines': [
+ 'GLES2_IMPL_IMPLEMENTATION',
+ ],
+ 'sources': [
+ '<@(gles2_implementation_source_files)',
+ ],
+ 'dependencies': [
+ '../native_client/tools.gyp:prep_toolchain',
+ '../base/base_untrusted.gyp:base_untrusted',
+ '../third_party/khronos/khronos.gyp:khronos_headers',
+ 'command_buffer/command_buffer_untrusted.gyp:gles2_utils_untrusted',
+ 'gles2_cmd_helper_untrusted',
+ ],
+ },
+ {
+ 'target_name': 'command_buffer_common_untrusted',
+ 'type': 'none',
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libcommand_buffer_common_untrusted.a',
+ 'build_glibc': 0,
+ 'build_newlib': 1,
+ 'build_irt': 1,
+ },
+ 'includes': [
+ 'command_buffer_common.gypi',
+ ],
+ 'dependencies': [
+ '../native_client/tools.gyp:prep_toolchain',
+ '../base/base_untrusted.gyp:base_untrusted',
+ 'command_buffer/command_buffer_untrusted.gyp:gles2_utils_untrusted',
+ ],
+ },
+ {
+ 'target_name': 'gles2_cmd_helper_untrusted',
+ 'type': 'none',
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libgles2_cmd_helper_untrusted.a',
+ 'build_glibc': 0,
+ 'build_newlib': 1,
+ 'build_irt': 1,
+ },
+ 'includes': [
+ 'gles2_cmd_helper.gypi',
+ ],
+ 'dependencies': [
+ '../native_client/tools.gyp:prep_toolchain',
+ '../base/base_untrusted.gyp:base_untrusted',
+ 'command_buffer_client_untrusted',
+ ],
+ },
+ {
+ 'target_name': 'command_buffer_client_untrusted',
+ 'type': 'none',
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libcommand_buffer_client_untrusted.a',
+ 'build_glibc': 0,
+ 'build_newlib': 1,
+ 'build_irt': 1,
+ },
+ 'includes': [
+ 'command_buffer_client.gypi',
+ ],
+ 'dependencies': [
+ '../native_client/tools.gyp:prep_toolchain',
+ '../base/base_untrusted.gyp:base_untrusted',
+ 'command_buffer_common_untrusted',
+ ],
+ },
+ {
+ 'target_name': 'gpu_ipc_untrusted',
+ 'type': 'none',
+ 'variables': {
+ 'nacl_untrusted_build': 1,
+ 'nlib_target': 'libgpu_ipc_untrusted.a',
+ 'build_glibc': 0,
+ 'build_newlib': 1,
+ 'build_irt': 1,
+ },
+ 'includes': [
+ 'gpu_ipc.gypi',
+ ],
+ 'dependencies': [
+ '../native_client/tools.gyp:prep_toolchain',
+ '../base/base_untrusted.gyp:base_untrusted',
+ 'command_buffer_common_untrusted',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/chromium/gpu/ipc/DEPS b/chromium/gpu/ipc/DEPS
new file mode 100644
index 00000000000..9634ba4f06a
--- /dev/null
+++ b/chromium/gpu/ipc/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+ "+base",
+ "+ipc",
+]
diff --git a/chromium/gpu/ipc/command_buffer_proxy.cc b/chromium/gpu/ipc/command_buffer_proxy.cc
new file mode 100644
index 00000000000..7ed6b0b467a
--- /dev/null
+++ b/chromium/gpu/ipc/command_buffer_proxy.cc
@@ -0,0 +1,5 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/command_buffer_proxy.h"
diff --git a/chromium/gpu/ipc/command_buffer_proxy.h b/chromium/gpu/ipc/command_buffer_proxy.h
new file mode 100644
index 00000000000..d33eae467e0
--- /dev/null
+++ b/chromium/gpu/ipc/command_buffer_proxy.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_IPC_COMMAND_BUFFER_PROXY_H_
+#define GPU_IPC_COMMAND_BUFFER_PROXY_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/command_buffer/common/command_buffer_shared.h"
+#include "gpu/command_buffer/common/mailbox.h"
+
+// Client side proxy that forwards messages synchronously to a
+// CommandBufferStub.
+class GPU_EXPORT CommandBufferProxy : public gpu::CommandBuffer {
+ public:
+ typedef base::Callback<void(
+ const std::string& msg, int id)> GpuConsoleMessageCallback;
+
+ CommandBufferProxy() { }
+
+ virtual ~CommandBufferProxy() { }
+
+ virtual int GetRouteID() const = 0;
+
+ // Invoke the task when the channel has been flushed. Takes care of deleting
+ // the task whether the echo succeeds or not.
+ virtual bool Echo(const base::Closure& callback) = 0;
+
+ // For offscreen contexts, produces the front buffer into a newly created
+ // mailbox.
+ virtual bool ProduceFrontBuffer(const gpu::Mailbox& mailbox) = 0;
+
+ virtual void SetChannelErrorCallback(const base::Closure& callback) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CommandBufferProxy);
+};
+
+#endif // GPU_IPC_COMMAND_BUFFER_PROXY_H_
diff --git a/chromium/gpu/ipc/gpu_command_buffer_traits.cc b/chromium/gpu/ipc/gpu_command_buffer_traits.cc
new file mode 100644
index 00000000000..d9fc17d1660
--- /dev/null
+++ b/chromium/gpu/ipc/gpu_command_buffer_traits.cc
@@ -0,0 +1,63 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/ipc/gpu_command_buffer_traits.h"
+#include "gpu/command_buffer/common/mailbox.h"
+
+namespace IPC {
+
+void ParamTraits<gpu::CommandBuffer::State> ::Write(Message* m,
+ const param_type& p) {
+ WriteParam(m, p.num_entries);
+ WriteParam(m, p.get_offset);
+ WriteParam(m, p.put_offset);
+ WriteParam(m, p.token);
+ WriteParam(m, static_cast<int32>(p.error));
+ WriteParam(m, p.generation);
+}
+
+bool ParamTraits<gpu::CommandBuffer::State> ::Read(const Message* m,
+ PickleIterator* iter,
+ param_type* p) {
+ int32 temp;
+ if (ReadParam(m, iter, &p->num_entries) &&
+ ReadParam(m, iter, &p->get_offset) &&
+ ReadParam(m, iter, &p->put_offset) &&
+ ReadParam(m, iter, &p->token) &&
+ ReadParam(m, iter, &temp) &&
+ ReadParam(m, iter, &p->generation)) {
+ p->error = static_cast<gpu::error::Error>(temp);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+void ParamTraits<gpu::CommandBuffer::State> ::Log(const param_type& p,
+ std::string* l) {
+ l->append("<CommandBuffer::State>");
+}
+
+void ParamTraits<gpu::Mailbox>::Write(Message* m, const param_type& p) {
+ m->WriteBytes(p.name, sizeof(p.name));
+}
+
+bool ParamTraits<gpu::Mailbox>::Read(const Message* m,
+ PickleIterator* iter,
+ param_type* p) {
+ const char* bytes = NULL;
+ if (!m->ReadBytes(iter, &bytes, sizeof(p->name)))
+ return false;
+ DCHECK(bytes);
+ memcpy(p->name, bytes, sizeof(p->name));
+ return true;
+}
+
+void ParamTraits<gpu::Mailbox>::Log(const param_type& p, std::string* l) {
+ for (size_t i = 0; i < sizeof(p.name); ++i)
+ *l += base::StringPrintf("%02x", p.name[i]);
+}
+
+
+} // namespace IPC
diff --git a/chromium/gpu/ipc/gpu_command_buffer_traits.h b/chromium/gpu/ipc/gpu_command_buffer_traits.h
new file mode 100644
index 00000000000..6b2531f763a
--- /dev/null
+++ b/chromium/gpu/ipc/gpu_command_buffer_traits.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_IPC_GPU_PARAM_TRAITS_H_
+#define GPU_IPC_GPU_PARAM_TRAITS_H_
+
+#include "ipc/ipc_message_utils.h"
+#include "gpu/command_buffer/common/command_buffer.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+struct Mailbox;
+}
+
+namespace IPC {
+
+template <>
+struct GPU_EXPORT ParamTraits<gpu::CommandBuffer::State> {
+ typedef gpu::CommandBuffer::State param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+template<>
+struct GPU_EXPORT ParamTraits<gpu::Mailbox> {
+ typedef gpu::Mailbox param_type;
+ static void Write(Message* m, const param_type& p);
+ static bool Read(const Message* m, PickleIterator* iter, param_type* p);
+ static void Log(const param_type& p, std::string* l);
+};
+
+} // namespace IPC
+
+#endif // GPU_IPC_GPU_PARAM_TRAITS_H_
diff --git a/chromium/gpu/tools/compositor_model_bench/compositor_model_bench.cc b/chromium/gpu/tools/compositor_model_bench/compositor_model_bench.cc
new file mode 100644
index 00000000000..6c39981ec8f
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/compositor_model_bench.cc
@@ -0,0 +1,404 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This tool is used to benchmark the render model used by the compositor
+
+// Most of this file is derived from the source of the tile_render_bench tool,
+// and has been changed to support running a sequence of independent
+// simulations for our different render models and test cases.
+
+#include <stdio.h>
+#include <sys/dir.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <X11/keysym.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+#include <queue>
+#include <string>
+#include <vector>
+
+#include "base/at_exit.h"
+#include "base/basictypes.h"
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/file_enumerator.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/time/time.h"
+
+#include "gpu/tools/compositor_model_bench/render_model_utils.h"
+#include "gpu/tools/compositor_model_bench/render_models.h"
+#include "gpu/tools/compositor_model_bench/render_tree.h"
+
+
+using base::TimeTicks;
+using file_util::CloseFile;
+using base::DirectoryExists;
+using file_util::OpenFile;
+using base::PathExists;
+using std::queue;
+using std::string;
+
+struct SimulationSpecification {
+ string simulation_name;
+ base::FilePath input_path;
+ RenderModel model_under_test;
+ TimeTicks simulation_start_time;
+ int frames_rendered;
+};
+
+// Forward declarations
+class Simulator;
+void _process_events(Simulator* sim);
+void _update_loop(Simulator* sim);
+
+class Simulator {
+ public:
+ Simulator(int seconds_per_test, const base::FilePath& output_path)
+ : current_sim_(NULL),
+ output_path_(output_path),
+ seconds_per_test_(seconds_per_test),
+ weak_factory_(this),
+ display_(NULL),
+ window_(0),
+ gl_context_(NULL),
+ window_width_(WINDOW_WIDTH),
+ window_height_(WINDOW_HEIGHT) {
+ }
+
+ ~Simulator() {
+ // Cleanup GL.
+ glXMakeCurrent(display_, 0, NULL);
+ glXDestroyContext(display_, gl_context_);
+
+ // Destroy window and display.
+ XDestroyWindow(display_, window_);
+ XCloseDisplay(display_);
+ }
+
+ void QueueTest(const base::FilePath& path) {
+ SimulationSpecification spec;
+
+ // To get a std::string, we'll try to get an ASCII simulation name.
+ // If the name of the file wasn't ASCII, this will give an empty simulation
+ // name, but that's not really harmful (we'll still warn about it though.)
+ spec.simulation_name = path.BaseName().RemoveExtension().MaybeAsASCII();
+ if (spec.simulation_name == "") {
+ LOG(WARNING) << "Simulation for path " << path.LossyDisplayName() <<
+ " will have a blank simulation name, since the file name isn't ASCII";
+ }
+ spec.input_path = path;
+ spec.model_under_test = ForwardRenderModel;
+ spec.frames_rendered = 0;
+
+ sims_remaining_.push(spec);
+
+ // The following lines are commented out pending the addition
+ // of the new render model once this version gets fully checked in.
+ //
+ // spec.model_under_test = KDTreeRenderModel;
+ // sims_remaining_.push(spec);
+ }
+
+ void Run() {
+ if (!sims_remaining_.size()) {
+ LOG(WARNING) << "No configuration files loaded.";
+ return;
+ }
+
+ base::AtExitManager at_exit;
+ base::MessageLoop loop;
+ if (!InitX11() || !InitGLContext()) {
+ LOG(FATAL) << "Failed to set up GUI.";
+ }
+
+ InitBuffers();
+
+ LOG(INFO) << "Running " << sims_remaining_.size() << " simulations.";
+
+ loop.PostTask(FROM_HERE,
+ base::Bind(&Simulator::ProcessEvents,
+ weak_factory_.GetWeakPtr()));
+ loop.Run();
+ }
+
+ void ProcessEvents() {
+ // Consume all the X events.
+ while (XPending(display_)) {
+ XEvent e;
+ XNextEvent(display_, &e);
+ switch (e.type) {
+ case Expose:
+ UpdateLoop();
+ break;
+ case ConfigureNotify:
+ Resize(e.xconfigure.width, e.xconfigure.height);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void UpdateLoop() {
+ if (UpdateTestStatus())
+ UpdateCurrentTest();
+ }
+
+ private:
+ // Initialize X11. Returns true if successful. This method creates the
+ // X11 window. Further initialization is done in X11VideoRenderer.
+ bool InitX11() {
+ display_ = XOpenDisplay(NULL);
+ if (!display_) {
+ LOG(FATAL) << "Cannot open display";
+ return false;
+ }
+
+ // Get properties of the screen.
+ int screen = DefaultScreen(display_);
+ int root_window = RootWindow(display_, screen);
+
+ // Creates the window.
+ window_ = XCreateSimpleWindow(display_,
+ root_window,
+ 1,
+ 1,
+ window_width_,
+ window_height_,
+ 0,
+ BlackPixel(display_, screen),
+ BlackPixel(display_, screen));
+ XStoreName(display_, window_, "Compositor Model Bench");
+
+ XSelectInput(display_, window_,
+ ExposureMask | KeyPressMask | StructureNotifyMask);
+ XMapWindow(display_, window_);
+
+ XResizeWindow(display_, window_, WINDOW_WIDTH, WINDOW_HEIGHT);
+
+ return true;
+ }
+
+ // Initialize the OpenGL context.
+ bool InitGLContext() {
+ if (!InitializeGLBindings(gfx::kGLImplementationDesktopGL)) {
+ LOG(FATAL) << "InitializeGLBindings failed";
+ return false;
+ }
+
+ XWindowAttributes attributes;
+ XGetWindowAttributes(display_, window_, &attributes);
+ XVisualInfo visual_info_template;
+ visual_info_template.visualid = XVisualIDFromVisual(attributes.visual);
+ int visual_info_count = 0;
+ XVisualInfo* visual_info_list = XGetVisualInfo(display_, VisualIDMask,
+ &visual_info_template,
+ &visual_info_count);
+
+ for (int i = 0; i < visual_info_count && !gl_context_; ++i) {
+ gl_context_ = glXCreateContext(display_, visual_info_list + i, 0,
+ True /* Direct rendering */);
+ }
+
+ XFree(visual_info_list);
+ if (!gl_context_) {
+ return false;
+ }
+
+ if (!glXMakeCurrent(display_, window_, gl_context_)) {
+ glXDestroyContext(display_, gl_context_);
+ gl_context_ = NULL;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool InitializeNextTest() {
+ SimulationSpecification& spec = sims_remaining_.front();
+ LOG(INFO) << "Initializing test for " << spec.simulation_name <<
+ "(" << ModelToString(spec.model_under_test) << ")";
+ const base::FilePath& path = spec.input_path;
+
+ RenderNode* root = NULL;
+ if (!(root = BuildRenderTreeFromFile(path))) {
+ LOG(ERROR) << "Couldn't parse test configuration file " <<
+ path.LossyDisplayName();
+ return false;
+ }
+
+ current_sim_ = ConstructSimulationModel(spec.model_under_test,
+ root,
+ window_width_,
+ window_height_);
+ if (!current_sim_)
+ return false;
+
+ return true;
+ }
+
+ void CleanupCurrentTest() {
+ LOG(INFO) << "Finished test " << sims_remaining_.front().simulation_name;
+
+ delete current_sim_;
+ current_sim_ = NULL;
+ }
+
+ void UpdateCurrentTest() {
+ ++sims_remaining_.front().frames_rendered;
+
+ if (current_sim_)
+ current_sim_->Update();
+
+ glXSwapBuffers(display_, window_);
+
+ XExposeEvent ev = { Expose, 0, 1, display_, window_,
+ 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0 };
+ XSendEvent(display_,
+ window_,
+ False,
+ ExposureMask,
+ reinterpret_cast<XEvent*>(&ev));
+
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&Simulator::UpdateLoop, weak_factory_.GetWeakPtr()));
+ }
+
+ void DumpOutput() {
+ LOG(INFO) << "Successfully ran " << sims_completed_.size() << " tests";
+
+ FILE* f = OpenFile(output_path_, "w");
+
+ if (!f) {
+ LOG(ERROR) << "Failed to open output file " <<
+ output_path_.LossyDisplayName();
+ exit(-1);
+ }
+
+ LOG(INFO) << "Writing results to " << output_path_.LossyDisplayName();
+
+ fputs("{\n\t\"results\": [\n", f);
+
+ while (sims_completed_.size()) {
+ SimulationSpecification i = sims_completed_.front();
+ fprintf(f,
+ "\t\t{\"simulation_name\":\"%s\",\n"
+ "\t\t\t\"render_model\":\"%s\",\n"
+ "\t\t\t\"frames_drawn\":%d\n"
+ "\t\t},\n",
+ i.simulation_name.c_str(),
+ ModelToString(i.model_under_test),
+ i.frames_rendered);
+ sims_completed_.pop();
+ }
+
+ fputs("\t]\n}", f);
+ CloseFile(f);
+ }
+
+ bool UpdateTestStatus() {
+ TimeTicks& current_start = sims_remaining_.front().simulation_start_time;
+ base::TimeDelta d = TimeTicks::Now() - current_start;
+ if (!current_start.is_null() && d.InSeconds() > seconds_per_test_) {
+ CleanupCurrentTest();
+ sims_completed_.push(sims_remaining_.front());
+ sims_remaining_.pop();
+ }
+
+ if (sims_remaining_.size() &&
+ sims_remaining_.front().simulation_start_time.is_null()) {
+ while (sims_remaining_.size() && !InitializeNextTest()) {
+ sims_remaining_.pop();
+ }
+ if (sims_remaining_.size()) {
+ sims_remaining_.front().simulation_start_time = TimeTicks::Now();
+ }
+ }
+
+ if (!sims_remaining_.size()) {
+ DumpOutput();
+ base::MessageLoop::current()->Quit();
+ return false;
+ }
+
+ return true;
+ }
+
+ void Resize(int width, int height) {
+ window_width_ = width;
+ window_height_ = height;
+ if (current_sim_)
+ current_sim_->Resize(window_width_, window_height_);
+ }
+
+ // Simulation task list for this execution
+ RenderModelSimulator* current_sim_;
+ queue<SimulationSpecification> sims_remaining_;
+ queue<SimulationSpecification> sims_completed_;
+ base::FilePath output_path_;
+ // Amount of time to run each simulation
+ int seconds_per_test_;
+ // GUI data
+ base::WeakPtrFactory<Simulator> weak_factory_;
+ Display* display_;
+ Window window_;
+ GLXContext gl_context_;
+ int window_width_;
+ int window_height_;
+};
+
+int main(int argc, char* argv[]) {
+ CommandLine::Init(argc, argv);
+ const CommandLine* cl = CommandLine::ForCurrentProcess();
+
+ if (argc != 3 && argc != 4) {
+ LOG(INFO) << "Usage: \n" <<
+ cl->GetProgram().BaseName().LossyDisplayName() <<
+ "--in=[input path] --out=[output path] (duration=[seconds])\n"
+ "The input path specifies either a JSON configuration file or\n"
+ "a directory containing only these files\n"
+ "(if a directory is specified, simulations will be run for\n"
+ "all files in that directory and subdirectories)\n"
+ "The optional duration parameter specifies the (integer)\n"
+ "number of seconds to be spent on each simulation.\n"
+ "Performance measurements for the specified simulation(s) are\n"
+ "written to the output path.";
+ return -1;
+ }
+
+ int seconds_per_test = 1;
+ if (cl->HasSwitch("duration")) {
+ seconds_per_test = atoi(cl->GetSwitchValueASCII("duration").c_str());
+ }
+
+ Simulator sim(seconds_per_test, cl->GetSwitchValuePath("out"));
+ base::FilePath inPath = cl->GetSwitchValuePath("in");
+
+ if (!PathExists(inPath)) {
+ LOG(FATAL) << "Path does not exist: " << inPath.LossyDisplayName();
+ return -1;
+ }
+
+ if (DirectoryExists(inPath)) {
+ LOG(INFO) << "(input path is a directory)";
+ base::FileEnumerator dirItr(inPath, true, base::FileEnumerator::FILES);
+ for (base::FilePath f = dirItr.Next(); !f.empty(); f = dirItr.Next()) {
+ sim.QueueTest(f);
+ }
+ } else {
+ LOG(INFO) << "(input path is a file)";
+ sim.QueueTest(inPath);
+ }
+
+ sim.Run();
+
+ return 0;
+}
diff --git a/chromium/gpu/tools/compositor_model_bench/forward_render_model.cc b/chromium/gpu/tools/compositor_model_bench/forward_render_model.cc
new file mode 100644
index 00000000000..c570bf3c5b4
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/forward_render_model.cc
@@ -0,0 +1,70 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/tools/compositor_model_bench/forward_render_model.h"
+
+#include <cstdlib>
+#include <vector>
+
+#include "gpu/tools/compositor_model_bench/render_model_utils.h"
+
+using std::vector;
+
+class ForwardRenderNodeVisitor : public RenderNodeVisitor {
+ public:
+ ForwardRenderNodeVisitor() {}
+
+ virtual void BeginVisitRenderNode(RenderNode* v) OVERRIDE {
+ NOTREACHED();
+ }
+
+ virtual void BeginVisitCCNode(CCNode* v) OVERRIDE {
+ if (!v->drawsContent())
+ return;
+ ConfigAndActivateShaderForNode(v);
+ DrawQuad(v->width(), v->height());
+ }
+
+ virtual void BeginVisitContentLayerNode(ContentLayerNode* l) OVERRIDE {
+ if (!l->drawsContent())
+ return;
+ ConfigAndActivateShaderForTiling(l);
+ // Now that we capture root layer tiles, a layer without tiles
+ // should not get drawn.
+ for (size_t n = 0; n < l->num_tiles(); ++n) {
+ const Tile* i = l->tile(n);
+ DrawTileQuad(i->texID, i->x, i->y);
+ }
+ }
+};
+
+ForwardRenderSimulator::ForwardRenderSimulator(RenderNode* root,
+ int window_width,
+ int window_height)
+ : RenderModelSimulator(root) {
+ textures_.reset(new TextureGenerator(root));
+ visitor_.reset(new ForwardRenderNodeVisitor());
+ glViewport(0, 0, window_width, window_height);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+}
+
+ForwardRenderSimulator::~ForwardRenderSimulator() {
+}
+
+void ForwardRenderSimulator::Update() {
+ glClearColor(0, 0, 1, 1);
+ glColorMask(true, true, true, true);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glColorMask(true, true, true, false);
+ BeginFrame();
+ root_->Accept(visitor_.get());
+}
+
+void ForwardRenderSimulator::Resize(int width, int height) {
+ glViewport(0, 0, width, height);
+}
+
diff --git a/chromium/gpu/tools/compositor_model_bench/forward_render_model.h b/chromium/gpu/tools/compositor_model_bench/forward_render_model.h
new file mode 100644
index 00000000000..76590fecdd9
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/forward_render_model.h
@@ -0,0 +1,34 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A render model simulator for the original model used in Chromium.
+
+#ifndef GPU_TOOLS_COMPOSITOR_MODEL_BENCH_FORWARD_RENDER_MODEL_H_
+#define GPU_TOOLS_COMPOSITOR_MODEL_BENCH_FORWARD_RENDER_MODEL_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/tools/compositor_model_bench/render_model_utils.h"
+#include "gpu/tools/compositor_model_bench/render_models.h"
+
+class ForwardRenderNodeVisitor;
+
+class ForwardRenderSimulator : public RenderModelSimulator {
+ public:
+ explicit ForwardRenderSimulator(RenderNode* root,
+ int window_width,
+ int window_height);
+ virtual ~ForwardRenderSimulator() OVERRIDE;
+ virtual void Update() OVERRIDE;
+ virtual void Resize(int width, int height) OVERRIDE;
+
+ private:
+ scoped_ptr<ForwardRenderNodeVisitor> visitor_;
+ scoped_ptr<TextureGenerator> textures_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(ForwardRenderSimulator);
+};
+
+#endif // GPU_TOOLS_COMPOSITOR_MODEL_BENCH_FORWARD_RENDER_MODEL_H_
+
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT0.txt.json
new file mode 100644
index 00000000000..2ec423f17ad
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 10}, {"y": 0, "x": 1, "texID": 24}, {"y": 0, "x": 2, "texID": 28}, {"y": 0, "x": 3, "texID": 25}, {"y": 0, "x": 4, "texID": 15}, {"y": 0, "x": 5, "texID": 3}, {"y": 0, "x": 6, "texID": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 431.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 416.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 691.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 690.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 688.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 688.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 690.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 688.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 688.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 691.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 685.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 677.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 691.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT1.txt.json
new file mode 100644
index 00000000000..2ec423f17ad
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 10}, {"y": 0, "x": 1, "texID": 24}, {"y": 0, "x": 2, "texID": 28}, {"y": 0, "x": 3, "texID": 25}, {"y": 0, "x": 4, "texID": 15}, {"y": 0, "x": 5, "texID": 3}, {"y": 0, "x": 6, "texID": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 431.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 416.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 691.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 690.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 688.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 688.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 690.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 688.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 688.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 691.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 685.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 677.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 691.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT10.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT10.txt.json
new file mode 100644
index 00000000000..845e5b11175
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT10.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 2, "x": 0}, {"y": 2, "x": 1}, {"y": 2, "x": 2}, {"y": 2, "x": 3}, {"y": 2, "x": 4}, {"y": 2, "x": 5}, {"y": 2, "x": 6}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 5}, {"y": 6, "x": 2, "texID": 18}, {"y": 6, "x": 3, "texID": 9}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 21}, {"y": 6, "x": 6, "texID": 20}, {"y": 7, "x": 0, "texID": 14}, {"y": 7, "x": 1, "texID": 16}, {"y": 7, "x": 2, "texID": 26}, {"y": 7, "x": 3, "texID": 23}, {"y": 7, "x": 4, "texID": 22}, {"y": 7, "x": 5, "texID": 27}, {"y": 7, "x": 6, "texID": 2}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -582.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -596.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -322.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, -322.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, -322.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, -322.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, -323.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, -324.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, -324.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -323.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -325.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -325.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, -321.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -328.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -336.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -322.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 367.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 367.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1013.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT11.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT11.txt.json
new file mode 100644
index 00000000000..845e5b11175
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT11.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 2, "x": 0}, {"y": 2, "x": 1}, {"y": 2, "x": 2}, {"y": 2, "x": 3}, {"y": 2, "x": 4}, {"y": 2, "x": 5}, {"y": 2, "x": 6}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 5}, {"y": 6, "x": 2, "texID": 18}, {"y": 6, "x": 3, "texID": 9}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 21}, {"y": 6, "x": 6, "texID": 20}, {"y": 7, "x": 0, "texID": 14}, {"y": 7, "x": 1, "texID": 16}, {"y": 7, "x": 2, "texID": 26}, {"y": 7, "x": 3, "texID": 23}, {"y": 7, "x": 4, "texID": 22}, {"y": 7, "x": 5, "texID": 27}, {"y": 7, "x": 6, "texID": 2}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -582.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -596.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -322.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, -322.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, -322.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, -322.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, -323.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, -324.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, -324.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -323.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -325.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -325.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, -321.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -328.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -336.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -322.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -580.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 367.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 367.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1013.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT12.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT12.txt.json
new file mode 100644
index 00000000000..350cdf61917
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT12.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 2, "x": 0}, {"y": 2, "x": 1}, {"y": 2, "x": 2}, {"y": 2, "x": 3}, {"y": 2, "x": 4}, {"y": 2, "x": 5}, {"y": 2, "x": 6}, {"y": 3, "x": 0}, {"y": 3, "x": 1}, {"y": 3, "x": 2}, {"y": 3, "x": 3}, {"y": 3, "x": 4}, {"y": 3, "x": 5}, {"y": 3, "x": 6}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 5}, {"y": 6, "x": 2, "texID": 18}, {"y": 6, "x": 3, "texID": 9}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 21}, {"y": 6, "x": 6, "texID": 20}, {"y": 7, "x": 0, "texID": 14}, {"y": 7, "x": 1, "texID": 16}, {"y": 7, "x": 2, "texID": 26}, {"y": 7, "x": 3, "texID": 23}, {"y": 7, "x": 4, "texID": 22}, {"y": 7, "x": 5, "texID": 27}, {"y": 7, "x": 6, "texID": 2}, {"y": 8, "x": 0, "texID": 8}, {"y": 8, "x": 1, "texID": 48}, {"y": 8, "x": 2, "texID": 15}, {"y": 8, "x": 3, "texID": 19}, {"y": 8, "x": 4, "texID": 24}, {"y": 8, "x": 5, "texID": 10}, {"y": 8, "x": 6, "texID": 47}, {"y": 9, "x": 0, "texID": 6}, {"y": 9, "x": 1, "texID": 1}, {"y": 9, "x": 2, "texID": 46}, {"y": 9, "x": 3, "texID": 4}, {"y": 9, "x": 4, "texID": 17}, {"y": 9, "x": 5, "texID": 44}, {"y": 9, "x": 6, "texID": 25}, {"y": 10, "x": 0, "texID": 3}, {"y": 10, "x": 1, "texID": 7}, {"y": 10, "x": 2, "texID": 50}, {"y": 10, "x": 3, "texID": 28}, {"y": 10, "x": 4, "texID": 12}, {"y": 10, "x": 5, "texID": 43}, {"y": 10, "x": 6, "texID": 49}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}, {"y": 12, "x": 0}, {"y": 12, "x": 1}, {"y": 12, "x": 2}, {"y": 12, "x": 3}, {"y": 12, "x": 4}, {"y": 12, "x": 5}, {"y": 12, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1336.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1350.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1076.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, -1076.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, -1076.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, -1076.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, -1077.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, -1078.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, -1078.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1077.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1079.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1079.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, -1075.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1082.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1090.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1076.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, -387.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, -387.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1767.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT13.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT13.txt.json
new file mode 100644
index 00000000000..350cdf61917
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT13.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 2, "x": 0}, {"y": 2, "x": 1}, {"y": 2, "x": 2}, {"y": 2, "x": 3}, {"y": 2, "x": 4}, {"y": 2, "x": 5}, {"y": 2, "x": 6}, {"y": 3, "x": 0}, {"y": 3, "x": 1}, {"y": 3, "x": 2}, {"y": 3, "x": 3}, {"y": 3, "x": 4}, {"y": 3, "x": 5}, {"y": 3, "x": 6}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 5}, {"y": 6, "x": 2, "texID": 18}, {"y": 6, "x": 3, "texID": 9}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 21}, {"y": 6, "x": 6, "texID": 20}, {"y": 7, "x": 0, "texID": 14}, {"y": 7, "x": 1, "texID": 16}, {"y": 7, "x": 2, "texID": 26}, {"y": 7, "x": 3, "texID": 23}, {"y": 7, "x": 4, "texID": 22}, {"y": 7, "x": 5, "texID": 27}, {"y": 7, "x": 6, "texID": 2}, {"y": 8, "x": 0, "texID": 8}, {"y": 8, "x": 1, "texID": 48}, {"y": 8, "x": 2, "texID": 15}, {"y": 8, "x": 3, "texID": 19}, {"y": 8, "x": 4, "texID": 24}, {"y": 8, "x": 5, "texID": 10}, {"y": 8, "x": 6, "texID": 47}, {"y": 9, "x": 0, "texID": 6}, {"y": 9, "x": 1, "texID": 1}, {"y": 9, "x": 2, "texID": 46}, {"y": 9, "x": 3, "texID": 4}, {"y": 9, "x": 4, "texID": 17}, {"y": 9, "x": 5, "texID": 44}, {"y": 9, "x": 6, "texID": 25}, {"y": 10, "x": 0, "texID": 3}, {"y": 10, "x": 1, "texID": 7}, {"y": 10, "x": 2, "texID": 50}, {"y": 10, "x": 3, "texID": 28}, {"y": 10, "x": 4, "texID": 12}, {"y": 10, "x": 5, "texID": 43}, {"y": 10, "x": 6, "texID": 49}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}, {"y": 12, "x": 0}, {"y": 12, "x": 1}, {"y": 12, "x": 2}, {"y": 12, "x": 3}, {"y": 12, "x": 4}, {"y": 12, "x": 5}, {"y": 12, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1336.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1350.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1076.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, -1076.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, -1076.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, -1076.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, -1077.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, -1078.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, -1078.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1077.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1079.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1079.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, -1075.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1082.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1090.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1076.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -1334.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, -387.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, -387.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -1767.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT2.txt.json
new file mode 100644
index 00000000000..cb4b95abf73
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 10}, {"y": 0, "x": 1, "texID": 24}, {"y": 0, "x": 2, "texID": 28}, {"y": 0, "x": 3, "texID": 25}, {"y": 0, "x": 4, "texID": 15}, {"y": 0, "x": 5, "texID": 3}, {"y": 0, "x": 6, "texID": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 325.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 310.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 585.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 584.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 584.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 584.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 584.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 582.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 582.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 584.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 582.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 582.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 585.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 579.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 571.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 585.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1274.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1274.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -106.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT3.txt.json
new file mode 100644
index 00000000000..cb4b95abf73
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 10}, {"y": 0, "x": 1, "texID": 24}, {"y": 0, "x": 2, "texID": 28}, {"y": 0, "x": 3, "texID": 25}, {"y": 0, "x": 4, "texID": 15}, {"y": 0, "x": 5, "texID": 3}, {"y": 0, "x": 6, "texID": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 325.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 310.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 585.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 584.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 584.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 584.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 584.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 582.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 582.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 584.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 582.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 582.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 585.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 579.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 571.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 585.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 327.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1274.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1274.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -106.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT4.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT4.txt.json
new file mode 100644
index 00000000000..3afc30f9492
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT4.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 111.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 96.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 371.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 370.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 370.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 370.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 370.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 368.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 368.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 370.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 368.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 368.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 371.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 365.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 357.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 371.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1060.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1060.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -320.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT5.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT5.txt.json
new file mode 100644
index 00000000000..3afc30f9492
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT5.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 111.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 96.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 371.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 370.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 370.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 370.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 370.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 368.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 368.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 370.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 368.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 368.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 371.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 365.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 357.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 371.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 113.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1060.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1060.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -320.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT6.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT6.txt.json
new file mode 100644
index 00000000000..1af61c0a046
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT6.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -49.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -63.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 211.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 210.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 210.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 210.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 210.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 208.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 208.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 210.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 208.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 208.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 211.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 205.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 197.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 211.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 900.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 900.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -480.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT7.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT7.txt.json
new file mode 100644
index 00000000000..1af61c0a046
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT7.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0, "texID": 20}, {"y": 1, "x": 1, "texID": 21}, {"y": 1, "x": 2, "texID": 5}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 9}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 18}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -49.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -63.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 211.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 210.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 210.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 210.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 210.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 208.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 208.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 210.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 208.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 208.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, 211.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 205.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 197.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 211.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -47.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 900.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 900.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -480.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT8.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT8.txt.json
new file mode 100644
index 00000000000..75f4d2654f3
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT8.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 5}, {"y": 6, "x": 2, "texID": 18}, {"y": 6, "x": 3, "texID": 9}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 21}, {"y": 6, "x": 6, "texID": 20}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -262.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -276.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -2.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, -2.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, -2.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, -2.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, -3.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, -4.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, -4.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -3.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -5.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -5.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, -1.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -8.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -16.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -2.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 687.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 687.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -693.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT9.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT9.txt.json
new file mode 100644
index 00000000000..75f4d2654f3
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT9.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 2, "x": 0, "texID": 26}, {"y": 2, "x": 1, "texID": 14}, {"y": 2, "x": 2, "texID": 16}, {"y": 2, "x": 3, "texID": 27}, {"y": 2, "x": 4, "texID": 2}, {"y": 2, "x": 5, "texID": 23}, {"y": 2, "x": 6, "texID": 22}, {"y": 3, "x": 0, "texID": 1}, {"y": 3, "x": 1, "texID": 12}, {"y": 3, "x": 2, "texID": 8}, {"y": 3, "x": 3, "texID": 19}, {"y": 3, "x": 4, "texID": 7}, {"y": 3, "x": 5, "texID": 4}, {"y": 3, "x": 6, "texID": 17}, {"y": 4, "x": 0, "texID": 43}, {"y": 4, "x": 1, "texID": 44}, {"y": 4, "x": 2, "texID": 46}, {"y": 4, "x": 3, "texID": 47}, {"y": 4, "x": 4, "texID": 48}, {"y": 4, "x": 5, "texID": 49}, {"y": 4, "x": 6, "texID": 50}, {"y": 5, "x": 0, "texID": 15}, {"y": 5, "x": 1, "texID": 10}, {"y": 5, "x": 2, "texID": 6}, {"y": 5, "x": 3, "texID": 24}, {"y": 5, "x": 4, "texID": 3}, {"y": 5, "x": 5, "texID": 28}, {"y": 5, "x": 6, "texID": 25}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 5}, {"y": 6, "x": 2, "texID": 18}, {"y": 6, "x": 3, "texID": 9}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 21}, {"y": 6, "x": 6, "texID": 20}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -262.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -276.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 50, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 49, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 41, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -2.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 48, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 42, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, -2.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 43, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, -2.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 44, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, -2.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 45, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, -3.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 46, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, -4.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 47, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, -4.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -3.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -5.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -5.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 135.5, -1.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -8.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -16.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -2.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, -260.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 687.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 687.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -693.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special0.txt.json
new file mode 100644
index 00000000000..3daf2ec4a32
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 431.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 416.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 37, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 36, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [921, 43]}, "skipsDraw": false, "layerID": 24, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 672.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 43}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [921, 45]}, "skipsDraw": false, "layerID": 31, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [91, 44]}, "skipsDraw": false, "layerID": 25, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [68, 44]}, "skipsDraw": false, "layerID": 26, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [52, 44]}, "skipsDraw": false, "layerID": 27, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [62, 45]}, "skipsDraw": false, "layerID": 28, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 671.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 45}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [64, 48]}, "skipsDraw": false, "layerID": 29, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 670.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 48}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [75, 48]}, "skipsDraw": false, "layerID": 30, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 670.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 48}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 671.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 45}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [921, 24]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 651.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 24}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 651.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 24}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 103.5, 650.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 648.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 648.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 50}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 672.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 43}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 80, "skipsDraw": false, "layerID": 72, "children": [{"drawsContent": false, "width": 71, "skipsDraw": false, "layerID": 70, "children": [{"drawsContent": true, "width": 79, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [79, 60]}, "skipsDraw": false, "layerID": 69, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 207.5, 632.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 60}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 207.5, 632.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 52}, {"drawsContent": true, "width": 28, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [28, 21]}, "skipsDraw": false, "layerID": 71, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 208.0, 652.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 21}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 208.0, 637.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 52}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 44}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 52, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special1.txt.json
new file mode 100644
index 00000000000..e6b3782b18b
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 431.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 416.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 37, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 36, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [921, 43]}, "skipsDraw": false, "layerID": 24, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 672.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 43}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [921, 45]}, "skipsDraw": false, "layerID": 31, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [91, 44]}, "skipsDraw": false, "layerID": 25, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [68, 44]}, "skipsDraw": false, "layerID": 26, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [52, 44]}, "skipsDraw": false, "layerID": 27, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [62, 45]}, "skipsDraw": false, "layerID": 28, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 671.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 45}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [64, 48]}, "skipsDraw": false, "layerID": 29, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 670.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 48}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 50}], "dim": [75, 48]}, "skipsDraw": false, "layerID": 30, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 670.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 48}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 671.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 45}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 51}], "dim": [921, 24]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 651.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 24}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 651.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 24}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 103.5, 650.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 648.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 648.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 50}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 672.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 43}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 80, "skipsDraw": false, "layerID": 124, "children": [{"drawsContent": false, "width": 71, "skipsDraw": false, "layerID": 122, "children": [{"drawsContent": true, "width": 79, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [79, 60]}, "skipsDraw": false, "layerID": 121, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 39.5, 21.0, 0.0, 1.0], "targetSurfaceID": 124, "height": 60}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 39.5, 21.0, 0.0, 1.0], "targetSurfaceID": 124, "height": 52}, {"drawsContent": true, "width": 28, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [28, 21]}, "skipsDraw": false, "layerID": 123, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 40.0, 41.5, 0.0, 1.0], "targetSurfaceID": 124, "height": 21}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 40.0, 26.0, 0.0, 1.0], "targetSurfaceID": 124, "height": 52}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 44}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 52, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special10.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special10.txt.json
new file mode 100644
index 00000000000..739e1475213
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special10.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 500, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 7, "x": 7}, {"y": 7, "x": 8}, {"y": 7, "x": 9}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 8, "x": 7}, {"y": 8, "x": 8}, {"y": 8, "x": 9}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 9, "x": 7}, {"y": 9, "x": 8}, {"y": 9, "x": 9}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 10, "x": 7}, {"y": 10, "x": 8}, {"y": 10, "x": 9}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}, {"y": 11, "x": 7}, {"y": 11, "x": 8}, {"y": 11, "x": 9}, {"y": 12, "x": 0}, {"y": 12, "x": 1}, {"y": 12, "x": 2}, {"y": 12, "x": 3}, {"y": 12, "x": 4}, {"y": 12, "x": 5}, {"y": 12, "x": 6}, {"y": 12, "x": 7}, {"y": 12, "x": 8}, {"y": 12, "x": 9}, {"y": 13, "x": 0}, {"y": 13, "x": 1}, {"y": 13, "x": 2}, {"y": 13, "x": 3}, {"y": 13, "x": 4}, {"y": 13, "x": 5}, {"y": 13, "x": 6}, {"y": 13, "x": 7}, {"y": 13, "x": 8}, {"y": 13, "x": 9}, {"y": 14, "x": 0}, {"y": 14, "x": 1}, {"y": 14, "x": 2}, {"y": 14, "x": 3}, {"y": 14, "x": 4}, {"y": 14, "x": 5}, {"y": 14, "x": 6}, {"y": 14, "x": 7}, {"y": 14, "x": 8}, {"y": 14, "x": 9}, {"y": 15, "x": 0}, {"y": 15, "x": 1}, {"y": 15, "x": 2}, {"y": 15, "x": 3}, {"y": 15, "x": 4}, {"y": 15, "x": 5}, {"y": 15, "x": 6}, {"y": 15, "x": 7}, {"y": 15, "x": 8}, {"y": 15, "x": 9}, {"y": 16, "x": 0}, {"y": 16, "x": 1}, {"y": 16, "x": 2}, {"y": 16, "x": 3}, {"y": 16, "x": 4}, {"y": 16, "x": 5}, {"y": 16, "x": 6}, {"y": 16, "x": 7}, {"y": 16, "x": 8}, {"y": 16, "x": 9}, {"y": 17, "x": 0}, {"y": 17, "x": 1}, {"y": 17, "x": 2}, {"y": 17, "x": 3}, {"y": 17, "x": 4}, {"y": 17, "x": 5}, {"y": 17, "x": 6}, {"y": 17, "x": 7}, {"y": 17, "x": 8}, {"y": 17, "x": 9}, {"y": 18, "x": 0}, {"y": 18, "x": 1}, {"y": 18, "x": 2}, {"y": 18, "x": 3}, {"y": 18, "x": 4}, {"y": 18, "x": 5}, {"y": 18, "x": 6}, {"y": 18, "x": 7}, {"y": 18, "x": 8}, {"y": 18, "x": 9}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 501, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 502, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 499, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 503, "children": [{"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 506, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 505, "children": [{"textures": [{"texID": 30, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 31, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 32, "format": "LUMINANCE", "height": 746, "width": 1326}], "targetSurfaceID": 500, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 672.0, 0.0, 1.0], "height": 746, "drawsContent": true, "width": 1326, "layerID": 514, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 678.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 758}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 750.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}, {"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 508, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 507, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 647.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 696}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 750.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}, {"drawsContent": true, "width": 262, "tiles": {"info": [{"y": 0, "x": 0, "texID": 115}], "dim": [262, 86]}, "skipsDraw": false, "layerID": 720, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1475.0, 947.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 86}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 2396.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 2396.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 704, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 705, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 706, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special11.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special11.txt.json
new file mode 100644
index 00000000000..33e1b9f0bad
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special11.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 500, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 4, "x": 0, "texID": 38}, {"y": 4, "x": 1, "texID": 39}, {"y": 4, "x": 2, "texID": 40}, {"y": 4, "x": 3, "texID": 41}, {"y": 4, "x": 4, "texID": 42}, {"y": 4, "x": 5, "texID": 43}, {"y": 4, "x": 6, "texID": 45}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 5, "x": 0, "texID": 7}, {"y": 5, "x": 1, "texID": 15}, {"y": 5, "x": 2, "texID": 28}, {"y": 5, "x": 3, "texID": 20}, {"y": 5, "x": 4, "texID": 17}, {"y": 5, "x": 5, "texID": 16}, {"y": 5, "x": 6, "texID": 2}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 7, "x": 7}, {"y": 7, "x": 8}, {"y": 7, "x": 9}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 8, "x": 7}, {"y": 8, "x": 8}, {"y": 8, "x": 9}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 9, "x": 7}, {"y": 9, "x": 8}, {"y": 9, "x": 9}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 10, "x": 7}, {"y": 10, "x": 8}, {"y": 10, "x": 9}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}, {"y": 11, "x": 7}, {"y": 11, "x": 8}, {"y": 11, "x": 9}, {"y": 12, "x": 0}, {"y": 12, "x": 1}, {"y": 12, "x": 2}, {"y": 12, "x": 3}, {"y": 12, "x": 4}, {"y": 12, "x": 5}, {"y": 12, "x": 6}, {"y": 12, "x": 7}, {"y": 12, "x": 8}, {"y": 12, "x": 9}, {"y": 13, "x": 0}, {"y": 13, "x": 1}, {"y": 13, "x": 2}, {"y": 13, "x": 3}, {"y": 13, "x": 4}, {"y": 13, "x": 5}, {"y": 13, "x": 6}, {"y": 13, "x": 7}, {"y": 13, "x": 8}, {"y": 13, "x": 9}, {"y": 14, "x": 0}, {"y": 14, "x": 1}, {"y": 14, "x": 2}, {"y": 14, "x": 3}, {"y": 14, "x": 4}, {"y": 14, "x": 5}, {"y": 14, "x": 6}, {"y": 14, "x": 7}, {"y": 14, "x": 8}, {"y": 14, "x": 9}, {"y": 15, "x": 0}, {"y": 15, "x": 1}, {"y": 15, "x": 2}, {"y": 15, "x": 3}, {"y": 15, "x": 4}, {"y": 15, "x": 5}, {"y": 15, "x": 6}, {"y": 15, "x": 7}, {"y": 15, "x": 8}, {"y": 15, "x": 9}, {"y": 16, "x": 0}, {"y": 16, "x": 1}, {"y": 16, "x": 2}, {"y": 16, "x": 3}, {"y": 16, "x": 4}, {"y": 16, "x": 5}, {"y": 16, "x": 6}, {"y": 16, "x": 7}, {"y": 16, "x": 8}, {"y": 16, "x": 9}, {"y": 17, "x": 0}, {"y": 17, "x": 1}, {"y": 17, "x": 2}, {"y": 17, "x": 3}, {"y": 17, "x": 4}, {"y": 17, "x": 5}, {"y": 17, "x": 6}, {"y": 17, "x": 7}, {"y": 17, "x": 8}, {"y": 17, "x": 9}, {"y": 18, "x": 0}, {"y": 18, "x": 1}, {"y": 18, "x": 2}, {"y": 18, "x": 3}, {"y": 18, "x": 4}, {"y": 18, "x": 5}, {"y": 18, "x": 6}, {"y": 18, "x": 7}, {"y": 18, "x": 8}, {"y": 18, "x": 9}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 501, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 502, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 499, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 503, "children": [{"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 506, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 505, "children": [{"textures": [{"texID": 30, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 31, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 32, "format": "LUMINANCE", "height": 746, "width": 1326}], "targetSurfaceID": 500, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 192.0, 0.0, 1.0], "height": 746, "drawsContent": true, "width": 1326, "layerID": 514, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 198.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 758}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 270.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}, {"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 508, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 507, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 167.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 696}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 270.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 1916.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 1916.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -480.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 704, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 705, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 706, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special12.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special12.txt.json
new file mode 100644
index 00000000000..7f98608afa8
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special12.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 500, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0}, {"y": 0, "x": 1}, {"y": 0, "x": 2}, {"y": 0, "x": 3}, {"y": 0, "x": 4}, {"y": 0, "x": 5}, {"y": 0, "x": 6}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 1, "x": 0}, {"y": 1, "x": 1}, {"y": 1, "x": 2}, {"y": 1, "x": 3}, {"y": 1, "x": 4}, {"y": 1, "x": 5}, {"y": 1, "x": 6}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 4, "x": 0, "texID": 38}, {"y": 4, "x": 1, "texID": 39}, {"y": 4, "x": 2, "texID": 40}, {"y": 4, "x": 3, "texID": 41}, {"y": 4, "x": 4, "texID": 42}, {"y": 4, "x": 5, "texID": 43}, {"y": 4, "x": 6, "texID": 45}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 5, "x": 0, "texID": 7}, {"y": 5, "x": 1, "texID": 15}, {"y": 5, "x": 2, "texID": 28}, {"y": 5, "x": 3, "texID": 20}, {"y": 5, "x": 4, "texID": 17}, {"y": 5, "x": 5, "texID": 16}, {"y": 5, "x": 6, "texID": 2}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 6, "x": 0, "texID": 13}, {"y": 6, "x": 1, "texID": 26}, {"y": 6, "x": 2, "texID": 4}, {"y": 6, "x": 3, "texID": 22}, {"y": 6, "x": 4, "texID": 11}, {"y": 6, "x": 5, "texID": 1}, {"y": 6, "x": 6, "texID": 12}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 7, "x": 7}, {"y": 7, "x": 8}, {"y": 7, "x": 9}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 8, "x": 7}, {"y": 8, "x": 8}, {"y": 8, "x": 9}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 9, "x": 7}, {"y": 9, "x": 8}, {"y": 9, "x": 9}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 10, "x": 7}, {"y": 10, "x": 8}, {"y": 10, "x": 9}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}, {"y": 11, "x": 7}, {"y": 11, "x": 8}, {"y": 11, "x": 9}, {"y": 12, "x": 0}, {"y": 12, "x": 1}, {"y": 12, "x": 2}, {"y": 12, "x": 3}, {"y": 12, "x": 4}, {"y": 12, "x": 5}, {"y": 12, "x": 6}, {"y": 12, "x": 7}, {"y": 12, "x": 8}, {"y": 12, "x": 9}, {"y": 13, "x": 0}, {"y": 13, "x": 1}, {"y": 13, "x": 2}, {"y": 13, "x": 3}, {"y": 13, "x": 4}, {"y": 13, "x": 5}, {"y": 13, "x": 6}, {"y": 13, "x": 7}, {"y": 13, "x": 8}, {"y": 13, "x": 9}, {"y": 14, "x": 0}, {"y": 14, "x": 1}, {"y": 14, "x": 2}, {"y": 14, "x": 3}, {"y": 14, "x": 4}, {"y": 14, "x": 5}, {"y": 14, "x": 6}, {"y": 14, "x": 7}, {"y": 14, "x": 8}, {"y": 14, "x": 9}, {"y": 15, "x": 0}, {"y": 15, "x": 1}, {"y": 15, "x": 2}, {"y": 15, "x": 3}, {"y": 15, "x": 4}, {"y": 15, "x": 5}, {"y": 15, "x": 6}, {"y": 15, "x": 7}, {"y": 15, "x": 8}, {"y": 15, "x": 9}, {"y": 16, "x": 0}, {"y": 16, "x": 1}, {"y": 16, "x": 2}, {"y": 16, "x": 3}, {"y": 16, "x": 4}, {"y": 16, "x": 5}, {"y": 16, "x": 6}, {"y": 16, "x": 7}, {"y": 16, "x": 8}, {"y": 16, "x": 9}, {"y": 17, "x": 0}, {"y": 17, "x": 1}, {"y": 17, "x": 2}, {"y": 17, "x": 3}, {"y": 17, "x": 4}, {"y": 17, "x": 5}, {"y": 17, "x": 6}, {"y": 17, "x": 7}, {"y": 17, "x": 8}, {"y": 17, "x": 9}, {"y": 18, "x": 0}, {"y": 18, "x": 1}, {"y": 18, "x": 2}, {"y": 18, "x": 3}, {"y": 18, "x": 4}, {"y": 18, "x": 5}, {"y": 18, "x": 6}, {"y": 18, "x": 7}, {"y": 18, "x": 8}, {"y": 18, "x": 9}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 501, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 502, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 499, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 503, "children": [{"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 506, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 505, "children": [{"textures": [{"texID": 30, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 31, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 32, "format": "LUMINANCE", "height": 746, "width": 1326}], "targetSurfaceID": 500, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 32.0, 0.0, 1.0], "height": 746, "drawsContent": true, "width": 1326, "layerID": 514, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 38.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 758}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 110.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}, {"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 508, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 507, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 7.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 696}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 110.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 1756.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 1756.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, -640.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 704, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 705, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 706, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special2.txt.json
new file mode 100644
index 00000000000..cabe2ed34e2
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 431.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 416.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 37, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 36, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [921, 43]}, "skipsDraw": false, "layerID": 24, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 672.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 43}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [921, 45]}, "skipsDraw": false, "layerID": 31, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [91, 44]}, "skipsDraw": false, "layerID": 25, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [68, 44]}, "skipsDraw": false, "layerID": 26, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [52, 44]}, "skipsDraw": false, "layerID": 27, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 672.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 44}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [62, 45]}, "skipsDraw": false, "layerID": 28, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 671.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 45}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [64, 48]}, "skipsDraw": false, "layerID": 29, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 670.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 48}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 50}], "dim": [75, 48]}, "skipsDraw": false, "layerID": 30, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 670.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 48}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 671.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 45}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 51}], "dim": [921, 24]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 651.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 24}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 651.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 24}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 103.5, 650.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 648.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 648.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 50}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 672.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 43}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 75, "skipsDraw": false, "layerID": 284, "children": [{"drawsContent": false, "width": 67, "skipsDraw": false, "layerID": 282, "children": [{"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 90}], "dim": [75, 60]}, "skipsDraw": false, "layerID": 281, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 140.5, 632.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 60}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 140.5, 632.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 52}, {"drawsContent": true, "width": 28, "tiles": {"info": [{"y": 0, "x": 0, "texID": 93}], "dim": [28, 21]}, "skipsDraw": false, "layerID": 283, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 141.0, 652.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 21}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 140.5, 637.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 52}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 44}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 52, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special3.txt.json
new file mode 100644
index 00000000000..d94359c0b90
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 32, "format": "LUMINANCE", "height": 518, "width": 921}, {"texID": 33, "format": "LUMINANCE", "height": 518, "width": 921}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 431.0, 0.0, 1.0], "height": 518, "drawsContent": true, "width": 921, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 416.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 489}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 37, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 36, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [921, 6]}, "skipsDraw": false, "layerID": 24, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 691.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [921, 8]}, "skipsDraw": false, "layerID": 31, "children": [{"drawsContent": true, "width": 91, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [91, 7]}, "skipsDraw": false, "layerID": 25, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 144.5, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 68, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [68, 7]}, "skipsDraw": false, "layerID": 26, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 210.0, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 27, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 994.0, 690.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 62, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [62, 8]}, "skipsDraw": false, "layerID": 28, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 951.0, 690.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 64, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [64, 11]}, "skipsDraw": false, "layerID": 29, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 688.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [75, 11]}, "skipsDraw": false, "layerID": 30, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 848.5, 688.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 690.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 35, "children": [{"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 38, "children": [{"drawsContent": true, "width": 921, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [921, 12]}, "skipsDraw": false, "layerID": 32, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 688.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": false, "width": 921, "skipsDraw": false, "layerID": 33, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 688.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}, {"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [37, 37]}, "skipsDraw": false, "layerID": 34, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 103.5, 691.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 37}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 685.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 677.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 691.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 559.5, 433.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 522}, {"drawsContent": false, "width": 75, "skipsDraw": false, "layerID": 328, "children": [{"drawsContent": false, "width": 67, "skipsDraw": false, "layerID": 326, "children": [{"drawsContent": true, "width": 75, "tiles": {"info": [{"y": 0, "x": 0, "texID": 100}], "dim": [75, 60]}, "skipsDraw": false, "layerID": 325, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 140.5, 632.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 60}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 140.5, 632.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 52}, {"drawsContent": true, "width": 28, "tiles": {"info": [{"y": 0, "x": 0, "texID": 101}], "dim": [28, 21]}, "skipsDraw": false, "layerID": 327, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 141.0, 652.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 21}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 140.5, 637.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 52}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 1380.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 2760}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 44}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 52, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special4.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special4.txt.json
new file mode 100644
index 00000000000..01b2de1a63d
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special4.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 360, "width": 640}, {"texID": 32, "format": "LUMINANCE", "height": 360, "width": 640}, {"texID": 33, "format": "LUMINANCE", "height": 360, "width": 640}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 337.0, 0.0, 1.0], "height": 360, "drawsContent": true, "width": 640, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 317.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 334}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 302.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 363}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 317.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 334}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 302.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 363}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 445, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 444, "children": [{"drawsContent": true, "width": 640, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [640, 14]}, "skipsDraw": false, "layerID": 443, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 459.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 14}, {"drawsContent": true, "width": 640, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [640, 34]}, "skipsDraw": false, "layerID": 437, "children": [{"drawsContent": true, "width": 66, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [66, 33]}, "skipsDraw": false, "layerID": 433, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 345.0, 467.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 33}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [52, 33]}, "skipsDraw": false, "layerID": 434, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 390.0, 467.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 33}, {"drawsContent": true, "width": 38, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [38, 33]}, "skipsDraw": false, "layerID": 435, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 933.0, 467.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 33}, {"drawsContent": true, "width": 48, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [48, 34]}, "skipsDraw": false, "layerID": 436, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 467.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}, {"drawsContent": true, "width": 48, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [48, 36]}, "skipsDraw": false, "layerID": 422, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 872.0, 466.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}, {"drawsContent": true, "width": 55, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [55, 36]}, "skipsDraw": false, "layerID": 423, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 834.5, 466.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 36}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 467.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 34}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 427, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 431, "children": [{"drawsContent": true, "width": 640, "tiles": {"info": [{"y": 0, "x": 0, "texID": 50}], "dim": [640, 21]}, "skipsDraw": false, "layerID": 424, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 453.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 21}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 425, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 453.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 21}, {"drawsContent": true, "width": 30, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [30, 30]}, "skipsDraw": false, "layerID": 426, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 315.0, 453.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 30}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 451.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 25}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 451.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 39}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 468.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 32}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 302.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 363}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 983.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 1966}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 983.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 1966}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 440, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special5.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special5.txt.json
new file mode 100644
index 00000000000..a2482275e71
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special5.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1594, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 360, "width": 640}, {"texID": 32, "format": "LUMINANCE", "height": 360, "width": 640}, {"texID": 33, "format": "LUMINANCE", "height": 360, "width": 640}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 337.0, 0.0, 1.0], "height": 360, "drawsContent": true, "width": 640, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 317.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 334}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 302.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 363}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 317.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 334}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 302.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 363}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 445, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 444, "children": [{"drawsContent": true, "width": 640, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [640, 6]}, "skipsDraw": false, "layerID": 443, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 481.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 640, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [640, 8]}, "skipsDraw": false, "layerID": 437, "children": [{"drawsContent": true, "width": 66, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [66, 7]}, "skipsDraw": false, "layerID": 433, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 345.0, 480.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 52, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [52, 7]}, "skipsDraw": false, "layerID": 434, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 390.0, 480.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 38, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [38, 7]}, "skipsDraw": false, "layerID": 435, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 933.0, 480.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 48, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [48, 8]}, "skipsDraw": false, "layerID": 436, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 904.0, 480.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 48, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [48, 10]}, "skipsDraw": false, "layerID": 422, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 872.0, 479.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 10}, {"drawsContent": true, "width": 55, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [55, 10]}, "skipsDraw": false, "layerID": 423, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 834.5, 479.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 10}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 480.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 427, "children": [{"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 431, "children": [{"drawsContent": true, "width": 640, "tiles": {"info": [{"y": 0, "x": 0, "texID": 50}], "dim": [640, 11]}, "skipsDraw": false, "layerID": 424, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 478.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": false, "width": 640, "skipsDraw": false, "layerID": 425, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 478.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 11}, {"drawsContent": true, "width": 30, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [30, 30]}, "skipsDraw": false, "layerID": 426, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 315.0, 482.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 30}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 477.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 25}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 471.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 26}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 481.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 632.0, 302.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 363}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 983.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 1966}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 983.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 1966}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [15, 993]}, "skipsDraw": false, "layerID": 440, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special6.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special6.txt.json
new file mode 100644
index 00000000000..17b4c595a3b
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special6.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 18, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 31, "format": "LUMINANCE", "height": 180, "width": 320}, {"texID": 32, "format": "LUMINANCE", "height": 180, "width": 320}, {"texID": 33, "format": "LUMINANCE", "height": 180, "width": 320}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 224.0, 0.0, 1.0], "height": 180, "drawsContent": true, "width": 320, "layerID": 23, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 183.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 112}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 181}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 20, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 19, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 183.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 112}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 181}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 497, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 496, "children": [{"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 30}], "dim": [320, 6]}, "skipsDraw": false, "layerID": 484, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 236.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}, {"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [320, 8]}, "skipsDraw": false, "layerID": 491, "children": [{"drawsContent": true, "width": 37, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [37, 7]}, "skipsDraw": false, "layerID": 485, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 580.5, 235.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 33, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [33, 7]}, "skipsDraw": false, "layerID": 486, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 601.5, 235.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 22, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [22, 7]}, "skipsDraw": false, "layerID": 487, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 871.0, 235.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 7}, {"drawsContent": true, "width": 32, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [32, 8]}, "skipsDraw": false, "layerID": 488, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 859.0, 235.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 34, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [34, 8]}, "skipsDraw": false, "layerID": 489, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 841.0, 235.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 38, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [38, 8]}, "skipsDraw": false, "layerID": 490, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 819.0, 235.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 235.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 495, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 498, "children": [{"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [320, 8]}, "skipsDraw": false, "layerID": 492, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 235.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 493, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 235.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 8}, {"drawsContent": true, "width": 22, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [22, 22]}, "skipsDraw": false, "layerID": 494, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 563.0, 238.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 22}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 236.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 12}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 231.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 16}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 236.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 6}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 181}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special7.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special7.txt.json
new file mode 100644
index 00000000000..3187a1dcbc2
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special7.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 500, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 501, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 502, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 499, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 503, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 506, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 505, "children": [{"textures": [{"texID": 30, "format": "LUMINANCE", "height": 180, "width": 320}, {"texID": 31, "format": "LUMINANCE", "height": 180, "width": 320}, {"texID": 32, "format": "LUMINANCE", "height": 180, "width": 320}], "targetSurfaceID": 500, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.0, 0.0, 1.0], "height": 180, "drawsContent": true, "width": 320, "layerID": 514, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 508, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 507, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 143.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 170}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 528, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 527, "children": [{"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [320, 4]}, "skipsDraw": false, "layerID": 515, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 227.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4}, {"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [320, 16]}, "skipsDraw": false, "layerID": 522, "children": [{"drawsContent": true, "width": 32, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [32, 15]}, "skipsDraw": false, "layerID": 516, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 578.0, 231.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 23, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [23, 15]}, "skipsDraw": false, "layerID": 517, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 601.5, 231.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 17, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [17, 15]}, "skipsDraw": false, "layerID": 518, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 873.5, 231.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 22, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [22, 16]}, "skipsDraw": false, "layerID": 519, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 859.0, 231.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 16}, {"drawsContent": true, "width": 24, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [24, 16]}, "skipsDraw": false, "layerID": 520, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 841.0, 231.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 16}, {"drawsContent": true, "width": 28, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [28, 16]}, "skipsDraw": false, "layerID": 521, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 819.0, 231.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 16}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 231.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 16}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 526, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 529, "children": [{"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 50}], "dim": [320, 7]}, "skipsDraw": false, "layerID": 523, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 224.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 7}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 524, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 224.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 7}, {"drawsContent": true, "width": 12, "tiles": {"info": [{"y": 0, "x": 0, "texID": 114}], "dim": [12, 12]}, "skipsDraw": false, "layerID": 525, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 568.0, 224.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 12}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 223.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 12}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 223.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 16}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 232.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 14}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special8.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special8.txt.json
new file mode 100644
index 00000000000..7f050c3cdbc
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special8.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 500, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 501, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 502, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 499, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 503, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 506, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 505, "children": [{"textures": [{"texID": 30, "format": "LUMINANCE", "height": 180, "width": 320}, {"texID": 31, "format": "LUMINANCE", "height": 180, "width": 320}, {"texID": 32, "format": "LUMINANCE", "height": 180, "width": 320}], "targetSurfaceID": 500, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.0, 0.0, 1.0], "height": 180, "drawsContent": true, "width": 320, "layerID": 514, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 508, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 507, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 143.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 170}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 528, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 527, "children": [{"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [320, 1]}, "skipsDraw": false, "layerID": 515, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 238.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 1}, {"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [320, 3]}, "skipsDraw": false, "layerID": 522, "children": [{"drawsContent": true, "width": 32, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [32, 2]}, "skipsDraw": false, "layerID": 516, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 578.0, 238.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 2}, {"drawsContent": true, "width": 23, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [23, 2]}, "skipsDraw": false, "layerID": 517, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 601.5, 238.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 2}, {"drawsContent": true, "width": 17, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [17, 2]}, "skipsDraw": false, "layerID": 518, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 873.5, 238.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 2}, {"drawsContent": true, "width": 22, "tiles": {"info": [{"y": 0, "x": 0, "texID": 40}], "dim": [22, 3]}, "skipsDraw": false, "layerID": 519, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 859.0, 237.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 3}, {"drawsContent": true, "width": 24, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [24, 3]}, "skipsDraw": false, "layerID": 520, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 841.0, 237.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 3}, {"drawsContent": true, "width": 28, "tiles": {"info": [{"y": 0, "x": 0, "texID": 42}], "dim": [28, 3]}, "skipsDraw": false, "layerID": 521, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 819.0, 237.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 3}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 237.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 3}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 526, "children": [{"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 529, "children": [{"drawsContent": true, "width": 320, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [320, 3]}, "skipsDraw": false, "layerID": 523, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 237.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 3}, {"drawsContent": false, "width": 320, "skipsDraw": false, "layerID": 524, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 237.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 3}, {"drawsContent": true, "width": 12, "tiles": {"info": [{"y": 0, "x": 0, "texID": 114}], "dim": [12, 12]}, "skipsDraw": false, "layerID": 525, "children": [], "type": "ContentLayer", "transform": [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 568.0, 238.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 12}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 236.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 12}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 233.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 11}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 238.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 1}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 722.0, 148.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 181}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special9.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special9.txt.json
new file mode 100644
index 00000000000..739e1475213
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/YT_special9.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 500, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 7, "x": 0}, {"y": 7, "x": 1}, {"y": 7, "x": 2}, {"y": 7, "x": 3}, {"y": 7, "x": 4}, {"y": 7, "x": 5}, {"y": 7, "x": 6}, {"y": 7, "x": 7}, {"y": 7, "x": 8}, {"y": 7, "x": 9}, {"y": 8, "x": 0}, {"y": 8, "x": 1}, {"y": 8, "x": 2}, {"y": 8, "x": 3}, {"y": 8, "x": 4}, {"y": 8, "x": 5}, {"y": 8, "x": 6}, {"y": 8, "x": 7}, {"y": 8, "x": 8}, {"y": 8, "x": 9}, {"y": 9, "x": 0}, {"y": 9, "x": 1}, {"y": 9, "x": 2}, {"y": 9, "x": 3}, {"y": 9, "x": 4}, {"y": 9, "x": 5}, {"y": 9, "x": 6}, {"y": 9, "x": 7}, {"y": 9, "x": 8}, {"y": 9, "x": 9}, {"y": 10, "x": 0}, {"y": 10, "x": 1}, {"y": 10, "x": 2}, {"y": 10, "x": 3}, {"y": 10, "x": 4}, {"y": 10, "x": 5}, {"y": 10, "x": 6}, {"y": 10, "x": 7}, {"y": 10, "x": 8}, {"y": 10, "x": 9}, {"y": 11, "x": 0}, {"y": 11, "x": 1}, {"y": 11, "x": 2}, {"y": 11, "x": 3}, {"y": 11, "x": 4}, {"y": 11, "x": 5}, {"y": 11, "x": 6}, {"y": 11, "x": 7}, {"y": 11, "x": 8}, {"y": 11, "x": 9}, {"y": 12, "x": 0}, {"y": 12, "x": 1}, {"y": 12, "x": 2}, {"y": 12, "x": 3}, {"y": 12, "x": 4}, {"y": 12, "x": 5}, {"y": 12, "x": 6}, {"y": 12, "x": 7}, {"y": 12, "x": 8}, {"y": 12, "x": 9}, {"y": 13, "x": 0}, {"y": 13, "x": 1}, {"y": 13, "x": 2}, {"y": 13, "x": 3}, {"y": 13, "x": 4}, {"y": 13, "x": 5}, {"y": 13, "x": 6}, {"y": 13, "x": 7}, {"y": 13, "x": 8}, {"y": 13, "x": 9}, {"y": 14, "x": 0}, {"y": 14, "x": 1}, {"y": 14, "x": 2}, {"y": 14, "x": 3}, {"y": 14, "x": 4}, {"y": 14, "x": 5}, {"y": 14, "x": 6}, {"y": 14, "x": 7}, {"y": 14, "x": 8}, {"y": 14, "x": 9}, {"y": 15, "x": 0}, {"y": 15, "x": 1}, {"y": 15, "x": 2}, {"y": 15, "x": 3}, {"y": 15, "x": 4}, {"y": 15, "x": 5}, {"y": 15, "x": 6}, {"y": 15, "x": 7}, {"y": 15, "x": 8}, {"y": 15, "x": 9}, {"y": 16, "x": 0}, {"y": 16, "x": 1}, {"y": 16, "x": 2}, {"y": 16, "x": 3}, {"y": 16, "x": 4}, {"y": 16, "x": 5}, {"y": 16, "x": 6}, {"y": 16, "x": 7}, {"y": 16, "x": 8}, {"y": 16, "x": 9}, {"y": 17, "x": 0}, {"y": 17, "x": 1}, {"y": 17, "x": 2}, {"y": 17, "x": 3}, {"y": 17, "x": 4}, {"y": 17, "x": 5}, {"y": 17, "x": 6}, {"y": 17, "x": 7}, {"y": 17, "x": 8}, {"y": 17, "x": 9}, {"y": 18, "x": 0}, {"y": 18, "x": 1}, {"y": 18, "x": 2}, {"y": 18, "x": 3}, {"y": 18, "x": 4}, {"y": 18, "x": 5}, {"y": 18, "x": 6}, {"y": 18, "x": 7}, {"y": 18, "x": 8}, {"y": 18, "x": 9}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 501, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 502, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 499, "children": [{"drawsContent": false, "width": 2413, "skipsDraw": false, "layerID": 503, "children": [{"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 506, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 505, "children": [{"textures": [{"texID": 30, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 31, "format": "LUMINANCE", "height": 746, "width": 1326}, {"texID": 32, "format": "LUMINANCE", "height": 746, "width": 1326}], "targetSurfaceID": 500, "vertex_shader": "VertexShaderPosTexYUVStretch", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 672.0, 0.0, 1.0], "height": 746, "drawsContent": true, "width": 1326, "layerID": 514, "type": "VideoLayer", "fragment_shader": "FragmentShaderYUVVideo"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 678.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 758}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 750.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}, {"drawsContent": false, "width": 1592, "skipsDraw": false, "layerID": 508, "children": [{"drawsContent": false, "width": 1350, "skipsDraw": false, "layerID": 507, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 795.0, 647.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 696}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 796.0, 750.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 903}, {"drawsContent": true, "width": 262, "tiles": {"info": [{"y": 0, "x": 0, "texID": 115}], "dim": [262, 86]}, "skipsDraw": false, "layerID": 720, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1475.0, 947.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 86}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 2396.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1206.5, 2396.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 4792}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 704, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 705, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 706, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 500, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 500, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra0.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra1.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra2.txt.json
new file mode 100644
index 00000000000..504583d8dcb
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 14, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 0, "x": 10}, {"y": 0, "x": 11}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 1, "x": 10}, {"y": 1, "x": 11}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 2, "x": 10}, {"y": 2, "x": 11}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 3, "x": 10}, {"y": 3, "x": 11}, {"y": 4, "x": 0}, {"y": 4, "x": 1}, {"y": 4, "x": 2}, {"y": 4, "x": 3}, {"y": 4, "x": 4}, {"y": 4, "x": 5}, {"y": 4, "x": 6}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 4, "x": 10}, {"y": 4, "x": 11}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 5, "x": 10}, {"y": 5, "x": 11}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 6, "x": 10}, {"y": 6, "x": 11}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 15, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 16, "children": [{"drawsContent": false, "width": 3009, "skipsDraw": false, "layerID": 13, "children": [{"drawsContent": false, "width": 3009, "skipsDraw": false, "layerID": 17, "children": [{"drawsContent": false, "width": 3000, "skipsDraw": false, "layerID": 20, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 1648, "premultiplied": false, "width": 3000}], "targetSurfaceID": 14, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1509.0, 833.0, 0.0, 1.0], "height": 1648, "drawsContent": true, "width": 3000, "layerID": 21, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1509.0, 833.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 1648}, {"drawsContent": true, "width": 428, "tiles": {"info": [{"y": 0, "x": 0, "texID": 32}, {"y": 0, "x": 1, "texID": 33}, {"y": 1, "x": 0, "texID": 34}, {"y": 1, "x": 1, "texID": 35}, {"y": 2, "x": 0}, {"y": 2, "x": 1}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1534.0, 786.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 613}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1504.5, 836.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 1672}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1504.5, 836.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 1672}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 36}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 26, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 27, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 38}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 28, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra3.txt.json
new file mode 100644
index 00000000000..4c1336ea541
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 14, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 0, "x": 10}, {"y": 0, "x": 11}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 1, "x": 10}, {"y": 1, "x": 11}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 2, "x": 10}, {"y": 2, "x": 11}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 3, "x": 10}, {"y": 3, "x": 11}, {"y": 4, "x": 0, "texID": 39}, {"y": 4, "x": 1, "texID": 40}, {"y": 4, "x": 2, "texID": 41}, {"y": 4, "x": 3, "texID": 42}, {"y": 4, "x": 4, "texID": 43}, {"y": 4, "x": 5, "texID": 44}, {"y": 4, "x": 6, "texID": 45}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 4, "x": 10}, {"y": 4, "x": 11}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 5, "x": 10}, {"y": 5, "x": 11}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 6, "x": 10}, {"y": 6, "x": 11}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 15, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 16, "children": [{"drawsContent": false, "width": 2089, "skipsDraw": false, "layerID": 13, "children": [{"drawsContent": false, "width": 2089, "skipsDraw": false, "layerID": 17, "children": [{"drawsContent": false, "width": 2083, "skipsDraw": false, "layerID": 20, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 1145, "premultiplied": false, "width": 2083}], "targetSurfaceID": 14, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1020.5, 412.5, 0.0, 1.0], "height": 1145, "drawsContent": true, "width": 2083, "layerID": 21, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1020.5, 412.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1145}, {"drawsContent": true, "width": 297, "tiles": {"info": [{"y": 0, "x": 0, "texID": 32}], "dim": [297, 424]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1064.5, 545.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 424}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1017.5, 414.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1161}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1017.5, 414.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1161}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -27.0, -166.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 38, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 39, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 40, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra4.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra4.txt.json
new file mode 100644
index 00000000000..4c1336ea541
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra4.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 14, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 0, "x": 10}, {"y": 0, "x": 11}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 1, "x": 10}, {"y": 1, "x": 11}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 2, "x": 10}, {"y": 2, "x": 11}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 3, "x": 10}, {"y": 3, "x": 11}, {"y": 4, "x": 0, "texID": 39}, {"y": 4, "x": 1, "texID": 40}, {"y": 4, "x": 2, "texID": 41}, {"y": 4, "x": 3, "texID": 42}, {"y": 4, "x": 4, "texID": 43}, {"y": 4, "x": 5, "texID": 44}, {"y": 4, "x": 6, "texID": 45}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 4, "x": 10}, {"y": 4, "x": 11}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 5, "x": 10}, {"y": 5, "x": 11}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 6, "x": 10}, {"y": 6, "x": 11}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 15, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 16, "children": [{"drawsContent": false, "width": 2089, "skipsDraw": false, "layerID": 13, "children": [{"drawsContent": false, "width": 2089, "skipsDraw": false, "layerID": 17, "children": [{"drawsContent": false, "width": 2083, "skipsDraw": false, "layerID": 20, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 1145, "premultiplied": false, "width": 2083}], "targetSurfaceID": 14, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1020.5, 412.5, 0.0, 1.0], "height": 1145, "drawsContent": true, "width": 2083, "layerID": 21, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1020.5, 412.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1145}, {"drawsContent": true, "width": 297, "tiles": {"info": [{"y": 0, "x": 0, "texID": 32}], "dim": [297, 424]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1064.5, 545.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 424}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1017.5, 414.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1161}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1017.5, 414.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1161}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -27.0, -166.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 38, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 39, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 40, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra5.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra5.txt.json
new file mode 100644
index 00000000000..4c1336ea541
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/abra5.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 14, "children": [{"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 15}, {"y": 0, "x": 1, "texID": 20}, {"y": 0, "x": 2, "texID": 16}, {"y": 0, "x": 3, "texID": 2}, {"y": 0, "x": 4, "texID": 7}, {"y": 0, "x": 5, "texID": 17}, {"y": 0, "x": 6, "texID": 28}, {"y": 0, "x": 7}, {"y": 0, "x": 8}, {"y": 0, "x": 9}, {"y": 0, "x": 10}, {"y": 0, "x": 11}, {"y": 1, "x": 0, "texID": 12}, {"y": 1, "x": 1, "texID": 1}, {"y": 1, "x": 2, "texID": 26}, {"y": 1, "x": 3, "texID": 13}, {"y": 1, "x": 4, "texID": 22}, {"y": 1, "x": 5, "texID": 11}, {"y": 1, "x": 6, "texID": 4}, {"y": 1, "x": 7}, {"y": 1, "x": 8}, {"y": 1, "x": 9}, {"y": 1, "x": 10}, {"y": 1, "x": 11}, {"y": 2, "x": 0, "texID": 6}, {"y": 2, "x": 1, "texID": 27}, {"y": 2, "x": 2, "texID": 18}, {"y": 2, "x": 3, "texID": 25}, {"y": 2, "x": 4, "texID": 8}, {"y": 2, "x": 5, "texID": 9}, {"y": 2, "x": 6, "texID": 10}, {"y": 2, "x": 7}, {"y": 2, "x": 8}, {"y": 2, "x": 9}, {"y": 2, "x": 10}, {"y": 2, "x": 11}, {"y": 3, "x": 0, "texID": 5}, {"y": 3, "x": 1, "texID": 21}, {"y": 3, "x": 2, "texID": 23}, {"y": 3, "x": 3, "texID": 24}, {"y": 3, "x": 4, "texID": 3}, {"y": 3, "x": 5, "texID": 19}, {"y": 3, "x": 6, "texID": 14}, {"y": 3, "x": 7}, {"y": 3, "x": 8}, {"y": 3, "x": 9}, {"y": 3, "x": 10}, {"y": 3, "x": 11}, {"y": 4, "x": 0, "texID": 39}, {"y": 4, "x": 1, "texID": 40}, {"y": 4, "x": 2, "texID": 41}, {"y": 4, "x": 3, "texID": 42}, {"y": 4, "x": 4, "texID": 43}, {"y": 4, "x": 5, "texID": 44}, {"y": 4, "x": 6, "texID": 45}, {"y": 4, "x": 7}, {"y": 4, "x": 8}, {"y": 4, "x": 9}, {"y": 4, "x": 10}, {"y": 4, "x": 11}, {"y": 5, "x": 0}, {"y": 5, "x": 1}, {"y": 5, "x": 2}, {"y": 5, "x": 3}, {"y": 5, "x": 4}, {"y": 5, "x": 5}, {"y": 5, "x": 6}, {"y": 5, "x": 7}, {"y": 5, "x": 8}, {"y": 5, "x": 9}, {"y": 5, "x": 10}, {"y": 5, "x": 11}, {"y": 6, "x": 0}, {"y": 6, "x": 1}, {"y": 6, "x": 2}, {"y": 6, "x": 3}, {"y": 6, "x": 4}, {"y": 6, "x": 5}, {"y": 6, "x": 6}, {"y": 6, "x": 7}, {"y": 6, "x": 8}, {"y": 6, "x": 9}, {"y": 6, "x": 10}, {"y": 6, "x": 11}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 15, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 16, "children": [{"drawsContent": false, "width": 2089, "skipsDraw": false, "layerID": 13, "children": [{"drawsContent": false, "width": 2089, "skipsDraw": false, "layerID": 17, "children": [{"drawsContent": false, "width": 2083, "skipsDraw": false, "layerID": 20, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 1145, "premultiplied": false, "width": 2083}], "targetSurfaceID": 14, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1020.5, 412.5, 0.0, 1.0], "height": 1145, "drawsContent": true, "width": 2083, "layerID": 21, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1020.5, 412.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1145}, {"drawsContent": true, "width": 297, "tiles": {"info": [{"y": 0, "x": 0, "texID": 32}], "dim": [297, 424]}, "skipsDraw": false, "layerID": 22, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1064.5, 545.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 424}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1017.5, 414.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1161}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1017.5, 414.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 1161}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -27.0, -166.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 1594, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [1594, 15]}, "skipsDraw": false, "layerID": 38, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 797.0, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 34}], "dim": [15, 978]}, "skipsDraw": false, "layerID": 39, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 489.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 978}, {"drawsContent": true, "width": 15, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [15, 15]}, "skipsDraw": false, "layerID": 40, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1601.5, 985.5, 0.0, 1.0], "targetSurfaceID": 14, "height": 15}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 14, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_0.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_1.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_2.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_3.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test00_3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_0.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_1.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_2.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_3.txt.json
new file mode 100644
index 00000000000..63f4cae1c53
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test01_3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_0.txt.json
new file mode 100644
index 00000000000..f21ffcc3b8f
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_1.txt.json
new file mode 100644
index 00000000000..f21ffcc3b8f
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_2.txt.json
new file mode 100644
index 00000000000..f21ffcc3b8f
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_3.txt.json
new file mode 100644
index 00000000000..f21ffcc3b8f
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test02_3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_0.txt.json
new file mode 100644
index 00000000000..12d26fedf44
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 33, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_1.txt.json
new file mode 100644
index 00000000000..12d26fedf44
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 33, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_2.txt.json
new file mode 100644
index 00000000000..12d26fedf44
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 33, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_3.txt.json
new file mode 100644
index 00000000000..12d26fedf44
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test03_3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 31, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 158.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 462.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 33, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 766.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}, {"drawsContent": false, "width": 300, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1070.0, 158.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 300}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_0.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_0.txt.json
new file mode 100644
index 00000000000..4c82c828f8b
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_0.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 31}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 36, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 38, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 21, "children": [{"textures": [{"texID": 40, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 22, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 23, "children": [{"textures": [{"texID": 42, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 24, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 25, "children": [{"textures": [{"texID": 44, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 26, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 27, "children": [{"textures": [{"texID": 46, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 28, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 47}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 29, "children": [{"textures": [{"texID": 48, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 30, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 49}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 31, "children": [{"textures": [{"texID": 50, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 32, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_1.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_1.txt.json
new file mode 100644
index 00000000000..4c82c828f8b
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_1.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 31}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 36, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 38, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 21, "children": [{"textures": [{"texID": 40, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 22, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 23, "children": [{"textures": [{"texID": 42, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 24, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 25, "children": [{"textures": [{"texID": 44, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 26, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 27, "children": [{"textures": [{"texID": 46, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 28, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 47}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 29, "children": [{"textures": [{"texID": 48, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 30, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 49}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 31, "children": [{"textures": [{"texID": 50, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 32, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_2.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_2.txt.json
new file mode 100644
index 00000000000..4c82c828f8b
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_2.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 31}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 36, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 38, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 21, "children": [{"textures": [{"texID": 40, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 22, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 23, "children": [{"textures": [{"texID": 42, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 24, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 25, "children": [{"textures": [{"texID": 44, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 26, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 27, "children": [{"textures": [{"texID": 46, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 28, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 47}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 29, "children": [{"textures": [{"texID": 48, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 30, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 49}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 31, "children": [{"textures": [{"texID": 50, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 32, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_3.txt.json b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_3.txt.json
new file mode 100644
index 00000000000..4c82c828f8b
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/measuring_confs/test04_3.txt.json
@@ -0,0 +1 @@
+{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 8, "children": [{"drawsContent": true, "width": 1609, "tiles": {"info": [{"y": 0, "x": 0, "texID": 5}, {"y": 0, "x": 1, "texID": 8}, {"y": 0, "x": 2, "texID": 17}, {"y": 0, "x": 3, "texID": 19}, {"y": 0, "x": 4, "texID": 26}, {"y": 0, "x": 5, "texID": 28}, {"y": 0, "x": 6, "texID": 3}, {"y": 1, "x": 0, "texID": 23}, {"y": 1, "x": 1, "texID": 22}, {"y": 1, "x": 2, "texID": 15}, {"y": 1, "x": 3, "texID": 11}, {"y": 1, "x": 4, "texID": 21}, {"y": 1, "x": 5, "texID": 13}, {"y": 1, "x": 6, "texID": 27}, {"y": 2, "x": 0, "texID": 7}, {"y": 2, "x": 1, "texID": 18}, {"y": 2, "x": 2, "texID": 14}, {"y": 2, "x": 3, "texID": 4}, {"y": 2, "x": 4, "texID": 24}, {"y": 2, "x": 5, "texID": 12}, {"y": 2, "x": 6, "texID": 1}, {"y": 3, "x": 0, "texID": 10}, {"y": 3, "x": 1, "texID": 9}, {"y": 3, "x": 2, "texID": 20}, {"y": 3, "x": 3, "texID": 2}, {"y": 3, "x": 4, "texID": 6}, {"y": 3, "x": 5, "texID": 25}, {"y": 3, "x": 6, "texID": 16}], "dim": [256, 256]}, "skipsDraw": false, "layerID": 9, "children": [{"drawsContent": false, "width": 0, "skipsDraw": false, "layerID": 10, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 7, "children": [{"drawsContent": false, "width": 1609, "skipsDraw": false, "layerID": 11, "children": [{"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 31}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 13, "children": [{"textures": [{"texID": 32, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 14, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 33}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 15, "children": [{"textures": [{"texID": 34, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 16, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 35}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 17, "children": [{"textures": [{"texID": 36, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 18, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 37}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 19, "children": [{"textures": [{"texID": 38, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 20, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 39}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 21, "children": [{"textures": [{"texID": 40, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 22, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 160.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 41}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 23, "children": [{"textures": [{"texID": 42, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 24, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 160.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 43}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 25, "children": [{"textures": [{"texID": 44, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 26, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 252.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 45}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 27, "children": [{"textures": [{"texID": 46, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 28, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 352.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 47}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 29, "children": [{"textures": [{"texID": 48, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 30, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 452.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}, {"drawsContent": true, "width": 304, "tiles": {"info": [{"y": 0, "x": 0, "texID": 49}], "dim": [304, 304]}, "skipsDraw": false, "layerID": 31, "children": [{"textures": [{"texID": 50, "format": "RGBA", "height": 300, "premultiplied": false, "width": 300}], "targetSurfaceID": 8, "vertex_shader": "VertexShaderPosTex", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "height": 300, "drawsContent": true, "width": 300, "layerID": 32, "type": "CanvasLayer", "fragment_shader": "FragmentShaderRGBATexFlipAlpha"}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 552.0, 252.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 304}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 804.5, 496.5, 0.0, 1.0], "targetSurfaceID": 8, "height": 993}], "type": "ContentLayer", "transform": [1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], "targetSurfaceID": 8, "height": 0} \ No newline at end of file
diff --git a/chromium/gpu/tools/compositor_model_bench/render_model_utils.cc b/chromium/gpu/tools/compositor_model_bench/render_model_utils.cc
new file mode 100644
index 00000000000..7e1eb5cc3e0
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/render_model_utils.cc
@@ -0,0 +1,174 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Whole-tree processing that's likely to be helpful in multiple render models.
+
+#include "gpu/tools/compositor_model_bench/render_model_utils.h"
+
+#include <cstdlib>
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/logging.h"
+
+TextureGenerator::TextureGenerator(RenderNode* root)
+ : stage_(DiscoveryStage),
+ images_generated_(0) {
+ DiscoverInputIDs(root);
+ GenerateGLTexIDs();
+ AssignIDMapping();
+ WriteOutNewIDs(root);
+ AllocateImageArray();
+ BuildTextureImages(root);
+}
+
+TextureGenerator::~TextureGenerator() {
+ if (tex_ids_.get()) {
+ glDeleteTextures(discovered_ids_.size(), tex_ids_.get());
+ }
+}
+
+void TextureGenerator::BeginVisitRenderNode(RenderNode* node) {
+ for (size_t n = 0; n < node->num_tiles(); ++n) {
+ Tile* i = node->tile(n);
+ HandleTexture(&i->texID,
+ node->tile_width(),
+ node->tile_height(),
+ GL_RGBA);
+ }
+}
+
+void TextureGenerator::BeginVisitCCNode(CCNode* node) {
+ for (size_t n = 0; n < node->num_textures(); ++n) {
+ Texture* i = node->texture(n);
+ HandleTexture(&i->texID, i->width, i->height, i->format);
+ }
+ BeginVisitRenderNode(node);
+}
+
+void TextureGenerator::DiscoverInputIDs(RenderNode* root) {
+ // Pass 1: see which texture ID's have been used.
+ stage_ = DiscoveryStage;
+ root->Accept(this);
+}
+
+void TextureGenerator::GenerateGLTexIDs() {
+ int numTextures = discovered_ids_.size();
+ tex_ids_.reset(new GLuint[numTextures]);
+ glGenTextures(numTextures, tex_ids_.get());
+}
+
+void TextureGenerator::AssignIDMapping() {
+ // In the original version of this code the assigned ID's were not
+ // GL tex ID's, but newly generated consecutive ID's that indexed
+ // into an array of GL tex ID's. There's no need for this and now
+ // I'm instead generating the GL tex ID's upfront and assigning
+ // *those* in the remapping -- this more accurately reflects the
+ // behavior in Chromium, and it also takes out some design
+ // complexity that came from the extra layer of indirection.
+ // HOWEVER -- when I was assigning my own ID's before, I did some
+ // clever tricks to make sure the assignation was idempotent.
+ // Instead of going to even more clever lengths to preserve that
+ // property, I now just assume that the visitor will encounter each
+ // node (and consequently each texture) exactly once during a
+ // traversal of the tree -- this shouldn't be a hard guarantee
+ // to make.
+ int j = 0;
+ typedef std::set<int>::iterator id_itr;
+ for (id_itr i = discovered_ids_.begin();
+ i != discovered_ids_.end();
+ ++i, ++j) {
+ remapped_ids_[*i] = tex_ids_[j];
+ }
+}
+
+void TextureGenerator::WriteOutNewIDs(RenderNode* root) {
+ // Pass 2: write the new texture ID's back into the texture objects.
+ stage_ = RemappingStage;
+ root->Accept(this);
+}
+
+void TextureGenerator::AllocateImageArray() {
+ image_data_.reset(new ImagePtr[discovered_ids_.size()]);
+ images_generated_ = 0;
+}
+
+void TextureGenerator::BuildTextureImages(RenderNode* root) {
+ // Pass 3: use the texture metadata to generate images for the
+ // textures, and set up the textures for use by OpenGL. This
+ // doesn't *have* to be a separate pass (it could be rolled
+ // into pass 2) but I think this is more clear and performance
+ // shouldn't be bad.
+ stage_ = ImageGenerationStage;
+ root->Accept(this);
+}
+
+void TextureGenerator::HandleTexture(int* texID,
+ int width,
+ int height,
+ GLenum format) {
+ if (*texID == -1)
+ return; // -1 means it's not a real texture.
+ switch (stage_) {
+ case DiscoveryStage:
+ discovered_ids_.insert(*texID);
+ break;
+ case RemappingStage:
+ *texID = remapped_ids_[*texID];
+ break;
+ case ImageGenerationStage:
+ // Only handle this one if we haven't already built a
+ // texture for its ID.
+ if (ids_for_completed_textures_.count(*texID))
+ return;
+ GenerateImageForTexture(*texID, width, height, format);
+ ids_for_completed_textures_.insert(*texID);
+ break;
+ }
+}
+
+void TextureGenerator::GenerateImageForTexture(int texID,
+ int width,
+ int height,
+ GLenum format) {
+ int bytes_per_pixel = FormatBytesPerPixel(format);
+ DCHECK_LE(bytes_per_pixel, 4);
+ int imgID = images_generated_++;
+ image_data_[imgID].reset(new uint8[width*height*bytes_per_pixel]);
+ // Pick random colors to use for this texture.
+ uint8 random_color[4];
+ for (int c = 0; c < 4; ++c) {
+ random_color[c] = std::rand() % 255;
+ }
+ // Create the image from those colors.
+ for (int x = 0; x < width; ++x) {
+ for (int y = 0; y < height; ++y) {
+ int pix_addr = (y * width + x) * bytes_per_pixel;
+ for (int c = 0; c < bytes_per_pixel; ++c) {
+ bool on = ((x/8) + (y/8)) % 2;
+ uint8 v = on ? random_color[c] : ~random_color[c];
+ (image_data_[imgID])[pix_addr + c] = v;
+ }
+ if (bytes_per_pixel == 4) { // Randomize alpha.
+ image_data_[imgID][pix_addr + 3] = std::rand() % 255;
+ }
+ }
+ }
+ // Set up GL texture.
+ glBindTexture(GL_TEXTURE_2D, texID);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ format,
+ width, height,
+ 0,
+ format,
+ GL_UNSIGNED_BYTE,
+ image_data_[imgID].get());
+}
+
diff --git a/chromium/gpu/tools/compositor_model_bench/render_model_utils.h b/chromium/gpu/tools/compositor_model_bench/render_model_utils.h
new file mode 100644
index 00000000000..eaa899110a6
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/render_model_utils.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Whole-tree processing that's likely to be helpful in multiple render models.
+
+#ifndef GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_MODEL_UTILS_H_
+#define GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_MODEL_UTILS_H_
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/tools/compositor_model_bench/render_tree.h"
+
+// This is a visitor that runs over the tree structure that was built from the
+// configuration file. It creates OpenGL textures (random checkerboards) that
+// match the specifications of the original textures and overwrites the old
+// texture ID's in the tree, replacing them with the matching new textures.
+class TextureGenerator : public RenderNodeVisitor {
+ public:
+ typedef scoped_ptr<uint8[]> ImagePtr;
+ typedef std::vector<Tile>::iterator tile_iter;
+
+ explicit TextureGenerator(RenderNode* root);
+ virtual ~TextureGenerator() OVERRIDE;
+
+ // RenderNodeVisitor functions look for textures and pass them
+ // off to HandleTexture (which behaves appropriately depending
+ // on which pass we are in.)
+ virtual void BeginVisitRenderNode(RenderNode* node) OVERRIDE;
+ virtual void BeginVisitCCNode(CCNode* node) OVERRIDE;
+
+ private:
+ enum TextureGenStage {
+ DiscoveryStage,
+ RemappingStage,
+ ImageGenerationStage
+ };
+
+ void DiscoverInputIDs(RenderNode* root);
+ void GenerateGLTexIDs();
+ void AssignIDMapping();
+ void WriteOutNewIDs(RenderNode* root);
+ void AllocateImageArray();
+ void BuildTextureImages(RenderNode* root);
+ void HandleTexture(int* texID, int width, int height, GLenum format);
+ void GenerateImageForTexture(int texID, int width, int height, GLenum format);
+
+ TextureGenStage stage_;
+ std::set<int> discovered_ids_;
+ scoped_ptr<GLuint[]> tex_ids_;
+ std::map<int, int> remapped_ids_;
+ scoped_ptr<ImagePtr[]> image_data_;
+ int images_generated_;
+ std::set<int> ids_for_completed_textures_;
+};
+
+#endif // GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_MODEL_UTILS_H_
+
diff --git a/chromium/gpu/tools/compositor_model_bench/render_models.cc b/chromium/gpu/tools/compositor_model_bench/render_models.cc
new file mode 100644
index 00000000000..bbbfac6cda6
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/render_models.cc
@@ -0,0 +1,41 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/tools/compositor_model_bench/render_models.h"
+
+#include <string>
+
+#include "gpu/tools/compositor_model_bench/forward_render_model.h"
+
+const char* ModelToString(RenderModel m) {
+ switch (m) {
+ case ForwardRenderModel:
+ return "Forward Rendering";
+ default:
+ return "(unknown render model name)";
+ }
+}
+
+RenderModelSimulator::RenderModelSimulator(RenderNode* root) : root_(root) {
+}
+
+RenderModelSimulator::~RenderModelSimulator() {
+}
+
+RenderModelSimulator* ConstructSimulationModel(RenderModel model,
+ RenderNode* render_tree_root,
+ int window_width,
+ int window_height) {
+ switch (model) {
+ case ForwardRenderModel:
+ return new ForwardRenderSimulator(render_tree_root,
+ window_width,
+ window_height);
+ default:
+ LOG(ERROR) << "Unrecognized render model. "
+ "If we know its name, then it's..." << ModelToString(model);
+ return 0;
+ }
+}
+
diff --git a/chromium/gpu/tools/compositor_model_bench/render_models.h b/chromium/gpu/tools/compositor_model_bench/render_models.h
new file mode 100644
index 00000000000..9da592b2365
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/render_models.h
@@ -0,0 +1,42 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Define the interface for a generic simulation, and a factory method for
+// instantiating different models.
+
+#ifndef GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_MODELS_H_
+#define GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_MODELS_H_
+
+#include "gpu/tools/compositor_model_bench/render_tree.h"
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+
+enum RenderModel {
+ ForwardRenderModel
+};
+
+const char* ModelToString(RenderModel m);
+
+class RenderModelSimulator {
+ public:
+ virtual ~RenderModelSimulator();
+ virtual void Update() = 0;
+ virtual void Resize(int width, int height) = 0;
+
+ protected:
+ explicit RenderModelSimulator(RenderNode* root);
+ scoped_ptr<RenderNode> root_;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(RenderModelSimulator);
+};
+
+RenderModelSimulator* ConstructSimulationModel(RenderModel model,
+ RenderNode* render_tree_root,
+ int window_width,
+ int window_height);
+
+#endif // GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_MODELS_H_
+
diff --git a/chromium/gpu/tools/compositor_model_bench/render_tree.cc b/chromium/gpu/tools/compositor_model_bench/render_tree.cc
new file mode 100644
index 00000000000..2e231860928
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/render_tree.cc
@@ -0,0 +1,483 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/tools/compositor_model_bench/render_tree.h"
+
+#include <sstream>
+#include <vector>
+
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/values.h"
+
+#include "gpu/tools/compositor_model_bench/shaders.h"
+
+using base::JSONReader;
+using base::JSONWriter;
+using base::Value;
+using file_util::ReadFileToString;
+using std::string;
+using std::vector;
+
+GLenum TextureFormatFromString(std::string format) {
+ if (format == "RGBA")
+ return GL_RGBA;
+ if (format == "RGB")
+ return GL_RGB;
+ if (format == "LUMINANCE")
+ return GL_LUMINANCE;
+ return GL_INVALID_ENUM;
+}
+
+const char* TextureFormatName(GLenum format) {
+ switch (format) {
+ case GL_RGBA:
+ return "RGBA";
+ case GL_RGB:
+ return "RGB";
+ case GL_LUMINANCE:
+ return "LUMINANCE";
+ default:
+ return "(unknown format)";
+ }
+}
+
+int FormatBytesPerPixel(GLenum format) {
+ switch (format) {
+ case GL_RGBA:
+ return 4;
+ case GL_RGB:
+ return 3;
+ case GL_LUMINANCE:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+RenderNode::RenderNode() {
+}
+
+RenderNode::~RenderNode() {
+}
+
+void RenderNode::Accept(RenderNodeVisitor* v) {
+ v->BeginVisitRenderNode(this);
+ v->EndVisitRenderNode(this);
+}
+
+ContentLayerNode::ContentLayerNode() {
+}
+
+ContentLayerNode::~ContentLayerNode() {
+}
+
+void ContentLayerNode::Accept(RenderNodeVisitor* v) {
+ v->BeginVisitContentLayerNode(this);
+ typedef vector<RenderNode*>::iterator node_itr;
+ for (node_itr i = children_.begin(); i != children_.end(); ++i) {
+ (*i)->Accept(v);
+ }
+ v->EndVisitContentLayerNode(this);
+}
+
+CCNode::CCNode() {
+}
+
+CCNode::~CCNode() {
+}
+
+void CCNode::Accept(RenderNodeVisitor* v) {
+ v->BeginVisitCCNode(this);
+ v->EndVisitCCNode(this);
+}
+
+RenderNodeVisitor::~RenderNodeVisitor() {
+}
+
+void RenderNodeVisitor::BeginVisitContentLayerNode(ContentLayerNode* v) {
+ this->BeginVisitRenderNode(v);
+}
+
+void RenderNodeVisitor::BeginVisitCCNode(CCNode* v) {
+ this->BeginVisitRenderNode(v);
+}
+
+void RenderNodeVisitor::EndVisitRenderNode(RenderNode* v) {
+}
+
+void RenderNodeVisitor::EndVisitContentLayerNode(ContentLayerNode* v) {
+ this->EndVisitRenderNode(v);
+}
+
+void RenderNodeVisitor::EndVisitCCNode(CCNode* v) {
+ this->EndVisitRenderNode(v);
+}
+
+RenderNode* InterpretNode(DictionaryValue* node);
+
+std::string ValueTypeAsString(Value::Type type) {
+ switch (type) {
+ case Value::TYPE_NULL:
+ return "NULL";
+ case Value::TYPE_BOOLEAN:
+ return "BOOLEAN";
+ case Value::TYPE_INTEGER:
+ return "INTEGER";
+ case Value::TYPE_DOUBLE:
+ return "DOUBLE";
+ case Value::TYPE_STRING:
+ return "STRING";
+ case Value::TYPE_BINARY:
+ return "BINARY";
+ case Value::TYPE_DICTIONARY:
+ return "DICTIONARY";
+ case Value::TYPE_LIST:
+ return "LIST";
+ default:
+ return "(UNKNOWN TYPE)";
+ }
+}
+
+// Makes sure that the key exists and has the type we expect.
+bool VerifyDictionaryEntry(DictionaryValue* node,
+ const std::string& key,
+ Value::Type type) {
+ if (!node->HasKey(key)) {
+ LOG(ERROR) << "Missing value for key: " << key;
+ return false;
+ }
+
+ Value* child;
+ node->Get(key, &child);
+ if (!child->IsType(type)) {
+ LOG(ERROR) << key << " did not have the expected type "
+ "(expected " << ValueTypeAsString(type) << ")";
+ return false;
+ }
+
+ return true;
+}
+
+// Makes sure that the list entry has the type we expect.
+bool VerifyListEntry(ListValue* l,
+ int idx,
+ Value::Type type,
+ const char* listName = 0) {
+ // Assume the idx is valid (since we'll be able to generate a better
+ // error message for this elsewhere.)
+ Value* el;
+ l->Get(idx, &el);
+ if (!el->IsType(type)) {
+ LOG(ERROR) << (listName ? listName : "List") << "element " << idx <<
+ " did not have the expected type (expected " <<
+ ValueTypeAsString(type) << ")\n";
+ return false;
+ }
+
+ return true;
+}
+
+bool InterpretCommonContents(DictionaryValue* node, RenderNode* c) {
+ if (!VerifyDictionaryEntry(node, "layerID", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(node, "width", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(node, "height", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(node, "drawsContent", Value::TYPE_BOOLEAN) ||
+ !VerifyDictionaryEntry(node, "targetSurfaceID", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(node, "transform", Value::TYPE_LIST)
+ ) {
+ return false;
+ }
+
+ int layerID;
+ node->GetInteger("layerID", &layerID);
+ c->set_layerID(layerID);
+ int width;
+ node->GetInteger("width", &width);
+ c->set_width(width);
+ int height;
+ node->GetInteger("height", &height);
+ c->set_height(height);
+ bool drawsContent;
+ node->GetBoolean("drawsContent", &drawsContent);
+ c->set_drawsContent(drawsContent);
+ int targetSurface;
+ node->GetInteger("targetSurfaceID", &targetSurface);
+ c->set_targetSurface(targetSurface);
+
+ ListValue* transform;
+ node->GetList("transform", &transform);
+ if (transform->GetSize() != 16) {
+ LOG(ERROR) << "4x4 transform matrix did not have 16 elements";
+ return false;
+ }
+ float transform_mat[16];
+ for (int i = 0; i < 16; ++i) {
+ if (!VerifyListEntry(transform, i, Value::TYPE_DOUBLE, "Transform"))
+ return false;
+ double el;
+ transform->GetDouble(i, &el);
+ transform_mat[i] = el;
+ }
+ c->set_transform(transform_mat);
+
+ if (node->HasKey("tiles")) {
+ if (!VerifyDictionaryEntry(node, "tiles", Value::TYPE_DICTIONARY))
+ return false;
+ DictionaryValue* tiles_dict;
+ node->GetDictionary("tiles", &tiles_dict);
+ if (!VerifyDictionaryEntry(tiles_dict, "dim", Value::TYPE_LIST))
+ return false;
+ ListValue* dim;
+ tiles_dict->GetList("dim", &dim);
+ if (!VerifyListEntry(dim, 0, Value::TYPE_INTEGER, "Tile dimension") ||
+ !VerifyListEntry(dim, 1, Value::TYPE_INTEGER, "Tile dimension")) {
+ return false;
+ }
+ int tile_width;
+ dim->GetInteger(0, &tile_width);
+ c->set_tile_width(tile_width);
+ int tile_height;
+ dim->GetInteger(1, &tile_height);
+ c->set_tile_height(tile_height);
+
+ if (!VerifyDictionaryEntry(tiles_dict, "info", Value::TYPE_LIST))
+ return false;
+ ListValue* tiles;
+ tiles_dict->GetList("info", &tiles);
+ for (unsigned int i = 0; i < tiles->GetSize(); ++i) {
+ if (!VerifyListEntry(tiles, i, Value::TYPE_DICTIONARY, "Tile info"))
+ return false;
+ DictionaryValue* tdict;
+ tiles->GetDictionary(i, &tdict);
+
+ if (!VerifyDictionaryEntry(tdict, "x", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(tdict, "y", Value::TYPE_INTEGER)) {
+ return false;
+ }
+ Tile t;
+ tdict->GetInteger("x", &t.x);
+ tdict->GetInteger("y", &t.y);
+ if (tdict->HasKey("texID")) {
+ if (!VerifyDictionaryEntry(tdict, "texID", Value::TYPE_INTEGER))
+ return false;
+ tdict->GetInteger("texID", &t.texID);
+ } else {
+ t.texID = -1;
+ }
+ c->add_tile(t);
+ }
+ }
+ return true;
+}
+
+bool InterpretCCData(DictionaryValue* node, CCNode* c) {
+ if (!VerifyDictionaryEntry(node, "vertex_shader", Value::TYPE_STRING) ||
+ !VerifyDictionaryEntry(node, "fragment_shader", Value::TYPE_STRING) ||
+ !VerifyDictionaryEntry(node, "textures", Value::TYPE_LIST)) {
+ return false;
+ }
+ string vertex_shader_name, fragment_shader_name;
+ node->GetString("vertex_shader", &vertex_shader_name);
+ node->GetString("fragment_shader", &fragment_shader_name);
+
+ c->set_vertex_shader(ShaderIDFromString(vertex_shader_name));
+ c->set_fragment_shader(ShaderIDFromString(fragment_shader_name));
+ ListValue* textures;
+ node->GetList("textures", &textures);
+ for (unsigned int i = 0; i < textures->GetSize(); ++i) {
+ if (!VerifyListEntry(textures, i, Value::TYPE_DICTIONARY, "Tex list"))
+ return false;
+ DictionaryValue* tex;
+ textures->GetDictionary(i, &tex);
+
+ if (!VerifyDictionaryEntry(tex, "texID", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(tex, "height", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(tex, "width", Value::TYPE_INTEGER) ||
+ !VerifyDictionaryEntry(tex, "format", Value::TYPE_STRING)) {
+ return false;
+ }
+ Texture t;
+ tex->GetInteger("texID", &t.texID);
+ tex->GetInteger("height", &t.height);
+ tex->GetInteger("width", &t.width);
+
+ string formatName;
+ tex->GetString("format", &formatName);
+ t.format = TextureFormatFromString(formatName);
+ if (t.format == GL_INVALID_ENUM) {
+ LOG(ERROR) << "Unrecognized texture format in layer " << c->layerID() <<
+ " (format: " << formatName << ")\n"
+ "The layer had " << textures->GetSize() << " children.";
+ return false;
+ }
+
+ c->add_texture(t);
+ }
+
+ if (c->vertex_shader() == SHADER_UNRECOGNIZED) {
+ LOG(ERROR) << "Unrecognized vertex shader name, layer " << c->layerID() <<
+ " (shader: " << vertex_shader_name << ")";
+ return false;
+ }
+
+ if (c->fragment_shader() == SHADER_UNRECOGNIZED) {
+ LOG(ERROR) << "Unrecognized fragment shader name, layer " << c->layerID() <<
+ " (shader: " << fragment_shader_name << ")";
+ return false;
+ }
+
+ return true;
+}
+
+RenderNode* InterpretContentLayer(DictionaryValue* node) {
+ ContentLayerNode* n = new ContentLayerNode;
+ if (!InterpretCommonContents(node, n))
+ return NULL;
+
+ if (!VerifyDictionaryEntry(node, "type", Value::TYPE_STRING) ||
+ !VerifyDictionaryEntry(node, "skipsDraw", Value::TYPE_BOOLEAN) ||
+ !VerifyDictionaryEntry(node, "children", Value::TYPE_LIST)) {
+ return NULL;
+ }
+
+ string type;
+ node->GetString("type", &type);
+ DCHECK_EQ(type, "ContentLayer");
+ bool skipsDraw;
+ node->GetBoolean("skipsDraw", &skipsDraw);
+ n->set_skipsDraw(skipsDraw);
+
+ ListValue* children;
+ node->GetList("children", &children);
+ for (unsigned int i = 0; i < children->GetSize(); ++i) {
+ DictionaryValue* childNode;
+ children->GetDictionary(i, &childNode);
+ RenderNode* child = InterpretNode(childNode);
+ if (child)
+ n->add_child(child);
+ }
+
+ return n;
+}
+
+RenderNode* InterpretCanvasLayer(DictionaryValue* node) {
+ CCNode* n = new CCNode;
+ if (!InterpretCommonContents(node, n))
+ return NULL;
+
+ if (!VerifyDictionaryEntry(node, "type", Value::TYPE_STRING)) {
+ return NULL;
+ }
+
+ string type;
+ node->GetString("type", &type);
+ assert(type == "CanvasLayer");
+
+ if (!InterpretCCData(node, n))
+ return NULL;
+
+ return n;
+}
+
+RenderNode* InterpretVideoLayer(DictionaryValue* node) {
+ CCNode* n = new CCNode;
+ if (!InterpretCommonContents(node, n))
+ return NULL;
+
+ if (!VerifyDictionaryEntry(node, "type", Value::TYPE_STRING)) {
+ return NULL;
+ }
+
+ string type;
+ node->GetString("type", &type);
+ assert(type == "VideoLayer");
+
+ if (!InterpretCCData(node, n))
+ return NULL;
+
+ return n;
+}
+
+RenderNode* InterpretImageLayer(DictionaryValue* node) {
+ CCNode* n = new CCNode;
+ if (!InterpretCommonContents(node, n))
+ return NULL;
+
+ if (!VerifyDictionaryEntry(node, "type", Value::TYPE_STRING)) {
+ return NULL;
+ }
+
+ string type;
+ node->GetString("type", &type);
+ assert(type == "ImageLayer");
+
+ if (!InterpretCCData(node, n))
+ return NULL;
+
+ return n;
+}
+
+RenderNode* InterpretNode(DictionaryValue* node) {
+ if (!VerifyDictionaryEntry(node, "type", Value::TYPE_STRING)) {
+ return NULL;
+ }
+
+ string type;
+ node->GetString("type", &type);
+ if (type == "ContentLayer")
+ return InterpretContentLayer(node);
+ if (type == "CanvasLayer")
+ return InterpretCanvasLayer(node);
+ if (type == "VideoLayer")
+ return InterpretVideoLayer(node);
+ if (type == "ImageLayer")
+ return InterpretImageLayer(node);
+
+
+ string outjson;
+ JSONWriter::WriteWithOptions(node, base::JSONWriter::OPTIONS_PRETTY_PRINT,
+ &outjson);
+ LOG(ERROR) << "Unrecognized node type! JSON:\n\n"
+ "-----------------------\n" <<
+ outjson <<
+ "-----------------------";
+
+ return NULL;
+}
+
+RenderNode* BuildRenderTreeFromFile(const base::FilePath& path) {
+ LOG(INFO) << "Reading " << path.LossyDisplayName();
+ string contents;
+ if (!ReadFileToString(path, &contents))
+ return NULL;
+
+ scoped_ptr<Value> root;
+ int error_code = 0;
+ string error_message;
+ root.reset(JSONReader::ReadAndReturnError(contents,
+ base::JSON_ALLOW_TRAILING_COMMAS,
+ &error_code,
+ &error_message));
+ if (!root.get()) {
+ LOG(ERROR) << "Failed to parse JSON file " << path.LossyDisplayName() <<
+ "\n(" << error_message << ")";
+ return NULL;
+ }
+
+ if (root->IsType(Value::TYPE_DICTIONARY)) {
+ DictionaryValue* v = static_cast<DictionaryValue*>(root.get());
+ RenderNode* tree = InterpretContentLayer(v);
+ return tree;
+ } else {
+ LOG(ERROR) << path.LossyDisplayName() <<
+ " doesn not encode a JSON dictionary.";
+ return NULL;
+ }
+}
+
diff --git a/chromium/gpu/tools/compositor_model_bench/render_tree.h b/chromium/gpu/tools/compositor_model_bench/render_tree.h
new file mode 100644
index 00000000000..adee4b81811
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/render_tree.h
@@ -0,0 +1,211 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Data structures for representing parts of Chromium's composited layer tree
+// and a function to load it from the JSON configuration file
+
+#ifndef GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_TREE_H_
+#define GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_TREE_H_
+
+#include <string>
+#include <vector>
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_vector.h"
+#include "gpu/tools/compositor_model_bench/shaders.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_implementation.h"
+
+// These are fairly arbitrary values based on how big my actual browser
+// window was.
+const int WINDOW_WIDTH = 1609;
+const int WINDOW_HEIGHT = 993;
+
+struct Tile {
+ int x;
+ int y;
+ int texID;
+};
+
+struct Texture {
+ int texID;
+ int height;
+ int width;
+ GLenum format;
+};
+
+GLenum TextureFormatFromString(std::string format);
+const char* TextureFormatName(GLenum format);
+int FormatBytesPerPixel(GLenum format);
+
+class RenderNodeVisitor;
+
+class RenderNode {
+ public:
+ RenderNode();
+ virtual ~RenderNode();
+ virtual void Accept(RenderNodeVisitor* v);
+
+ int layerID() {
+ return layerID_;
+ }
+
+ void set_layerID(int id) {
+ layerID_ = id;
+ }
+
+ int width() {
+ return width_;
+ }
+
+ void set_width(int width) {
+ width_ = width;
+ }
+
+ int height() {
+ return height_;
+ }
+
+ void set_height(int height) {
+ height_ = height;
+ }
+
+ bool drawsContent() {
+ return drawsContent_;
+ }
+
+ void set_drawsContent(bool draws) {
+ drawsContent_ = draws;
+ }
+
+ void set_targetSurface(int surface) {
+ targetSurface_ = surface;
+ }
+
+ float* transform() {
+ return transform_;
+ }
+
+ void set_transform(float* mat) {
+ memcpy(reinterpret_cast<void*>(transform_),
+ reinterpret_cast<void*>(mat),
+ 16 * sizeof(transform_[0]));
+ }
+
+ void add_tile(Tile t) {
+ tiles_.push_back(t);
+ }
+
+ size_t num_tiles() {
+ return tiles_.size();
+ }
+
+ Tile* tile(size_t index) {
+ return &tiles_[index];
+ }
+
+ int tile_width() {
+ return tile_width_;
+ }
+
+ void set_tile_width(int width) {
+ tile_width_ = width;
+ }
+
+ int tile_height() {
+ return tile_height_;
+ }
+
+ void set_tile_height(int height) {
+ tile_height_ = height;
+ }
+
+ private:
+ int layerID_;
+ int width_;
+ int height_;
+ bool drawsContent_;
+ int targetSurface_;
+ float transform_[16];
+ std::vector<Tile> tiles_;
+ int tile_width_;
+ int tile_height_;
+};
+
+class ContentLayerNode : public RenderNode {
+ public:
+ ContentLayerNode();
+ virtual ~ContentLayerNode();
+ virtual void Accept(RenderNodeVisitor* v) OVERRIDE;
+
+ void set_skipsDraw(bool skips) {
+ skipsDraw_ = skips;
+ }
+
+ void add_child(RenderNode* child) {
+ children_.push_back(child);
+ }
+
+ private:
+ ScopedVector<RenderNode> children_;
+ bool skipsDraw_;
+};
+
+class CCNode : public RenderNode {
+ public:
+ CCNode();
+ virtual ~CCNode();
+
+ virtual void Accept(RenderNodeVisitor* v) OVERRIDE;
+
+ ShaderID vertex_shader() {
+ return vertex_shader_;
+ }
+
+ void set_vertex_shader(ShaderID shader) {
+ vertex_shader_ = shader;
+ }
+
+ ShaderID fragment_shader() {
+ return fragment_shader_;
+ }
+
+ void set_fragment_shader(ShaderID shader) {
+ fragment_shader_ = shader;
+ }
+
+ void add_texture(Texture t) {
+ textures_.push_back(t);
+ }
+
+ size_t num_textures() {
+ return textures_.size();
+ }
+
+ Texture* texture(size_t index) {
+ return &textures_[index];
+ }
+
+ private:
+ ShaderID vertex_shader_;
+ ShaderID fragment_shader_;
+ std::vector<Texture> textures_;
+};
+
+class RenderNodeVisitor {
+ public:
+ virtual ~RenderNodeVisitor();
+
+ virtual void BeginVisitRenderNode(RenderNode* v) = 0;
+ virtual void BeginVisitContentLayerNode(ContentLayerNode* v);
+ virtual void BeginVisitCCNode(CCNode* v);
+ virtual void EndVisitRenderNode(RenderNode* v);
+ virtual void EndVisitContentLayerNode(ContentLayerNode* v);
+ virtual void EndVisitCCNode(CCNode* v);
+};
+
+RenderNode* BuildRenderTreeFromFile(const base::FilePath& path);
+
+#endif // GPU_TOOLS_COMPOSITOR_MODEL_BENCH_RENDER_TREE_H_
+
diff --git a/chromium/gpu/tools/compositor_model_bench/shaders.cc b/chromium/gpu/tools/compositor_model_bench/shaders.cc
new file mode 100644
index 00000000000..5559e73a558
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/shaders.cc
@@ -0,0 +1,450 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpu/tools/compositor_model_bench/shaders.h"
+
+#include <algorithm>
+
+#include "gpu/tools/compositor_model_bench/render_model_utils.h"
+#include "gpu/tools/compositor_model_bench/render_tree.h"
+
+using std::min;
+
+static const int kPositionLocation = 0;
+static const int kTexCoordLocation = 1;
+
+static unsigned g_quad_vertices_vbo;
+static unsigned g_quad_elements_vbo;
+
+// Store a pointer to the transform matrix of the active layer (the complete
+// transform isn't build until we draw the quad; then we can apply
+// translation/scaling/projection)
+static float* g_current_layer_transform;
+
+// In addition to the transform, store other useful information about tiled
+// layers that we'll need to render each tile's quad
+static float g_current_tile_layer_width;
+static float g_current_tile_layer_height;
+static float g_current_tile_width;
+static float g_current_tile_height;
+
+static const float yuv2RGB[9] = {
+ 1.164f, 1.164f, 1.164f,
+ 0.f, -.391f, 2.018f,
+ 1.596f, -.813f, 0.f
+};
+
+// Store shader programs in a sparse array so that they can be addressed easily.
+static int g_program_objects[SHADER_ID_MAX*SHADER_ID_MAX];
+static int g_active_index = -1;
+
+///////////////////////////////////////////////////////////////////////////////
+// L R B T N F
+// glOrtho(0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, -1, 1); // column major
+
+static float g_projection_matrix[] = {
+ 2.0 / WINDOW_WIDTH, 0.0, 0.0, 0.0,
+ 0.0, 2.0 / -WINDOW_HEIGHT, 0.0, 0.0,
+ 0.0, 0.0, -1.0, 0.0,
+ -1.0, 1.0, 0.0, 1.0
+};
+
+#define ADDR(i, j) (i*4 + j) /* column major */
+static void Project(const float* v, float* p) {
+ for (int i = 0; i < 4; ++i) {
+ for (int j = 0; j < 4; ++j) {
+ p[ADDR(i, j)] = 0;
+ for (int k = 0; k < 4; ++k) {
+ p[ADDR(i, j)] += g_projection_matrix[ADDR(k, i)] * v[ADDR(j, k)];
+ }
+ }
+ }
+}
+
+static void Scale(const float* in, float* out, float sx, float sy, float sz) {
+ for (int i = 0; i < 4; ++i)
+ out[i] = in[i] * sx;
+ for (int j = 4; j < 8; ++j)
+ out[j] = in[j] * sy;
+ for (int k = 8; k < 12; ++k)
+ out[k] = in[k] * sz;
+ for (int l = 12; l < 16; ++l)
+ out[l] = in[l];
+}
+
+static void TranslateInPlace(float* m, float tx, float ty, float tz) {
+ m[12] += tx;
+ m[13] += ty;
+ m[14] += tz;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ShaderID ShaderIDFromString(std::string name) {
+ if (name == "VertexShaderPosTexYUVStretch")
+ return VERTEX_SHADER_POS_TEX_YUV_STRETCH;
+ if (name == "VertexShaderPosTex")
+ return VERTEX_SHADER_POS_TEX;
+ if (name == "VertexShaderPosTexTransform")
+ return VERTEX_SHADER_POS_TEX_TRANSFORM;
+ if (name == "FragmentShaderYUVVideo")
+ return FRAGMENT_SHADER_YUV_VIDEO;
+ if (name == "FragmentShaderRGBATexFlipAlpha")
+ return FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA;
+ if (name == "FragmentShaderRGBATexAlpha")
+ return FRAGMENT_SHADER_RGBA_TEX_ALPHA;
+ return SHADER_UNRECOGNIZED;
+}
+
+std::string ShaderNameFromID(ShaderID id) {
+ switch (id) {
+ case VERTEX_SHADER_POS_TEX_YUV_STRETCH:
+ return "VertexShaderPosTexYUVStretch";
+ case VERTEX_SHADER_POS_TEX:
+ return "VertexShaderPosTex";
+ case VERTEX_SHADER_POS_TEX_TRANSFORM:
+ return "VertexShaderPosTexTransform";
+ case FRAGMENT_SHADER_YUV_VIDEO:
+ return "FragmentShaderYUVVideo";
+ case FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA:
+ return "FragmentShaderRGBATexFlipAlpha";
+ case FRAGMENT_SHADER_RGBA_TEX_ALPHA:
+ return "FragmentShaderRGBATexAlpha";
+ default:
+ return "(unknown shader)";
+ }
+}
+
+#define SHADER0(Src) #Src
+#define SHADER(Src) SHADER0(Src)
+
+const char* GetShaderSource(ShaderID shader) {
+ switch (shader) {
+ case VERTEX_SHADER_POS_TEX_YUV_STRETCH:
+ return SHADER(
+ #ifdef GL_ES
+ precision mediump float;
+ #endif
+ attribute vec4 a_position;
+ attribute vec2 a_texCoord;
+ uniform mat4 matrix;
+ varying vec2 y_texCoord;
+ varying vec2 uv_texCoord;
+ uniform float y_widthScaleFactor;
+ uniform float uv_widthScaleFactor;
+ void main() {
+ gl_Position = matrix * a_position;
+ y_texCoord = vec2(y_widthScaleFactor * a_texCoord.x,
+ a_texCoord.y);
+ uv_texCoord = vec2(uv_widthScaleFactor * a_texCoord.x,
+ a_texCoord.y);
+ });
+ break;
+ case VERTEX_SHADER_POS_TEX:
+ return SHADER(
+ attribute vec4 a_position;
+ attribute vec2 a_texCoord;
+ uniform mat4 matrix;
+ varying vec2 v_texCoord;
+ void main() {
+ gl_Position = matrix * a_position;
+ v_texCoord = a_texCoord;
+ });
+ break;
+ case VERTEX_SHADER_POS_TEX_TRANSFORM:
+ return SHADER(
+ attribute vec4 a_position;
+ attribute vec2 a_texCoord;
+ uniform mat4 matrix;
+ uniform vec4 texTransform;
+ varying vec2 v_texCoord;
+ void main() {
+ gl_Position = matrix * a_position;
+ v_texCoord = a_texCoord*texTransform.zw + texTransform.xy;
+ });
+ break;
+ case FRAGMENT_SHADER_YUV_VIDEO:
+ return SHADER(
+ #ifdef GL_ES
+ precision mediump float;
+ precision mediump int;
+ #endif
+ varying vec2 y_texCoord;
+ varying vec2 uv_texCoord;
+ uniform sampler2D y_texture;
+ uniform sampler2D u_texture;
+ uniform sampler2D v_texture;
+ uniform float alpha;
+ uniform vec3 yuv_adj;
+ uniform mat3 cc_matrix;
+ void main() {
+ float y_raw = texture2D(y_texture, y_texCoord).x;
+ float u_unsigned = texture2D(u_texture, uv_texCoord).x;
+ float v_unsigned = texture2D(v_texture, uv_texCoord).x;
+ vec3 yuv = vec3(y_raw, u_unsigned, v_unsigned) + yuv_adj;
+ vec3 rgb = cc_matrix * yuv;
+ gl_FragColor = vec4(rgb, 1.0) * alpha;
+ });
+ break;
+ case FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA:
+ return SHADER(
+ #ifdef GL_ES
+ precision mediump float;
+ #endif
+ varying vec2 v_texCoord;
+ uniform sampler2D s_texture;
+ uniform float alpha;
+ void main() {
+ vec4 texColor = texture2D(s_texture,
+ vec2(v_texCoord.x, 1.0 - v_texCoord.y));
+ gl_FragColor = vec4(texColor.x,
+ texColor.y,
+ texColor.z,
+ texColor.w) * alpha;
+ });
+ break;
+ case FRAGMENT_SHADER_RGBA_TEX_ALPHA:
+ return SHADER(
+ #ifdef GL_ES
+ precision mediump float;
+ #endif
+ varying vec2 v_texCoord;
+ uniform sampler2D s_texture;
+ uniform float alpha;
+ void main() {
+ vec4 texColor = texture2D(s_texture, v_texCoord);
+ gl_FragColor = texColor * alpha;
+ });
+ break;
+ default:
+ printf("Shader source requested for unknown shader\n");
+ return "";
+ }
+}
+
+int GetProgramIdx(ShaderID v, ShaderID f) {
+ return v * SHADER_ID_MAX + f;
+}
+
+static void ReportAnyShaderCompilationErrors(GLuint shader, ShaderID id) {
+ GLint status;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
+ if (status)
+ return;
+ // Get the length of the log string
+ GLsizei length;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
+ scoped_ptr<GLchar[]> log(new GLchar[length+1]);
+ glGetShaderInfoLog(shader, length, NULL, log.get());
+ LOG(ERROR) << log.get() << " in shader " << ShaderNameFromID(id);
+}
+
+static int ActivateShader(ShaderID v, ShaderID f, float* layer_transform) {
+ int program_index = GetProgramIdx(v, f);
+ if (!g_program_objects[program_index]) {
+ g_program_objects[program_index] = glCreateProgramObjectARB();
+ GLenum vs = glCreateShaderObjectARB(GL_VERTEX_SHADER);
+ GLenum fs = glCreateShaderObjectARB(GL_FRAGMENT_SHADER);
+ const char* vs_source = GetShaderSource(v);
+ const char* fs_source = GetShaderSource(f);
+ glShaderSourceARB(vs, 1, &vs_source, 0);
+ glShaderSourceARB(fs, 1, &fs_source, 0);
+ glCompileShaderARB(vs);
+ ReportAnyShaderCompilationErrors(vs, v);
+ glCompileShaderARB(fs);
+ ReportAnyShaderCompilationErrors(fs, f);
+ glAttachObjectARB(g_program_objects[program_index], vs);
+ glAttachObjectARB(g_program_objects[program_index], fs);
+ glBindAttribLocationARB(g_program_objects[program_index],
+ kPositionLocation,
+ "a_position");
+ glBindAttribLocationARB(g_program_objects[program_index],
+ kTexCoordLocation,
+ "a_texCoord");
+ glLinkProgramARB(g_program_objects[program_index]);
+ }
+ if (g_active_index != program_index)
+ glUseProgramObjectARB(g_program_objects[program_index]);
+ g_active_index = program_index;
+
+ g_current_layer_transform = layer_transform;
+
+ return g_program_objects[program_index];
+}
+
+void ConfigAndActivateShaderForNode(CCNode* n) {
+ ShaderID vs = n->vertex_shader();
+ ShaderID fs = n->fragment_shader();
+ float* transform = n->transform();
+ int program = ActivateShader(vs, fs, transform);
+ if (vs == VERTEX_SHADER_POS_TEX_YUV_STRETCH) {
+ GLint y_scale = glGetUniformLocationARB(program, "y_widthScaleFactor");
+ GLint uv_scale = glGetUniformLocationARB(program, "uv_widthScaleFactor");
+ glUniform1fARB(y_scale, 1.0);
+ glUniform1fARB(uv_scale, 1.0);
+ }
+ if (vs == VERTEX_SHADER_POS_TEX_TRANSFORM) {
+ GLint texTrans = glGetUniformLocationARB(program, "texTransform");
+ glUniform4fARB(texTrans, 0.0, 0.0, 0.0, 0.0);
+ }
+ if (fs == FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA) {
+ DCHECK_EQ(n->num_textures(), 1u);
+ DCHECK_NE(n->texture(0)->texID, -1);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, n->texture(0)->texID);
+ int sTexLoc = glGetUniformLocationARB(program, "s_texture");
+ glUniform1iARB(sTexLoc, 0);
+ }
+ if (fs == FRAGMENT_SHADER_YUV_VIDEO) {
+ DCHECK_EQ(n->num_textures(), 3u);
+ DCHECK_NE(n->texture(0)->texID, -1);
+ DCHECK_NE(n->texture(1)->texID, -1);
+ DCHECK_NE(n->texture(2)->texID, -1);
+ // Bind Y tex.
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, n->texture(0)->texID);
+ int yTexLoc = glGetUniformLocationARB(program, "y_texture");
+ glUniform1iARB(yTexLoc, 0);
+ // Bind U tex.
+ glActiveTexture(GL_TEXTURE0 + 1);
+ glBindTexture(GL_TEXTURE_2D, n->texture(1)->texID);
+ int uTexLoc = glGetUniformLocationARB(program, "u_texture");
+ glUniform1iARB(uTexLoc, 1);
+ // Bind V tex.
+ glActiveTexture(GL_TEXTURE0 + 2);
+ glBindTexture(GL_TEXTURE_2D, n->texture(2)->texID);
+ int vTexLoc = glGetUniformLocationARB(program, "v_texture");
+ glUniform1iARB(vTexLoc, 2);
+ // Set YUV offset.
+ int yuvAdjLoc = glGetUniformLocationARB(program, "yuv_adj");
+ glUniform3fARB(yuvAdjLoc, -0.0625f, -0.5f, -0.5f);
+ // Set YUV matrix.
+ int ccMatLoc = glGetUniformLocationARB(program, "cc_matrix");
+ glUniformMatrix3fvARB(ccMatLoc, 1, false, yuv2RGB);
+ }
+ GLint alpha = glGetUniformLocationARB(program, "alpha");
+ glUniform1fARB(alpha, 0.9);
+}
+
+void ConfigAndActivateShaderForTiling(ContentLayerNode* n) {
+ int program = ActivateShader(VERTEX_SHADER_POS_TEX_TRANSFORM,
+ FRAGMENT_SHADER_RGBA_TEX_ALPHA,
+ n->transform());
+ GLint texTrans = glGetUniformLocationARB(program, "texTransform");
+ glUniform4fARB(texTrans, 0.0, 0.0, 1.0, 1.0);
+ GLint alpha = glGetUniformLocationARB(program, "alpha");
+ glUniform1fARB(alpha, 0.9);
+
+ g_current_tile_layer_width = n->width();
+ g_current_tile_layer_height = n->height();
+ g_current_tile_width = n->tile_width();
+ g_current_tile_height = n->tile_height();
+}
+
+void DeleteShaders() {
+ g_active_index = -1;
+ glUseProgramObjectARB(0);
+ for (int i = 0; i < SHADER_ID_MAX*SHADER_ID_MAX; ++i) {
+ if (g_program_objects[i]) {
+ glDeleteObjectARB(g_program_objects[i]);
+ }
+ g_program_objects[i] = 0;
+ }
+}
+
+void InitBuffers() {
+ // Vertex positions and texture coordinates for the 4 corners of a 1x1 quad.
+ float vertices[] = { -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
+ -0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
+ 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
+ 0.5f, 0.5f, 0.0f, 1.0f, 1.0f };
+ uint16_t indices[] = { 0, 1, 2, 0, 2, 3};
+
+ glGenBuffers(1, &g_quad_vertices_vbo);
+ glGenBuffers(1, &g_quad_elements_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, g_quad_vertices_vbo);
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(vertices),
+ vertices,
+ GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_quad_elements_vbo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(indices),
+ indices,
+ GL_STATIC_DRAW);
+}
+
+void BeginFrame() {
+ glBindBuffer(GL_ARRAY_BUFFER, g_quad_vertices_vbo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, g_quad_elements_vbo);
+ unsigned offset = 0;
+ glVertexAttribPointer(kPositionLocation,
+ 3,
+ GL_FLOAT,
+ false,
+ 5 * sizeof(float),
+ reinterpret_cast<void*>(offset));
+ offset += 3 * sizeof(float);
+ glVertexAttribPointer(kTexCoordLocation,
+ 2,
+ GL_FLOAT,
+ false,
+ 5 * sizeof(float),
+ reinterpret_cast<void*>(offset));
+ glEnableVertexAttribArray(kPositionLocation);
+ glEnableVertexAttribArray(kTexCoordLocation);
+}
+
+void DrawQuad(float width, float height) {
+ float mv_transform[16];
+ float proj_transform[16];
+ Scale(g_current_layer_transform, mv_transform, width, height, 1.0);
+ Project(mv_transform, proj_transform);
+ GLint mat = glGetUniformLocationARB(g_program_objects[g_active_index],
+ "matrix");
+ glUniformMatrix4fvARB(mat, 1, GL_TRUE, proj_transform);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+}
+
+void DrawTileQuad(GLuint texID, int x, int y) {
+ float left = g_current_tile_width*x;
+ float top = g_current_tile_height*y;
+ if (left > g_current_tile_layer_width || top > g_current_tile_layer_height)
+ return;
+
+ float right = min(left+g_current_tile_width, g_current_tile_layer_width);
+ float bottom = min(top+g_current_tile_height, g_current_tile_layer_height);
+ float width = right-left;
+ float height = bottom-top;
+
+ int prog = g_program_objects[g_active_index];
+
+ // Scale the texture if the full tile rectangle doesn't get drawn.
+ float u_scale = width / g_current_tile_width;
+ float v_scale = height / g_current_tile_height;
+ GLint texTrans = glGetUniformLocationARB(prog, "texTransform");
+ glUniform4fARB(texTrans, 0.0, 0.0, u_scale, v_scale);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texID);
+ int texLoc = glGetUniformLocationARB(prog, "s_texture");
+ glUniform1iARB(texLoc, 0);
+
+ float mv_transform[16];
+ float proj_transform[16];
+ Scale(g_current_layer_transform, mv_transform, width, height, 1.0);
+
+ // We have to position the tile by its center.
+ float center_x = (left+right)/2 - g_current_tile_layer_width/2;
+ float center_y = (top+bottom)/2 - g_current_tile_layer_height/2;
+ TranslateInPlace(mv_transform, center_x, center_y, 0.0);
+
+ Project(mv_transform, proj_transform);
+ GLint mat = glGetUniformLocationARB(prog, "matrix");
+ glUniformMatrix4fvARB(mat, 1, GL_TRUE, proj_transform);
+
+ glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0);
+}
+
diff --git a/chromium/gpu/tools/compositor_model_bench/shaders.h b/chromium/gpu/tools/compositor_model_bench/shaders.h
new file mode 100644
index 00000000000..459403542fd
--- /dev/null
+++ b/chromium/gpu/tools/compositor_model_bench/shaders.h
@@ -0,0 +1,52 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Shaders from Chromium and an interface for setting them up
+
+#ifndef GPU_TOOLS_COMPOSITOR_MODEL_BENCH_SHADERS_H_
+#define GPU_TOOLS_COMPOSITOR_MODEL_BENCH_SHADERS_H_
+
+#include <string>
+
+// Forward declarations.
+class CCNode;
+class ContentLayerNode;
+
+typedef unsigned int GLuint;
+
+enum ShaderID {
+ SHADER_UNRECOGNIZED = 0,
+ VERTEX_SHADER_POS_TEX_YUV_STRETCH,
+ VERTEX_SHADER_POS_TEX,
+ VERTEX_SHADER_POS_TEX_TRANSFORM,
+ FRAGMENT_SHADER_YUV_VIDEO,
+ FRAGMENT_SHADER_RGBA_TEX_FLIP_ALPHA,
+ FRAGMENT_SHADER_RGBA_TEX_ALPHA,
+ SHADER_ID_MAX
+};
+
+ShaderID ShaderIDFromString(std::string name);
+std::string ShaderNameFromID(ShaderID id);
+
+void ConfigAndActivateShaderForNode(CCNode* n);
+
+// Call once to set up the parameters for an entire tiled layer, then use
+// DrawTileQuad for each tile to be drawn.
+void ConfigAndActivateShaderForTiling(ContentLayerNode* n);
+
+// One-off function to set up global VBO's that will be used every time
+// we want to draw a quad.
+void InitBuffers();
+
+// Per-frame initialization of the VBO's (to replicate behavior in Chrome.)
+void BeginFrame();
+
+// Draw the quad in those VBO's.
+void DrawQuad(float width, float height);
+
+// Draw the quad in those VBO's for an individual tile within a tiled layer.
+// x and y give the 2D index of the tile.
+void DrawTileQuad(GLuint texID, int x, int y);
+
+#endif // GPU_TOOLS_COMPOSITOR_MODEL_BENCH_SHADERS_H_
diff --git a/chromium/gpu/tools/tools.gyp b/chromium/gpu/tools/tools.gyp
new file mode 100644
index 00000000000..05807a61563
--- /dev/null
+++ b/chromium/gpu/tools/tools.gyp
@@ -0,0 +1,37 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ ],
+ 'conditions': [
+ ['OS == "linux" and target_arch != "arm"', {
+ 'targets': [
+ {
+ 'target_name': 'compositor_model_bench',
+ 'type': 'executable',
+ 'dependencies': [
+ '../../base/base.gyp:base',
+ '../../ui/gl/gl.gyp:gl',
+ ],
+ 'libraries': [
+ '-lGL',
+ '-ldl',
+ ],
+ 'sources': [
+ 'compositor_model_bench/compositor_model_bench.cc',
+ 'compositor_model_bench/render_tree.cc',
+ 'compositor_model_bench/shaders.cc',
+ 'compositor_model_bench/render_models.cc',
+ 'compositor_model_bench/render_model_utils.cc',
+ 'compositor_model_bench/forward_render_model.cc',
+ ],
+ },
+ ],
+ }],
+ ],
+}