summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gpu/BUILD.gn1
-rw-r--r--gpu/GLES2/gl2chromium_autogen.h4
-rw-r--r--gpu/GLES2/gl2extchromium.h35
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py26
-rw-r--r--gpu/command_buffer/client/gles2_c_lib_autogen.h28
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h32
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc56
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h1
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h11
-rw-r--r--gpu/command_buffer/client/gles2_interface_autogen.h8
-rw-r--r--gpu/command_buffer/client/gles2_interface_stub_autogen.h8
-rw-r--r--gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h12
-rw-r--r--gpu/command_buffer/client/gles2_trace_implementation_autogen.h8
-rw-r--r--gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h23
-rw-r--r--gpu/command_buffer/client/program_info_manager.cc38
-rw-r--r--gpu/command_buffer/client/program_info_manager.h8
-rw-r--r--gpu/command_buffer/cmd_buffer_functions.txt6
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h160
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h46
-rw-r--r--gpu/command_buffer/common/gles2_cmd_ids_autogen.h5
-rw-r--r--gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h19
-rw-r--r--gpu/command_buffer/service/context_group.cc11
-rw-r--r--gpu/command_buffer/service/context_group.h5
-rw-r--r--gpu/command_buffer/service/disk_cache_proto.proto6
-rw-r--r--gpu/command_buffer/service/feature_info.cc36
-rw-r--r--gpu/command_buffer/service/feature_info.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc254
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc15
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.h6
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc50
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h9
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_extensions.cc20
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_programs.cc13
-rw-r--r--gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h6
-rw-r--r--gpu/command_buffer/service/memory_program_cache.cc87
-rw-r--r--gpu/command_buffer/service/memory_program_cache.h12
-rw-r--r--gpu/command_buffer/service/memory_program_cache_unittest.cc39
-rw-r--r--gpu/command_buffer/service/mocks.h21
-rw-r--r--gpu/command_buffer/service/program_manager.cc245
-rw-r--r--gpu/command_buffer/service/program_manager.h59
-rw-r--r--gpu/command_buffer/service/program_manager_unittest.cc237
-rw-r--r--gpu/command_buffer/service/shader_manager.cc34
-rw-r--r--gpu/command_buffer/service/shader_manager.h17
-rw-r--r--gpu/command_buffer/service/shader_manager_unittest.cc36
-rw-r--r--gpu/command_buffer/service/shader_translator.cc9
-rw-r--r--gpu/command_buffer/service/shader_translator.h3
-rw-r--r--gpu/command_buffer/service/shader_translator_unittest.cc136
-rw-r--r--gpu/command_buffer/service/test_helper.cc110
-rw-r--r--gpu/command_buffer/service/test_helper.h39
-rw-r--r--gpu/command_buffer/tests/gl_ext_blend_func_extended_unittest.cc653
-rw-r--r--gpu/gpu.gyp3
-rw-r--r--gpu/skia_bindings/gl_bindings_skia_cmd_buffer.cc2
-rw-r--r--mojo/gpu/mojo_gles2_impl_autogen.cc17
-rw-r--r--mojo/gpu/mojo_gles2_impl_autogen.h8
-rw-r--r--mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h13
-rw-r--r--third_party/mojo/src/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h568
-rwxr-xr-xui/gl/generate_bindings.py19
-rw-r--r--ui/gl/gl_bindings.h10
-rw-r--r--ui/gl/gl_bindings_api_autogen_gl.h1
-rw-r--r--ui/gl/gl_bindings_autogen_gl.cc57
-rw-r--r--ui/gl/gl_bindings_autogen_gl.h8
-rw-r--r--ui/gl/gl_bindings_autogen_mock.cc37
-rw-r--r--ui/gl/gl_bindings_autogen_mock.h12
-rw-r--r--ui/gl/gl_enums_implementation_autogen.h18
-rw-r--r--ui/gl/gl_mock_autogen_gl.h1
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,