diff options
65 files changed, 3158 insertions, 320 deletions
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn index 7193022..0462e45 100644 --- a/gpu/BUILD.gn +++ b/gpu/BUILD.gn @@ -127,6 +127,7 @@ test("gl_tests") { "command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc", "command_buffer/tests/gl_cube_map_texture_unittest.cc", "command_buffer/tests/gl_depth_texture_unittest.cc", + "command_buffer/tests/gl_ext_blend_func_extended_unittest.cc", "command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc", "command_buffer/tests/gl_ext_srgb_unittest.cc", "command_buffer/tests/gl_fence_sync_unittest.cc", diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h index 0cea2ef..f01a448 100644 --- a/gpu/GLES2/gl2chromium_autogen.h +++ b/gpu/GLES2/gl2chromium_autogen.h @@ -376,5 +376,9 @@ #define glBlendBarrierKHR GLES2_GET_FUN(BlendBarrierKHR) #define glApplyScreenSpaceAntialiasingCHROMIUM \ GLES2_GET_FUN(ApplyScreenSpaceAntialiasingCHROMIUM) +#define glBindFragDataLocationIndexedEXT \ + GLES2_GET_FUN(BindFragDataLocationIndexedEXT) +#define glBindFragDataLocationEXT GLES2_GET_FUN(BindFragDataLocationEXT) +#define glGetFragDataIndexEXT GLES2_GET_FUN(GetFragDataIndexEXT) #endif // GPU_GLES2_GL2CHROMIUM_AUTOGEN_H_ diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h index 7253500..8118de0 100644 --- a/gpu/GLES2/gl2extchromium.h +++ b/gpu/GLES2/gl2extchromium.h @@ -1169,12 +1169,47 @@ typedef void(GL_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENCHROMIUMPROC)( #endif /* GL_CHROMIUM_path_rendering */ + #ifndef GL_EXT_multisample_compatibility #define GL_EXT_multisample_compatibility 1 #define GL_MULTISAMPLE_EXT 0x809D #define GL_SAMPLE_ALPHA_TO_ONE_EXT 0x809F #endif /* GL_EXT_multisample_compatiblity */ +#ifndef GL_EXT_blend_func_extended +#define GL_EXT_blend_func_extended 1 + +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glBindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name); +GL_APICALL void GL_APIENTRY glBindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name); +GL_APICALL GLint GL_APIENTRY glGetFragDataIndexEXT(GLuint program, + const char* name); +#endif + +typedef void(GL_APIENTRYP PFNGLBINDFRAGDATALOCATIONINDEXEDEXT)( + GLuint program, + GLuint colorNumber, + GLuint index, + const char* name); +typedef void(GL_APIENTRYP PFNGLBINDFRAGDATALOCATIONEXT)(GLuint program, + GLuint colorNumber, + const char* name); +typedef GLint(GL_APIENTRYP PFNGLGETFRAGDATAINDEXEXT)(GLuint program, + const GLchar* name); + +#define GL_SRC_ALPHA_SATURATE_EXT 0x0308 +#define GL_SRC1_ALPHA_EXT 0x8589 // OpenGL 1.5 token value +#define GL_SRC1_COLOR_EXT 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC +#endif /* GL_EXT_blend_func_extended */ + #ifdef __cplusplus } #endif diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py index eb5724a..76708f5 100755 --- a/gpu/command_buffer/build_gles2_cmd_buffer.py +++ b/gpu/command_buffer/build_gles2_cmd_buffer.py @@ -2864,6 +2864,16 @@ _FUNCTION_INFO = { 'result': ['GLint'], 'error_return': -1, }, + 'GetFragDataIndexEXT': { + 'type': 'Custom', + 'data_transfer_methods': ['shm'], + 'cmd_args': + 'GLidProgram program, uint32_t name_bucket_id, GLint* index', + 'result': ['GLint'], + 'error_return': -1, + 'extension': 'EXT_blend_func_extended', + 'extension_flag': 'ext_blend_func_extended', + }, 'GetFragDataLocation': { 'type': 'Custom', 'data_transfer_methods': ['shm'], @@ -4017,6 +4027,22 @@ _FUNCTION_INFO = { 'extension': True, 'chromium': True, }, + 'BindFragDataLocationEXT': { + 'type': 'GLchar', + 'data_transfer_methods': ['bucket'], + 'needs_size': True, + 'gl_test_func': 'DoBindFragDataLocationEXT', + 'extension': 'EXT_blend_func_extended', + 'extension_flag': 'ext_blend_func_extended', + }, + 'BindFragDataLocationIndexedEXT': { + 'type': 'GLchar', + 'data_transfer_methods': ['bucket'], + 'needs_size': True, + 'gl_test_func': 'DoBindFragDataLocationIndexedEXT', + 'extension': 'EXT_blend_func_extended', + 'extension_flag': 'ext_blend_func_extended', + }, 'BindUniformLocationCHROMIUM': { 'type': 'GLchar', 'extension': 'CHROMIUM_bind_uniform_location', diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h index b274a6b..8cb59a9 100644 --- a/gpu/command_buffer/client/gles2_c_lib_autogen.h +++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h @@ -1704,6 +1704,21 @@ void GL_APIENTRY GLES2BlendBarrierKHR() { void GL_APIENTRY GLES2ApplyScreenSpaceAntialiasingCHROMIUM() { gles2::GetGLContext()->ApplyScreenSpaceAntialiasingCHROMIUM(); } +void GL_APIENTRY GLES2BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) { + gles2::GetGLContext()->BindFragDataLocationIndexedEXT(program, colorNumber, + index, name); +} +void GL_APIENTRY GLES2BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) { + gles2::GetGLContext()->BindFragDataLocationEXT(program, colorNumber, name); +} +GLint GL_APIENTRY GLES2GetFragDataIndexEXT(GLuint program, const char* name) { + return gles2::GetGLContext()->GetFragDataIndexEXT(program, name); +} namespace gles2 { @@ -2994,6 +3009,19 @@ extern const NameToFunc g_gles2_function_table[] = { glApplyScreenSpaceAntialiasingCHROMIUM), }, { + "glBindFragDataLocationIndexedEXT", + reinterpret_cast<GLES2FunctionPointer>( + glBindFragDataLocationIndexedEXT), + }, + { + "glBindFragDataLocationEXT", + reinterpret_cast<GLES2FunctionPointer>(glBindFragDataLocationEXT), + }, + { + "glGetFragDataIndexEXT", + reinterpret_cast<GLES2FunctionPointer>(glGetFragDataIndexEXT), + }, + { NULL, NULL, }, }; diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h index b5cf24c..b87750a 100644 --- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h +++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h @@ -3166,4 +3166,36 @@ void ApplyScreenSpaceAntialiasingCHROMIUM() { } } +void BindFragDataLocationIndexedEXTBucket(GLuint program, + GLuint colorNumber, + GLuint index, + uint32_t name_bucket_id) { + gles2::cmds::BindFragDataLocationIndexedEXTBucket* c = + GetCmdSpace<gles2::cmds::BindFragDataLocationIndexedEXTBucket>(); + if (c) { + c->Init(program, colorNumber, index, name_bucket_id); + } +} + +void BindFragDataLocationEXTBucket(GLuint program, + GLuint colorNumber, + uint32_t name_bucket_id) { + gles2::cmds::BindFragDataLocationEXTBucket* c = + GetCmdSpace<gles2::cmds::BindFragDataLocationEXTBucket>(); + if (c) { + c->Init(program, colorNumber, name_bucket_id); + } +} + +void GetFragDataIndexEXT(GLuint program, + uint32_t name_bucket_id, + uint32_t index_shm_id, + uint32_t index_shm_offset) { + gles2::cmds::GetFragDataIndexEXT* c = + GetCmdSpace<gles2::cmds::GetFragDataIndexEXT>(); + if (c) { + c->Init(program, name_bucket_id, index_shm_id, index_shm_offset); + } +} + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 6a00426..7c7f99d 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc @@ -1396,6 +1396,33 @@ void GLES2Implementation::BindAttribLocation( CheckGLError(); } +void GLES2Implementation::BindFragDataLocationEXT(GLuint program, + GLuint colorName, + const char* name) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFragDataLocationEXT(" + << program << ", " << colorName << ", " << name << ")"); + SetBucketAsString(kResultBucketId, name); + helper_->BindFragDataLocationEXTBucket(program, colorName, kResultBucketId); + helper_->SetBucketSize(kResultBucketId, 0); + CheckGLError(); +} + +void GLES2Implementation::BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorName, + GLuint index, + const char* name) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindFragDataLocationEXT(" + << program << ", " << colorName << ", " << index << ", " + << name << ")"); + SetBucketAsString(kResultBucketId, name); + helper_->BindFragDataLocationIndexedEXTBucket(program, colorName, index, + kResultBucketId); + helper_->SetBucketSize(kResultBucketId, 0); + CheckGLError(); +} + void GLES2Implementation::BindUniformLocationCHROMIUM( GLuint program, GLint location, const char* name) { GPU_CLIENT_SINGLE_THREAD_CHECK(); @@ -1607,6 +1634,35 @@ bool GLES2Implementation::GetProgramivHelper( return got_value; } +GLint GLES2Implementation::GetFragDataIndexEXTHelper(GLuint program, + const char* name) { + typedef cmds::GetFragDataIndexEXT::Result Result; + Result* result = GetResultAs<Result*>(); + if (!result) { + return -1; + } + *result = -1; + SetBucketAsCString(kResultBucketId, name); + helper_->GetFragDataIndexEXT(program, kResultBucketId, GetResultShmId(), + GetResultShmOffset()); + WaitForCmd(); + helper_->SetBucketSize(kResultBucketId, 0); + return *result; +} + +GLint GLES2Implementation::GetFragDataIndexEXT(GLuint program, + const char* name) { + GPU_CLIENT_SINGLE_THREAD_CHECK(); + GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetFragDataIndexEXT(" << program + << ", " << name << ")"); + TRACE_EVENT0("gpu", "GLES2::GetFragDataIndexEXT"); + GLint loc = share_group_->program_info_manager()->GetFragDataIndex( + this, program, name); + GPU_CLIENT_LOG("returned " << loc); + CheckGLError(); + return loc; +} + GLint GLES2Implementation::GetFragDataLocationHelper( GLuint program, const char* name) { typedef cmds::GetFragDataLocation::Result Result; diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 1c2eba9..1c55b83 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h @@ -215,6 +215,7 @@ class GLES2_IMPL_EXPORT GLES2Implementation void GetProgramInfoCHROMIUMHelper(GLuint program, std::vector<int8>* result); GLint GetAttribLocationHelper(GLuint program, const char* name); GLint GetUniformLocationHelper(GLuint program, const char* name); + GLint GetFragDataIndexEXTHelper(GLuint program, const char* name); GLint GetFragDataLocationHelper(GLuint program, const char* name); bool GetActiveAttribHelper( GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h index 0a4f886..10ebcc3 100644 --- a/gpu/command_buffer/client/gles2_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_implementation_autogen.h @@ -1184,4 +1184,15 @@ void BlendBarrierKHR() override; void ApplyScreenSpaceAntialiasingCHROMIUM() override; +void BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) override; + +void BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) override; + +GLint GetFragDataIndexEXT(GLuint program, const char* name) override; + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h index 77872e7..374cb26 100644 --- a/gpu/command_buffer/client/gles2_interface_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_autogen.h @@ -885,4 +885,12 @@ virtual void ProgramPathFragmentInputGenCHROMIUM(GLuint program, virtual GLenum GetGraphicsResetStatusKHR() = 0; virtual void BlendBarrierKHR() = 0; virtual void ApplyScreenSpaceAntialiasingCHROMIUM() = 0; +virtual void BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) = 0; +virtual void BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) = 0; +virtual GLint GetFragDataIndexEXT(GLuint program, const char* name) = 0; #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h index 5469525..489afa2 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h @@ -859,4 +859,12 @@ void ProgramPathFragmentInputGenCHROMIUM(GLuint program, GLenum GetGraphicsResetStatusKHR() override; void BlendBarrierKHR() override; void ApplyScreenSpaceAntialiasingCHROMIUM() override; +void BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) override; +void BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) override; +GLint GetFragDataIndexEXT(GLuint program, const char* name) override; #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h index 867652f..148f3af 100644 --- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h @@ -1159,4 +1159,16 @@ GLenum GLES2InterfaceStub::GetGraphicsResetStatusKHR() { } void GLES2InterfaceStub::BlendBarrierKHR() {} void GLES2InterfaceStub::ApplyScreenSpaceAntialiasingCHROMIUM() {} +void GLES2InterfaceStub::BindFragDataLocationIndexedEXT( + GLuint /* program */, + GLuint /* colorNumber */, + GLuint /* index */, + const char* /* name */) {} +void GLES2InterfaceStub::BindFragDataLocationEXT(GLuint /* program */, + GLuint /* colorNumber */, + const char* /* name */) {} +GLint GLES2InterfaceStub::GetFragDataIndexEXT(GLuint /* program */, + const char* /* name */) { + return 0; +} #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_INTERFACE_STUB_IMPL_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h index 209215e..8347572 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h @@ -859,4 +859,12 @@ void ProgramPathFragmentInputGenCHROMIUM(GLuint program, GLenum GetGraphicsResetStatusKHR() override; void BlendBarrierKHR() override; void ApplyScreenSpaceAntialiasingCHROMIUM() override; +void BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) override; +void BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) override; +GLint GetFragDataIndexEXT(GLuint program, const char* name) override; #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h index 77c6ab6..5f67456 100644 --- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h +++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h @@ -2475,4 +2475,27 @@ void GLES2TraceImplementation::ApplyScreenSpaceAntialiasingCHROMIUM() { gl_->ApplyScreenSpaceAntialiasingCHROMIUM(); } +void GLES2TraceImplementation::BindFragDataLocationIndexedEXT( + GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", + "GLES2Trace::BindFragDataLocationIndexedEXT"); + gl_->BindFragDataLocationIndexedEXT(program, colorNumber, index, name); +} + +void GLES2TraceImplementation::BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindFragDataLocationEXT"); + gl_->BindFragDataLocationEXT(program, colorNumber, name); +} + +GLint GLES2TraceImplementation::GetFragDataIndexEXT(GLuint program, + const char* name) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GetFragDataIndexEXT"); + return gl_->GetFragDataIndexEXT(program, name); +} + #endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_TRACE_IMPLEMENTATION_IMPL_AUTOGEN_H_ diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc index 939473a..d047b57 100644 --- a/gpu/command_buffer/client/program_info_manager.cc +++ b/gpu/command_buffer/client/program_info_manager.cc @@ -160,6 +160,19 @@ GLuint ProgramInfoManager::Program::GetUniformIndex( return GL_INVALID_INDEX; } +GLint ProgramInfoManager::Program::GetFragDataIndex( + const std::string& name) const { + auto iter = frag_data_indices_.find(name); + if (iter == frag_data_indices_.end()) + return -1; + return iter->second; +} + +void ProgramInfoManager::Program::CacheFragDataIndex(const std::string& name, + GLint index) { + frag_data_indices_[name] = index; +} + GLint ProgramInfoManager::Program::GetFragDataLocation( const std::string& name) const { base::hash_map<std::string, GLint>::const_iterator iter = @@ -725,6 +738,31 @@ GLint ProgramInfoManager::GetUniformLocation( return gl->GetUniformLocationHelper(program, name); } +GLint ProgramInfoManager::GetFragDataIndex(GLES2Implementation* gl, + GLuint program, + const char* name) { + // TODO(zmo): make FragData indexes part of the ProgramInfo that are + // fetched from the service side. See crbug.com/452104. + { + base::AutoLock auto_lock(lock_); + Program* info = GetProgramInfo(gl, program, kNone); + if (info) { + GLint possible_index = info->GetFragDataIndex(name); + if (possible_index != -1) + return possible_index; + } + } + GLint index = gl->GetFragDataIndexEXTHelper(program, name); + if (index != -1) { + base::AutoLock auto_lock(lock_); + Program* info = GetProgramInfo(gl, program, kNone); + if (info) { + info->CacheFragDataIndex(name, index); + } + } + return index; +} + GLint ProgramInfoManager::GetFragDataLocation( GLES2Implementation* gl, GLuint program, const char* name) { // TODO(zmo): make FragData locations part of the ProgramInfo that are diff --git a/gpu/command_buffer/client/program_info_manager.h b/gpu/command_buffer/client/program_info_manager.h index fa74ea5..fbae19a 100644 --- a/gpu/command_buffer/client/program_info_manager.h +++ b/gpu/command_buffer/client/program_info_manager.h @@ -38,6 +38,10 @@ class GLES2_IMPL_EXPORT ProgramInfoManager { GLint GetUniformLocation( GLES2Implementation* gl, GLuint program, const char* name); + GLint GetFragDataIndex(GLES2Implementation* gl, + GLuint program, + const char* name); + GLint GetFragDataLocation( GLES2Implementation* gl, GLuint program, const char* name); @@ -166,6 +170,9 @@ class GLES2_IMPL_EXPORT ProgramInfoManager { bool GetUniformsiv( GLsizei count, const GLuint* indices, GLenum pname, GLint* params); + GLint GetFragDataIndex(const std::string& name) const; + void CacheFragDataIndex(const std::string& name, GLint index); + GLint GetFragDataLocation(const std::string& name) const; void CacheFragDataLocation(const std::string& name, GLint loc); @@ -232,6 +239,7 @@ class GLES2_IMPL_EXPORT ProgramInfoManager { std::vector<UniformES3> uniforms_es3_; base::hash_map<std::string, GLint> frag_data_locations_; + base::hash_map<std::string, GLint> frag_data_indices_; }; Program* GetProgramInfo( diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt index 42ed5f5..8c9baf0 100644 --- a/gpu/command_buffer/cmd_buffer_functions.txt +++ b/gpu/command_buffer/cmd_buffer_functions.txt @@ -352,3 +352,9 @@ GL_APICALL void GL_APIENTRY glBlendBarrierKHR (void); // Extension GL_CHROMIUM_screen_space_antialiasing GL_APICALL void GL_APIENTRY glApplyScreenSpaceAntialiasingCHROMIUM (void); + +// Extension EXT_blend_func_extended +GL_APICALL void GL_APIENTRY glBindFragDataLocationIndexedEXT (GLidProgram program, GLuint colorNumber, GLuint index, const char* name); +GL_APICALL void GL_APIENTRY glBindFragDataLocationEXT (GLidProgram program, GLuint colorNumber, const char* name); +GL_APICALL GLint GL_APIENTRY glGetFragDataIndexEXT (GLidProgram program, const char* name); + diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h index b26cea0..ec3a09b 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h @@ -15434,4 +15434,164 @@ static_assert( offsetof(ApplyScreenSpaceAntialiasingCHROMIUM, header) == 0, "offset of ApplyScreenSpaceAntialiasingCHROMIUM header should be 0"); +struct BindFragDataLocationIndexedEXTBucket { + typedef BindFragDataLocationIndexedEXTBucket ValueType; + static const CommandId kCmdId = kBindFragDataLocationIndexedEXTBucket; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _program, + GLuint _colorNumber, + GLuint _index, + uint32_t _name_bucket_id) { + SetHeader(); + program = _program; + colorNumber = _colorNumber; + index = _index; + name_bucket_id = _name_bucket_id; + } + + void* Set(void* cmd, + GLuint _program, + GLuint _colorNumber, + GLuint _index, + uint32_t _name_bucket_id) { + static_cast<ValueType*>(cmd) + ->Init(_program, _colorNumber, _index, _name_bucket_id); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t program; + uint32_t colorNumber; + uint32_t index; + uint32_t name_bucket_id; +}; + +static_assert(sizeof(BindFragDataLocationIndexedEXTBucket) == 20, + "size of BindFragDataLocationIndexedEXTBucket should be 20"); +static_assert( + offsetof(BindFragDataLocationIndexedEXTBucket, header) == 0, + "offset of BindFragDataLocationIndexedEXTBucket header should be 0"); +static_assert( + offsetof(BindFragDataLocationIndexedEXTBucket, program) == 4, + "offset of BindFragDataLocationIndexedEXTBucket program should be 4"); +static_assert( + offsetof(BindFragDataLocationIndexedEXTBucket, colorNumber) == 8, + "offset of BindFragDataLocationIndexedEXTBucket colorNumber should be 8"); +static_assert( + offsetof(BindFragDataLocationIndexedEXTBucket, index) == 12, + "offset of BindFragDataLocationIndexedEXTBucket index should be 12"); +static_assert(offsetof(BindFragDataLocationIndexedEXTBucket, name_bucket_id) == + 16, + "offset of BindFragDataLocationIndexedEXTBucket name_bucket_id " + "should be 16"); + +struct BindFragDataLocationEXTBucket { + typedef BindFragDataLocationEXTBucket ValueType; + static const CommandId kCmdId = kBindFragDataLocationEXTBucket; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _program, GLuint _colorNumber, uint32_t _name_bucket_id) { + SetHeader(); + program = _program; + colorNumber = _colorNumber; + name_bucket_id = _name_bucket_id; + } + + void* Set(void* cmd, + GLuint _program, + GLuint _colorNumber, + uint32_t _name_bucket_id) { + static_cast<ValueType*>(cmd)->Init(_program, _colorNumber, _name_bucket_id); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t program; + uint32_t colorNumber; + uint32_t name_bucket_id; +}; + +static_assert(sizeof(BindFragDataLocationEXTBucket) == 16, + "size of BindFragDataLocationEXTBucket should be 16"); +static_assert(offsetof(BindFragDataLocationEXTBucket, header) == 0, + "offset of BindFragDataLocationEXTBucket header should be 0"); +static_assert(offsetof(BindFragDataLocationEXTBucket, program) == 4, + "offset of BindFragDataLocationEXTBucket program should be 4"); +static_assert( + offsetof(BindFragDataLocationEXTBucket, colorNumber) == 8, + "offset of BindFragDataLocationEXTBucket colorNumber should be 8"); +static_assert( + offsetof(BindFragDataLocationEXTBucket, name_bucket_id) == 12, + "offset of BindFragDataLocationEXTBucket name_bucket_id should be 12"); + +struct GetFragDataIndexEXT { + typedef GetFragDataIndexEXT ValueType; + static const CommandId kCmdId = kGetFragDataIndexEXT; + static const cmd::ArgFlags kArgFlags = cmd::kFixed; + static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3); + + typedef GLint Result; + + static uint32_t ComputeSize() { + return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT + } + + void SetHeader() { header.SetCmd<ValueType>(); } + + void Init(GLuint _program, + uint32_t _name_bucket_id, + uint32_t _index_shm_id, + uint32_t _index_shm_offset) { + SetHeader(); + program = _program; + name_bucket_id = _name_bucket_id; + index_shm_id = _index_shm_id; + index_shm_offset = _index_shm_offset; + } + + void* Set(void* cmd, + GLuint _program, + uint32_t _name_bucket_id, + uint32_t _index_shm_id, + uint32_t _index_shm_offset) { + static_cast<ValueType*>(cmd) + ->Init(_program, _name_bucket_id, _index_shm_id, _index_shm_offset); + return NextCmdAddress<ValueType>(cmd); + } + + gpu::CommandHeader header; + uint32_t program; + uint32_t name_bucket_id; + uint32_t index_shm_id; + uint32_t index_shm_offset; +}; + +static_assert(sizeof(GetFragDataIndexEXT) == 20, + "size of GetFragDataIndexEXT should be 20"); +static_assert(offsetof(GetFragDataIndexEXT, header) == 0, + "offset of GetFragDataIndexEXT header should be 0"); +static_assert(offsetof(GetFragDataIndexEXT, program) == 4, + "offset of GetFragDataIndexEXT program should be 4"); +static_assert(offsetof(GetFragDataIndexEXT, name_bucket_id) == 8, + "offset of GetFragDataIndexEXT name_bucket_id should be 8"); +static_assert(offsetof(GetFragDataIndexEXT, index_shm_id) == 12, + "offset of GetFragDataIndexEXT index_shm_id should be 12"); +static_assert(offsetof(GetFragDataIndexEXT, index_shm_offset) == 16, + "offset of GetFragDataIndexEXT index_shm_offset should be 16"); + #endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h index 95a8ab8..939ea4e 100644 --- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h @@ -5298,4 +5298,50 @@ TEST_F(GLES2FormatTest, ApplyScreenSpaceAntialiasingCHROMIUM) { CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); } +TEST_F(GLES2FormatTest, BindFragDataLocationIndexedEXTBucket) { + cmds::BindFragDataLocationIndexedEXTBucket& cmd = + *GetBufferAs<cmds::BindFragDataLocationIndexedEXTBucket>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLuint>(12), + static_cast<GLuint>(13), static_cast<uint32_t>(14)); + EXPECT_EQ( + static_cast<uint32_t>(cmds::BindFragDataLocationIndexedEXTBucket::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.colorNumber); + EXPECT_EQ(static_cast<GLuint>(13), cmd.index); + EXPECT_EQ(static_cast<uint32_t>(14), cmd.name_bucket_id); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, BindFragDataLocationEXTBucket) { + cmds::BindFragDataLocationEXTBucket& cmd = + *GetBufferAs<cmds::BindFragDataLocationEXTBucket>(); + void* next_cmd = cmd.Set(&cmd, static_cast<GLuint>(11), + static_cast<GLuint>(12), static_cast<uint32_t>(13)); + EXPECT_EQ(static_cast<uint32_t>(cmds::BindFragDataLocationEXTBucket::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.colorNumber); + EXPECT_EQ(static_cast<uint32_t>(13), cmd.name_bucket_id); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + +TEST_F(GLES2FormatTest, GetFragDataIndexEXT) { + cmds::GetFragDataIndexEXT& cmd = *GetBufferAs<cmds::GetFragDataIndexEXT>(); + void* next_cmd = + cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12), + static_cast<uint32_t>(13), static_cast<uint32_t>(14)); + EXPECT_EQ(static_cast<uint32_t>(cmds::GetFragDataIndexEXT::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_t>(12), cmd.name_bucket_id); + EXPECT_EQ(static_cast<uint32_t>(13), cmd.index_shm_id); + EXPECT_EQ(static_cast<uint32_t>(14), cmd.index_shm_offset); + CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd)); +} + #endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_ diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h index 22e5b0a..38dad79 100644 --- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h @@ -331,7 +331,10 @@ OP(BindFragmentInputLocationCHROMIUMBucket) /* 572 */ \ OP(ProgramPathFragmentInputGenCHROMIUM) /* 573 */ \ OP(BlendBarrierKHR) /* 574 */ \ - OP(ApplyScreenSpaceAntialiasingCHROMIUM) /* 575 */ + OP(ApplyScreenSpaceAntialiasingCHROMIUM) /* 575 */ \ + OP(BindFragDataLocationIndexedEXTBucket) /* 576 */ \ + OP(BindFragDataLocationEXTBucket) /* 577 */ \ + OP(GetFragDataIndexEXT) /* 578 */ enum CommandId { kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this. 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 b84fbb0..af31a51 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h +++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h @@ -643,6 +643,9 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { 0x78FB, "GL_RGB_YCBCR_422_CHROMIUM", }, { + 0x78FC, "GL_RGB_YCBCR_420V_CHROMIUM", + }, + { 0x80000000, "GL_MULTISAMPLE_BUFFER_BIT7_QCOM", }, { @@ -1279,6 +1282,9 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { 0x8576, "GL_CONSTANT_CHROMIUM", }, { + 0x8589, "GL_SRC1_ALPHA_EXT", + }, + { 0x85B5, "GL_VERTEX_ARRAY_BINDING_OES", }, { @@ -1555,6 +1561,18 @@ static const GLES2Util::EnumToString enum_to_string_table[] = { 0x88F0, "GL_DEPTH24_STENCIL8_OES", }, { + 0x88F9, "GL_SRC1_COLOR_EXT", + }, + { + 0x88FA, "GL_ONE_MINUS_SRC1_COLOR_EXT", + }, + { + 0x88FB, "GL_ONE_MINUS_SRC1_ALPHA_EXT", + }, + { + 0x88FC, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT", + }, + { 0x88FD, "GL_VERTEX_ATTRIB_ARRAY_INTEGER", }, { @@ -3956,6 +3974,7 @@ std::string GLES2Util::GetStringImageInternalFormat(uint32_t value) { {GL_RGB, "GL_RGB"}, {GL_RGB_YUV_420_CHROMIUM, "GL_RGB_YUV_420_CHROMIUM"}, {GL_RGB_YCBCR_422_CHROMIUM, "GL_RGB_YCBCR_422_CHROMIUM"}, + {GL_RGB_YCBCR_420V_CHROMIUM, "GL_RGB_YCBCR_420V_CHROMIUM"}, {GL_RGBA, "GL_RGBA"}, }; return GLES2Util::GetQualifiedEnumString(string_table, diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc index aeae5c6..cdda09f 100644 --- a/gpu/command_buffer/service/context_group.cc +++ b/gpu/command_buffer/service/context_group.cc @@ -67,6 +67,7 @@ ContextGroup::ContextGroup( max_vertex_uniform_vectors_(0u), max_color_attachments_(1u), max_draw_buffers_(1u), + max_dual_source_draw_buffers_(0u), program_cache_(NULL), feature_info_(feature_info) { { @@ -139,6 +140,11 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, if (max_draw_buffers_ < 1) max_draw_buffers_ = 1; } + if (feature_info_->feature_flags().ext_blend_func_extended) { + GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, + &max_dual_source_draw_buffers_); + DCHECK(max_dual_source_draw_buffers_ >= 1); + } buffer_manager_.reset( new BufferManager(memory_tracker_.get(), feature_info_.get())); @@ -285,8 +291,9 @@ bool ContextGroup::Initialize(GLES2Decoder* decoder, path_manager_.reset(new PathManager()); - program_manager_.reset(new ProgramManager( - program_cache_, max_varying_vectors_, feature_info_.get())); + program_manager_.reset( + new ProgramManager(program_cache_, max_varying_vectors_, + max_dual_source_draw_buffers_, feature_info_.get())); if (!texture_manager_->Initialize()) { LOG(ERROR) << "Context::Group::Initialize failed because texture manager " diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h index ad2c5df..fa9d3ac 100644 --- a/gpu/command_buffer/service/context_group.h +++ b/gpu/command_buffer/service/context_group.h @@ -123,6 +123,10 @@ class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> { return max_draw_buffers_; } + uint32 max_dual_source_draw_buffers() const { + return max_dual_source_draw_buffers_; + } + FeatureInfo* feature_info() { return feature_info_.get(); } @@ -271,6 +275,7 @@ class GPU_EXPORT ContextGroup : public base::RefCounted<ContextGroup> { uint32 max_vertex_uniform_vectors_; uint32 max_color_attachments_; uint32 max_draw_buffers_; + uint32 max_dual_source_draw_buffers_; ProgramCache* program_cache_; diff --git a/gpu/command_buffer/service/disk_cache_proto.proto b/gpu/command_buffer/service/disk_cache_proto.proto index b1059a6..6d78f4b 100644 --- a/gpu/command_buffer/service/disk_cache_proto.proto +++ b/gpu/command_buffer/service/disk_cache_proto.proto @@ -27,11 +27,17 @@ message ShaderVaryingProto { optional bool is_invariant = 3; } +message ShaderOutputVariableProto { + optional ShaderVariableProto basic = 1; + optional int32 location = 2; +} + message ShaderProto { optional bytes sha = 1; repeated ShaderAttributeProto attribs = 2; repeated ShaderUniformProto uniforms = 3; repeated ShaderVaryingProto varyings = 4; + repeated ShaderOutputVariableProto output_variables = 5; } message GpuProgramProto { diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc index 472fcb6..76494a6 100644 --- a/gpu/command_buffer/service/feature_info.cc +++ b/gpu/command_buffer/service/feature_info.cc @@ -176,7 +176,8 @@ FeatureInfo::FeatureFlags::FeatureFlags() enable_subscribe_uniform(false), emulate_primitive_restart_fixed_index(false), ext_render_buffer_format_bgra8888(false), - ext_multisample_compatibility(false) {} + ext_multisample_compatibility(false), + ext_blend_func_extended(false) {} FeatureInfo::Workarounds::Workarounds() : #define GPU_OP(type, name) name(false), @@ -226,7 +227,8 @@ void FeatureInfo::InitializeBasicState(const base::CommandLine* command_line) { // The shader translator is needed to translate from WebGL-conformant GLES SL // to normal GLES SL, enforce WebGL conformance, translate from GLES SL 1.0 to - // target context GLSL, etc. + // target context GLSL, implement emulation of OpenGL ES features on OpenGL, + // etc. // The flag here is for testing only. disable_shader_translator_ = command_line->HasSwitch(switches::kDisableGLSLTranslator); @@ -1186,6 +1188,36 @@ void FeatureInfo::InitializeFeatures() { } UMA_HISTOGRAM_BOOLEAN("GPU.TextureRG", feature_flags_.ext_texture_rg); + bool has_opengl_dual_source_blending = + gl_version_info_->IsAtLeastGL(3, 3) || + (gl_version_info_->IsAtLeastGL(3, 2) && + extensions.Contains("GL_ARB_blend_func_extended")); + if (!disable_shader_translator_ && + ((gl_version_info_->IsAtLeastGL(3, 2) && + has_opengl_dual_source_blending) || + (gl_version_info_->IsAtLeastGLES(3, 0) && + extensions.Contains("GL_EXT_blend_func_extended")))) { + // Note: to simplify the code, we do not expose EXT_blend_func_extended + // unless the service context supports ES 3.0. This means the theoretical ES + // 2.0 implementation with EXT_blend_func_extended is not sufficient. + feature_flags_.ext_blend_func_extended = true; + AddExtensionString("GL_EXT_blend_func_extended"); + + // NOTE: SRC_ALPHA_SATURATE is valid for ES2 src blend factor. + // SRC_ALPHA_SATURATE is valid for ES3 src and dst blend factor. + validators_.dst_blend_factor.AddValue(GL_SRC_ALPHA_SATURATE_EXT); + + validators_.src_blend_factor.AddValue(GL_SRC1_ALPHA_EXT); + validators_.dst_blend_factor.AddValue(GL_SRC1_ALPHA_EXT); + validators_.src_blend_factor.AddValue(GL_SRC1_COLOR_EXT); + validators_.dst_blend_factor.AddValue(GL_SRC1_COLOR_EXT); + validators_.src_blend_factor.AddValue(GL_ONE_MINUS_SRC1_COLOR_EXT); + validators_.dst_blend_factor.AddValue(GL_ONE_MINUS_SRC1_COLOR_EXT); + validators_.src_blend_factor.AddValue(GL_ONE_MINUS_SRC1_ALPHA_EXT); + validators_.dst_blend_factor.AddValue(GL_ONE_MINUS_SRC1_ALPHA_EXT); + validators_.g_l_state.AddValue(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT); + } + #if !defined(OS_MACOSX) if (workarounds_.ignore_egl_sync_failures) { gfx::GLFenceEGL::SetIgnoreFailures(); diff --git a/gpu/command_buffer/service/feature_info.h b/gpu/command_buffer/service/feature_info.h index c958315..f372f02 100644 --- a/gpu/command_buffer/service/feature_info.h +++ b/gpu/command_buffer/service/feature_info.h @@ -87,6 +87,7 @@ class GPU_EXPORT FeatureInfo : public base::RefCounted<FeatureInfo> { bool emulate_primitive_restart_fixed_index; bool ext_render_buffer_format_bgra8888; bool ext_multisample_compatibility; + bool ext_blend_func_extended; }; struct Workarounds { diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 34ddc02..1dec5cf 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc @@ -294,13 +294,10 @@ static bool CharacterIsValidForGLES(unsigned char c) { return false; } -static bool StringIsValidForGLES(const char* str) { - for (; *str; ++str) { - if (!CharacterIsValidForGLES(*str)) { - return false; - } - } - return true; +static bool StringIsValidForGLES(const std::string& str) { + return str.length() == 0 || + std::find_if_not(str.begin(), str.end(), CharacterIsValidForGLES) == + str.end(); } // This class prevents any GL errors that occur when it is in scope from @@ -1200,9 +1197,22 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { client_id, service_id, group_->max_vertex_attribs(), client_visible); } - void DoBindAttribLocation(GLuint client_id, GLuint index, const char* name); - void DoBindUniformLocationCHROMIUM( - GLuint client_id, GLint location, const char* name); + void DoBindAttribLocation(GLuint client_id, + GLuint index, + const std::string& name); + + error::Error DoBindFragDataLocation(GLuint program_id, + GLuint colorName, + const std::string& name); + + error::Error DoBindFragDataLocationIndexed(GLuint program_id, + GLuint colorName, + GLuint index, + const std::string& name); + + void DoBindUniformLocationCHROMIUM(GLuint client_id, + GLint location, + const std::string& name); error::Error GetAttribLocationHelper( GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset, @@ -1216,6 +1226,11 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset, const std::string& name_str); + error::Error GetFragDataIndexHelper(GLuint program_id, + uint32 index_shm_id, + uint32 index_shm_offset, + const std::string& name_str); + // Wrapper for glShaderSource. void DoShaderSource( GLuint client_id, GLsizei count, const char** data, const GLint* length); @@ -1859,7 +1874,8 @@ class GLES2DecoderImpl : public GLES2Decoder, public ErrorStateClient { void DoBindFragmentInputLocationCHROMIUM(GLuint program_id, GLint location, - const char* name); + const std::string& name); + // Generate a member function prototype for each command in an automated and // typesafe way. #define GLES2_CMD_OP(name) \ @@ -3178,6 +3194,7 @@ bool GLES2DecoderImpl::InitializeShaderTranslator() { resources.MaxDrawBuffers = group_->max_draw_buffers(); resources.MaxExpressionComplexity = 256; resources.MaxCallStackDepth = 256; + resources.MaxDualSourceDrawBuffers = group_->max_dual_source_draw_buffers(); GLint range[2] = { 0, 0 }; GLint precision = 0; @@ -3210,6 +3227,8 @@ bool GLES2DecoderImpl::InitializeShaderTranslator() { features().ext_shader_texture_lod ? 1 : 0; resources.NV_draw_buffers = features().nv_draw_buffers ? 1 : 0; + resources.EXT_blend_func_extended = + features().ext_blend_func_extended ? 1 : 0; } ShShaderSpec shader_spec; @@ -5485,6 +5504,12 @@ bool GLES2DecoderImpl::GetHelper( params[0] = group_->bind_generates_resource() ? 1 : 0; } return true; + case GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT: + *num_written = 1; + if (params) { + params[0] = group_->max_dual_source_draw_buffers(); + } + return true; default: if (pname >= GL_DRAW_BUFFER0_ARB && pname < GL_DRAW_BUFFER0_ARB + group_->max_draw_buffers()) { @@ -5614,14 +5639,15 @@ void GLES2DecoderImpl::DoGetBufferParameteriv( &state_, target, pname, params); } -void GLES2DecoderImpl::DoBindAttribLocation( - GLuint program_id, GLuint index, const char* name) { +void GLES2DecoderImpl::DoBindAttribLocation(GLuint program_id, + GLuint index, + const std::string& name) { if (!StringIsValidForGLES(name)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glBindAttribLocation", "Invalid character"); return; } - if (ProgramManager::IsInvalidPrefix(name, strlen(name))) { + if (ProgramManager::HasBuiltInPrefix(name)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, "glBindAttribLocation", "reserved prefix"); return; @@ -5643,7 +5669,7 @@ void GLES2DecoderImpl::DoBindAttribLocation( // Program::ExecuteBindAttribLocationCalls() right before link. program->SetAttribLocationBinding(name, static_cast<GLint>(index)); // TODO(zmo): Get rid of the following glBindAttribLocation call. - glBindAttribLocation(program->service_id(), index, name); + glBindAttribLocation(program->service_id(), index, name.c_str()); } error::Error GLES2DecoderImpl::HandleBindAttribLocationBucket( @@ -5661,19 +5687,121 @@ error::Error GLES2DecoderImpl::HandleBindAttribLocationBucket( if (!bucket->GetAsString(&name_str)) { return error::kInvalidArguments; } - DoBindAttribLocation(program, index, name_str.c_str()); + DoBindAttribLocation(program, index, name_str); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::DoBindFragDataLocation(GLuint program_id, + GLuint colorName, + const std::string& name) { + const char kFunctionName[] = "glBindFragDataLocationEXT"; + if (!StringIsValidForGLES(name)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "invalid character"); + return error::kNoError; + } + if (ProgramManager::HasBuiltInPrefix(name)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "reserved prefix"); + return error::kNoError; + } + if (colorName >= group_->max_draw_buffers()) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, + "colorName out of range"); + return error::kNoError; + } + Program* program = GetProgramInfoNotShader(program_id, kFunctionName); + if (!program) { + return error::kNoError; + } + program->SetProgramOutputLocationBinding(name, colorName); return error::kNoError; } -void GLES2DecoderImpl::DoBindUniformLocationCHROMIUM( - GLuint program_id, GLint location, const char* name) { +error::Error GLES2DecoderImpl::HandleBindFragDataLocationEXTBucket( + uint32 immediate_data_size, + const void* cmd_data) { + if (!features().ext_blend_func_extended) { + return error::kUnknownCommand; + } + const gles2::cmds::BindFragDataLocationEXTBucket& c = + *static_cast<const gles2::cmds::BindFragDataLocationEXTBucket*>(cmd_data); + GLuint program = static_cast<GLuint>(c.program); + GLuint colorNumber = static_cast<GLuint>(c.colorNumber); + 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; + } + return DoBindFragDataLocation(program, colorNumber, name_str); +} + +error::Error GLES2DecoderImpl::DoBindFragDataLocationIndexed( + GLuint program_id, + GLuint colorName, + GLuint index, + const std::string& name) { + const char kFunctionName[] = "glBindFragDataLocationIndexEXT"; + if (!StringIsValidForGLES(name)) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "invalid character"); + return error::kNoError; + } + if (ProgramManager::HasBuiltInPrefix(name)) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "reserved prefix"); + return error::kNoError; + } + if (index != 0 && index != 1) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "index out of range"); + return error::kNoError; + } + if ((index == 0 && colorName >= group_->max_draw_buffers()) || + (index == 1 && colorName >= group_->max_dual_source_draw_buffers())) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, + "colorName out of range for the color index"); + return error::kNoError; + } + Program* program = GetProgramInfoNotShader(program_id, kFunctionName); + if (!program) { + return error::kNoError; + } + program->SetProgramOutputLocationIndexedBinding(name, colorName, index); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleBindFragDataLocationIndexedEXTBucket( + uint32 immediate_data_size, + const void* cmd_data) { + if (!features().ext_blend_func_extended) { + return error::kUnknownCommand; + } + const gles2::cmds::BindFragDataLocationIndexedEXTBucket& c = + *static_cast<const gles2::cmds::BindFragDataLocationIndexedEXTBucket*>( + cmd_data); + GLuint program = static_cast<GLuint>(c.program); + GLuint colorNumber = static_cast<GLuint>(c.colorNumber); + 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; + } + return DoBindFragDataLocationIndexed(program, colorNumber, index, name_str); +} + +void GLES2DecoderImpl::DoBindUniformLocationCHROMIUM(GLuint program_id, + GLint location, + const std::string& name) { if (!StringIsValidForGLES(name)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glBindUniformLocationCHROMIUM", "Invalid character"); return; } - if (ProgramManager::IsInvalidPrefix(name, strlen(name))) { + if (ProgramManager::HasBuiltInPrefix(name)) { LOCAL_SET_GL_ERROR( GL_INVALID_OPERATION, "glBindUniformLocationCHROMIUM", "reserved prefix"); @@ -5715,7 +5843,7 @@ error::Error GLES2DecoderImpl::HandleBindUniformLocationCHROMIUMBucket( if (!bucket->GetAsString(&name_str)) { return error::kInvalidArguments; } - DoBindUniformLocationCHROMIUM(program, location, name_str.c_str()); + DoBindUniformLocationCHROMIUM(program, location, name_str); return error::kNoError; } @@ -9360,7 +9488,7 @@ error::Error GLES2DecoderImpl::HandleScheduleCALayerCHROMIUM( 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())) { + if (!StringIsValidForGLES(name_str)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glGetAttribLocation", "Invalid character"); return error::kNoError; @@ -9408,7 +9536,7 @@ error::Error GLES2DecoderImpl::HandleGetAttribLocation( 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())) { + if (!StringIsValidForGLES(name_str)) { LOCAL_SET_GL_ERROR( GL_INVALID_VALUE, "glGetUniformLocation", "Invalid character"); return error::kNoError; @@ -9508,6 +9636,7 @@ error::Error GLES2DecoderImpl::HandleGetUniformIndices( error::Error GLES2DecoderImpl::GetFragDataLocationHelper( GLuint client_id, uint32 location_shm_id, uint32 location_shm_offset, const std::string& name_str) { + const char kFunctionName[] = "glGetFragDataLocation"; GLint* location = GetSharedMemoryAs<GLint*>( location_shm_id, location_shm_offset, sizeof(GLint)); if (!location) { @@ -9517,12 +9646,17 @@ error::Error GLES2DecoderImpl::GetFragDataLocationHelper( if (*location != -1) { return error::kInvalidArguments; } - Program* program = GetProgramInfoNotShader( - client_id, "glGetFragDataLocation"); + Program* program = GetProgramInfoNotShader(client_id, kFunctionName); if (!program) { return error::kNoError; } - *location = glGetFragDataLocation(program->service_id(), name_str.c_str()); + if (!program->IsValid()) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "program not linked"); + return error::kNoError; + } + + *location = program->GetFragDataLocation(name_str); return error::kNoError; } @@ -9545,6 +9679,55 @@ error::Error GLES2DecoderImpl::HandleGetFragDataLocation( c.program, c.location_shm_id, c.location_shm_offset, name_str); } +error::Error GLES2DecoderImpl::GetFragDataIndexHelper( + GLuint program_id, + uint32 index_shm_id, + uint32 index_shm_offset, + const std::string& name_str) { + const char kFunctionName[] = "glGetFragDataIndexEXT"; + GLint* index = + GetSharedMemoryAs<GLint*>(index_shm_id, index_shm_offset, sizeof(GLint)); + if (!index) { + return error::kOutOfBounds; + } + // Check that the client initialized the result. + if (*index != -1) { + return error::kInvalidArguments; + } + Program* program = GetProgramInfoNotShader(program_id, kFunctionName); + if (!program) { + return error::kNoError; + } + if (!program->IsValid()) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, + "program not linked"); + return error::kNoError; + } + + *index = program->GetFragDataIndex(name_str); + return error::kNoError; +} + +error::Error GLES2DecoderImpl::HandleGetFragDataIndexEXT( + uint32 immediate_data_size, + const void* cmd_data) { + if (!features().ext_blend_func_extended) { + return error::kUnknownCommand; + } + const gles2::cmds::GetFragDataIndexEXT& c = + *static_cast<const gles2::cmds::GetFragDataIndexEXT*>(cmd_data); + 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 GetFragDataIndexHelper(c.program, c.index_shm_id, c.index_shm_offset, + name_str); +} + error::Error GLES2DecoderImpl::HandleGetUniformBlockIndex( uint32 immediate_data_size, const void* cmd_data) { if (!unsafe_es3_apis_enabled()) @@ -15288,23 +15471,24 @@ GLES2DecoderImpl::HandleStencilThenCoverStrokePathInstancedCHROMIUM( return error::kNoError; } -void GLES2DecoderImpl::DoBindFragmentInputLocationCHROMIUM(GLuint program_id, - GLint location, - const char* name) { +void GLES2DecoderImpl::DoBindFragmentInputLocationCHROMIUM( + GLuint program_id, + GLint location, + const std::string& name) { static const char kFunctionName[] = "glBindFragmentInputLocationCHROMIUM"; - Program* program = GetProgram(program_id); - if (!program || program->IsDeleted()) { - LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "invalid program"); - return; - } if (!StringIsValidForGLES(name)) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, "invalid character"); return; } - if (ProgramManager::IsInvalidPrefix(name, strlen(name))) { + if (ProgramManager::HasBuiltInPrefix(name)) { LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "reserved prefix"); return; } + Program* program = GetProgram(program_id); + if (!program || program->IsDeleted()) { + LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, kFunctionName, "invalid program"); + return; + } if (location < 0 || static_cast<uint32>(location) >= group_->max_varying_vectors() * 4) { LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, kFunctionName, @@ -15335,7 +15519,7 @@ error::Error GLES2DecoderImpl::HandleBindFragmentInputLocationCHROMIUMBucket( if (!bucket->GetAsString(&name_str)) { return error::kInvalidArguments; } - DoBindFragmentInputLocationCHROMIUM(program, location, name_str.c_str()); + DoBindFragmentInputLocationCHROMIUM(program, location, name_str); return error::kNoError; } diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc index 3f6d20d..c09c658 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc @@ -1533,6 +1533,17 @@ TEST_P(GLES2DecoderDoCommandsTest, DoCommandsBadArgSize) { EXPECT_EQ(entries_per_cmd_ + cmds_[1].header.size, num_processed); } +void GLES3DecoderWithESSL3ShaderTest::SetUp() { + base::CommandLine command_line(0, nullptr); + command_line.AppendSwitch(switches::kEnableUnsafeES3APIs); + InitState init; + init.gl_version = "OpenGL ES 3.0"; + init.bind_generates_resource = true; + init.context_type = CONTEXT_TYPE_OPENGLES3; + InitDecoderWithCommandLine(init, &command_line); + SetupDefaultProgram(); +} + INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderTest, ::testing::Bool()); INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderWithShaderTest, ::testing::Bool()); @@ -1547,5 +1558,9 @@ INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderDoCommandsTest, ::testing::Bool()); INSTANTIATE_TEST_CASE_P(Service, GLES3DecoderTest, ::testing::Bool()); +INSTANTIATE_TEST_CASE_P(Service, + GLES3DecoderWithESSL3ShaderTest, + ::testing::Bool()); + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h index a57903c..4cab05c 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.h @@ -82,6 +82,12 @@ class GLES3DecoderTest : public GLES2DecoderTest { void SetUp() override; }; +class GLES3DecoderWithESSL3ShaderTest : public GLES2DecoderWithShaderTestBase { + public: + GLES3DecoderWithESSL3ShaderTest() { shader_language_version_ = 300; } + void SetUp() override; +}; + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc index c704c28..b149135 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc @@ -120,7 +120,8 @@ GLES2DecoderTestBase::GLES2DecoderTestBase() cached_color_mask_alpha_(true), cached_depth_mask_(true), cached_stencil_front_mask_(static_cast<GLuint>(-1)), - cached_stencil_back_mask_(static_cast<GLuint>(-1)) { + cached_stencil_back_mask_(static_cast<GLuint>(-1)), + shader_language_version_(100) { memset(immediate_buffer_, 0xEE, sizeof(immediate_buffer_)); } @@ -1498,7 +1499,10 @@ const GLenum GLES2DecoderTestBase::kUniform7Type; const GLenum GLES2DecoderTestBase::kUniformCubemapType; const GLint GLES2DecoderTestBase::kInvalidUniformLocation; const GLint GLES2DecoderTestBase::kBadUniformIndex; - +const GLint GLES2DecoderTestBase::kOutputVariable1Size; +const GLenum GLES2DecoderTestBase::kOutputVariable1Type; +const GLuint GLES2DecoderTestBase::kOutputVariable1ColorName; +const GLuint GLES2DecoderTestBase::kOutputVariable1Index; #endif const char* GLES2DecoderTestBase::kAttrib1Name = "attrib1"; @@ -1512,6 +1516,9 @@ const char* GLES2DecoderTestBase::kUniform5Name = "uniform5"; const char* GLES2DecoderTestBase::kUniform6Name = "uniform6"; const char* GLES2DecoderTestBase::kUniform7Name = "uniform7"; +const char* GLES2DecoderTestBase::kOutputVariable1Name = "gl_FragColor"; +const char* GLES2DecoderTestBase::kOutputVariable1NameESSL3 = "color"; + void GLES2DecoderTestBase::SetupDefaultProgram() { { static AttribInfo attribs[] = { @@ -1660,6 +1667,19 @@ void GLES2DecoderTestBase::SetupShader( 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) { + static TestHelper::ProgramOutputInfo kProgramOutputsESSL1[] = {{ + kOutputVariable1Name, kOutputVariable1Size, kOutputVariable1Type, + kOutputVariable1ColorName, kOutputVariable1Index, + }}; + static TestHelper::ProgramOutputInfo kProgramOutputsESSL3[] = {{ + kOutputVariable1NameESSL3, kOutputVariable1Size, kOutputVariable1Type, + kOutputVariable1ColorName, kOutputVariable1Index, + }}; + TestHelper::ProgramOutputInfo* program_outputs = + shader_language_version_ == 100 ? kProgramOutputsESSL1 + : kProgramOutputsESSL3; + const size_t kNumProgramOutputs = 1; + { InSequence s; @@ -1671,9 +1691,11 @@ void GLES2DecoderTestBase::SetupShader( AttachShader(program_service_id, fragment_shader_service_id)) .Times(1) .RetiresOnSaturation(); - TestHelper::SetupShaderExpectations(gl_.get(), group_->feature_info(), - attribs, num_attribs, uniforms, - num_uniforms, program_service_id); + + TestHelper::SetupShaderExpectationsWithVaryings( + gl_.get(), group_->feature_info(), attribs, num_attribs, uniforms, + num_uniforms, nullptr, 0, program_outputs, kNumProgramOutputs, + program_service_id); } DoCreateShader( @@ -1682,10 +1704,20 @@ void GLES2DecoderTestBase::SetupShader( GL_FRAGMENT_SHADER, fragment_shader_client_id, fragment_shader_service_id); - TestHelper::SetShaderStates( - gl_.get(), GetShader(vertex_shader_client_id), true); - TestHelper::SetShaderStates( - gl_.get(), GetShader(fragment_shader_client_id), true); + TestHelper::SetShaderStates(gl_.get(), GetShader(vertex_shader_client_id), + true, nullptr, nullptr, &shader_language_version_, + nullptr, nullptr, nullptr, nullptr, nullptr, + nullptr); + + OutputVariableList frag_output_variable_list; + frag_output_variable_list.push_back(TestHelper::ConstructOutputVariable( + program_outputs[0].type, program_outputs[0].size, GL_MEDIUM_FLOAT, true, + program_outputs[0].name)); + + TestHelper::SetShaderStates(gl_.get(), GetShader(fragment_shader_client_id), + true, nullptr, nullptr, &shader_language_version_, + nullptr, nullptr, nullptr, nullptr, + &frag_output_variable_list, nullptr); cmds::AttachShader attach_cmd; attach_cmd.Init(program_client_id, vertex_shader_client_id); diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h index d19937d..7746969 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h @@ -584,6 +584,13 @@ class GLES2DecoderTestBase : public ::testing::TestWithParam<bool> { static const GLint kInvalidUniformLocation = 30; static const GLint kBadUniformIndex = 1000; + static const GLint kOutputVariable1Size = 0; + static const GLenum kOutputVariable1Type = GL_FLOAT_VEC4; + static const GLuint kOutputVariable1ColorName = 7; + static const GLuint kOutputVariable1Index = 0; + static const char* kOutputVariable1Name; + static const char* kOutputVariable1NameESSL3; + // 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_; @@ -642,6 +649,8 @@ class GLES2DecoderTestBase : public ::testing::TestWithParam<bool> { EnableFlags enable_flags_; + int shader_language_version_; + private: class MockCommandBufferEngine : public CommandBufferEngine { public: diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc index c0b6de5..d295183 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc @@ -520,6 +520,26 @@ INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderTestWithEXTMultisampleCompatibility, ::testing::Bool()); +class GLES2DecoderTestWithBlendFuncExtended : public GLES2DecoderTest { + public: + GLES2DecoderTestWithBlendFuncExtended() {} + void SetUp() override { + InitState init; + init.gl_version = "opengl es 3.0"; + init.has_alpha = true; + init.has_depth = true; + init.request_alpha = true; + init.request_depth = true; + init.bind_generates_resource = true; + init.extensions = "GL_EXT_blend_func_extended"; + InitDecoder(init); + } +}; +INSTANTIATE_TEST_CASE_P(Service, + GLES2DecoderTestWithBlendFuncExtended, + ::testing::Bool()); + + TEST_P(GLES2DecoderTestWithCHROMIUMPathRendering, GenDeletePaths) { static GLuint kFirstClientID = client_path_id_ + 88; static GLsizei kPathCount = 58; diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc index 8d67537..cb49ae9 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc @@ -2016,27 +2016,22 @@ TEST_P(GLES2DecoderWithShaderTest, GetAttribLocationInvalidArgs) { EXPECT_NE(error::kNoError, ExecuteCmd(cmd)); } -TEST_P(GLES2DecoderWithShaderTest, GetFragDataLocation) { +TEST_P(GLES3DecoderWithESSL3ShaderTest, GetFragDataLocation) { const uint32 kBucketId = 123; - const GLint kLocation = 10; - const char* kName = "color"; typedef GetFragDataLocation::Result Result; Result* result = GetSharedMemoryAs<Result*>(); - SetBucketAsCString(kBucketId, kName); + SetBucketAsCString(kBucketId, kOutputVariable1NameESSL3); *result = -1; GetFragDataLocation cmd; cmd.Init(client_program_id_, kBucketId, kSharedMemoryId, kSharedMemoryOffset); - EXPECT_CALL(*gl_, GetFragDataLocation(kServiceProgramId, StrEq(kName))) - .WillOnce(Return(kLocation)) - .RetiresOnSaturation(); decoder_->set_unsafe_es3_apis_enabled(true); EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); - EXPECT_EQ(kLocation, *result); + EXPECT_EQ(static_cast<GLint>(kOutputVariable1ColorName), *result); decoder_->set_unsafe_es3_apis_enabled(false); EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd)); } -TEST_P(GLES2DecoderWithShaderTest, GetFragDataLocationInvalidArgs) { +TEST_P(GLES3DecoderWithESSL3ShaderTest, GetFragDataLocationInvalidArgs) { const uint32 kBucketId = 123; typedef GetFragDataLocation::Result Result; Result* result = GetSharedMemoryAs<Result*>(); 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 981d100..7a201b7 100644 --- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h +++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h @@ -363,7 +363,11 @@ static const GLenum valid_hint_target_table_es3[] = { }; static const GLenum valid_image_internal_format_table[] = { - GL_RGB, GL_RGB_YUV_420_CHROMIUM, GL_RGB_YCBCR_422_CHROMIUM, GL_RGBA, + GL_RGB, + GL_RGB_YUV_420_CHROMIUM, + GL_RGB_YCBCR_422_CHROMIUM, + GL_RGB_YCBCR_420V_CHROMIUM, + GL_RGBA, }; static const GLenum valid_image_usage_table[] = { diff --git a/gpu/command_buffer/service/memory_program_cache.cc b/gpu/command_buffer/service/memory_program_cache.cc index 74809a9..1841348 100644 --- a/gpu/command_buffer/service/memory_program_cache.cc +++ b/gpu/command_buffer/service/memory_program_cache.cc @@ -40,12 +40,6 @@ namespace gles2 { namespace { -enum ShaderMapType { - ATTRIB_MAP = 0, - UNIFORM_MAP, - VARYING_MAP -}; - void FillShaderVariableProto( ShaderVariableProto* proto, const sh::ShaderVariable& variable) { proto->set_type(variable.type); @@ -79,6 +73,12 @@ void FillShaderVaryingProto( proto->set_is_invariant(varying.isInvariant); } +void FillShaderOutputVariableProto(ShaderOutputVariableProto* proto, + const sh::OutputVariable& attrib) { + FillShaderVariableProto(proto->mutable_basic(), attrib); + proto->set_location(attrib.location); +} + void FillShaderProto(ShaderProto* proto, const char* sha, const Shader* shader) { proto->set_sha(sha, gpu::gles2::ProgramCache::kHashLength); @@ -97,6 +97,11 @@ void FillShaderProto(ShaderProto* proto, const char* sha, ShaderVaryingProto* info = proto->add_varyings(); FillShaderVaryingProto(info, iter->second); } + for (auto iter = shader->output_variable_list().begin(); + iter != shader->output_variable_list().end(); ++iter) { + ShaderOutputVariableProto* info = proto->add_output_variables(); + FillShaderOutputVariableProto(info, *iter); + } } void RetrieveShaderVariableInfo( @@ -138,6 +143,14 @@ void RetrieveShaderVaryingInfo( (*map)[proto.basic().mapped_name()] = varying; } +void RetrieveShaderOutputVariableInfo(const ShaderOutputVariableProto& proto, + OutputVariableList* list) { + sh::OutputVariable output_variable; + RetrieveShaderVariableInfo(proto.basic(), &output_variable); + output_variable.location = proto.location(); + list->push_back(output_variable); +} + void RunShaderCallback(const ShaderCacheCallback& callback, GpuProgramProto* proto, std::string sha_string) { @@ -213,9 +226,11 @@ ProgramCache::ProgramLoadResult MemoryProgramCache::LoadLinkedProgram( shader_a->set_attrib_map(value->attrib_map_0()); shader_a->set_uniform_map(value->uniform_map_0()); shader_a->set_varying_map(value->varying_map_0()); + shader_a->set_output_variable_list(value->output_variable_list_0()); shader_b->set_attrib_map(value->attrib_map_1()); shader_b->set_uniform_map(value->uniform_map_1()); shader_b->set_varying_map(value->varying_map_1()); + shader_b->set_output_variable_list(value->output_variable_list_1()); if (!shader_callback.is_null() && !base::CommandLine::ForCurrentProcess()->HasSwitch( @@ -302,20 +317,14 @@ void MemoryProgramCache::SaveLinkedProgram( 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(), - shader_a->varying_map(), - b_sha, - shader_b->attrib_map(), - shader_b->uniform_map(), - shader_b->varying_map(), - this)); + store_.Put( + sha_string, + new ProgramCacheValue( + length, format, binary.release(), sha_string, a_sha, + shader_a->attrib_map(), shader_a->uniform_map(), + shader_a->varying_map(), shader_a->output_variable_list(), b_sha, + shader_b->attrib_map(), shader_b->uniform_map(), + shader_b->varying_map(), shader_b->output_variable_list(), this)); UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb", curr_size_bytes_ / 1024); @@ -327,6 +336,7 @@ void MemoryProgramCache::LoadProgram(const std::string& program) { AttributeMap vertex_attribs; UniformMap vertex_uniforms; VaryingMap vertex_varyings; + OutputVariableList vertex_output_variables; for (int i = 0; i < proto->vertex_shader().attribs_size(); i++) { RetrieveShaderAttributeInfo(proto->vertex_shader().attribs(i), &vertex_attribs); @@ -339,10 +349,15 @@ void MemoryProgramCache::LoadProgram(const std::string& program) { RetrieveShaderVaryingInfo(proto->vertex_shader().varyings(i), &vertex_varyings); } + for (int i = 0; i < proto->vertex_shader().output_variables_size(); i++) { + RetrieveShaderOutputVariableInfo( + proto->vertex_shader().output_variables(i), &vertex_output_variables); + } AttributeMap fragment_attribs; UniformMap fragment_uniforms; VaryingMap fragment_varyings; + OutputVariableList fragment_output_variables; for (int i = 0; i < proto->fragment_shader().attribs_size(); i++) { RetrieveShaderAttributeInfo(proto->fragment_shader().attribs(i), &fragment_attribs); @@ -355,24 +370,24 @@ void MemoryProgramCache::LoadProgram(const std::string& program) { RetrieveShaderVaryingInfo(proto->fragment_shader().varyings(i), &fragment_varyings); } + for (int i = 0; i < proto->fragment_shader().output_variables_size(); i++) { + RetrieveShaderOutputVariableInfo( + proto->fragment_shader().output_variables(i), + &fragment_output_variables); + } 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, - vertex_varyings, - proto->fragment_shader().sha().c_str(), - fragment_attribs, - fragment_uniforms, - fragment_varyings, - this)); + 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, vertex_varyings, vertex_output_variables, + proto->fragment_shader().sha().c_str(), fragment_attribs, + fragment_uniforms, fragment_varyings, fragment_output_variables, + this)); UMA_HISTOGRAM_COUNTS("GPU.ProgramCache.MemorySizeAfterKb", curr_size_bytes_ / 1024); @@ -390,10 +405,12 @@ MemoryProgramCache::ProgramCacheValue::ProgramCacheValue( const AttributeMap& attrib_map_0, const UniformMap& uniform_map_0, const VaryingMap& varying_map_0, + const OutputVariableList& output_variable_list_0, const char* shader_1_hash, const AttributeMap& attrib_map_1, const UniformMap& uniform_map_1, const VaryingMap& varying_map_1, + const OutputVariableList& output_variable_list_1, MemoryProgramCache* program_cache) : length_(length), format_(format), @@ -403,10 +420,12 @@ MemoryProgramCache::ProgramCacheValue::ProgramCacheValue( attrib_map_0_(attrib_map_0), uniform_map_0_(uniform_map_0), varying_map_0_(varying_map_0), + output_variable_list_0_(output_variable_list_0), shader_1_hash_(shader_1_hash, kHashLength), attrib_map_1_(attrib_map_1), uniform_map_1_(uniform_map_1), varying_map_1_(varying_map_1), + output_variable_list_1_(output_variable_list_1), program_cache_(program_cache) { program_cache_->curr_size_bytes_ += length_; program_cache_->LinkedProgramCacheSuccess(program_hash); diff --git a/gpu/command_buffer/service/memory_program_cache.h b/gpu/command_buffer/service/memory_program_cache.h index 593625d..7e9b83d 100644 --- a/gpu/command_buffer/service/memory_program_cache.h +++ b/gpu/command_buffer/service/memory_program_cache.h @@ -57,10 +57,12 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache { const AttributeMap& attrib_map_0, const UniformMap& uniform_map_0, const VaryingMap& varying_map_0, + const OutputVariableList& output_variable_list_0, const char* shader_1_hash, const AttributeMap& attrib_map_1, const UniformMap& uniform_map_1, const VaryingMap& varying_map_1, + const OutputVariableList& output_variable_list_1, MemoryProgramCache* program_cache); GLsizei length() const { @@ -91,6 +93,10 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache { return varying_map_0_; } + const OutputVariableList& output_variable_list_0() const { + return output_variable_list_0_; + } + const std::string& shader_1_hash() const { return shader_1_hash_; } @@ -107,6 +113,10 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache { return varying_map_1_; } + const OutputVariableList& output_variable_list_1() const { + return output_variable_list_1_; + } + private: friend class base::RefCounted<ProgramCacheValue>; @@ -120,10 +130,12 @@ class GPU_EXPORT MemoryProgramCache : public ProgramCache { const AttributeMap attrib_map_0_; const UniformMap uniform_map_0_; const VaryingMap varying_map_0_; + const OutputVariableList output_variable_list_0_; const std::string shader_1_hash_; const AttributeMap attrib_map_1_; const UniformMap uniform_map_1_; const VaryingMap varying_map_1_; + const OutputVariableList output_variable_list_1_; MemoryProgramCache* const program_cache_; DISALLOW_COPY_AND_ASSIGN(ProgramCacheValue); diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc index a005db9..f92860f 100644 --- a/gpu/command_buffer/service/memory_program_cache_unittest.cc +++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc @@ -100,9 +100,11 @@ class MemoryProgramCacheTest : public GpuServiceTest { AttributeMap vertex_attrib_map; UniformMap vertex_uniform_map; VaryingMap vertex_varying_map; + OutputVariableList vertex_output_variable_list; AttributeMap fragment_attrib_map; UniformMap fragment_uniform_map; VaryingMap fragment_varying_map; + OutputVariableList fragment_output_variable_list; vertex_attrib_map["a"] = TestHelper::ConstructAttribute( GL_FLOAT_VEC2, 34, GL_LOW_FLOAT, false, "a"); @@ -112,24 +114,28 @@ class MemoryProgramCacheTest : public GpuServiceTest { GL_FLOAT_VEC3, 3114, GL_HIGH_FLOAT, true, "b"); vertex_varying_map["c"] = TestHelper::ConstructVarying( GL_FLOAT_VEC4, 2, GL_HIGH_FLOAT, true, "c"); + vertex_output_variable_list.push_back(TestHelper::ConstructOutputVariable( + GL_FLOAT, 0, GL_HIGH_FLOAT, true, "d")); fragment_attrib_map["jjjbb"] = TestHelper::ConstructAttribute( GL_FLOAT_MAT4, 1114, GL_MEDIUM_FLOAT, false, "jjjbb"); fragment_uniform_map["k"] = TestHelper::ConstructUniform( GL_FLOAT_MAT2, 34413, GL_MEDIUM_FLOAT, true, "k"); fragment_varying_map["c"] = TestHelper::ConstructVarying( GL_FLOAT_VEC4, 2, GL_HIGH_FLOAT, true, "c"); + fragment_output_variable_list.push_back(TestHelper::ConstructOutputVariable( + GL_FLOAT, 0, GL_HIGH_FLOAT, true, "d")); vertex_shader_->set_source("bbbalsldkdkdkd"); fragment_shader_->set_source("bbbal sldkdkdkas 134 ad"); + TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true, nullptr, + nullptr, nullptr, &vertex_attrib_map, + &vertex_uniform_map, &vertex_varying_map, + nullptr, &vertex_output_variable_list, nullptr); TestHelper::SetShaderStates( - gl_.get(), vertex_shader_, true, NULL, NULL, NULL, - &vertex_attrib_map, &vertex_uniform_map, &vertex_varying_map, - NULL, NULL); - TestHelper::SetShaderStates( - gl_.get(), fragment_shader_, true, NULL, NULL, NULL, + gl_.get(), fragment_shader_, true, nullptr, nullptr, nullptr, &fragment_attrib_map, &fragment_uniform_map, &fragment_varying_map, - NULL, NULL); + nullptr, &fragment_output_variable_list, nullptr); } void SetExpectationsForSaveLinkedProgram( @@ -254,17 +260,22 @@ TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) { AttributeMap vertex_attrib_map = vertex_shader_->attrib_map(); UniformMap vertex_uniform_map = vertex_shader_->uniform_map(); VaryingMap vertex_varying_map = vertex_shader_->varying_map(); + OutputVariableList vertex_output_variable_list = + vertex_shader_->output_variable_list(); AttributeMap fragment_attrib_map = fragment_shader_->attrib_map(); UniformMap fragment_uniform_map = fragment_shader_->uniform_map(); VaryingMap fragment_varying_map = fragment_shader_->varying_map(); + OutputVariableList fragment_output_variable_list = + fragment_shader_->output_variable_list(); vertex_shader_->set_attrib_map(AttributeMap()); vertex_shader_->set_uniform_map(UniformMap()); vertex_shader_->set_varying_map(VaryingMap()); + vertex_shader_->set_output_variable_list(OutputVariableList()); fragment_shader_->set_attrib_map(AttributeMap()); fragment_shader_->set_uniform_map(UniformMap()); fragment_shader_->set_varying_map(VaryingMap()); - + fragment_shader_->set_output_variable_list(OutputVariableList()); SetExpectationsForLoadLinkedProgram(kProgramId, &emulator); EXPECT_EQ(ProgramCache::PROGRAM_LOAD_SUCCESS, cache_->LoadLinkedProgram( @@ -283,9 +294,13 @@ TEST_F(MemoryProgramCacheTest, CacheLoadMatchesSave) { EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map()); EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map()); EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map()); + EXPECT_EQ(vertex_output_variable_list, + vertex_shader_->output_variable_list()); EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map()); EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map()); EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map()); + EXPECT_EQ(fragment_output_variable_list, + fragment_shader_->output_variable_list()); #endif } @@ -309,16 +324,22 @@ TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) { AttributeMap vertex_attrib_map = vertex_shader_->attrib_map(); UniformMap vertex_uniform_map = vertex_shader_->uniform_map(); VaryingMap vertex_varying_map = vertex_shader_->varying_map(); + OutputVariableList vertex_output_variable_list = + vertex_shader_->output_variable_list(); AttributeMap fragment_attrib_map = fragment_shader_->attrib_map(); UniformMap fragment_uniform_map = fragment_shader_->uniform_map(); VaryingMap fragment_varying_map = fragment_shader_->varying_map(); + OutputVariableList fragment_output_variable_list = + fragment_shader_->output_variable_list(); vertex_shader_->set_attrib_map(AttributeMap()); vertex_shader_->set_uniform_map(UniformMap()); vertex_shader_->set_varying_map(VaryingMap()); + vertex_shader_->set_output_variable_list(OutputVariableList()); fragment_shader_->set_attrib_map(AttributeMap()); fragment_shader_->set_uniform_map(UniformMap()); fragment_shader_->set_varying_map(VaryingMap()); + fragment_shader_->set_output_variable_list(OutputVariableList()); SetExpectationsForLoadLinkedProgram(kProgramId, &emulator); @@ -341,9 +362,13 @@ TEST_F(MemoryProgramCacheTest, LoadProgramMatchesSave) { EXPECT_EQ(vertex_attrib_map, vertex_shader_->attrib_map()); EXPECT_EQ(vertex_uniform_map, vertex_shader_->uniform_map()); EXPECT_EQ(vertex_varying_map, vertex_shader_->varying_map()); + EXPECT_EQ(vertex_output_variable_list, + vertex_shader_->output_variable_list()); EXPECT_EQ(fragment_attrib_map, fragment_shader_->attrib_map()); EXPECT_EQ(fragment_uniform_map, fragment_shader_->uniform_map()); EXPECT_EQ(fragment_varying_map, fragment_shader_->varying_map()); + EXPECT_EQ(fragment_output_variable_list, + fragment_shader_->output_variable_list()); #endif } diff --git a/gpu/command_buffer/service/mocks.h b/gpu/command_buffer/service/mocks.h index 2ef657f..a9a7efb 100644 --- a/gpu/command_buffer/service/mocks.h +++ b/gpu/command_buffer/service/mocks.h @@ -95,16 +95,17 @@ class MockShaderTranslator : public ShaderTranslatorInterface { const ShBuiltInResources* resources, ShShaderOutput shader_output_language, ShCompileOptions driver_bug_workarounds)); - MOCK_CONST_METHOD9(Translate, bool( - const std::string& shader_source, - std::string* info_log, - std::string* translated_source, - int* shader_version, - AttributeMap* attrib_map, - UniformMap* uniform_map, - VaryingMap* varying_map, - InterfaceBlockMap* interface_block_map, - NameMap* name_map)); + MOCK_CONST_METHOD10(Translate, + bool(const std::string& shader_source, + std::string* info_log, + std::string* translated_source, + int* shader_version, + AttributeMap* attrib_map, + UniformMap* uniform_map, + VaryingMap* varying_map, + InterfaceBlockMap* interface_block_map, + OutputVariableList* output_variable_list, + NameMap* name_map)); MOCK_CONST_METHOD0( GetStringForOptionsThatWouldAffectCompilation, std::string()); private: diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc index bfff34c..45b0c55 100644 --- a/gpu/command_buffer/service/program_manager.cc +++ b/gpu/command_buffer/service/program_manager.cc @@ -28,6 +28,7 @@ #include "gpu/command_buffer/service/program_cache.h" #include "gpu/command_buffer/service/shader_manager.h" #include "third_party/re2/re2/re2.h" +#include "ui/gl/gl_version_info.h" using base::TimeDelta; using base::TimeTicks; @@ -249,10 +250,9 @@ Program::UniformInfo::UniformInfo(const std::string& client_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); +bool ProgramManager::HasBuiltInPrefix(const std::string& name) { + return name.length() >= 3 && name[0] == 'g' && name[1] == 'l' && + name[2] == '_'; } Program::Program(ProgramManager* manager, GLuint service_id) @@ -279,6 +279,7 @@ void Program::Reset() { uniform_locations_.clear(); fragment_input_infos_.clear(); fragment_input_locations_.clear(); + program_output_infos_.clear(); sampler_indices_.clear(); attrib_location_to_index_map_.clear(); } @@ -519,6 +520,7 @@ void Program::Update() { #endif UpdateFragmentInputs(); + UpdateProgramOutputs(); valid_ = true; } @@ -563,8 +565,7 @@ void Program::UpdateUniforms() { GLint service_location = -1; // Force builtin uniforms (gl_DepthRange) to have invalid location. - if (!ProgramManager::IsInvalidPrefix(service_name.c_str(), - service_name.size())) { + if (!ProgramManager::HasBuiltInPrefix(service_name)) { service_location = glGetUniformLocation(service_id_, service_name.c_str()); } @@ -701,9 +702,9 @@ void Program::UpdateFragmentInputs() { // A fragment shader can have gl_FragCoord, gl_FrontFacing or gl_PointCoord // built-ins as its input, as well as custom varyings. We are interested in // custom varyings, client is allowed to bind only them. - if (ProgramManager::IsInvalidPrefix(name_buffer.get(), name_length)) - continue; std::string service_name(name_buffer.get(), name_length); + if (ProgramManager::HasBuiltInPrefix(service_name)) + continue; // Unlike when binding uniforms, we expect the driver to give correct // names: "name" for simple variable, "name[0]" for an array. GLsizei query_length = 0; @@ -788,6 +789,55 @@ void Program::UpdateFragmentInputs() { } } +void Program::UpdateProgramOutputs() { + if (!feature_info().gl_version_info().IsES3Capable() || + feature_info().disable_shader_translator()) + return; + + Shader* fragment_shader = + attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get(); + + for (auto const& output_var : fragment_shader->output_variable_list()) { + const std::string& service_name = output_var.mappedName; + // A fragment shader can have gl_FragColor, gl_SecondaryFragColor, etc + // built-ins as its output, as well as custom varyings. We are interested + // only in custom varyings, client is allowed to bind only them. + if (ProgramManager::HasBuiltInPrefix(service_name)) + continue; + + std::string client_name = output_var.name; + if (output_var.arraySize == 0) { + GLint color_name = + glGetFragDataLocation(service_id_, service_name.c_str()); + if (color_name < 0) + continue; + GLint index = 0; + if (feature_info().feature_flags().ext_blend_func_extended) + index = glGetFragDataIndex(service_id_, service_name.c_str()); + if (index < 0) + continue; + program_output_infos_.push_back( + ProgramOutputInfo(color_name, index, client_name)); + } else { + for (size_t ii = 0; ii < output_var.arraySize; ++ii) { + std::string array_spec(std::string("[") + base::IntToString(ii) + "]"); + std::string service_element_name(service_name + array_spec); + GLint color_name = + glGetFragDataLocation(service_id_, service_element_name.c_str()); + if (color_name < 0) + continue; + GLint index = 0; + if (feature_info().feature_flags().ext_blend_func_extended) + index = glGetFragDataIndex(service_id_, service_element_name.c_str()); + if (index < 0) + continue; + program_output_infos_.push_back( + ProgramOutputInfo(color_name, index, client_name + array_spec)); + } + } + } +} + void Program::ExecuteBindAttribLocationCalls() { for (const auto& key_value : bind_attrib_location_map_) { const std::string* mapped_name = GetAttribMappedName(key_value.first); @@ -827,6 +877,96 @@ bool Program::ExecuteTransformFeedbackVaryingsCall() { return true; } +void Program::ExecuteProgramOutputBindCalls() { + if (feature_info().disable_shader_translator()) { + return; + } + + Shader* fragment_shader = + attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get(); + DCHECK(fragment_shader && fragment_shader->valid()); + + if (fragment_shader->shader_version() != 100) { + // ES SL 1.00 does not have mechanism for introducing variables that could + // be bound. This means that ES SL 1.00 binding calls would be to + // non-existing variable names. Binding calls are only executed with ES SL + // 3.00 and higher. + for (auto const& output_var : fragment_shader->output_variable_list()) { + size_t count = std::max(output_var.arraySize, 1u); + bool is_array = output_var.arraySize > 0; + + for (size_t jj = 0; jj < count; ++jj) { + std::string name = output_var.name; + std::string array_spec; + if (is_array) { + array_spec = std::string("[") + base::IntToString(jj) + "]"; + name += array_spec; + } + auto it = bind_program_output_location_index_map_.find(name); + if (it == bind_program_output_location_index_map_.end()) + continue; + + std::string mapped_name = output_var.mappedName; + if (is_array) { + mapped_name += array_spec; + } + const auto& binding = it->second; + if (binding.second == 0) { + // Handles the cases where client called glBindFragDataLocation as + // well as glBindFragDataLocationIndexed with index == 0. + glBindFragDataLocation(service_id_, binding.first, + mapped_name.c_str()); + } else { + DCHECK(feature_info().feature_flags().ext_blend_func_extended); + glBindFragDataLocationIndexed(service_id_, binding.first, + binding.second, mapped_name.c_str()); + } + } + } + return; + } + + // Support for EXT_blend_func_extended when used with ES SL 1.00 client + // shader. + + if (feature_info().gl_version_info().is_es || + !feature_info().feature_flags().ext_blend_func_extended) + return; + + // The underlying context does not support EXT_blend_func_extended + // natively, need to emulate it. + + // ES SL 1.00 is the only language which contains GLSL built-ins + // that need to be bound to color indices. If clients use other + // languages, they also bind the output variables themselves. + // Map gl_SecondaryFragColorEXT / gl_SecondaryFragDataEXT of + // EXT_blend_func_extended to real color indexes. + for (auto const& output_var : fragment_shader->output_variable_list()) { + const std::string& name = output_var.mappedName; + if (name == "gl_FragColor") { + DCHECK_EQ(-1, output_var.location); + DCHECK_EQ(0u, output_var.arraySize); + // We leave these unbound by not giving a binding name. The driver will + // bind this. + } else if (name == "gl_FragData") { + DCHECK_EQ(-1, output_var.location); + DCHECK_NE(0u, output_var.arraySize); + // We leave these unbound by not giving a binding name. The driver will + // bind this. + } else if (name == "gl_SecondaryFragColorEXT") { + DCHECK_EQ(-1, output_var.location); + DCHECK_EQ(0u, output_var.arraySize); + glBindFragDataLocationIndexed(service_id_, 0, 1, + "angle_SecondaryFragColor"); + } else if (name == "gl_SecondaryFragDataEXT") { + DCHECK_EQ(-1, output_var.location); + DCHECK_NE(0u, output_var.arraySize); + glBindFragDataLocationIndexed(service_id_, 0, 1, + "angle_SecondaryFragData"); + } + } +} + bool Program::Link(ShaderManager* manager, Program::VaryingsPackingOption varyings_packing_option, const ShaderCacheCallback& shader_callback) { @@ -905,6 +1045,10 @@ bool Program::Link(ShaderManager* manager, set_log_info("glBindFragmentInputLocationCHROMIUM() conflicts"); return false; } + if (DetectProgramOutputLocationBindingConflicts()) { + set_log_info("glBindFragDataLocation() conflicts"); + return false; + } if (DetectBuiltInInvariantConflicts()) { set_log_info("Invariant settings for certain built-in varyings " "have to match"); @@ -925,6 +1069,9 @@ bool Program::Link(ShaderManager* manager, if (!ExecuteTransformFeedbackVaryingsCall()) { return false; } + + ExecuteProgramOutputBindCalls(); + before_time = TimeTicks::Now(); if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) { glProgramParameteri(service_id(), @@ -1148,6 +1295,20 @@ void Program::SetFragmentInputLocationBinding(const std::string& name, bind_fragment_input_location_map_[name + "[0]"] = location; } +void Program::SetProgramOutputLocationBinding(const std::string& name, + GLuint color_name) { + SetProgramOutputLocationIndexedBinding(name, color_name, 0); +} + +void Program::SetProgramOutputLocationIndexedBinding(const std::string& name, + GLuint color_name, + GLuint index) { + bind_program_output_location_index_map_[name] = + std::make_pair(color_name, index); + bind_program_output_location_index_map_[name + "[0]"] = + std::make_pair(color_name, index); +} + void Program::GetVertexAttribData( const std::string& name, std::string* original_name, GLenum* type) const { DCHECK(original_name); @@ -1541,6 +1702,42 @@ bool Program::DetectFragmentInputLocationBindingConflicts() const { return false; } +bool Program::DetectProgramOutputLocationBindingConflicts() const { + if (feature_info().disable_shader_translator()) { + return false; + } + + Shader* shader = + attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get(); + DCHECK(shader && shader->valid()); + + if (shader->shader_version() == 100) + return false; + + std::set<LocationIndexMap::mapped_type> location_binding_used; + for (auto const& output_var : shader->output_variable_list()) { + if (!output_var.staticUse) + continue; + + size_t count = std::max(output_var.arraySize, 1u); + bool is_array = output_var.arraySize > 0; + + for (size_t jj = 0; jj < count; ++jj) { + std::string name = output_var.name; + if (is_array) + name += std::string("[") + base::IntToString(jj) + "]"; + + auto it = bind_program_output_location_index_map_.find(name); + if (it == bind_program_output_location_index_map_.end()) + continue; + auto result = location_binding_used.insert(it->second); + if (!result.second) + return true; + } + } + return false; +} + bool Program::DetectBuiltInInvariantConflicts() const { DCHECK(attached_shaders_[0].get() && attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER && @@ -2019,6 +2216,36 @@ bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const { return true; } +const Program::ProgramOutputInfo* Program::GetProgramOutputInfo( + const std::string& name) const { + for (const auto& info : program_output_infos_) { + if (info.name == name) { + return &info; + } + } + return nullptr; +} + +GLint Program::GetFragDataLocation(const std::string& original_name) const { + DCHECK(IsValid()); + const ProgramOutputInfo* info = GetProgramOutputInfo(original_name); + if (!info) + info = GetProgramOutputInfo(original_name + "[0]"); + if (!info) + return -1; + return info->color_name; +} + +GLint Program::GetFragDataIndex(const std::string& original_name) const { + DCHECK(IsValid()); + const ProgramOutputInfo* info = GetProgramOutputInfo(original_name); + if (!info) + info = GetProgramOutputInfo(original_name + "[0]"); + if (!info) + return -1; + return info->index; +} + void Program::TransformFeedbackVaryings(GLsizei count, const char* const* varyings, GLenum buffer_mode) { @@ -2041,11 +2268,13 @@ Program::~Program() { ProgramManager::ProgramManager(ProgramCache* program_cache, uint32 max_varying_vectors, + uint32 max_dual_source_draw_buffers, FeatureInfo* feature_info) : program_count_(0), have_context_(true), program_cache_(program_cache), max_varying_vectors_(max_varying_vectors), + max_dual_source_draw_buffers_(max_dual_source_draw_buffers), feature_info_(feature_info) {} ProgramManager::~ProgramManager() { diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h index 942659d..eb3be7c 100644 --- a/gpu/command_buffer/service/program_manager.h +++ b/gpu/command_buffer/service/program_manager.h @@ -20,6 +20,7 @@ namespace gpu { namespace gles2 { +class FeatureInfo; class ProgramCache; class ProgramManager; class Shader; @@ -69,6 +70,16 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { GLenum type; GLuint location; }; + struct ProgramOutputInfo { + ProgramOutputInfo(GLuint _color_name, + GLuint _index, + const std::string& _name) + : color_name(_color_name), index(_index), name(_name) {} + ProgramOutputInfo() : color_name(0), index(0) {} + GLuint color_name; + GLuint index; + std::string name; + }; struct UniformInfo { UniformInfo(); @@ -144,8 +155,10 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { typedef std::vector<FragmentInputInfo> FragmentInputInfoVector; typedef std::vector<ShaderVariableLocationEntry<FragmentInputInfo>> FragmentInputLocationVector; + typedef std::vector<ProgramOutputInfo> ProgramOutputInfoVector; typedef std::vector<int> SamplerIndices; typedef std::map<std::string, GLint> LocationMap; + typedef std::map<std::string, std::pair<GLuint, GLuint>> LocationIndexMap; typedef std::vector<std::string> StringVector; Program(ProgramManager* manager, GLuint service_id); @@ -209,6 +222,10 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { // -1 for bound, non-existing uniform. bool IsInactiveUniformLocationByFakeLocation(GLint fake_location) const; + // Gets the ProgramOutputInfo of a fragment output by name. + const ProgramOutputInfo* GetProgramOutputInfo( + const std::string& original_name) const; + // Gets all the program info. void GetProgramInfo( ProgramManager* manager, CommonDecoder::Bucket* bucket) const; @@ -226,6 +243,14 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { // glGetProgramInfoCHROMIUM. bool GetUniformsES3(CommonDecoder::Bucket* bucket) const; + // Returns the fragment shader output variable color name binding. + // Returns -1 if |original_name| is not an out variable or error. + GLint GetFragDataLocation(const std::string& original_name) const; + + // Returns the fragment shader output variable color index binding. + // Returns -1 if |original_name| is not an out variable or error. + GLint GetFragDataIndex(const std::string& original_name) 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. @@ -285,6 +310,15 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { // glBindFragmentInputLocationCHROMIUM() call. void SetFragmentInputLocationBinding(const std::string& name, GLint location); + // Sets program output variable location. Also sets color index to zero. + void SetProgramOutputLocationBinding(const std::string& name, + GLuint colorName); + + // Sets program output variable location and color index. + void SetProgramOutputLocationIndexedBinding(const std::string& name, + GLuint colorName, + GLuint index); + // Detects if there are attribute location conflicts from // glBindAttribLocation() calls. // We only consider the declared attributes in the program. @@ -310,6 +344,11 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { // We only consider the statically used fragment inputs in the program. bool DetectFragmentInputLocationBindingConflicts() const; + // Detects if there are program output location conflicts from + // glBindFragDataLocation and ..LocationIndexedEXT calls. + // We only consider the statically used program outputs in the program. + bool DetectProgramOutputLocationBindingConflicts() const; + // Return true if any built-in invariant matching rules are broken as in // GLSL ES spec 1.00.17, section 4.6.4, Invariance and Linkage. bool DetectBuiltInInvariantConflicts() const; @@ -372,6 +411,7 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { void Update(); void UpdateUniforms(); void UpdateFragmentInputs(); + void UpdateProgramOutputs(); // Process the program log, replacing the hashed names with original names. std::string ProcessLogInfo(const std::string& log); @@ -405,6 +445,8 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { // Returns false upon failure. bool ExecuteTransformFeedbackVaryingsCall(); + void ExecuteProgramOutputBindCalls(); + // Query VertexAttrib data returned by ANGLE translator by the mapped name. void GetVertexAttribData( const std::string& name, std::string* original_name, GLenum* type) const; @@ -447,6 +489,8 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { FragmentInputInfoVector fragment_input_infos_; FragmentInputLocationVector fragment_input_locations_; + ProgramOutputInfoVector program_output_infos_; + // The program this Program is tracking. GLuint service_id_; @@ -482,6 +526,10 @@ class GPU_EXPORT Program : public base::RefCounted<Program> { // Fragment input-location binding map from // glBindFragmentInputLocationCHROMIUM() calls. LocationMap bind_fragment_input_location_map_; + + // output variable - (location,index) binding map from + // glBindFragDataLocation() and ..IndexedEXT() calls. + LocationIndexMap bind_program_output_location_index_map_; }; // Tracks the Programs. @@ -492,6 +540,7 @@ class GPU_EXPORT ProgramManager { public: explicit ProgramManager(ProgramCache* program_cache, uint32 max_varying_vectors, + uint32 max_dual_source_draw_buffers, FeatureInfo* feature_info); ~ProgramManager(); @@ -522,8 +571,9 @@ class GPU_EXPORT ProgramManager { // 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); + // Returns true if |name| has a prefix that is intended for GL built-in shader + // variables. + static bool HasBuiltInPrefix(const std::string& name); // Check if a Program is owned by this ProgramManager. bool IsOwned(Program* program) const; @@ -534,6 +584,10 @@ class GPU_EXPORT ProgramManager { return max_varying_vectors_; } + uint32 max_dual_source_draw_buffers() const { + return max_dual_source_draw_buffers_; + } + private: friend class Program; @@ -560,6 +614,7 @@ class GPU_EXPORT ProgramManager { ProgramCache* program_cache_; uint32 max_varying_vectors_; + uint32 max_dual_source_draw_buffers_; scoped_refptr<FeatureInfo> feature_info_; diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc index 404017f..8343e56 100644 --- a/gpu/command_buffer/service/program_manager_unittest.cc +++ b/gpu/command_buffer/service/program_manager_unittest.cc @@ -21,6 +21,7 @@ #include "gpu/command_buffer/service/test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gl/gl_mock.h" +#include "ui/gl/gl_version_info.h" using ::testing::_; using ::testing::DoAll; @@ -38,6 +39,8 @@ namespace gles2 { namespace { const uint32 kMaxVaryingVectors = 8; +const uint32 kMaxDrawBuffers = 8; +const uint32 kMaxDualSourceDrawBuffers = 8; void ShaderCacheCb(const std::string& key, const std::string& shader) {} @@ -51,8 +54,9 @@ uint32 ComputeOffset(const void* start, const void* position) { class ProgramManagerTestBase : public GpuServiceTest { protected: virtual void SetupProgramManager() { - manager_.reset( - new ProgramManager(NULL, kMaxVaryingVectors, feature_info_.get())); + manager_.reset(new ProgramManager(nullptr, kMaxVaryingVectors, + kMaxDualSourceDrawBuffers, + feature_info_.get())); } void SetUpBase(const char* gl_version, const char* gl_extensions, @@ -215,6 +219,13 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { static const GLint kInvalidUniformLocation = 30; static const GLint kBadUniformIndex = 1000; + static const char* kOutputVariable1Name; + static const GLint kOutputVariable1Size = 1; + static const GLenum kOutputVariable1Precision = GL_MEDIUM_FLOAT; + static const bool kOutputVariable1StaticUse = true; + static const GLint kOutputVariable1Location = -1; + static const GLenum kOutputVariable1Type = GL_FLOAT_VEC4; + static const size_t kNumAttribs; static const size_t kNumUniforms; @@ -225,7 +236,8 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { typedef enum { kVarUniform, kVarVarying, - kVarAttribute + kVarAttribute, + kVarOutput, } VarCategory; typedef struct { @@ -299,14 +311,16 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { return (static_cast<bool>(link_status) == expected_link_status); } - Program* SetupShaderVariableTest(const VarInfo* vertex_variables, - size_t vertex_variable_size, - const VarInfo* fragment_variables, - size_t fragment_variable_size) { + Program* SetupProgramForVariables(const VarInfo* vertex_variables, + size_t vertex_variable_size, + const VarInfo* fragment_variables, + size_t fragment_variable_size, + const int* const shader_version = nullptr) { // Set up shader AttributeMap vertex_attrib_map; UniformMap vertex_uniform_map; VaryingMap vertex_varying_map; + OutputVariableList vertex_output_variable_list; for (size_t ii = 0; ii < vertex_variable_size; ++ii) { switch (vertex_variables[ii].category) { case kVarAttribute: @@ -336,6 +350,13 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { vertex_variables[ii].static_use, vertex_variables[ii].name); break; + case kVarOutput: + vertex_output_variable_list.push_back( + TestHelper::ConstructOutputVariable( + vertex_variables[ii].type, vertex_variables[ii].size, + vertex_variables[ii].precision, + vertex_variables[ii].static_use, vertex_variables[ii].name)); + break; default: NOTREACHED(); } @@ -344,6 +365,7 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { AttributeMap frag_attrib_map; UniformMap frag_uniform_map; VaryingMap frag_varying_map; + OutputVariableList frag_output_variable_list; for (size_t ii = 0; ii < fragment_variable_size; ++ii) { switch (fragment_variables[ii].category) { case kVarAttribute: @@ -373,6 +395,14 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { fragment_variables[ii].static_use, fragment_variables[ii].name); break; + case kVarOutput: + frag_output_variable_list.push_back( + TestHelper::ConstructOutputVariable( + fragment_variables[ii].type, fragment_variables[ii].size, + fragment_variables[ii].precision, + fragment_variables[ii].static_use, + fragment_variables[ii].name)); + break; default: NOTREACHED(); } @@ -386,12 +416,14 @@ class ProgramManagerWithShaderTest : public ProgramManagerTestBase { // Check shader got created. EXPECT_TRUE(vshader != NULL && fshader != NULL); // Set Status - TestHelper::SetShaderStates( - gl_.get(), vshader, true, NULL, NULL, NULL, &vertex_attrib_map, - &vertex_uniform_map, &vertex_varying_map, NULL, NULL); - TestHelper::SetShaderStates( - gl_.get(), fshader, true, NULL, NULL, NULL, - &frag_attrib_map, &frag_uniform_map, &frag_varying_map, NULL, NULL); + TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, + shader_version, &vertex_attrib_map, + &vertex_uniform_map, &vertex_varying_map, + nullptr, &vertex_output_variable_list, nullptr); + TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, + shader_version, &frag_attrib_map, + &frag_uniform_map, &frag_varying_map, nullptr, + &frag_output_variable_list, nullptr); // Set up program Program* program = @@ -502,6 +534,7 @@ const char* ProgramManagerWithShaderTest::kUniform2NameWithArrayIndex = const char* ProgramManagerWithShaderTest::kUniform3Name = "uniform3"; const char* ProgramManagerWithShaderTest::kUniform3NameWithArrayIndex = "uniform3[0]"; +const char* ProgramManagerWithShaderTest::kOutputVariable1Name = "outputVar1"; TEST_F(ProgramManagerWithShaderTest, GetAttribInfos) { const Program* program = SetupDefaultProgram(); @@ -805,6 +838,7 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) { AttributeMap attrib_map; UniformMap uniform_map; VaryingMap varying_map; + OutputVariableList output_variable_list; attrib_map[kAttrib1Name] = TestHelper::ConstructAttribute( kAttrib1Type, kAttrib1Size, kAttrib1Precision, kAttribStaticUse, kAttrib1Name); @@ -823,18 +857,22 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) { uniform_map[kUniform3Name] = TestHelper::ConstructUniform( kUniform3Type, kUniform3Size, kUniform3Precision, kUniform3StaticUse, kUniform3Name); + output_variable_list.push_back(TestHelper::ConstructOutputVariable( + kOutputVariable1Type, kOutputVariable1Size, kOutputVariable1Precision, + kOutputVariable1StaticUse, kOutputVariable1Name)); + Shader* vshader = shader_manager_.CreateShader( kVertexShaderClientId, kVertexShaderServiceId, GL_VERTEX_SHADER); ASSERT_TRUE(vshader != NULL); - TestHelper::SetShaderStates( - gl_.get(), vshader, true, NULL, NULL, NULL, - &attrib_map, &uniform_map, &varying_map, NULL, NULL); + TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, + nullptr, &attrib_map, &uniform_map, &varying_map, + nullptr, &output_variable_list, nullptr); Shader* fshader = shader_manager_.CreateShader( kFragmentShaderClientId, kFragmentShaderServiceId, GL_FRAGMENT_SHADER); ASSERT_TRUE(fshader != NULL); - TestHelper::SetShaderStates( - gl_.get(), fshader, true, NULL, NULL, NULL, - &attrib_map, &uniform_map, &varying_map, NULL, NULL); + TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, + nullptr, &attrib_map, &uniform_map, &varying_map, + nullptr, &output_variable_list, nullptr); static ProgramManagerWithShaderTest::AttribInfo kAttribs[] = { { kAttrib1Name, kAttrib1Size, kAttrib1Type, kAttrib1Location, }, { kAttrib2Name, kAttrib2Size, kAttrib2BadType, kAttrib2Location, }, @@ -1497,9 +1535,9 @@ TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) { // Check shader got created. ASSERT_TRUE(vshader != NULL && fshader != NULL); // Set Status - TestHelper::SetShaderStates( - gl_.get(), vshader, true, NULL, NULL, NULL, &attrib_map, NULL, NULL, - NULL, NULL); + TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, + nullptr, &attrib_map, nullptr, nullptr, nullptr, + nullptr, nullptr); // Check attrib infos got copied. for (AttributeMap::const_iterator it = attrib_map.begin(); it != attrib_map.end(); ++it) { @@ -1512,10 +1550,9 @@ TEST_F(ProgramManagerWithShaderTest, BindAttribLocationConflicts) { EXPECT_EQ(it->second.staticUse, variable_info->staticUse); EXPECT_EQ(it->second.name, variable_info->name); } - TestHelper::SetShaderStates( - gl_.get(), fshader, true, NULL, NULL, NULL, &attrib_map, NULL, NULL, - NULL, NULL); - + TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, + nullptr, &attrib_map, nullptr, nullptr, nullptr, + nullptr, nullptr); // Set up program Program* program = manager_->CreateProgram(kClientProgramId, kServiceProgramId); @@ -1581,13 +1618,12 @@ TEST_F(ProgramManagerWithShaderTest, UniformsPrecisionMismatch) { // Check shader got created. ASSERT_TRUE(vshader != NULL && fshader != NULL); // Set Status - TestHelper::SetShaderStates( - gl_.get(), vshader, true, NULL, NULL, NULL, NULL, - &vertex_uniform_map, NULL, NULL, NULL); - TestHelper::SetShaderStates( - gl_.get(), fshader, true, NULL, NULL, NULL, NULL, - &frag_uniform_map, NULL, NULL, NULL); - + TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, + nullptr, nullptr, &vertex_uniform_map, nullptr, + nullptr, nullptr, nullptr); + TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, + nullptr, nullptr, &frag_uniform_map, nullptr, + nullptr, nullptr, nullptr); // Set up program Program* program = manager_->CreateProgram(kClientProgramId, kServiceProgramId); @@ -1609,8 +1645,8 @@ TEST_F(ProgramManagerWithShaderTest, VaryingTypeMismatch) { { GL_FLOAT_VEC3, 1, GL_MEDIUM_FLOAT, true, "a", kVarVarying }; const VarInfo kFragmentVarying = { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarVarying }; - Program* program = SetupShaderVariableTest( - &kVertexVarying, 1, &kFragmentVarying, 1); + Program* program = + SetupProgramForVariables(&kVertexVarying, 1, &kFragmentVarying, 1); std::string conflicting_name; @@ -1626,8 +1662,8 @@ TEST_F(ProgramManagerWithShaderTest, VaryingArraySizeMismatch) { { GL_FLOAT, 2, GL_MEDIUM_FLOAT, true, "a", kVarVarying }; const VarInfo kFragmentVarying = { GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a", kVarVarying }; - Program* program = SetupShaderVariableTest( - &kVertexVarying, 1, &kFragmentVarying, 1); + Program* program = + SetupProgramForVariables(&kVertexVarying, 1, &kFragmentVarying, 1); std::string conflicting_name; @@ -1643,8 +1679,8 @@ TEST_F(ProgramManagerWithShaderTest, VaryingPrecisionMismatch) { { GL_FLOAT, 2, GL_HIGH_FLOAT, true, "a", kVarVarying }; const VarInfo kFragmentVarying = { GL_FLOAT, 2, GL_MEDIUM_FLOAT, true, "a", kVarVarying }; - Program* program = SetupShaderVariableTest( - &kVertexVarying, 1, &kFragmentVarying, 1); + Program* program = + SetupProgramForVariables(&kVertexVarying, 1, &kFragmentVarying, 1); std::string conflicting_name; @@ -1658,8 +1694,7 @@ TEST_F(ProgramManagerWithShaderTest, VaryingPrecisionMismatch) { TEST_F(ProgramManagerWithShaderTest, VaryingMissing) { const VarInfo kFragmentVarying = { GL_FLOAT, 3, GL_MEDIUM_FLOAT, true, "a", kVarVarying }; - Program* program = SetupShaderVariableTest( - NULL, 0, &kFragmentVarying, 1); + Program* program = SetupProgramForVariables(nullptr, 0, &kFragmentVarying, 1); std::string conflicting_name; @@ -1674,8 +1709,7 @@ TEST_F(ProgramManagerWithShaderTest, VaryingMissing) { TEST_F(ProgramManagerWithShaderTest, InactiveVarying) { const VarInfo kFragmentVarying = { GL_FLOAT, 3, GL_MEDIUM_FLOAT, false, "a", kVarVarying }; - Program* program = SetupShaderVariableTest( - NULL, 0, &kFragmentVarying, 1); + Program* program = SetupProgramForVariables(nullptr, 0, &kFragmentVarying, 1); std::string conflicting_name; @@ -1692,8 +1726,8 @@ TEST_F(ProgramManagerWithShaderTest, AttribUniformNameConflict) { { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarAttribute }; const VarInfo kFragmentUniform = { GL_FLOAT_VEC4, 1, GL_MEDIUM_FLOAT, true, "a", kVarUniform }; - Program* program = SetupShaderVariableTest( - &kVertexAttribute, 1, &kFragmentUniform, 1); + Program* program = + SetupProgramForVariables(&kVertexAttribute, 1, &kFragmentUniform, 1); std::string conflicting_name; @@ -1712,8 +1746,8 @@ TEST_F(ProgramManagerWithShaderTest, TooManyVaryings) { { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, true, "a", kVarVarying }, { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying } }; - Program* program = SetupShaderVariableTest( - kVertexVaryings, 2, kFragmentVaryings, 2); + Program* program = + SetupProgramForVariables(kVertexVaryings, 2, kFragmentVaryings, 2); EXPECT_FALSE( program->CheckVaryingsPacking(Program::kCountOnlyStaticallyUsed)); @@ -1730,8 +1764,8 @@ TEST_F(ProgramManagerWithShaderTest, TooManyInactiveVaryings) { { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, false, "a", kVarVarying }, { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying } }; - Program* program = SetupShaderVariableTest( - kVertexVaryings, 2, kFragmentVaryings, 2); + Program* program = + SetupProgramForVariables(kVertexVaryings, 2, kFragmentVaryings, 2); EXPECT_TRUE( program->CheckVaryingsPacking(Program::kCountOnlyStaticallyUsed)); @@ -1749,8 +1783,8 @@ TEST_F(ProgramManagerWithShaderTest, CountAllVaryingsInPacking) { { GL_FLOAT_VEC4, 4, GL_MEDIUM_FLOAT, false, "a", kVarVarying }, { GL_FLOAT_VEC4, 5, GL_MEDIUM_FLOAT, true, "b", kVarVarying } }; - Program* program = SetupShaderVariableTest( - kVertexVaryings, 2, kFragmentVaryings, 2); + Program* program = + SetupProgramForVariables(kVertexVaryings, 2, kFragmentVaryings, 2); EXPECT_FALSE(program->CheckVaryingsPacking(Program::kCountAll)); } @@ -1910,6 +1944,7 @@ class ProgramManagerWithCacheTest : public ProgramManagerTestBase { protected: void SetupProgramManager() override { manager_.reset(new ProgramManager(cache_.get(), kMaxVaryingVectors, + kMaxDualSourceDrawBuffers, feature_info_.get())); } @@ -1931,10 +1966,12 @@ class ProgramManagerWithCacheTest : public ProgramManagerTestBase { program_->AttachShader(&shader_manager_, vertex_shader_); program_->AttachShader(&shader_manager_, fragment_shader_); } + void TearDown() override { shader_manager_.Destroy(false); ProgramManagerTestBase::TearDown(); } + void SetShadersCompiled() { TestHelper::SetShaderStates(gl_.get(), vertex_shader_, true); TestHelper::SetShaderStates(gl_.get(), fragment_shader_, true); @@ -2019,9 +2056,9 @@ class ProgramManagerWithCacheTest : public ProgramManagerTestBase { } void SetExpectationsForProgramLoadSuccess(GLuint service_program_id) { - TestHelper::SetupProgramSuccessExpectations(gl_.get(), feature_info_.get(), - nullptr, 0, nullptr, 0, nullptr, - 0, service_program_id); + TestHelper::SetupProgramSuccessExpectations( + gl_.get(), feature_info_.get(), nullptr, 0, nullptr, 0, nullptr, 0, + nullptr, 0, service_program_id); } void SetExpectationsForProgramLink() { @@ -2177,7 +2214,6 @@ const char* ProgramManagerWithPathRenderingTest::kFragmentInput1Name = "color1"; const char* ProgramManagerWithPathRenderingTest::kFragmentInput2Name = "color2"; const char* ProgramManagerWithPathRenderingTest::kFragmentInput2GLName = "color2[0]"; - const char* ProgramManagerWithPathRenderingTest::kFragmentInput3Name = "color3"; const char* ProgramManagerWithPathRenderingTest::kFragmentInput3GLName = "color3[0]"; @@ -2205,10 +2241,10 @@ TEST_P(ProgramManagerWithPathRenderingTest, BindFragmentInputLocation) { kFragmentInput3StaticUse, kFragmentInput3Name); TestHelper::SetShaderStates(gl_.get(), vshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, &varying_map, nullptr, - nullptr); + nullptr, nullptr); TestHelper::SetShaderStates(gl_.get(), fshader, true, nullptr, nullptr, nullptr, nullptr, nullptr, &varying_map, nullptr, - nullptr); + nullptr, nullptr); Program* program = manager_->CreateProgram(kClientProgramId, kServiceProgramId); ASSERT_TRUE(program != NULL); @@ -2238,7 +2274,7 @@ TEST_P(ProgramManagerWithPathRenderingTest, BindFragmentInputLocation) { TestHelper::SetupShaderExpectationsWithVaryings( gl_.get(), feature_info_.get(), nullptr, 0, nullptr, 0, kFragmentInputExpectationInfos, arraysize(kFragmentInputExpectationInfos), - kServiceProgramId); + nullptr, 0, kServiceProgramId); program->Link(NULL, Program::kCountOnlyStaticallyUsed, base::Bind(&ShaderCacheCb)); const Program::FragmentInputInfo* info1 = @@ -2273,5 +2309,90 @@ INSTANTIATE_TEST_CASE_P( make_gl_ext_tuple("4.5", "GL_NV_path_rendering"), make_gl_ext_tuple("opengl es 3.1", "GL_NV_path_rendering"))); +class ProgramManagerDualSourceBlendingTest + : public ProgramManagerWithShaderTest, + public testing::WithParamInterface< + testing::tuple<const char*, const char*>> { + public: + ProgramManagerDualSourceBlendingTest() {} + + protected: + void SetUpWithFeatureInfo(FeatureInfo* feature_info) { + const char* gl_version = testing::get<0>(GetParam()); + const char* gl_extensions = testing::get<1>(GetParam()); + SetUpBase(gl_version, gl_extensions, feature_info); + } + + void SetUp() override { SetUpWithFeatureInfo(nullptr); } +}; + +class ProgramManagerDualSourceBlendingES2Test + : public ProgramManagerDualSourceBlendingTest {}; + +TEST_P(ProgramManagerDualSourceBlendingES2Test, UseSecondaryFragCoord) { + DCHECK(feature_info_->feature_flags().ext_blend_func_extended); + + const VarInfo kFragmentVaryings[] = { + {GL_FLOAT_VEC4, 0, GL_MEDIUM_FLOAT, true, "gl_SecondaryFragColorEXT", + kVarOutput}, + {GL_FLOAT_VEC4, 0, GL_MEDIUM_FLOAT, true, "gl_FragColor", kVarOutput}, + }; + + int shader_version = 100; + Program* program = + SetupProgramForVariables(nullptr, 0, kFragmentVaryings, + arraysize(kFragmentVaryings), &shader_version); + + const gfx::GLVersionInfo& gl_version = feature_info_->gl_version_info(); + if (!gl_version.is_es) { + // The call is expected only for OpenGL. OpenGL ES expects to + // output GLES SL 1.00, which does not bind. + EXPECT_CALL(*(gl_.get()), + BindFragDataLocationIndexed(kServiceProgramId, 0, 1, + StrEq("angle_SecondaryFragColor"))) + .Times(1) + .RetiresOnSaturation(); + } + + EXPECT_TRUE(LinkAsExpected(program, true)); +} + +TEST_P(ProgramManagerDualSourceBlendingES2Test, UseSecondaryFragData) { + const VarInfo kFragmentVaryings[] = { + {GL_FLOAT_VEC4, kMaxDualSourceDrawBuffers, GL_MEDIUM_FLOAT, true, + "gl_SecondaryFragDataEXT", kVarOutput}, + {GL_FLOAT_VEC4, kMaxDrawBuffers, GL_MEDIUM_FLOAT, true, "gl_FragData", + kVarOutput}, + }; + + int shader_version = 100; + Program* program = + SetupProgramForVariables(nullptr, 0, kFragmentVaryings, + arraysize(kFragmentVaryings), &shader_version); + + const gfx::GLVersionInfo& gl_version = feature_info_->gl_version_info(); + if (!gl_version.is_es) { + // The call is expected only for OpenGL. OpenGL ES expects to + // output GLES SL 1.00, which does not bind. + EXPECT_CALL(*(gl_.get()), + BindFragDataLocationIndexed(kServiceProgramId, 0, 1, + StrEq("angle_SecondaryFragData"))) + .Times(1) + .RetiresOnSaturation(); + } + + EXPECT_TRUE(LinkAsExpected(program, true)); +} + +INSTANTIATE_TEST_CASE_P( + SupportedContexts, + ProgramManagerDualSourceBlendingES2Test, + testing::Values( + make_gl_ext_tuple("3.2", + "GL_ARB_draw_buffers GL_ARB_blend_func_extended " + "GL_ARB_program_interface_query"), + make_gl_ext_tuple("opengl es 3.1", + "GL_EXT_draw_buffers GL_EXT_blend_func_extended"))); + } // namespace gles2 } // namespace gpu diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc index 342a476..22df5f7 100644 --- a/gpu/command_buffer/service/shader_manager.cc +++ b/gpu/command_buffer/service/shader_manager.cc @@ -69,15 +69,10 @@ void Shader::DoCompile() { const char* source_for_driver = last_compiled_source_.c_str(); ShaderTranslatorInterface* translator = translator_.get(); if (translator) { - bool success = translator->Translate(last_compiled_source_, - &log_info_, - &translated_source_, - &shader_version_, - &attrib_map_, - &uniform_map_, - &varying_map_, - &interface_block_map_, - &name_map_); + bool success = translator->Translate( + last_compiled_source_, &log_info_, &translated_source_, + &shader_version_, &attrib_map_, &uniform_map_, &varying_map_, + &interface_block_map_, &output_variable_list_, &name_map_); if (!success) { return; } @@ -215,6 +210,15 @@ const std::string* Shader::GetInterfaceBlockMappedName( return NULL; } +const std::string* Shader::GetOutputVariableMappedName( + const std::string& original_name) const { + for (const auto& value : output_variable_list_) { + if (value.name == original_name) + return &value.mappedName; + } + return nullptr; +} + const std::string* Shader::GetOriginalNameFromHashedName( const std::string& hashed_name) const { NameMap::const_iterator it = name_map_.find(hashed_name); @@ -249,6 +253,18 @@ const sh::InterfaceBlock* Shader::GetInterfaceBlockInfo( return it != interface_block_map_.end() ? &it->second : NULL; } +const sh::OutputVariable* Shader::GetOutputVariableInfo( + const std::string& name) const { + std::string mapped_name = GetTopVariableName(name); + // Number of output variables is expected to be so low that + // a linear search of a list should be faster than using a map. + for (const auto& value : output_variable_list_) { + if (value.mappedName == mapped_name) + return &value; + } + return nullptr; +} + ShaderManager::ShaderManager() {} ShaderManager::~ShaderManager() { diff --git a/gpu/command_buffer/service/shader_manager.h b/gpu/command_buffer/service/shader_manager.h index 3288bff..1869371 100644 --- a/gpu/command_buffer/service/shader_manager.h +++ b/gpu/command_buffer/service/shader_manager.h @@ -88,6 +88,8 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> { const sh::Varying* GetVaryingInfo(const std::string& name) const; const sh::InterfaceBlock* GetInterfaceBlockInfo( const std::string& name) const; + const sh::OutputVariable* GetOutputVariableInfo( + const std::string& name) const; // If the original_name is not found, return NULL. const std::string* GetAttribMappedName( @@ -105,6 +107,10 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> { const std::string* GetInterfaceBlockMappedName( const std::string& original_name) const; + // If the original_name is not found, return NULL. + const std::string* GetOutputVariableMappedName( + 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; @@ -144,6 +150,10 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> { return varying_map_; } + const OutputVariableList& output_variable_list() const { + return output_variable_list_; + } + // Used by program cache. const InterfaceBlockMap& interface_block_map() const { return interface_block_map_; @@ -177,6 +187,12 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> { uniform_map_[uniform.mappedName] = uniform; } + void set_output_variable_list( + const OutputVariableList& output_variable_list) { + // copied because cache might be cleared + output_variable_list_ = output_variable_list; + } + private: friend class base::RefCounted<Shader>; friend class ShaderManager; @@ -237,6 +253,7 @@ class GPU_EXPORT Shader : public base::RefCounted<Shader> { UniformMap uniform_map_; VaryingMap varying_map_; InterfaceBlockMap interface_block_map_; + OutputVariableList output_variable_list_; // The name hashing info when the shader was last compiled. NameMap name_map_; diff --git a/gpu/command_buffer/service/shader_manager_unittest.cc b/gpu/command_buffer/service/shader_manager_unittest.cc index c125cfe..93471ec 100644 --- a/gpu/command_buffer/service/shader_manager_unittest.cc +++ b/gpu/command_buffer/service/shader_manager_unittest.cc @@ -126,6 +126,11 @@ TEST_F(ShaderManagerTest, DoCompile) { const GLenum kVarying1Precision = GL_HIGH_FLOAT; const bool kVarying1StaticUse = false; const char* kVarying1Name = "varying1"; + const GLenum kOutputVariable1Type = GL_FLOAT_VEC4; + const GLint kOutputVariable1Size = 4; + const GLenum kOutputVariable1Precision = GL_MEDIUM_FLOAT; + const char* kOutputVariable1Name = "gl_FragColor"; + const bool kOutputVariable1StaticUse = true; // Check we can create shader. Shader* shader1 = manager_.CreateShader( @@ -187,10 +192,13 @@ TEST_F(ShaderManagerTest, DoCompile) { varying_map[kVarying1Name] = TestHelper::ConstructVarying( kVarying1Type, kVarying1Size, kVarying1Precision, kVarying1StaticUse, kVarying1Name); - + OutputVariableList output_variable_list; + output_variable_list.push_back(TestHelper::ConstructOutputVariable( + kOutputVariable1Type, kOutputVariable1Size, kOutputVariable1Precision, + kOutputVariable1StaticUse, kOutputVariable1Name)); TestHelper::SetShaderStates( - gl_.get(), shader1, true, &kLog, &kTranslatedSource, NULL, - &attrib_map, &uniform_map, &varying_map, NULL, NULL); + gl_.get(), shader1, true, &kLog, &kTranslatedSource, nullptr, &attrib_map, + &uniform_map, &varying_map, nullptr, &output_variable_list, nullptr); EXPECT_TRUE(shader1->valid()); // When compilation succeeds, no log is recorded. EXPECT_STREQ("", shader1->log_info().c_str()); @@ -233,17 +241,33 @@ TEST_F(ShaderManagerTest, DoCompile) { EXPECT_EQ(it->second.staticUse, variable_info->staticUse); EXPECT_STREQ(it->second.name.c_str(), variable_info->name.c_str()); } + // Check output variable infos got copied. + EXPECT_EQ(output_variable_list.size(), + shader1->output_variable_list().size()); + for (auto it = output_variable_list.begin(); it != output_variable_list.end(); + ++it) { + const sh::OutputVariable* variable_info = + shader1->GetOutputVariableInfo(it->mappedName); + ASSERT_TRUE(variable_info != nullptr); + EXPECT_EQ(it->type, variable_info->type); + EXPECT_EQ(it->arraySize, variable_info->arraySize); + EXPECT_EQ(it->precision, variable_info->precision); + EXPECT_EQ(it->staticUse, variable_info->staticUse); + EXPECT_STREQ(it->name.c_str(), variable_info->name.c_str()); + } // Compile failure case. - TestHelper::SetShaderStates( - gl_.get(), shader1, false, &kLog, &kTranslatedSource, NULL, - &attrib_map, &uniform_map, &varying_map, NULL, NULL); + TestHelper::SetShaderStates(gl_.get(), shader1, false, &kLog, + &kTranslatedSource, nullptr, &attrib_map, + &uniform_map, &varying_map, nullptr, + &output_variable_list, nullptr); EXPECT_FALSE(shader1->valid()); EXPECT_STREQ(kLog.c_str(), shader1->log_info().c_str()); EXPECT_STREQ("", shader1->translated_source().c_str()); EXPECT_TRUE(shader1->attrib_map().empty()); EXPECT_TRUE(shader1->uniform_map().empty()); EXPECT_TRUE(shader1->varying_map().empty()); + EXPECT_TRUE(shader1->output_variable_list().empty()); } TEST_F(ShaderManagerTest, ShaderInfoUseCount) { diff --git a/gpu/command_buffer/service/shader_translator.cc b/gpu/command_buffer/service/shader_translator.cc index 92c7f9d..255caff 100644 --- a/gpu/command_buffer/service/shader_translator.cc +++ b/gpu/command_buffer/service/shader_translator.cc @@ -71,6 +71,11 @@ void GetVaryings(ShHandle compiler, VaryingMap* var_map) { (*var_map)[(*varyings)[ii].mappedName] = (*varyings)[ii]; } } +void GetOutputVariables(ShHandle compiler, OutputVariableList* var_list) { + if (!var_list) + return; + *var_list = *ShGetOutputVariables(compiler); +} void GetInterfaceBlocks(ShHandle compiler, InterfaceBlockMap* var_map) { if (!var_map) @@ -206,6 +211,7 @@ bool ShaderTranslator::Translate(const std::string& shader_source, UniformMap* uniform_map, VaryingMap* varying_map, InterfaceBlockMap* interface_block_map, + OutputVariableList* output_variable_list, NameMap* name_map) const { // Make sure this instance is initialized. DCHECK(compiler_ != NULL); @@ -224,11 +230,12 @@ bool ShaderTranslator::Translate(const std::string& shader_source, } // Get shader version. *shader_version = ShGetShaderVersion(compiler_); - // Get info for attribs, uniforms, and varyings. + // Get info for attribs, uniforms, varyings and output variables. GetAttributes(compiler_, attrib_map); GetUniforms(compiler_, uniform_map); GetVaryings(compiler_, varying_map); GetInterfaceBlocks(compiler_, interface_block_map); + GetOutputVariables(compiler_, output_variable_list); // Get info for name hashing. GetNameHashingInfo(compiler_, name_map); } diff --git a/gpu/command_buffer/service/shader_translator.h b/gpu/command_buffer/service/shader_translator.h index 58ba69f..5a4914d 100644 --- a/gpu/command_buffer/service/shader_translator.h +++ b/gpu/command_buffer/service/shader_translator.h @@ -24,6 +24,7 @@ namespace gles2 { // Mapping between variable name and info. typedef base::hash_map<std::string, sh::Attribute> AttributeMap; +typedef std::vector<sh::OutputVariable> OutputVariableList; typedef base::hash_map<std::string, sh::Uniform> UniformMap; typedef base::hash_map<std::string, sh::Varying> VaryingMap; typedef base::hash_map<std::string, sh::InterfaceBlock> InterfaceBlockMap; @@ -58,6 +59,7 @@ class ShaderTranslatorInterface UniformMap* uniform_map, VaryingMap* varying_map, InterfaceBlockMap* interface_block_map, + OutputVariableList* output_variable_list, NameMap* name_map) const = 0; // Return a string that is unique for a specfic set of options that would @@ -109,6 +111,7 @@ class GPU_EXPORT ShaderTranslator UniformMap* uniform_map, VaryingMap* varying_map, InterfaceBlockMap* interface_block_map, + OutputVariableList* output_variable_list, NameMap* name_map) const override; std::string GetStringForOptionsThatWouldAffectCompilation() const override; diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc index eff11c1..e5b3f6b 100644 --- a/gpu/command_buffer/service/shader_translator_unittest.cc +++ b/gpu/command_buffer/service/shader_translator_unittest.cc @@ -98,16 +98,13 @@ TEST_F(ShaderTranslatorTest, ValidVertexShader) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_TRUE(vertex_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_TRUE(vertex_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); + // Info log must be NULL. EXPECT_TRUE(info_log.empty()); // Translated shader must be valid and non-empty. @@ -118,6 +115,7 @@ TEST_F(ShaderTranslatorTest, ValidVertexShader) { EXPECT_TRUE(uniform_map.empty()); EXPECT_TRUE(interface_block_map.empty()); EXPECT_EQ(1u, varying_map.size()); + EXPECT_TRUE(output_variable_list.empty()); // There should be no name mapping. EXPECT_TRUE(name_map.empty()); } @@ -136,16 +134,12 @@ TEST_F(ShaderTranslatorTest, InvalidVertexShader) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_FALSE(vertex_translator_->Translate(bad_shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_FALSE(vertex_translator_->Translate( + bad_shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be valid and non-empty. ASSERT_FALSE(info_log.empty()); // Translated shader must be NULL. @@ -156,19 +150,15 @@ TEST_F(ShaderTranslatorTest, InvalidVertexShader) { EXPECT_TRUE(uniform_map.empty()); EXPECT_TRUE(varying_map.empty()); EXPECT_TRUE(interface_block_map.empty()); + EXPECT_TRUE(output_variable_list.empty()); EXPECT_TRUE(name_map.empty()); // Try a good shader after bad. info_log.clear(); - EXPECT_TRUE(vertex_translator_->Translate(good_shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_TRUE(vertex_translator_->Translate( + good_shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); EXPECT_TRUE(info_log.empty()); EXPECT_FALSE(translated_source.empty()); EXPECT_TRUE(interface_block_map.empty()); @@ -187,16 +177,12 @@ TEST_F(ShaderTranslatorTest, ValidFragmentShader) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_TRUE(fragment_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_TRUE(fragment_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be NULL. EXPECT_TRUE(info_log.empty()); // Translated shader must be valid and non-empty. @@ -208,6 +194,8 @@ TEST_F(ShaderTranslatorTest, ValidFragmentShader) { EXPECT_TRUE(varying_map.empty()); EXPECT_TRUE(interface_block_map.empty()); EXPECT_TRUE(name_map.empty()); + // gl_FragColor. + EXPECT_EQ(1u, output_variable_list.size()); } TEST_F(ShaderTranslatorTest, InvalidFragmentShader) { @@ -219,17 +207,13 @@ TEST_F(ShaderTranslatorTest, InvalidFragmentShader) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; // An invalid shader should fail. - EXPECT_FALSE(fragment_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_FALSE(fragment_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be valid and non-empty. EXPECT_FALSE(info_log.empty()); // Translated shader must be NULL. @@ -239,6 +223,7 @@ TEST_F(ShaderTranslatorTest, InvalidFragmentShader) { EXPECT_TRUE(attrib_map.empty()); EXPECT_TRUE(uniform_map.empty()); EXPECT_TRUE(varying_map.empty()); + EXPECT_TRUE(output_variable_list.empty()); EXPECT_TRUE(name_map.empty()); } @@ -255,16 +240,12 @@ TEST_F(ShaderTranslatorTest, GetAttributes) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_TRUE(vertex_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_TRUE(vertex_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be NULL. EXPECT_TRUE(info_log.empty()); // Translated shader must be valid and non-empty. @@ -303,16 +284,12 @@ TEST_F(ShaderTranslatorTest, GetUniforms) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_TRUE(fragment_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_TRUE(fragment_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be NULL. EXPECT_TRUE(info_log.empty()); // Translated shader must be valid and non-empty. @@ -344,6 +321,9 @@ TEST_F(ShaderTranslatorTest, GetUniforms) { EXPECT_EQ(1u, info->arraySize); EXPECT_STREQ("color", info->name.c_str()); EXPECT_STREQ("bar[1].foo.color[0]", original_name.c_str()); + EXPECT_EQ(1u, output_variable_list.size()); + ASSERT_TRUE(output_variable_list.size() > 0); + EXPECT_EQ(output_variable_list[0].mappedName, "gl_FragColor"); } @@ -372,16 +352,12 @@ TEST_F(ES3ShaderTranslatorTest, InvalidInterfaceBlocks) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_FALSE(fragment_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_FALSE(fragment_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be valid and non-empty. ASSERT_FALSE(info_log.empty()); // Translated shader must be NULL. @@ -415,16 +391,12 @@ TEST_F(ES3ShaderTranslatorTest, GetInterfaceBlocks) { UniformMap uniform_map; VaryingMap varying_map; InterfaceBlockMap interface_block_map; + OutputVariableList output_variable_list; NameMap name_map; - EXPECT_TRUE(fragment_translator_->Translate(shader, - &info_log, - &translated_source, - &shader_version, - &attrib_map, - &uniform_map, - &varying_map, - &interface_block_map, - &name_map)); + EXPECT_TRUE(fragment_translator_->Translate( + shader, &info_log, &translated_source, &shader_version, &attrib_map, + &uniform_map, &varying_map, &interface_block_map, &output_variable_list, + &name_map)); // Info log must be NULL. EXPECT_TRUE(info_log.empty()); // Translated shader must be valid and non-empty. @@ -509,7 +481,7 @@ TEST_P(ShaderTranslatorOutputVersionTest, HasCorrectOutputGLSLVersion) { int shader_version; EXPECT_TRUE(translator->Translate(kShader, nullptr, &translated_source, &shader_version, nullptr, nullptr, nullptr, - nullptr, nullptr)); + nullptr, nullptr, nullptr)); std::string expected_version_directive = testing::get<1>(GetParam()); if (expected_version_directive.empty()) { diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc index 2c8fc25..40c285a 100644 --- a/gpu/command_buffer/service/test_helper.cc +++ b/gpu/command_buffer/service/test_helper.cc @@ -339,6 +339,16 @@ void TestHelper::SetupContextGroupInitExpectations( .WillOnce(SetArgumentPointee<1>(kMaxSamples)) .RetiresOnSaturation(); } + + if (gl_info.IsAtLeastGL(3, 3) || + (gl_info.IsAtLeastGL(3, 2) && + strstr(extensions, "GL_ARB_blend_func_extended")) || + (gl_info.is_es && strstr(extensions, "GL_EXT_blend_func_extended"))) { + EXPECT_CALL(*gl, GetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, _)) + .WillOnce(SetArgumentPointee<1>(8)) + .RetiresOnSaturation(); + } + EXPECT_CALL(*gl, GetIntegerv(GL_MAX_VERTEX_ATTRIBS, _)) .WillOnce(SetArgumentPointee<1>(kNumVertexAttribs)) .RetiresOnSaturation(); @@ -689,6 +699,8 @@ void TestHelper::SetupProgramSuccessExpectations( size_t num_uniforms, VaryingInfo* varyings, size_t num_varyings, + ProgramOutputInfo* program_outputs, + size_t num_program_outputs, GLuint service_id) { EXPECT_CALL(*gl, GetProgramiv(service_id, GL_LINK_STATUS, _)) @@ -724,7 +736,7 @@ void TestHelper::SetupProgramSuccessExpectations( SetArrayArgument<6>(info.name, info.name + strlen(info.name) + 1))) .RetiresOnSaturation(); - if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { + if (!ProgramManager::HasBuiltInPrefix(info.name)) { EXPECT_CALL(*gl, GetAttribLocation(service_id, StrEq(info.name))) .WillOnce(Return(info.location)) .RetiresOnSaturation(); @@ -799,7 +811,9 @@ void TestHelper::SetupProgramSuccessExpectations( SetArrayArgument<5>( info.name, info.name + strlen(info.name) + 1))) .RetiresOnSaturation(); - if (!ProgramManager::IsInvalidPrefix(info.name, strlen(info.name))) { + if (ProgramManager::HasBuiltInPrefix(info.name)) + continue; + static const GLenum kPropsArray[] = {GL_LOCATION, GL_TYPE, GL_ARRAY_SIZE}; static const size_t kPropsSize = arraysize(kPropsArray); @@ -818,6 +832,26 @@ void TestHelper::SetupProgramSuccessExpectations( })) .RetiresOnSaturation(); } + } + if (feature_info->gl_version_info().IsES3Capable() && + !feature_info->disable_shader_translator()) { + for (size_t ii = 0; ii < num_program_outputs; ++ii) { + ProgramOutputInfo& info = program_outputs[ii]; + if (ProgramManager::HasBuiltInPrefix(info.name)) + continue; + + EXPECT_CALL(*gl, GetFragDataLocation(service_id, StrEq(info.name))) + .WillOnce(Return(info.color_name)) + .RetiresOnSaturation(); + if (feature_info->feature_flags().ext_blend_func_extended) { + EXPECT_CALL(*gl, GetFragDataIndex(service_id, StrEq(info.name))) + .WillOnce(Return(info.index)) + .RetiresOnSaturation(); + } else { + // Test case must not use indices, or the context of the testcase has to + // support the dual source blending. + DCHECK(info.index == 0); + } } } } @@ -834,8 +868,8 @@ void TestHelper::SetupShaderExpectations(::gfx::MockGLInterface* gl, EXPECT_CALL(*gl, LinkProgram(service_id)).Times(1).RetiresOnSaturation(); SetupProgramSuccessExpectations(gl, feature_info, attribs, num_attribs, - uniforms, num_uniforms, nullptr, 0, - service_id); + uniforms, num_uniforms, nullptr, 0, nullptr, + 0, service_id); } void TestHelper::SetupShaderExpectationsWithVaryings( @@ -847,6 +881,8 @@ void TestHelper::SetupShaderExpectationsWithVaryings( size_t num_uniforms, VaryingInfo* varyings, size_t num_varyings, + ProgramOutputInfo* program_outputs, + size_t num_program_outputs, GLuint service_id) { InSequence s; @@ -855,9 +891,9 @@ void TestHelper::SetupShaderExpectationsWithVaryings( .Times(1) .RetiresOnSaturation(); - SetupProgramSuccessExpectations(gl, feature_info, attribs, num_attribs, - uniforms, num_uniforms, varyings, - num_varyings, service_id); + SetupProgramSuccessExpectations( + gl, feature_info, attribs, num_attribs, uniforms, num_uniforms, varyings, + num_varyings, program_outputs, num_program_outputs, service_id); } void TestHelper::DoBufferData( @@ -905,16 +941,18 @@ void TestHelper::SetTexParameteriWithExpectations( // static void TestHelper::SetShaderStates( - ::gfx::MockGLInterface* gl, Shader* shader, - bool expected_valid, - const std::string* const expected_log_info, - const std::string* const expected_translated_source, - const int* const expected_shader_version, - const AttributeMap* const expected_attrib_map, - const UniformMap* const expected_uniform_map, - const VaryingMap* const expected_varying_map, - const InterfaceBlockMap* const expected_interface_block_map, - const NameMap* const expected_name_map) { + ::gfx::MockGLInterface* gl, + Shader* shader, + bool expected_valid, + const std::string* const expected_log_info, + const std::string* const expected_translated_source, + const int* const expected_shader_version, + const AttributeMap* const expected_attrib_map, + const UniformMap* const expected_uniform_map, + const VaryingMap* const expected_varying_map, + const InterfaceBlockMap* const expected_interface_block_map, + const OutputVariableList* const expected_output_variable_list, + const NameMap* const expected_name_map) { const std::string empty_log_info; const std::string* log_info = (expected_log_info && !expected_valid) ? expected_log_info : &empty_log_info; @@ -938,6 +976,11 @@ void TestHelper::SetShaderStates( const InterfaceBlockMap* interface_block_map = (expected_interface_block_map && expected_valid) ? expected_interface_block_map : &empty_interface_block_map; + const OutputVariableList empty_output_variable_list; + const OutputVariableList* output_variable_list = + (expected_output_variable_list && expected_valid) + ? expected_output_variable_list + : &empty_output_variable_list; const NameMap empty_name_map; const NameMap* name_map = (expected_name_map && expected_valid) ? expected_name_map : &empty_name_map; @@ -945,13 +988,14 @@ void TestHelper::SetShaderStates( MockShaderTranslator* mock_translator = new MockShaderTranslator; scoped_refptr<ShaderTranslatorInterface> translator(mock_translator); EXPECT_CALL(*mock_translator, Translate(_, - NotNull(), // log_info - NotNull(), // translated_source - NotNull(), // shader_version - NotNull(), // attrib_map - NotNull(), // uniform_map - NotNull(), // varying_map - NotNull(), // interface_block_map + NotNull(), // log_info + NotNull(), // translated_source + NotNull(), // shader_version + NotNull(), // attrib_map + NotNull(), // uniform_map + NotNull(), // varying_map + NotNull(), // interface_block_map + NotNull(), // output_variable_list NotNull())) // name_map .WillOnce(DoAll(SetArgumentPointee<1>(*log_info), SetArgumentPointee<2>(*translated_source), @@ -960,8 +1004,8 @@ void TestHelper::SetShaderStates( SetArgumentPointee<5>(*uniform_map), SetArgumentPointee<6>(*varying_map), SetArgumentPointee<7>(*interface_block_map), - SetArgumentPointee<8>(*name_map), - Return(expected_valid))) + SetArgumentPointee<8>(*output_variable_list), + SetArgumentPointee<9>(*name_map), Return(expected_valid))) .RetiresOnSaturation(); if (expected_valid) { EXPECT_CALL(*gl, ShaderSource(shader->service_id(), 1, _, NULL)) @@ -983,8 +1027,8 @@ void TestHelper::SetShaderStates( // static void TestHelper::SetShaderStates( ::gfx::MockGLInterface* gl, Shader* shader, bool valid) { - SetShaderStates( - gl, shader, valid, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + SetShaderStates(gl, shader, valid, nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, nullptr, nullptr); } // static @@ -1011,6 +1055,16 @@ sh::Varying TestHelper::ConstructVarying( type, array_size, precision, static_use, name); } +sh::OutputVariable TestHelper::ConstructOutputVariable( + GLenum type, + GLint array_size, + GLenum precision, + bool static_use, + const std::string& name) { + return ConstructShaderVariable<sh::OutputVariable>( + type, array_size, precision, static_use, name); +} + ScopedGLImplementationSetter::ScopedGLImplementationSetter( gfx::GLImplementation implementation) : old_implementation_(gfx::GetGLImplementation()) { diff --git a/gpu/command_buffer/service/test_helper.h b/gpu/command_buffer/service/test_helper.h index 33c91fb..7072428 100644 --- a/gpu/command_buffer/service/test_helper.h +++ b/gpu/command_buffer/service/test_helper.h @@ -82,6 +82,13 @@ class TestHelper { GLint real_location; GLint desired_location; }; + struct ProgramOutputInfo { + const char* name; + GLint size; + GLenum type; + GLint color_name; + GLuint index; + }; static void SetupContextGroupInitExpectations( ::gfx::MockGLInterface* gl, @@ -126,17 +133,22 @@ class TestHelper { size_t num_uniforms, VaryingInfo* varyings, size_t num_varyings, + ProgramOutputInfo* program_outputs, + size_t num_program_outputs, GLuint service_id); - static void SetupProgramSuccessExpectations(::gfx::MockGLInterface* gl, - const FeatureInfo* feature_info, - AttribInfo* attribs, - size_t num_attribs, - UniformInfo* uniforms, - size_t num_uniforms, - VaryingInfo* varyings, - size_t num_varyings, - GLuint service_id); + static void SetupProgramSuccessExpectations( + ::gfx::MockGLInterface* gl, + const FeatureInfo* feature_info, + AttribInfo* attribs, + size_t num_attribs, + UniformInfo* uniforms, + size_t num_uniforms, + VaryingInfo* varyings, + size_t num_varyings, + ProgramOutputInfo* program_outputs, + size_t num_program_outputs, + GLuint service_id); static void DoBufferData( ::gfx::MockGLInterface* gl, MockErrorState* error_state, @@ -149,7 +161,8 @@ class TestHelper { GLenum pname, GLint value, GLenum error); static void SetShaderStates( - ::gfx::MockGLInterface* gl, Shader* shader, + ::gfx::MockGLInterface* gl, + Shader* shader, bool expected_valid, const std::string* const expected_log_info, const std::string* const expected_translated_source, @@ -158,6 +171,7 @@ class TestHelper { const UniformMap* const expected_uniform_map, const VaryingMap* const expected_varying_map, const InterfaceBlockMap* const expected_interface_block_map, + const OutputVariableList* const expected_output_variable_list, const NameMap* const expected_name_map); static void SetShaderStates( @@ -172,6 +186,11 @@ class TestHelper { static sh::Varying ConstructVarying( GLenum type, GLint array_size, GLenum precision, bool static_use, const std::string& name); + static sh::OutputVariable ConstructOutputVariable(GLenum type, + GLint array_size, + GLenum precision, + bool static_use, + const std::string& name); private: static void SetupTextureInitializationExpectations(::gfx::MockGLInterface* gl, diff --git a/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc b/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc new file mode 100644 index 0000000..d2f01ab --- /dev/null +++ b/gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc @@ -0,0 +1,653 @@ +// Copyright (c) 2015 The Chromium 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 <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES2/gl2extchromium.h> +#include <GLES3/gl3.h> + +#include "base/command_line.h" +#include "base/strings/string_number_conversions.h" +#include "gpu/command_buffer/service/gpu_switches.h" +#include "gpu/command_buffer/tests/gl_manager.h" +#include "gpu/command_buffer/tests/gl_test_utils.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gl/gl_switches.h" + +#define SHADER(Src) #Src +#define BFE_SHADER(Src) "#extension GL_EXT_blend_func_extended : require\n" #Src + +namespace { +// Partial implementation of weight function for GLES 2 blend equation that +// is dual-source aware. +template <int factor, int index> +float Weight(float /*dst*/[4], float src[4], float src1[4]) { + if (factor == GL_SRC_COLOR) + return src[index]; + if (factor == GL_SRC_ALPHA) + return src[3]; + if (factor == GL_SRC1_COLOR_EXT) + return src1[index]; + if (factor == GL_SRC1_ALPHA_EXT) + return src1[3]; + if (factor == GL_ONE_MINUS_SRC1_COLOR_EXT) + return 1.0f - src1[index]; + if (factor == GL_ONE_MINUS_SRC1_ALPHA_EXT) + return 1.0f - src1[3]; + return 0.0f; +} + +// Implementation of GLES 2 blend equation that is dual-source aware. +template <int RGBs, int RGBd, int As, int Ad> +void BlendEquationFuncAdd(float dst[4], + float src[4], + float src1[4], + uint8 result[4]) { + float r[4]; + r[0] = src[0] * Weight<RGBs, 0>(dst, src, src1) + + dst[0] * Weight<RGBd, 0>(dst, src, src1); + r[1] = src[1] * Weight<RGBs, 1>(dst, src, src1) + + dst[1] * Weight<RGBd, 1>(dst, src, src1); + r[2] = src[2] * Weight<RGBs, 2>(dst, src, src1) + + dst[2] * Weight<RGBd, 2>(dst, src, src1); + r[3] = src[3] * Weight<As, 3>(dst, src, src1) + + dst[3] * Weight<Ad, 3>(dst, src, src1); + for (int i = 0; i < 4; ++i) { + result[i] = static_cast<uint8>( + std::floor(std::max(0.0f, std::min(1.0f, r[i])) * 255.0f)); + } +} + +} // namespace + +namespace gpu { + +class EXTBlendFuncExtendedTest : public testing::Test { + public: + protected: + void SetUp() override { gl_.Initialize(GLManager::Options()); } + + void TearDown() override { gl_.Destroy(); } + bool IsApplicable() const { + return GLTestHelper::HasExtension("GL_EXT_blend_func_extended"); + } + GLManager gl_; +}; + +TEST_F(EXTBlendFuncExtendedTest, TestMaxDualSourceDrawBuffers) { + if (!IsApplicable()) + return; + + GLint maxDualSourceDrawBuffers = 0; + glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT, &maxDualSourceDrawBuffers); + EXPECT_GT(maxDualSourceDrawBuffers, 0); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); +} + +class EXTBlendFuncExtendedDrawTest : public testing::TestWithParam<bool> { + public: + static const GLsizei kWidth = 100; + static const GLsizei kHeight = 100; + EXTBlendFuncExtendedDrawTest() : program_(0) {} + + protected: + void SetUp() override { + GLManager::Options options; + options.size = gfx::Size(kWidth, kHeight); + options.force_shader_name_hashing = GetParam(); + base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); + gl_.InitializeWithCommandLine(options, &command_line); + } + + bool IsApplicable() const { + return GLTestHelper::HasExtension("GL_EXT_blend_func_extended"); + } + + virtual const char* GetVertexShader() { + // clang-format off + static const char* kVertexShader = + SHADER( + attribute vec4 position; + void main() { + gl_Position = position; + }); + // clang-format on + return kVertexShader; + } + + void CreateProgramWithFragmentShader(const char* fragment_shader_str) { + GLuint vertex_shader = + GLTestHelper::LoadShader(GL_VERTEX_SHADER, GetVertexShader()); + GLuint fragment_shader = + GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, fragment_shader_str); + ASSERT_NE(0u, vertex_shader); + ASSERT_NE(0u, fragment_shader); + program_ = glCreateProgram(); + ASSERT_NE(0u, program_); + glAttachShader(program_, vertex_shader); + glAttachShader(program_, fragment_shader); + glDeleteShader(vertex_shader); + glDeleteShader(fragment_shader); + } + + testing::AssertionResult LinkProgram() { + glLinkProgram(program_); + GLint linked = 0; + glGetProgramiv(program_, GL_LINK_STATUS, &linked); + if (linked == 0) { + char buffer[1024]; + GLsizei length = 0; + glGetProgramInfoLog(program_, sizeof(buffer), &length, buffer); + std::string log(buffer, length); + return testing::AssertionFailure() << "Error linking program: " << log; + } + glUseProgram(program_); + position_loc_ = glGetAttribLocation(program_, "position"); + src_loc_ = glGetUniformLocation(program_, "src"); + src1_loc_ = glGetUniformLocation(program_, "src1"); + return testing::AssertionSuccess(); + } + + void TearDown() override { + if (program_ != 0) + glDeleteProgram(program_); + gl_.Destroy(); + } + + void DrawAndVerify() { + float kDst[4] = {0.5f, 0.5f, 0.5f, 0.5f}; + float kSrc[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float kSrc1[4] = {0.3f, 0.6f, 0.9f, 0.7f}; + + glUniform4f(src_loc_, kSrc[0], kSrc[1], kSrc[2], kSrc[3]); + glUniform4f(src1_loc_, kSrc1[0], kSrc1[1], kSrc1[2], kSrc1[3]); + + GLTestHelper::SetupUnitQuad(position_loc_); + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFuncSeparate(GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, + GL_ONE_MINUS_SRC1_COLOR_EXT, + GL_ONE_MINUS_SRC1_ALPHA_EXT); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Draw one triangle (bottom left half). + glViewport(0, 0, kWidth, kHeight); + glClearColor(kDst[0], kDst[1], kDst[2], kDst[3]); + glClear(GL_COLOR_BUFFER_BIT); + glDrawArrays(GL_TRIANGLES, 0, 6); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + // Verify. + uint8 color[4]; + BlendEquationFuncAdd<GL_SRC1_COLOR_EXT, GL_SRC_ALPHA, + GL_ONE_MINUS_SRC1_COLOR_EXT, + GL_ONE_MINUS_SRC1_ALPHA_EXT>(kDst, kSrc, kSrc1, color); + + EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth / 4, (3 * kHeight) / 4, 1, 1, + 1, color)); + EXPECT_TRUE(GLTestHelper::CheckPixels(kWidth - 1, 0, 1, 1, 1, color)); + } + + protected: + GLuint program_; + GLuint position_loc_; + GLuint src_loc_; + GLuint src1_loc_; + GLManager gl_; +}; + +TEST_P(EXTBlendFuncExtendedDrawTest, ESSL1FragColor) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragColorShader = + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + void main() { + gl_FragColor = src; + gl_SecondaryFragColorEXT = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragColorShader); + LinkProgram(); + DrawAndVerify(); +} + +TEST_P(EXTBlendFuncExtendedDrawTest, ESSL1FragData) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragDataShader = + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + void main() { + gl_FragData[0] = src; + gl_SecondaryFragDataEXT[0] = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragDataShader); + LinkProgram(); + DrawAndVerify(); +} + +class EXTBlendFuncExtendedES3DrawTest : public EXTBlendFuncExtendedDrawTest { + protected: + void SetUp() override { + GLManager::Options options; + options.size = gfx::Size(kWidth, kHeight); + options.context_type = gles2::CONTEXT_TYPE_OPENGLES3; + options.force_shader_name_hashing = GetParam(); + base::CommandLine command_line(*base::CommandLine::ForCurrentProcess()); + command_line.AppendSwitch(switches::kEnableUnsafeES3APIs); + gl_.InitializeWithCommandLine(options, &command_line); + } + bool IsApplicable() const { + return gl_.IsInitialized() && EXTBlendFuncExtendedDrawTest::IsApplicable(); + } + const char* GetVertexShader() override { + // clang-format off + static const char* kVertexShader = + "#version 300 es\n" + SHADER( + in vec4 position; + void main() { + gl_Position = position; + }); + // clang-format on + return kVertexShader; + } +}; + +TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3Var) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragColorShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragColor; + out vec4 SecondaryFragColor; + void main() { + FragColor = src; + SecondaryFragColor = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragColorShader); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); + LinkProgram(); + DrawAndVerify(); +} + +TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindArrayWithSimpleName) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragDataShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragData[1]; + out vec4 SecondaryFragData[1]; + void main() { + FragData[0] = src; + SecondaryFragData[0] = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragDataShader); + glBindFragDataLocationEXT(program_, 0, "FragData"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData"); + LinkProgram(); + DrawAndVerify(); +} + +TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindSimpleVarAsArrayNoBind) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragDataShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragData; + out vec4 SecondaryFragData; + void main() { + FragData = src; + SecondaryFragData = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragDataShader); + glBindFragDataLocationEXT(program_, 0, "FragData[0]"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData[0]"); + // Does not fail, since FragData[0] and SecondaryFragData[0] do not exist. + EXPECT_TRUE(LinkProgram()); + + EXPECT_EQ(-1, glGetFragDataLocation(program_, "FragData[0]")); + EXPECT_EQ(0, glGetFragDataLocation(program_, "FragData")); + EXPECT_EQ(1, glGetFragDataLocation(program_, "SecondaryFragData")); + // Did not bind index. + EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "SecondaryFragData")); + + glBindFragDataLocationEXT(program_, 0, "FragData"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData"); + EXPECT_TRUE(LinkProgram()); + DrawAndVerify(); +} + +TEST_P(EXTBlendFuncExtendedES3DrawTest, ESSL3BindArrayAsArray) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragDataShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragData[1]; + out vec4 SecondaryFragData[1]; + void main() { + FragData[0] = src; + SecondaryFragData[0] = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragDataShader); + glBindFragDataLocationEXT(program_, 0, "FragData[0]"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragData[0]"); + LinkProgram(); + DrawAndVerify(); +} + +TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3Getters) { + if (!IsApplicable()) + return; + // clang-format off + static const char* kFragColorShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragColor; + out vec4 SecondaryFragColor; + void main() { + FragColor = src; + SecondaryFragColor = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragColorShader); + glBindFragDataLocationEXT(program_, 0, "FragColor"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); + + // Getters return GL error before linking. + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + GLint location = glGetFragDataLocation(program_, "FragColor"); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + GLint index = glGetFragDataIndexEXT(program_, "FragColor"); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + location = glGetFragDataLocation(program_, "SecondaryFragColor"); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); + EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError()); + LinkProgram(); + + // Getters return location and index after linking. Run twice to confirm that + // setters do not affect the getters until next link. + for (int i = 0; i < 2; ++i) { + SCOPED_TRACE(testing::Message() << "Testing getters after link, iteration " + << i); + + location = glGetFragDataLocation(program_, "FragColor"); + EXPECT_EQ(0, location); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + index = glGetFragDataIndexEXT(program_, "FragColor"); + EXPECT_EQ(0, index); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + location = glGetFragDataLocation(program_, "SecondaryFragColor"); + EXPECT_EQ(0, location); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); + EXPECT_EQ(1, index); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // The calls should not affect the getters until re-linking. + glBindFragDataLocationEXT(program_, 0, "SecondaryFragColor"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "FragColor"); + } + + LinkProgram(); + + location = glGetFragDataLocation(program_, "FragColor"); + EXPECT_EQ(0, location); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + index = glGetFragDataIndexEXT(program_, "FragColor"); + EXPECT_EQ(1, index); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + location = glGetFragDataLocation(program_, "SecondaryFragColor"); + EXPECT_EQ(0, location); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + index = glGetFragDataIndexEXT(program_, "SecondaryFragColor"); + EXPECT_EQ(0, index); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + + // Unknown colors return location -1, index -1. + location = glGetFragDataLocation(program_, "UnknownColor"); + EXPECT_EQ(-1, location); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + index = glGetFragDataIndexEXT(program_, "UnknownColor"); + EXPECT_EQ(-1, index); + + // Reset the settings and verify that the driver gets them correct. + glBindFragDataLocationEXT(program_, 0, "FragColor"); + glBindFragDataLocationIndexedEXT(program_, 0, 1, "SecondaryFragColor"); + LinkProgram(); + DrawAndVerify(); +} + +// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT, +// glGetFragDataLocation, glGetFragDataIndexEXT work correctly with +// GLSL array output variables. The output variable can be bound by +// referring to the variable name with or without the first element array +// accessor. The getters can query location of the individual elements in +// the array. The test does not actually use the base test drawing, +// since the drivers at the time of writing do not support multiple +// buffers and dual source blending. +TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3GettersArray) { + if (!IsApplicable()) + return; + const GLint kTestArraySize = 2; + const GLint kFragData0Location = 2; + const GLint kFragData1Location = 1; + const GLint kUnusedLocation = 5; + + // The test binds kTestArraySize -sized array to location 1 for test purposes. + // The GL_MAX_DRAW_BUFFERS must be > kTestArraySize, since an + // array will be bound to continuous locations, starting from the first + // location. + GLint maxDrawBuffers = 0; + glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); + EXPECT_LT(kTestArraySize, maxDrawBuffers); + + // clang-format off + static const char* kFragColorShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragData[2]; + void main() { + FragData[0] = src; + FragData[1] = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragColorShader); + + for (int testcase = 0; testcase < 4; ++testcase) { + if (testcase == 0) { + glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData[0]"); + glBindFragDataLocationEXT(program_, kFragData0Location, "FragData"); + glBindFragDataLocationEXT(program_, kFragData1Location, "FragData[1]"); + } else if (testcase == 1) { + glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData"); + glBindFragDataLocationEXT(program_, kFragData0Location, "FragData[0]"); + glBindFragDataLocationEXT(program_, kFragData1Location, "FragData[1]"); + } else if (testcase == 2) { + glBindFragDataLocationIndexedEXT(program_, kUnusedLocation, 0, + "FragData[0]"); + glBindFragDataLocationIndexedEXT(program_, kFragData0Location, 0, + "FragData"); + glBindFragDataLocationIndexedEXT(program_, kFragData1Location, 0, + "FragData[1]"); + } else if (testcase == 3) { + glBindFragDataLocationIndexedEXT(program_, kUnusedLocation, 0, + "FragData"); + glBindFragDataLocationIndexedEXT(program_, kFragData0Location, 0, + "FragData[0]"); + glBindFragDataLocationIndexedEXT(program_, kFragData1Location, 0, + "FragData[1]"); + } + + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + LinkProgram(); + EXPECT_EQ(kFragData0Location, glGetFragDataLocation(program_, "FragData")); + EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData")); + EXPECT_EQ(kFragData0Location, + glGetFragDataLocation(program_, "FragData[0]")); + EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData[0]")); + EXPECT_EQ(kFragData1Location, + glGetFragDataLocation(program_, "FragData[1]")); + EXPECT_EQ(0, glGetFragDataIndexEXT(program_, "FragData[1]")); + + // Index bigger than the GLSL variable array length does not find anything. + EXPECT_EQ(-1, glGetFragDataLocation(program_, "FragData[3]")); + } +} + +// Test that tests glBindFragDataLocationEXT, glBindFragDataLocationIndexedEXT +// conflicts +// with GLSL output variables. +TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3Conflicts) { + if (!IsApplicable()) + return; + const GLint kTestArraySize = 2; + const GLint kColorName0Location = 0; + const GLint kColorName1Location = 1; + GLint maxDrawBuffers = 0; + glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); + EXPECT_LT(kTestArraySize, maxDrawBuffers); + + // clang-format off + static const char* kFragColorShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragData0; + out vec4 FragData1; + void main() { + FragData0 = src; + FragData1 = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragColorShader); + + glBindFragDataLocationEXT(program_, kColorName0Location, "FragData0"); + glBindFragDataLocationEXT(program_, kColorName0Location, "FragData1"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_FALSE(LinkProgram()); + + glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0, + "FragData0"); + glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0, + "FragData1"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_FALSE(LinkProgram()); + + glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1, + "FragData0"); + glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1, + "FragData1"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_FALSE(LinkProgram()); + + // Test that correct binding actually works. + glBindFragDataLocationEXT(program_, kColorName0Location, "FragData0"); + glBindFragDataLocationEXT(program_, kColorName1Location, "FragData1"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_TRUE(LinkProgram()); + + glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 0, + "FragData0"); + glBindFragDataLocationIndexedEXT(program_, kColorName0Location, 1, + "FragData1"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_TRUE(LinkProgram()); +} + +// Test that tests glBindFragDataLocationEXT conflicts +// with GLSL array output variables. +TEST_P(EXTBlendFuncExtendedES3DrawTest, ES3ConflictsArray) { + if (!IsApplicable()) + return; + const GLint kTestArraySize = 2; + const GLint kColorName0Location = 0; + const GLint kColorName1Location = 1; + const GLint kUnusedLocation = 5; + GLint maxDrawBuffers = 0; + glGetIntegerv(GL_MAX_DRAW_BUFFERS_EXT, &maxDrawBuffers); + EXPECT_LT(kTestArraySize, maxDrawBuffers); + + // clang-format off + static const char* kFragColorShader = + "#version 300 es\n" + BFE_SHADER( + precision mediump float; + uniform vec4 src; + uniform vec4 src1; + out vec4 FragData[2]; + void main() { + FragData[0] = src; + FragData[1] = src1; + }); + // clang-format on + CreateProgramWithFragmentShader(kFragColorShader); + + glBindFragDataLocationEXT(program_, kColorName1Location, "FragData"); + glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_FALSE(LinkProgram()); + glBindFragDataLocationEXT(program_, kUnusedLocation, "FragData"); + glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[0]"); + glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_FALSE(LinkProgram()); + // Test that binding actually works. + glBindFragDataLocationEXT(program_, kColorName0Location, "FragData[0]"); + glBindFragDataLocationEXT(program_, kColorName1Location, "FragData[1]"); + EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); + EXPECT_TRUE(LinkProgram()); +} + +INSTANTIATE_TEST_CASE_P(TranslatorVariants, + EXTBlendFuncExtendedDrawTest, + ::testing::Bool()); + +INSTANTIATE_TEST_CASE_P(TranslatorVariants, + EXTBlendFuncExtendedES3DrawTest, + ::testing::Bool()); + +} // namespace gpu diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp index 68aaaff..14c4ea3 100644 --- a/gpu/gpu.gyp +++ b/gpu/gpu.gyp @@ -367,7 +367,8 @@ 'command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc', 'command_buffer/tests/gl_cube_map_texture_unittest.cc', 'command_buffer/tests/gl_depth_texture_unittest.cc', - 'command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc', + 'command_buffer/tests/gl_ext_blend_func_extended_unittest.cc', + 'command_buffer/tests/gl_ext_multisample_compatibility_unittest.cc', 'command_buffer/tests/gl_ext_srgb_unittest.cc', 'command_buffer/tests/gl_fence_sync_unittest.cc', 'command_buffer/tests/gl_gpu_memory_buffer_unittest.cc', diff --git a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc index 9afc900..0203d07 100644 --- a/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc +++ b/gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc @@ -143,6 +143,8 @@ void InitCommandBufferSkiaGLBinding(GrGLInterface* interface) { glRenderbufferStorageMultisampleCHROMIUM; functions->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleEXT; + functions->fBindFragDataLocation = glBindFragDataLocationEXT; + functions->fBindFragDataLocationIndexed = glBindFragDataLocationIndexedEXT; functions->fBindUniformLocation = glBindUniformLocationCHROMIUM; functions->fBlitFramebuffer = glBlitFramebufferCHROMIUM; functions->fGenerateMipmap = glGenerateMipmap; diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc index 8f817e3..2b2538a 100644 --- a/mojo/gpu/mojo_gles2_impl_autogen.cc +++ b/mojo/gpu/mojo_gles2_impl_autogen.cc @@ -1909,5 +1909,22 @@ void MojoGLES2Impl::ApplyScreenSpaceAntialiasingCHROMIUM() { MojoGLES2MakeCurrent(context_); glApplyScreenSpaceAntialiasingCHROMIUM(); } +void MojoGLES2Impl::BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) { + MojoGLES2MakeCurrent(context_); + glBindFragDataLocationIndexedEXT(program, colorNumber, index, name); +} +void MojoGLES2Impl::BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) { + MojoGLES2MakeCurrent(context_); + glBindFragDataLocationEXT(program, colorNumber, name); +} +GLint MojoGLES2Impl::GetFragDataIndexEXT(GLuint program, const char* name) { + MojoGLES2MakeCurrent(context_); + return glGetFragDataIndexEXT(program, name); +} } // namespace mojo diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h index e207ca4..c00372dd 100644 --- a/mojo/gpu/mojo_gles2_impl_autogen.h +++ b/mojo/gpu/mojo_gles2_impl_autogen.h @@ -888,6 +888,14 @@ class MojoGLES2Impl : public gpu::gles2::GLES2Interface { GLenum GetGraphicsResetStatusKHR() override; void BlendBarrierKHR() override; void ApplyScreenSpaceAntialiasingCHROMIUM() override; + void BindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) override; + void BindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) override; + GLint GetFragDataIndexEXT(GLuint program, const char* name) override; private: MojoGLES2Context context_; diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h index a6c8585..c0668d3 100644 --- a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h +++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h @@ -568,3 +568,16 @@ VISIT_GL_CALL(ProgramPathFragmentInputGenCHROMIUM, VISIT_GL_CALL(GetGraphicsResetStatusKHR, GLenum, (), ()) VISIT_GL_CALL(BlendBarrierKHR, void, (), ()) VISIT_GL_CALL(ApplyScreenSpaceAntialiasingCHROMIUM, void, (), ()) +VISIT_GL_CALL( + BindFragDataLocationIndexedEXT, + void, + (GLuint program, GLuint colorNumber, GLuint index, const char* name), + (program, colorNumber, index, name)) +VISIT_GL_CALL(BindFragDataLocationEXT, + void, + (GLuint program, GLuint colorNumber, const char* name), + (program, colorNumber, name)) +VISIT_GL_CALL(GetFragDataIndexEXT, + GLint, + (GLuint program, const char* name), + (program, name)) diff --git a/third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h new file mode 100644 index 0000000..88ab603 --- /dev/null +++ b/third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h @@ -0,0 +1,568 @@ +// Copyright 2014 The Chromium 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 +// It's formatted by clang-format using chromium coding style: +// clang-format -i -style=chromium filename +// DO NOT EDIT! + +VISIT_GL_CALL(ShallowFinishCHROMIUM, void, (), ()) +VISIT_GL_CALL(ShallowFlushCHROMIUM, void, (), ()) +VISIT_GL_CALL(OrderingBarrierCHROMIUM, void, (), ()) +VISIT_GL_CALL( + BlitFramebufferCHROMIUM, + void, + (GLint srcX0, + GLint srcY0, + GLint srcX1, + GLint srcY1, + GLint dstX0, + GLint dstY0, + GLint dstX1, + GLint dstY1, + GLbitfield mask, + GLenum filter), + (srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter)) +VISIT_GL_CALL(RenderbufferStorageMultisampleCHROMIUM, + void, + (GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height), + (target, samples, internalformat, width, height)) +VISIT_GL_CALL(RenderbufferStorageMultisampleEXT, + void, + (GLenum target, + GLsizei samples, + GLenum internalformat, + GLsizei width, + GLsizei height), + (target, samples, internalformat, width, height)) +VISIT_GL_CALL(FramebufferTexture2DMultisampleEXT, + void, + (GLenum target, + GLenum attachment, + GLenum textarget, + GLuint texture, + GLint level, + GLsizei samples), + (target, attachment, textarget, texture, level, samples)) +VISIT_GL_CALL(TexStorage2DEXT, + void, + (GLenum target, + GLsizei levels, + GLenum internalFormat, + GLsizei width, + GLsizei height), + (target, levels, internalFormat, width, height)) +VISIT_GL_CALL(GenQueriesEXT, void, (GLsizei n, GLuint* queries), (n, queries)) +VISIT_GL_CALL(DeleteQueriesEXT, + void, + (GLsizei n, const GLuint* queries), + (n, queries)) +VISIT_GL_CALL(QueryCounterEXT, void, (GLuint id, GLenum target), (id, target)) +VISIT_GL_CALL(IsQueryEXT, GLboolean, (GLuint id), (id)) +VISIT_GL_CALL(BeginQueryEXT, void, (GLenum target, GLuint id), (target, id)) +VISIT_GL_CALL(EndQueryEXT, void, (GLenum target), (target)) +VISIT_GL_CALL(GetQueryivEXT, + void, + (GLenum target, GLenum pname, GLint* params), + (target, pname, params)) +VISIT_GL_CALL(GetQueryObjectivEXT, + void, + (GLuint id, GLenum pname, GLint* params), + (id, pname, params)) +VISIT_GL_CALL(GetQueryObjectuivEXT, + void, + (GLuint id, GLenum pname, GLuint* params), + (id, pname, params)) +VISIT_GL_CALL(GetQueryObjecti64vEXT, + void, + (GLuint id, GLenum pname, GLint64* params), + (id, pname, params)) +VISIT_GL_CALL(GetQueryObjectui64vEXT, + void, + (GLuint id, GLenum pname, GLuint64* params), + (id, pname, params)) +VISIT_GL_CALL(SetDisjointValueSyncCHROMIUM, void, (), ()) +VISIT_GL_CALL(InsertEventMarkerEXT, + void, + (GLsizei length, const GLchar* marker), + (length, marker)) +VISIT_GL_CALL(PushGroupMarkerEXT, + void, + (GLsizei length, const GLchar* marker), + (length, marker)) +VISIT_GL_CALL(PopGroupMarkerEXT, void, (), ()) +VISIT_GL_CALL(GenVertexArraysOES, + void, + (GLsizei n, GLuint* arrays), + (n, arrays)) +VISIT_GL_CALL(DeleteVertexArraysOES, + void, + (GLsizei n, const GLuint* arrays), + (n, arrays)) +VISIT_GL_CALL(IsVertexArrayOES, GLboolean, (GLuint array), (array)) +VISIT_GL_CALL(BindVertexArrayOES, void, (GLuint array), (array)) +VISIT_GL_CALL(SwapBuffers, void, (), ()) +VISIT_GL_CALL(GetMaxValueInBufferCHROMIUM, + GLuint, + (GLuint buffer_id, GLsizei count, GLenum type, GLuint offset), + (buffer_id, count, type, offset)) +VISIT_GL_CALL(EnableFeatureCHROMIUM, + GLboolean, + (const char* feature), + (feature)) +VISIT_GL_CALL(MapBufferCHROMIUM, + void*, + (GLuint target, GLenum access), + (target, access)) +VISIT_GL_CALL(UnmapBufferCHROMIUM, GLboolean, (GLuint target), (target)) +VISIT_GL_CALL(MapBufferSubDataCHROMIUM, + void*, + (GLuint target, GLintptr offset, GLsizeiptr size, GLenum access), + (target, offset, size, access)) +VISIT_GL_CALL(UnmapBufferSubDataCHROMIUM, void, (const void* mem), (mem)) +VISIT_GL_CALL( + MapTexSubImage2DCHROMIUM, + void*, + (GLenum target, + GLint level, + GLint xoffset, + GLint yoffset, + GLsizei width, + GLsizei height, + GLenum format, + GLenum type, + GLenum access), + (target, level, xoffset, yoffset, width, height, format, type, access)) +VISIT_GL_CALL(UnmapTexSubImage2DCHROMIUM, void, (const void* mem), (mem)) +VISIT_GL_CALL(ResizeCHROMIUM, + void, + (GLuint width, GLuint height, GLfloat scale_factor), + (width, height, scale_factor)) +VISIT_GL_CALL(GetRequestableExtensionsCHROMIUM, const GLchar*, (), ()) +VISIT_GL_CALL(RequestExtensionCHROMIUM, + void, + (const char* extension), + (extension)) +VISIT_GL_CALL(GetProgramInfoCHROMIUM, + void, + (GLuint program, GLsizei bufsize, GLsizei* size, void* info), + (program, bufsize, size, info)) +VISIT_GL_CALL(CreateStreamTextureCHROMIUM, GLuint, (GLuint texture), (texture)) +VISIT_GL_CALL( + CreateImageCHROMIUM, + GLuint, + (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat), + (buffer, width, height, internalformat)) +VISIT_GL_CALL(DestroyImageCHROMIUM, void, (GLuint image_id), (image_id)) +VISIT_GL_CALL( + CreateGpuMemoryBufferImageCHROMIUM, + GLuint, + (GLsizei width, GLsizei height, GLenum internalformat, GLenum usage), + (width, height, internalformat, usage)) +VISIT_GL_CALL(GetTranslatedShaderSourceANGLE, + void, + (GLuint shader, GLsizei bufsize, GLsizei* length, char* source), + (shader, bufsize, length, source)) +VISIT_GL_CALL(PostSubBufferCHROMIUM, + void, + (GLint x, GLint y, GLint width, GLint height), + (x, y, width, height)) +VISIT_GL_CALL(TexImageIOSurface2DCHROMIUM, + void, + (GLenum target, + GLsizei width, + GLsizei height, + GLuint ioSurfaceId, + GLuint plane), + (target, width, height, ioSurfaceId, plane)) +VISIT_GL_CALL(CopyTextureCHROMIUM, + void, + (GLenum target, + GLenum source_id, + GLenum dest_id, + GLint internalformat, + GLenum dest_type, + GLboolean unpack_flip_y, + GLboolean unpack_premultiply_alpha, + GLboolean unpack_unmultiply_alpha), + (target, + source_id, + dest_id, + internalformat, + dest_type, + unpack_flip_y, + unpack_premultiply_alpha, + unpack_unmultiply_alpha)) +VISIT_GL_CALL(CopySubTextureCHROMIUM, + void, + (GLenum target, + GLenum source_id, + GLenum dest_id, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height, + GLboolean unpack_flip_y, + GLboolean unpack_premultiply_alpha, + GLboolean unpack_unmultiply_alpha), + (target, + source_id, + dest_id, + xoffset, + yoffset, + x, + y, + width, + height, + unpack_flip_y, + unpack_premultiply_alpha, + unpack_unmultiply_alpha)) +VISIT_GL_CALL(CompressedCopyTextureCHROMIUM, + void, + (GLenum target, GLenum source_id, GLenum dest_id), + (target, source_id, dest_id)) +VISIT_GL_CALL( + CompressedCopySubTextureCHROMIUM, + void, + (GLenum target, + GLenum source_id, + GLenum dest_id, + GLint xoffset, + GLint yoffset, + GLint x, + GLint y, + GLsizei width, + GLsizei height), + (target, source_id, dest_id, xoffset, yoffset, x, y, width, height)) +VISIT_GL_CALL(DrawArraysInstancedANGLE, + void, + (GLenum mode, GLint first, GLsizei count, GLsizei primcount), + (mode, first, count, primcount)) +VISIT_GL_CALL(DrawElementsInstancedANGLE, + void, + (GLenum mode, + GLsizei count, + GLenum type, + const void* indices, + GLsizei primcount), + (mode, count, type, indices, primcount)) +VISIT_GL_CALL(VertexAttribDivisorANGLE, + void, + (GLuint index, GLuint divisor), + (index, divisor)) +VISIT_GL_CALL(GenMailboxCHROMIUM, void, (GLbyte * mailbox), (mailbox)) +VISIT_GL_CALL(ProduceTextureCHROMIUM, + void, + (GLenum target, const GLbyte* mailbox), + (target, mailbox)) +VISIT_GL_CALL(ProduceTextureDirectCHROMIUM, + void, + (GLuint texture, GLenum target, const GLbyte* mailbox), + (texture, target, mailbox)) +VISIT_GL_CALL(ConsumeTextureCHROMIUM, + void, + (GLenum target, const GLbyte* mailbox), + (target, mailbox)) +VISIT_GL_CALL(CreateAndConsumeTextureCHROMIUM, + GLuint, + (GLenum target, const GLbyte* mailbox), + (target, mailbox)) +VISIT_GL_CALL(BindUniformLocationCHROMIUM, + void, + (GLuint program, GLint location, const char* name), + (program, location, name)) +VISIT_GL_CALL(GenValuebuffersCHROMIUM, + void, + (GLsizei n, GLuint* buffers), + (n, buffers)) +VISIT_GL_CALL(DeleteValuebuffersCHROMIUM, + void, + (GLsizei n, const GLuint* valuebuffers), + (n, valuebuffers)) +VISIT_GL_CALL(IsValuebufferCHROMIUM, + GLboolean, + (GLuint valuebuffer), + (valuebuffer)) +VISIT_GL_CALL(BindValuebufferCHROMIUM, + void, + (GLenum target, GLuint valuebuffer), + (target, valuebuffer)) +VISIT_GL_CALL(SubscribeValueCHROMIUM, + void, + (GLenum target, GLenum subscription), + (target, subscription)) +VISIT_GL_CALL(PopulateSubscribedValuesCHROMIUM, void, (GLenum target), (target)) +VISIT_GL_CALL(UniformValuebufferCHROMIUM, + void, + (GLint location, GLenum target, GLenum subscription), + (location, target, subscription)) +VISIT_GL_CALL(BindTexImage2DCHROMIUM, + void, + (GLenum target, GLint imageId), + (target, imageId)) +VISIT_GL_CALL(ReleaseTexImage2DCHROMIUM, + void, + (GLenum target, GLint imageId), + (target, imageId)) +VISIT_GL_CALL(TraceBeginCHROMIUM, + void, + (const char* category_name, const char* trace_name), + (category_name, trace_name)) +VISIT_GL_CALL(TraceEndCHROMIUM, void, (), ()) +VISIT_GL_CALL(DiscardFramebufferEXT, + void, + (GLenum target, GLsizei count, const GLenum* attachments), + (target, count, attachments)) +VISIT_GL_CALL(LoseContextCHROMIUM, + void, + (GLenum current, GLenum other), + (current, other)) +VISIT_GL_CALL(InsertSyncPointCHROMIUM, GLuint, (), ()) +VISIT_GL_CALL(WaitSyncPointCHROMIUM, void, (GLuint sync_point), (sync_point)) +VISIT_GL_CALL(InsertFenceSyncCHROMIUM, GLuint64, (), ()) +VISIT_GL_CALL(GenSyncTokenCHROMIUM, + void, + (GLuint64 fence_sync, GLbyte* sync_token), + (fence_sync, sync_token)) +VISIT_GL_CALL(GenUnverifiedSyncTokenCHROMIUM, + void, + (GLuint64 fence_sync, GLbyte* sync_token), + (fence_sync, sync_token)) +VISIT_GL_CALL(WaitSyncTokenCHROMIUM, + void, + (const GLbyte* sync_token), + (sync_token)) +VISIT_GL_CALL(DrawBuffersEXT, + void, + (GLsizei count, const GLenum* bufs), + (count, bufs)) +VISIT_GL_CALL(DiscardBackbufferCHROMIUM, void, (), ()) +VISIT_GL_CALL(ScheduleOverlayPlaneCHROMIUM, + void, + (GLint plane_z_order, + GLenum plane_transform, + GLuint overlay_texture_id, + GLint bounds_x, + GLint bounds_y, + GLint bounds_width, + GLint bounds_height, + GLfloat uv_x, + GLfloat uv_y, + GLfloat uv_width, + GLfloat uv_height), + (plane_z_order, + plane_transform, + overlay_texture_id, + bounds_x, + bounds_y, + bounds_width, + bounds_height, + uv_x, + uv_y, + uv_width, + uv_height)) +VISIT_GL_CALL(SwapInterval, void, (GLint interval), (interval)) +VISIT_GL_CALL(FlushDriverCachesCHROMIUM, void, (), ()) +VISIT_GL_CALL(MatrixLoadfCHROMIUM, + void, + (GLenum matrixMode, const GLfloat* m), + (matrixMode, m)) +VISIT_GL_CALL(MatrixLoadIdentityCHROMIUM, + void, + (GLenum matrixMode), + (matrixMode)) +VISIT_GL_CALL(GenPathsCHROMIUM, GLuint, (GLsizei range), (range)) +VISIT_GL_CALL(DeletePathsCHROMIUM, + void, + (GLuint path, GLsizei range), + (path, range)) +VISIT_GL_CALL(IsPathCHROMIUM, GLboolean, (GLuint path), (path)) +VISIT_GL_CALL(PathCommandsCHROMIUM, + void, + (GLuint path, + GLsizei numCommands, + const GLubyte* commands, + GLsizei numCoords, + GLenum coordType, + const GLvoid* coords), + (path, numCommands, commands, numCoords, coordType, coords)) +VISIT_GL_CALL(PathParameterfCHROMIUM, + void, + (GLuint path, GLenum pname, GLfloat value), + (path, pname, value)) +VISIT_GL_CALL(PathParameteriCHROMIUM, + void, + (GLuint path, GLenum pname, GLint value), + (path, pname, value)) +VISIT_GL_CALL(PathStencilFuncCHROMIUM, + void, + (GLenum func, GLint ref, GLuint mask), + (func, ref, mask)) +VISIT_GL_CALL(StencilFillPathCHROMIUM, + void, + (GLuint path, GLenum fillMode, GLuint mask), + (path, fillMode, mask)) +VISIT_GL_CALL(StencilStrokePathCHROMIUM, + void, + (GLuint path, GLint reference, GLuint mask), + (path, reference, mask)) +VISIT_GL_CALL(CoverFillPathCHROMIUM, + void, + (GLuint path, GLenum coverMode), + (path, coverMode)) +VISIT_GL_CALL(CoverStrokePathCHROMIUM, + void, + (GLuint path, GLenum coverMode), + (path, coverMode)) +VISIT_GL_CALL(StencilThenCoverFillPathCHROMIUM, + void, + (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode), + (path, fillMode, mask, coverMode)) +VISIT_GL_CALL(StencilThenCoverStrokePathCHROMIUM, + void, + (GLuint path, GLint reference, GLuint mask, GLenum coverMode), + (path, reference, mask, coverMode)) +VISIT_GL_CALL(StencilFillPathInstancedCHROMIUM, + void, + (GLsizei numPaths, + GLenum pathNameType, + const GLvoid* paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum transformType, + const GLfloat* transformValues), + (numPaths, + pathNameType, + paths, + pathBase, + fillMode, + mask, + transformType, + transformValues)) +VISIT_GL_CALL(StencilStrokePathInstancedCHROMIUM, + void, + (GLsizei numPaths, + GLenum pathNameType, + const GLvoid* paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum transformType, + const GLfloat* transformValues), + (numPaths, + pathNameType, + paths, + pathBase, + reference, + mask, + transformType, + transformValues)) +VISIT_GL_CALL(CoverFillPathInstancedCHROMIUM, + void, + (GLsizei numPaths, + GLenum pathNameType, + const GLvoid* paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat* transformValues), + (numPaths, + pathNameType, + paths, + pathBase, + coverMode, + transformType, + transformValues)) +VISIT_GL_CALL(CoverStrokePathInstancedCHROMIUM, + void, + (GLsizei numPaths, + GLenum pathNameType, + const GLvoid* paths, + GLuint pathBase, + GLenum coverMode, + GLenum transformType, + const GLfloat* transformValues), + (numPaths, + pathNameType, + paths, + pathBase, + coverMode, + transformType, + transformValues)) +VISIT_GL_CALL(StencilThenCoverFillPathInstancedCHROMIUM, + void, + (GLsizei numPaths, + GLenum pathNameType, + const GLvoid* paths, + GLuint pathBase, + GLenum fillMode, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat* transformValues), + (numPaths, + pathNameType, + paths, + pathBase, + fillMode, + mask, + coverMode, + transformType, + transformValues)) +VISIT_GL_CALL(StencilThenCoverStrokePathInstancedCHROMIUM, + void, + (GLsizei numPaths, + GLenum pathNameType, + const GLvoid* paths, + GLuint pathBase, + GLint reference, + GLuint mask, + GLenum coverMode, + GLenum transformType, + const GLfloat* transformValues), + (numPaths, + pathNameType, + paths, + pathBase, + reference, + mask, + coverMode, + transformType, + transformValues)) +VISIT_GL_CALL(BindFragmentInputLocationCHROMIUM, + void, + (GLuint program, GLint location, const char* name), + (program, location, name)) +VISIT_GL_CALL(ProgramPathFragmentInputGenCHROMIUM, + void, + (GLuint program, + GLint location, + GLenum genMode, + GLint components, + const GLfloat* coeffs), + (program, location, genMode, components, coeffs)) +VISIT_GL_CALL(GetGraphicsResetStatusKHR, GLenum, (), ()) +VISIT_GL_CALL(BlendBarrierKHR, void, (), ()) +VISIT_GL_CALL(ApplyScreenSpaceAntialiasingCHROMIUM, void, (), ()) +VISIT_GL_CALL( + BindFragDataLocationIndexedEXT, + void, + (GLuint program, GLuint colorNumber, GLuint index, const char* name), + (program, colorNumber, index, name)) +VISIT_GL_CALL(BindFragDataLocationEXT, + void, + (GLuint program, GLuint colorNumber, const char* name), + (program, colorNumber, name)) +VISIT_GL_CALL(GetFragDataIndexEXT, + GLint, + (GLuint program, const char* name), + (program, name)) diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py index d5019b8..c1d08a0 100755 --- a/ui/gl/generate_bindings.py +++ b/ui/gl/generate_bindings.py @@ -79,12 +79,19 @@ GL_FUNCTIONS = [ 'arguments': 'GLenum target, GLuint index, GLuint buffer, GLintptr offset, ' 'GLsizeiptr size', }, { 'return_type': 'void', - 'names': ['glBindFragDataLocation'], + 'versions': [{ 'name': 'glBindFragDataLocation', + 'extensions': ['GL_ARB_blend_func_extended'] }, + { 'name': 'glBindFragDataLocationEXT', + 'extensions': ['GL_EXT_blend_func_extended'] }], 'arguments': 'GLuint program, GLuint colorNumber, const char* name', }, { 'return_type': 'void', - 'names': ['glBindFragDataLocationIndexed'], + 'versions': [{ 'name': 'glBindFragDataLocationIndexed', + 'extensions': ['GL_ARB_blend_func_extended'] }, + { 'name': 'glBindFragDataLocationIndexedEXT', + 'extensions': ['GL_EXT_blend_func_extended'] }], 'arguments': - 'GLuint program, GLuint colorNumber, GLuint index, const char* name', }, + 'GLuint program, GLuint colorNumber, GLuint index, const char* name', +}, { 'return_type': 'void', 'names': ['glBindFramebufferEXT', 'glBindFramebuffer'], 'arguments': 'GLenum target, GLuint framebuffer', }, @@ -543,6 +550,12 @@ GL_FUNCTIONS = [ 'names': ['glGetFloatv'], 'arguments': 'GLenum pname, GLfloat* params', }, { 'return_type': 'GLint', + 'versions': [{'name': 'glGetFragDataIndex', + 'extensions': ['GL_ARB_blend_func_extended']}, + {'name': 'glGetFragDataIndexEXT', + 'extensions': ['GL_EXT_blend_func_extended']}], + 'arguments': 'GLuint program, const char* name', }, +{ 'return_type': 'GLint', 'versions': [{ 'name': 'glGetFragDataLocation' }], 'arguments': 'GLuint program, const char* name', }, { 'return_type': 'void', diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h index 1fcb36c..911cd9f 100644 --- a/ui/gl/gl_bindings.h +++ b/ui/gl/gl_bindings.h @@ -334,6 +334,16 @@ #define GL_FRAGMENT_INPUT_NV 0x936D #endif +#ifndef GL_EXT_blend_func_extended +#define GL_EXT_blend_func_extended 1 +#define GL_SRC_ALPHA_SATURATE_EXT 0x0308 +#define GL_SRC1_ALPHA_EXT 0x8589 // OpenGL 1.5 token value +#define GL_SRC1_COLOR_EXT 0x88F9 +#define GL_ONE_MINUS_SRC1_COLOR_EXT 0x88FA +#define GL_ONE_MINUS_SRC1_ALPHA_EXT 0x88FB +#define GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT 0x88FC +#endif /* GL_EXT_blend_func_extended */ + #define GL_GLEXT_PROTOTYPES 1 #if defined(OS_WIN) diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h index 4d86720..93039f6 100644 --- a/ui/gl/gl_bindings_api_autogen_gl.h +++ b/ui/gl/gl_bindings_api_autogen_gl.h @@ -344,6 +344,7 @@ void glGetBufferParameterivFn(GLenum target, GLenum glGetErrorFn(void) override; void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) override; void glGetFloatvFn(GLenum pname, GLfloat* params) override; +GLint glGetFragDataIndexFn(GLuint program, const char* name) override; GLint glGetFragDataLocationFn(GLuint program, const char* name) override; void glGetFramebufferAttachmentParameterivEXTFn(GLenum target, GLenum attachment, diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc index e7482d7..eabd4ae 100644 --- a/ui/gl/gl_bindings_autogen_gl.cc +++ b/ui/gl/gl_bindings_autogen_gl.cc @@ -202,6 +202,7 @@ void DriverGL::InitializeStaticBindings() { fn.glGetFenceivNVFn = 0; fn.glGetFloatvFn = reinterpret_cast<glGetFloatvProc>(GetGLProcAddress("glGetFloatv")); + fn.glGetFragDataIndexFn = 0; fn.glGetFragDataLocationFn = 0; fn.glGetFramebufferAttachmentParameterivEXTFn = 0; fn.glGetGraphicsResetStatusARBFn = 0; @@ -481,6 +482,8 @@ void DriverGL::InitializeDynamicBindings(GLContext* context) { extensions.find("GL_APPLE_fence ") != std::string::npos; ext.b_GL_APPLE_vertex_array_object = extensions.find("GL_APPLE_vertex_array_object ") != std::string::npos; + ext.b_GL_ARB_blend_func_extended = + extensions.find("GL_ARB_blend_func_extended ") != std::string::npos; ext.b_GL_ARB_draw_buffers = extensions.find("GL_ARB_draw_buffers ") != std::string::npos; ext.b_GL_ARB_draw_instanced = @@ -509,6 +512,8 @@ void DriverGL::InitializeDynamicBindings(GLContext* context) { std::string::npos; ext.b_GL_CHROMIUM_glgetstringi_hack = extensions.find("GL_CHROMIUM_glgetstringi_hack ") != std::string::npos; + ext.b_GL_EXT_blend_func_extended = + extensions.find("GL_EXT_blend_func_extended ") != std::string::npos; ext.b_GL_EXT_debug_marker = extensions.find("GL_EXT_debug_marker ") != std::string::npos; ext.b_GL_EXT_direct_state_access = @@ -525,6 +530,8 @@ void DriverGL::InitializeDynamicBindings(GLContext* context) { extensions.find("GL_EXT_framebuffer_multisample ") != std::string::npos; ext.b_GL_EXT_framebuffer_object = extensions.find("GL_EXT_framebuffer_object ") != std::string::npos; + ext.b_GL_EXT_gpu_shader4 = + extensions.find("GL_EXT_gpu_shader4 ") != std::string::npos; ext.b_GL_EXT_map_buffer_range = extensions.find("GL_EXT_map_buffer_range ") != std::string::npos; ext.b_GL_EXT_multisampled_render_to_texture = @@ -601,16 +608,23 @@ void DriverGL::InitializeDynamicBindings(GLContext* context) { } debug_fn.glBindFragDataLocationFn = 0; - if (ver->IsAtLeastGL(3u, 0u)) { + if (ver->IsAtLeastGL(3u, 0u) || ext.b_GL_ARB_blend_func_extended) { fn.glBindFragDataLocationFn = reinterpret_cast<glBindFragDataLocationProc>( GetGLProcAddress("glBindFragDataLocation")); + } else if (ext.b_GL_EXT_gpu_shader4 || ext.b_GL_EXT_blend_func_extended) { + fn.glBindFragDataLocationFn = reinterpret_cast<glBindFragDataLocationProc>( + GetGLProcAddress("glBindFragDataLocationEXT")); } debug_fn.glBindFragDataLocationIndexedFn = 0; - if (ver->IsAtLeastGL(3u, 3u)) { + if (ver->IsAtLeastGL(3u, 3u) || ext.b_GL_ARB_blend_func_extended) { fn.glBindFragDataLocationIndexedFn = reinterpret_cast<glBindFragDataLocationIndexedProc>( GetGLProcAddress("glBindFragDataLocationIndexed")); + } else if (ext.b_GL_EXT_blend_func_extended) { + fn.glBindFragDataLocationIndexedFn = + reinterpret_cast<glBindFragDataLocationIndexedProc>( + GetGLProcAddress("glBindFragDataLocationIndexedEXT")); } debug_fn.glBindFramebufferEXTFn = 0; @@ -1157,6 +1171,15 @@ void DriverGL::InitializeDynamicBindings(GLContext* context) { GetGLProcAddress("glGetFenceivNV")); } + debug_fn.glGetFragDataIndexFn = 0; + if (ver->IsAtLeastGL(3u, 3u) || ext.b_GL_ARB_blend_func_extended) { + fn.glGetFragDataIndexFn = reinterpret_cast<glGetFragDataIndexProc>( + GetGLProcAddress("glGetFragDataIndex")); + } else if (ext.b_GL_EXT_blend_func_extended) { + fn.glGetFragDataIndexFn = reinterpret_cast<glGetFragDataIndexProc>( + GetGLProcAddress("glGetFragDataIndexEXT")); + } + debug_fn.glGetFragDataLocationFn = 0; if (ver->IsAtLeastGL(3u, 0u) || ver->IsAtLeastGLES(3u, 0u)) { fn.glGetFragDataLocationFn = reinterpret_cast<glGetFragDataLocationProc>( @@ -3188,6 +3211,15 @@ static void GL_BINDING_CALL Debug_glGetFloatv(GLenum pname, GLfloat* params) { g_driver_gl.debug_fn.glGetFloatvFn(pname, params); } +static GLint GL_BINDING_CALL Debug_glGetFragDataIndex(GLuint program, + const char* name) { + GL_SERVICE_LOG("glGetFragDataIndex" + << "(" << program << ", " << name << ")"); + GLint result = g_driver_gl.debug_fn.glGetFragDataIndexFn(program, name); + GL_SERVICE_LOG("GL_RESULT: " << result); + return result; +} + static GLint GL_BINDING_CALL Debug_glGetFragDataLocation(GLuint program, const char* name) { GL_SERVICE_LOG("glGetFragDataLocation" @@ -5591,6 +5623,10 @@ void DriverGL::InitializeDebugBindings() { debug_fn.glGetFloatvFn = fn.glGetFloatvFn; fn.glGetFloatvFn = Debug_glGetFloatv; } + if (!debug_fn.glGetFragDataIndexFn) { + debug_fn.glGetFragDataIndexFn = fn.glGetFragDataIndexFn; + fn.glGetFragDataIndexFn = Debug_glGetFragDataIndex; + } if (!debug_fn.glGetFragDataLocationFn) { debug_fn.glGetFragDataLocationFn = fn.glGetFragDataLocationFn; fn.glGetFragDataLocationFn = Debug_glGetFragDataLocation; @@ -7103,6 +7139,10 @@ void GLApiBase::glGetFloatvFn(GLenum pname, GLfloat* params) { driver_->fn.glGetFloatvFn(pname, params); } +GLint GLApiBase::glGetFragDataIndexFn(GLuint program, const char* name) { + return driver_->fn.glGetFragDataIndexFn(program, name); +} + GLint GLApiBase::glGetFragDataLocationFn(GLuint program, const char* name) { return driver_->fn.glGetFragDataLocationFn(program, name); } @@ -9104,6 +9144,11 @@ void TraceGLApi::glGetFloatvFn(GLenum pname, GLfloat* params) { gl_api_->glGetFloatvFn(pname, params); } +GLint TraceGLApi::glGetFragDataIndexFn(GLuint program, const char* name) { + TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataIndex") + return gl_api_->glGetFragDataIndexFn(program, name); +} + GLint TraceGLApi::glGetFragDataLocationFn(GLuint program, const char* name) { TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetFragDataLocation") return gl_api_->glGetFragDataLocationFn(program, name); @@ -11415,6 +11460,14 @@ void NoContextGLApi::glGetFloatvFn(GLenum pname, GLfloat* params) { LOG(ERROR) << "Trying to call glGetFloatv() without current GL context"; } +GLint NoContextGLApi::glGetFragDataIndexFn(GLuint program, const char* name) { + NOTREACHED() + << "Trying to call glGetFragDataIndex() without current GL context"; + LOG(ERROR) + << "Trying to call glGetFragDataIndex() without current GL context"; + return 0; +} + GLint NoContextGLApi::glGetFragDataLocationFn(GLuint program, const char* name) { NOTREACHED() diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h index 457c5e4..c568d21 100644 --- a/ui/gl/gl_bindings_autogen_gl.h +++ b/ui/gl/gl_bindings_autogen_gl.h @@ -401,6 +401,8 @@ typedef void(GL_BINDING_CALL* glGetFenceivNVProc)(GLuint fence, GLenum pname, GLint* params); typedef void(GL_BINDING_CALL* glGetFloatvProc)(GLenum pname, GLfloat* params); +typedef GLint(GL_BINDING_CALL* glGetFragDataIndexProc)(GLuint program, + const char* name); typedef GLint(GL_BINDING_CALL* glGetFragDataLocationProc)(GLuint program, const char* name); typedef void(GL_BINDING_CALL* glGetFramebufferAttachmentParameterivEXTProc)( @@ -1031,6 +1033,7 @@ struct ExtensionsGL { bool b_GL_ANGLE_translated_shader_source; bool b_GL_APPLE_fence; bool b_GL_APPLE_vertex_array_object; + bool b_GL_ARB_blend_func_extended; bool b_GL_ARB_draw_buffers; bool b_GL_ARB_draw_instanced; bool b_GL_ARB_get_program_binary; @@ -1045,6 +1048,7 @@ struct ExtensionsGL { bool b_GL_ARB_vertex_array_object; bool b_GL_CHROMIUM_gles_depth_binding_hack; bool b_GL_CHROMIUM_glgetstringi_hack; + bool b_GL_EXT_blend_func_extended; bool b_GL_EXT_debug_marker; bool b_GL_EXT_direct_state_access; bool b_GL_EXT_discard_framebuffer; @@ -1053,6 +1057,7 @@ struct ExtensionsGL { bool b_GL_EXT_framebuffer_blit; bool b_GL_EXT_framebuffer_multisample; bool b_GL_EXT_framebuffer_object; + bool b_GL_EXT_gpu_shader4; bool b_GL_EXT_map_buffer_range; bool b_GL_EXT_multisampled_render_to_texture; bool b_GL_EXT_occlusion_query_boolean; @@ -1204,6 +1209,7 @@ struct ProcsGL { glGetErrorProc glGetErrorFn; glGetFenceivNVProc glGetFenceivNVFn; glGetFloatvProc glGetFloatvFn; + glGetFragDataIndexProc glGetFragDataIndexFn; glGetFragDataLocationProc glGetFragDataLocationFn; glGetFramebufferAttachmentParameterivEXTProc glGetFramebufferAttachmentParameterivEXTFn; @@ -1740,6 +1746,7 @@ class GL_EXPORT GLApi { virtual GLenum glGetErrorFn(void) = 0; virtual void glGetFenceivNVFn(GLuint fence, GLenum pname, GLint* params) = 0; virtual void glGetFloatvFn(GLenum pname, GLfloat* params) = 0; + virtual GLint glGetFragDataIndexFn(GLuint program, const char* name) = 0; virtual GLint glGetFragDataLocationFn(GLuint program, const char* name) = 0; virtual void glGetFramebufferAttachmentParameterivEXTFn(GLenum target, GLenum attachment, @@ -2459,6 +2466,7 @@ class GL_EXPORT GLApi { #define glGetError ::gfx::g_current_gl_context->glGetErrorFn #define glGetFenceivNV ::gfx::g_current_gl_context->glGetFenceivNVFn #define glGetFloatv ::gfx::g_current_gl_context->glGetFloatvFn +#define glGetFragDataIndex ::gfx::g_current_gl_context->glGetFragDataIndexFn #define glGetFragDataLocation \ ::gfx::g_current_gl_context->glGetFragDataLocationFn #define glGetFramebufferAttachmentParameterivEXT \ diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc index b356561..43baa49 100644 --- a/ui/gl/gl_bindings_autogen_mock.cc +++ b/ui/gl/gl_bindings_autogen_mock.cc @@ -101,6 +101,14 @@ MockGLInterface::Mock_glBindFragDataLocation(GLuint program, } void GL_BINDING_CALL +MockGLInterface::Mock_glBindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name) { + MakeFunctionUnique("glBindFragDataLocationEXT"); + interface_->BindFragDataLocation(program, colorNumber, name); +} + +void GL_BINDING_CALL MockGLInterface::Mock_glBindFragDataLocationIndexed(GLuint program, GLuint colorNumber, GLuint index, @@ -110,6 +118,15 @@ MockGLInterface::Mock_glBindFragDataLocationIndexed(GLuint program, } void GL_BINDING_CALL +MockGLInterface::Mock_glBindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name) { + MakeFunctionUnique("glBindFragDataLocationIndexedEXT"); + interface_->BindFragDataLocationIndexed(program, colorNumber, index, name); +} + +void GL_BINDING_CALL MockGLInterface::Mock_glBindFramebuffer(GLenum target, GLuint framebuffer) { MakeFunctionUnique("glBindFramebuffer"); interface_->BindFramebufferEXT(target, framebuffer); @@ -1188,6 +1205,18 @@ void GL_BINDING_CALL MockGLInterface::Mock_glGetFloatv(GLenum pname, } GLint GL_BINDING_CALL +MockGLInterface::Mock_glGetFragDataIndex(GLuint program, const char* name) { + MakeFunctionUnique("glGetFragDataIndex"); + return interface_->GetFragDataIndex(program, name); +} + +GLint GL_BINDING_CALL +MockGLInterface::Mock_glGetFragDataIndexEXT(GLuint program, const char* name) { + MakeFunctionUnique("glGetFragDataIndexEXT"); + return interface_->GetFragDataIndex(program, name); +} + +GLint GL_BINDING_CALL MockGLInterface::Mock_glGetFragDataLocation(GLuint program, const char* name) { MakeFunctionUnique("glGetFragDataLocation"); return interface_->GetFragDataLocation(program, name); @@ -2857,8 +2886,12 @@ void* GL_BINDING_CALL MockGLInterface::GetGLProcAddress(const char* name) { return reinterpret_cast<void*>(Mock_glBindBufferRange); if (strcmp(name, "glBindFragDataLocation") == 0) return reinterpret_cast<void*>(Mock_glBindFragDataLocation); + if (strcmp(name, "glBindFragDataLocationEXT") == 0) + return reinterpret_cast<void*>(Mock_glBindFragDataLocationEXT); if (strcmp(name, "glBindFragDataLocationIndexed") == 0) return reinterpret_cast<void*>(Mock_glBindFragDataLocationIndexed); + if (strcmp(name, "glBindFragDataLocationIndexedEXT") == 0) + return reinterpret_cast<void*>(Mock_glBindFragDataLocationIndexedEXT); if (strcmp(name, "glBindFramebuffer") == 0) return reinterpret_cast<void*>(Mock_glBindFramebuffer); if (strcmp(name, "glBindFramebufferEXT") == 0) @@ -3149,6 +3182,10 @@ void* GL_BINDING_CALL MockGLInterface::GetGLProcAddress(const char* name) { return reinterpret_cast<void*>(Mock_glGetFenceivNV); if (strcmp(name, "glGetFloatv") == 0) return reinterpret_cast<void*>(Mock_glGetFloatv); + if (strcmp(name, "glGetFragDataIndex") == 0) + return reinterpret_cast<void*>(Mock_glGetFragDataIndex); + if (strcmp(name, "glGetFragDataIndexEXT") == 0) + return reinterpret_cast<void*>(Mock_glGetFragDataIndexEXT); if (strcmp(name, "glGetFragDataLocation") == 0) return reinterpret_cast<void*>(Mock_glGetFragDataLocation); if (strcmp(name, "glGetFramebufferAttachmentParameteriv") == 0) diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h index f97521e..52d4034 100644 --- a/ui/gl/gl_bindings_autogen_mock.h +++ b/ui/gl/gl_bindings_autogen_mock.h @@ -30,11 +30,19 @@ static void GL_BINDING_CALL Mock_glBindBufferRange(GLenum target, static void GL_BINDING_CALL Mock_glBindFragDataLocation(GLuint program, GLuint colorNumber, const char* name); +static void GL_BINDING_CALL Mock_glBindFragDataLocationEXT(GLuint program, + GLuint colorNumber, + const char* name); static void GL_BINDING_CALL Mock_glBindFragDataLocationIndexed(GLuint program, GLuint colorNumber, GLuint index, const char* name); +static void GL_BINDING_CALL +Mock_glBindFragDataLocationIndexedEXT(GLuint program, + GLuint colorNumber, + GLuint index, + const char* name); static void GL_BINDING_CALL Mock_glBindFramebuffer(GLenum target, GLuint framebuffer); static void GL_BINDING_CALL Mock_glBindFramebufferEXT(GLenum target, @@ -447,6 +455,10 @@ static void GL_BINDING_CALL Mock_glGetFenceivNV(GLuint fence, GLenum pname, GLint* params); static void GL_BINDING_CALL Mock_glGetFloatv(GLenum pname, GLfloat* params); +static GLint GL_BINDING_CALL Mock_glGetFragDataIndex(GLuint program, + const char* name); +static GLint GL_BINDING_CALL Mock_glGetFragDataIndexEXT(GLuint program, + const char* name); static GLint GL_BINDING_CALL Mock_glGetFragDataLocation(GLuint program, const char* name); static void GL_BINDING_CALL diff --git a/ui/gl/gl_enums_implementation_autogen.h b/ui/gl/gl_enums_implementation_autogen.h index a4812cb..a7e984a 100644 --- a/ui/gl/gl_enums_implementation_autogen.h +++ b/ui/gl/gl_enums_implementation_autogen.h @@ -649,9 +649,18 @@ static const GLEnums::EnumToString enum_to_string_table[] = { 0x8B6A, "GL_FLOAT_MAT4x3_NV", }, { + 0x88FA, "GL_ONE_MINUS_SRC1_COLOR_EXT", + }, + { 0x93D0, "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR", }, { + 0x88FC, "GL_MAX_DUAL_SOURCE_DRAW_BUFFERS_EXT", + }, + { + 0x78FC, "GL_RGB_YCBCR_420V_CHROMIUM", + }, + { 0x9143, "GL_MAX_DEBUG_MESSAGE_LENGTH_KHR", }, { @@ -829,6 +838,9 @@ static const GLEnums::EnumToString enum_to_string_table[] = { 0x83F0, "GL_COMPRESSED_RGB_S3TC_DXT1_EXT", }, { + 0x88F9, "GL_SRC1_COLOR_EXT", + }, + { 0x8D6A, "GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT", }, { @@ -2119,6 +2131,9 @@ static const GLEnums::EnumToString enum_to_string_table[] = { 0x8519, "GL_TEXTURE_CUBE_MAP_POSITIVE_Z", }, { + 0x88FB, "GL_ONE_MINUS_SRC1_ALPHA_EXT", + }, + { 0x8514, "GL_TEXTURE_BINDING_CUBE_MAP", }, { @@ -2923,6 +2938,9 @@ static const GLEnums::EnumToString enum_to_string_table[] = { 0x8C85, "GL_TRANSFORM_FEEDBACK_BUFFER_SIZE", }, { + 0x8589, "GL_SRC1_ALPHA_EXT", + }, + { 0x00008000, "GL_COVERAGE_BUFFER_BIT_NV", }, { diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h index 2a34acd..fff4bc5 100644 --- a/ui/gl/gl_mock_autogen_gl.h +++ b/ui/gl/gl_mock_autogen_gl.h @@ -340,6 +340,7 @@ MOCK_METHOD3(GetBufferParameteriv, MOCK_METHOD0(GetError, GLenum()); MOCK_METHOD3(GetFenceivNV, void(GLuint fence, GLenum pname, GLint* params)); MOCK_METHOD2(GetFloatv, void(GLenum pname, GLfloat* params)); +MOCK_METHOD2(GetFragDataIndex, GLint(GLuint program, const char* name)); MOCK_METHOD2(GetFragDataLocation, GLint(GLuint program, const char* name)); MOCK_METHOD4( GetFramebufferAttachmentParameterivEXT, |