From 39354677501b1634757ad98eca0109734f03da7b Mon Sep 17 00:00:00 2001 From: "reveman@chromium.org" Date: Wed, 16 Apr 2014 11:37:09 +0000 Subject: [PATCH] gpu: Add CHROMIUM_sync_query extension. This adds a GL_COMMANDS_COMPLETED_CHROMIUM query target that provide a finer granularity of synchronizing GL command completion than offered by glFinish(). BUG=269808,356871,273274 TEST=gpu_unittests --gtest_filter=GLES2DecoderManualInitTest.BeginEndQueryEXTCommandsCompletedCHROMIUM Review URL: https://codereview.chromium.org/238933003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@264173 0039d316-1c4b-4281-b951-d872f2087c98 --- .../extensions/CHROMIUM/CHROMIUM_sync_query.txt | 53 +++++++++++++++ gpu/GLES2/gl2extchromium.h | 9 +++ gpu/command_buffer/build_gles2_cmd_buffer.py | 1 + .../gles2_cmd_utils_implementation_autogen.h | 10 ++- gpu/command_buffer/service/feature_info.cc | 6 ++ gpu/command_buffer/service/feature_info.h | 1 + gpu/command_buffer/service/gles2_cmd_decoder.cc | 8 +++ .../service/gles2_cmd_decoder_unittest.cc | 76 +++++++++++++++++++++- .../gles2_cmd_validation_implementation_autogen.h | 3 +- gpu/command_buffer/service/query_manager.cc | 53 +++++++++++++++ gpu/command_buffer/tests/gl_query_unittest.cc | 16 +++++ ui/gl/gl_bindings.h | 3 + 12 files changed, 236 insertions(+), 3 deletions(-) create mode 100644 gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_query.txt diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_query.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_query.txt new file mode 100644 index 000000000000..98763d0a3836 --- /dev/null +++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_sync_query.txt @@ -0,0 +1,53 @@ +Name + + CHROMIUM_sync_query + +Name Strings + + GL_CHROMIUM_sync_query + +Version + + Last Modifed Date: April 15, 2014 + +Dependencies + + OpenGL ES 2.0 is required. + + EXT_occlusion_query_boolean is required. + +Overview + + This extension provides a query mechanism that allow for synchronization + between the host CPU and the GPU, which may be accessing the same + resources (typically memory). + + This extension is useful in conjunction with CHROMIUM_map_image to + determine when it is safe to access a mapped image. Once the result of + a COMMANDS_COMPLETED_CHROMIUM query is available, all drawing commands + issued before the query must have finished. This ensures that the memory + corresponding to the issued commands can be safely modified (assuming no + other outstanding drawing commands are issued subsequent to the query). + +New Procedures and Functions + + None. + +Errors + + None. + +New Tokens + + Accepted by the parameter of BeginQueryEXT, EndQueryEXT, + and GetQueryivEXT: + + COMMANDS_COMPLETED_CHROMIUM 0x84F7 + +New State + + None. + +Revision History + + 4/15/2014 Documented the extension diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index db4f12ff9075..0bdf7174f176 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h @@ -692,6 +692,15 @@ typedef void(GL_APIENTRYP PFNGLSCHEDULEOVERLAYPLANECHROMIUMPROC)( GLfloat uv_height); #endif /* GL_CHROMIUM_schedule_overlay_plane */ +/* GL_CHROMIUM_sync_query */ +#ifndef GL_CHROMIUM_sync_query +#define GL_CHROMIUM_sync_query 1 + +#ifndef GL_COMMANDS_COMPLETED_CHROMIUM +#define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7 +#endif +#endif /* GL_CHROMIUM_sync_query */ + #ifdef __cplusplus } #endif diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index 84d70c0d4111..7105edf4cbba 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -841,6 +841,7 @@ _ENUM_LISTS = { 'GL_LATENCY_QUERY_CHROMIUM', 'GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM', 'GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM', + 'GL_COMMANDS_COMPLETED_CHROMIUM', ], }, 'RenderBufferParameter': { diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h index 62f1c308c176..e9f4f699adb3 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h @@ -179,6 +179,7 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { {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", }, + {0x84F7, "GL_COMMANDS_COMPLETED_CHROMIUM", }, {0x881E, "GL_LUMINANCE16F_EXT", }, {0x84FA, "GL_UNSIGNED_INT_24_8_OES", }, {0x881F, "GL_LUMINANCE_ALPHA16F_EXT", }, @@ -353,6 +354,7 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { {0x8C93, "GL_ATC_RGBA_EXPLICIT_ALPHA_AMD", }, {0x00000002, "GL_CONTEXT_FLAG_DEBUG_BIT_KHR", }, {0x00000001, "GL_SYNC_FLUSH_COMMANDS_BIT_APPLE", }, + {0x9248, "GL_OVERLAY_TRANSFORM_ROTATE_90_CHROMIUM", }, {0x00000004, "GL_COLOR_BUFFER_BIT2_QCOM", }, {0x1702, "GL_TEXTURE", }, {0x00000008, "GL_COLOR_BUFFER_BIT3_QCOM", }, @@ -385,6 +387,7 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { {0x8DF6, "GL_UNSIGNED_INT_10_10_10_2_OES", }, {0x8230, "GL_RG32F_EXT", }, {0x8DF7, "GL_INT_10_10_10_2_OES", }, + {0x9246, "GL_OVERLAY_TRANSFORM_FLIP_HORIZONTAL_CHROMIUM", }, {0x8B69, "GL_FLOAT_MAT4x2_NV", }, {0x812D, "GL_CLAMP_TO_BORDER_NV", }, {0x812F, "GL_CLAMP_TO_EDGE", }, @@ -604,8 +607,11 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { {0x1F02, "GL_VERSION", }, {0x1F01, "GL_RENDERER", }, {0x1F00, "GL_VENDOR", }, + {0x9247, "GL_OVERLAY_TRANSFORM_FLIP_VERTICAL_CHROMIUM", }, {0x2701, "GL_LINEAR_MIPMAP_NEAREST", }, + {0x9245, "GL_OVERLAY_TRANSFORM_NONE_CHROMIUM", }, {0x92B4, "GL_INVERT_OVG_NV", }, + {0x9249, "GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM", }, {0x0B94, "GL_STENCIL_FAIL", }, {0x8B4C, "GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS", }, {0x8B4D, "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS", }, @@ -634,6 +640,7 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { {0x1004, "GL_TEXTURE_BORDER_COLOR_NV", }, {0x8B48, "GL_SHADER_OBJECT_EXT", }, {0x912F, "GL_TEXTURE_IMMUTABLE_FORMAT_EXT", }, + {0x924A, "GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM", }, {0x20000000, "GL_MULTISAMPLE_BUFFER_BIT5_QCOM", }, {0x0DE1, "GL_TEXTURE_2D", }, {0x80C9, "GL_BLEND_SRC_RGB", }, @@ -1163,7 +1170,8 @@ std::string GLES2Util::GetStringQueryTarget(uint32 value) { {GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, "GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM"}, {GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, - "GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM"}, }; + "GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM"}, + {GL_COMMANDS_COMPLETED_CHROMIUM, "GL_COMMANDS_COMPLETED_CHROMIUM"}, }; return GLES2Util::GetQualifiedEnumString( string_table, arraysize(string_table), value); } diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 81af90836e5c..b488318687aa 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -103,6 +103,7 @@ FeatureInfo::FeatureFlags::FeatureFlags() : chromium_color_buffer_float_rgba(false), chromium_color_buffer_float_rgb(false), chromium_framebuffer_multisample(false), + chromium_sync_query(false), use_core_framebuffer_multisample(false), multisampled_render_to_texture(false), use_img_for_multisampled_render_to_texture(false), @@ -784,6 +785,11 @@ void FeatureInfo::InitializeFeatures() { AddExtensionString("GL_EXT_discard_framebuffer"); feature_flags_.ext_discard_framebuffer = true; } + + if (ui_gl_fence_works) { + AddExtensionString("GL_CHROMIUM_sync_query"); + feature_flags_.chromium_sync_query = true; + } } void FeatureInfo::AddExtensionString(const std::string& str) { diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index 31f82349b54c..b9ac853212bf 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -31,6 +31,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted { bool chromium_color_buffer_float_rgba; bool chromium_color_buffer_float_rgb; bool chromium_framebuffer_multisample; + bool chromium_sync_query; // Use glBlitFramebuffer() and glRenderbufferStorageMultisample() with // GL_EXT_framebuffer_multisample-style semantics, since they are exposed // as core GL functions on this implementation. diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index a886513fb9bf..d0b040b06c41 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -9535,6 +9535,14 @@ error::Error GLES2DecoderImpl::HandleBeginQueryEXT( case GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM: case GL_GET_ERROR_QUERY_CHROMIUM: break; + case GL_COMMANDS_COMPLETED_CHROMIUM: + if (!features().chromium_sync_query) { + LOCAL_SET_GL_ERROR( + GL_INVALID_OPERATION, "glBeginQueryEXT", + "not enabled for commands completed queries"); + return error::kNoError; + } + break; default: if (!features().occlusion_query_boolean) { LOCAL_SET_GL_ERROR( diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 3c53d6331722..eece2502eff8 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -7112,6 +7112,7 @@ const QueryType kQueryTypes[] = { { GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, false }, { GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, false }, { GL_GET_ERROR_QUERY_CHROMIUM, false }, + { GL_COMMANDS_COMPLETED_CHROMIUM, false }, { GL_ANY_SAMPLES_PASSED_EXT, true }, }; @@ -7125,7 +7126,7 @@ static void CheckBeginEndQueryBadMemoryFails( // We need to reset the decoder on each iteration, because we lose the // context every time. GLES2DecoderTestBase::InitState init; - init.extensions = "GL_EXT_occlusion_query_boolean"; + init.extensions = "GL_EXT_occlusion_query_boolean GL_ARB_sync"; init.gl_version = "opengl es 2.0"; init.has_alpha = true; init.request_alpha = true; @@ -7160,6 +7161,13 @@ static void CheckBeginEndQueryBadMemoryFails( .WillOnce(Return(GL_NO_ERROR)) .RetiresOnSaturation(); } + GLsync kGlSync = reinterpret_cast(0xdeadbeef); + if (query_type.type == GL_COMMANDS_COMPLETED_CHROMIUM) { + EXPECT_CALL(*gl, Flush()).RetiresOnSaturation(); + EXPECT_CALL(*gl, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) + .WillOnce(Return(kGlSync)) + .RetiresOnSaturation(); + } EndQueryEXT end_cmd; end_cmd.Init(query_type.type, 1); @@ -7175,6 +7183,11 @@ static void CheckBeginEndQueryBadMemoryFails( .WillOnce(SetArgumentPointee<2>(1)) .RetiresOnSaturation(); } + if (query_type.type == GL_COMMANDS_COMPLETED_CHROMIUM) { + EXPECT_CALL(*gl, ClientWaitSync(kGlSync, _, _)) + .WillOnce(Return(GL_ALREADY_SIGNALED)) + .RetiresOnSaturation(); + } QueryManager* query_manager = test->GetDecoder()->GetQueryManager(); ASSERT_TRUE(query_manager != NULL); @@ -7189,6 +7202,8 @@ static void CheckBeginEndQueryBadMemoryFails( .Times(1) .RetiresOnSaturation(); } + if (query_type.type == GL_COMMANDS_COMPLETED_CHROMIUM) + EXPECT_CALL(*gl, DeleteSync(kGlSync)).Times(1).RetiresOnSaturation(); test->ResetDecoder(); } @@ -7276,6 +7291,65 @@ TEST_F(GLES2DecoderTest, BeginEndQueryEXTGetErrorQueryCHROMIUM) { static_cast(sync->result)); } +TEST_F(GLES2DecoderManualInitTest, BeginEndQueryEXTCommandsCompletedCHROMIUM) { + InitState init; + init.extensions = "GL_EXT_occlusion_query_boolean GL_ARB_sync"; + init.gl_version = "opengl es 2.0"; + init.has_alpha = true; + init.request_alpha = true; + init.bind_generates_resource = true; + InitDecoder(init); + + GenHelper(kNewClientId); + + BeginQueryEXT begin_cmd; + begin_cmd.Init(GL_COMMANDS_COMPLETED_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()); + + GLsync kGlSync = reinterpret_cast(0xdeadbeef); + EXPECT_CALL(*gl_, Flush()).RetiresOnSaturation(); + EXPECT_CALL(*gl_, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)) + .WillOnce(Return(kGlSync)) + .RetiresOnSaturation(); + + EndQueryEXT end_cmd; + end_cmd.Init(GL_COMMANDS_COMPLETED_CHROMIUM, 1); + EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_TRUE(query->pending()); + + EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _)) + .WillOnce(Return(GL_TIMEOUT_EXPIRED)) + .RetiresOnSaturation(); + bool process_success = query_manager->ProcessPendingQueries(); + + EXPECT_TRUE(process_success); + EXPECT_TRUE(query->pending()); + + EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _)) + .WillOnce(Return(GL_ALREADY_SIGNALED)) + .RetiresOnSaturation(); + process_success = query_manager->ProcessPendingQueries(); + + EXPECT_TRUE(process_success); + EXPECT_FALSE(query->pending()); + QuerySync* sync = static_cast(shared_memory_address_); + EXPECT_EQ(static_cast(0), static_cast(sync->result)); + + EXPECT_CALL(*gl_, DeleteSync(kGlSync)).Times(1).RetiresOnSaturation(); + ResetDecoder(); +} + TEST_F(GLES2DecoderTest, ProduceAndConsumeTextureCHROMIUM) { Mailbox mailbox = Mailbox::Generate(); diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h index ca49ced6f810..d296018a0da3 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h @@ -214,7 +214,8 @@ static const GLenum valid_query_target_table[] = { GL_COMMANDS_ISSUED_CHROMIUM, GL_LATENCY_QUERY_CHROMIUM, GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, - GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, }; + GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM, + GL_COMMANDS_COMPLETED_CHROMIUM, }; static const GLenum valid_read_pixel_format_table[] = {GL_ALPHA, GL_RGB, GL_RGBA, }; diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc index 9f1d3a7169c3..30c036ed98d0 100644 --- a/gpu/command_buffer/service/query_manager.cc +++ b/gpu/command_buffer/service/query_manager.cc @@ -16,6 +16,7 @@ #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" +#include "ui/gl/gl_fence.h" namespace gpu { namespace gles2 { @@ -389,6 +390,55 @@ void GetErrorQuery::Destroy(bool /* have_context */) { GetErrorQuery::~GetErrorQuery() { } +class CommandsCompletedQuery : public QueryManager::Query { + public: + CommandsCompletedQuery(QueryManager* manager, + GLenum target, + int32 shm_id, + uint32 shm_offset); + + // Overridden from QueryManager::Query: + virtual bool Begin() OVERRIDE; + virtual bool End(base::subtle::Atomic32 submit_count) OVERRIDE; + virtual bool Process() OVERRIDE; + virtual void Destroy(bool have_context) OVERRIDE; + + protected: + virtual ~CommandsCompletedQuery(); + + private: + scoped_ptr fence_; +}; + +CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager, + GLenum target, + int32 shm_id, + uint32 shm_offset) + : Query(manager, target, shm_id, shm_offset) {} + +bool CommandsCompletedQuery::Begin() { return true; } + +bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) { + fence_.reset(gfx::GLFence::Create()); + DCHECK(fence_); + return AddToPendingQueue(submit_count); +} + +bool CommandsCompletedQuery::Process() { + if (fence_ && !fence_->HasCompleted()) + return true; + return MarkAsCompleted(0); +} + +void CommandsCompletedQuery::Destroy(bool have_context) { + if (have_context && !IsDeleted()) { + fence_.reset(); + MarkAsDeleted(); + } +} + +CommandsCompletedQuery::~CommandsCompletedQuery() {} + QueryManager::QueryManager( GLES2Decoder* decoder, FeatureInfo* feature_info) @@ -444,6 +494,9 @@ QueryManager::Query* QueryManager::CreateQuery( case GL_GET_ERROR_QUERY_CHROMIUM: query = new GetErrorQuery(this, target, shm_id, shm_offset); break; + case GL_COMMANDS_COMPLETED_CHROMIUM: + query = new CommandsCompletedQuery(this, target, shm_id, shm_offset); + break; default: { GLuint service_id = 0; glGenQueriesARB(1, &service_id); diff --git a/gpu/command_buffer/tests/gl_query_unittest.cc b/gpu/command_buffer/tests/gl_query_unittest.cc index 9a8948fa1547..52423a832714 100644 --- a/gpu/command_buffer/tests/gl_query_unittest.cc +++ b/gpu/command_buffer/tests/gl_query_unittest.cc @@ -150,6 +150,22 @@ TEST_F(QueryTest, DISABLED_LatencyQueryBasic) { EXPECT_LE(query_result, kTimePrecisionMicroseconds); } +TEST_F(QueryTest, SyncQueryBasic) { + EXPECT_TRUE(GLTestHelper::HasExtension("GL_CHROMIUM_sync_query")); + + GLuint query = 0; + glGenQueriesEXT(1, &query); + + glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query); + glEndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM); + + glFinish(); + + GLuint available = 0; + glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &available); + EXPECT_TRUE(available); +} + } // namespace gpu diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index 8e0f2c6e613e..8b136088fed8 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h @@ -128,6 +128,9 @@ #define GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM 0x84F5 #define GL_ASYNC_PIXEL_PACK_COMPLETED_CHROMIUM 0x84F6 +// GL_CHROMIUM_sync_query +#define GL_COMMANDS_COMPLETED_CHROMIUM 0x84F7 + // GL_OES_texure_3D #define GL_SAMPLER_3D_OES 0x8B5F -- 2.11.4.GIT