summaryrefslogtreecommitdiffstats
path: root/gpu/command_buffer/service
diff options
context:
space:
mode:
authorkkinnunen <kkinnunen@nvidia.com>2015-12-04 01:36:31 -0800
committerCommit bot <commit-bot@chromium.org>2015-12-04 09:37:12 +0000
commit8cefb231216c2777281f37a30e3fb8e67513ee2b (patch)
tree2d0163eed0729e5f7a8fb55fb03b034eddcb5305 /gpu/command_buffer/service
parent91db68e8cb2080d1e9e07858efea3f7e198112a9 (diff)
downloadchromium_src-8cefb231216c2777281f37a30e3fb8e67513ee2b.zip
chromium_src-8cefb231216c2777281f37a30e3fb8e67513ee2b.tar.gz
chromium_src-8cefb231216c2777281f37a30e3fb8e67513ee2b.tar.bz2
command_buffer: Implement EXT_blend_func_extended
Implement EXT_blend_func_extended for command buffer ES 2.0 and ES 3.0 contexts. For the ES 2.0 context, the extension supports dual-source blending with pre-defined gl_SecondaryFragColorEXT and gl_SecondaryFragDataEXT variables. Currently EXT_blend_func_extended is only exposed if the service context supports program interface query. This means OpenGL context or OpenGL ES 3.1 context. This is to simplify the unit test expectation conditions. Theoretically also ES 2.0 and ES 3.0 service contexts could support EXT_blend_func_extended, but probably there will never be such a driver. BUG=506765 Review URL: https://codereview.chromium.org/1309743005 Cr-Commit-Position: refs/heads/master@{#363175}
Diffstat (limited to 'gpu/command_buffer/service')
-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
28 files changed, 1203 insertions, 313 deletions
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,