Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(207)

Unified Diff: gpu/command_buffer/service/program_manager.cc

Issue 1309743005: command_buffer: Implement EXT_blend_func_extended (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@new-05-path-fragment-input-gen
Patch Set: address review comments Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: gpu/command_buffer/service/program_manager.cc
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index bd7a8802def3fa06b2b1025fba46d5699b0740bd..025b4db6363739fc2967a861259f90b441524103 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -26,6 +26,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;
@@ -241,10 +242,9 @@ Program::UniformInfo::UniformInfo(GLsizei _size,
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)
@@ -271,6 +271,7 @@ void Program::Reset() {
attrib_infos_.clear();
uniform_infos_.clear();
fragment_input_infos_.clear();
+ program_output_infos_.clear();
sampler_indices_.clear();
attrib_location_to_index_map_.clear();
}
@@ -446,13 +447,15 @@ void Program::ClearUniforms(
namespace {
struct VariableInfoData {
- VariableInfoData() : size(-1), type(GL_NONE), location(0), added(false) {}
+ VariableInfoData()
+ : size(-1), type(GL_NONE), location(0), index(-1), added(false) {}
std::string queried_name;
std::string corrected_name;
std::string original_name;
GLsizei size;
GLenum type;
GLint location;
+ GLint index;
Kimmo Kinnunen 2015/10/08 13:18:12 removed also this stale hunk.
bool added;
};
@@ -551,8 +554,7 @@ void Program::Update() {
for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
VariableInfoData& data = uniform_data[ii];
// Force builtin uniforms (gl_DepthRange) to have invalid location.
- if (ProgramManager::IsInvalidPrefix(data.queried_name.c_str(),
- data.queried_name.size())) {
+ if (ProgramManager::HasBuiltInPrefix(data.queried_name)) {
data.location = -1;
} else {
VariableInfoData& data = uniform_data[ii];
@@ -608,7 +610,10 @@ void Program::Update() {
// gl_PointCoord built-ins as its input, as well as custom
// varyings. We are interested only in custom varyings,
// client is allowed to bind only them.
- if (!ProgramManager::IsInvalidPrefix(name_buffer.get(), length)) {
+ std::string queried_name(name_buffer.get(), length);
+ if (ProgramManager::HasBuiltInPrefix(queried_name)) {
+ continue;
+ }
length = 0;
Zhenyao Mo 2015/09/30 00:23:48 indentation wrong
Kimmo Kinnunen 2015/10/08 13:18:12 Done.
GLenum props[] = {GL_LOCATION, GL_TYPE, GL_ARRAY_SIZE};
GLint values[arraysize(props)] = {
@@ -622,13 +627,12 @@ void Program::Update() {
data.location = values[0];
data.type = values[1];
data.size = values[2];
- data.queried_name = std::string(name_buffer.get());
- GetCorrectedVariableData(kVaryingVariableInfo, data.queried_name,
+ data.queried_name = queried_name;
+ GetCorrectedVariableData(kFragmentInputVariableInfo, data.queried_name,
&data.corrected_name, &data.original_name,
&data.size, &data.type);
fragment_input_data.push_back(data);
- }
}
next_available_index = 0;
@@ -656,6 +660,76 @@ void Program::Update() {
}
}
+ if (feature_info().feature_flags().ext_blend_func_extended) {
+ // Query the fragment output variables from the driver. We expose
Kimmo Kinnunen 2015/10/08 13:18:12 I ended up removing this program interface query u
+ // ext_blend_func_extended only
+ // if service context supports program interface query.
+ GLint num_fragment_outputs = 0;
+ max_len = 0;
+ glGetProgramInterfaceiv(service_id_, GL_PROGRAM_OUTPUT, GL_ACTIVE_RESOURCES,
+ &num_fragment_outputs);
+
+ glGetProgramInterfaceiv(service_id_, GL_PROGRAM_OUTPUT, GL_MAX_NAME_LENGTH,
+ &max_len);
+ DCHECK(num_fragment_outputs <= 0 || max_len > 0);
+ name_buffer.reset(new char[max_len]);
+
+ for (GLint ii = 0; ii < num_fragment_outputs; ++ii) {
+ GLsizei length = 0;
+ glGetProgramResourceName(service_id_, GL_PROGRAM_OUTPUT, ii, max_len,
+ &length, name_buffer.get());
+ DCHECK(length < max_len);
+ DCHECK(length == 0 || name_buffer[length] == '\0');
+ // 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.
+ std::string queried_name(name_buffer.get(), length);
+ if (ProgramManager::HasBuiltInPrefix(queried_name)) {
+ continue;
+ }
+ length = 0;
+ GLenum props[] = {GL_LOCATION, GL_LOCATION_INDEX, GL_TYPE, GL_ARRAY_SIZE};
+ GLint values[arraysize(props)] = {
+ 0,
+ };
+ glGetProgramResourceiv(service_id_, GL_PROGRAM_OUTPUT, ii,
+ arraysize(props), props, arraysize(values),
+ &length, values);
+ DCHECK(length == arraysize(props));
+
+ const GLint& colorName = values[0];
+ const GLint& index = values[1];
+ GLenum type = values[2];
+ GLsizei size = values[3];
+ std::string original_name;
+ std::string corrected_name;
+ GetCorrectedVariableData(kProgramOutputVariableInfo, queried_name,
+ &corrected_name, &original_name, &size, &type);
+ program_output_infos_.push_back(
+ ProgramOutputInfo(size, type, colorName, index, original_name));
+ }
+ } else if (feature_info().gl_version_info().IsES3Capable() &&
+ !feature_info().disable_shader_translator()) {
+ Shader* fragment_shader =
+ attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+ if (fragment_shader && fragment_shader->valid()) {
+ for (auto const& output_var : fragment_shader->output_variable_list()) {
+ const std::string& name = output_var.mappedName;
Kimmo Kinnunen 2015/10/08 13:18:12 So the code would always still have the translator
+ GLenum type = output_var.type;
+ GLsizei size = output_var.arraySize;
+ std::string original_name;
+ std::string corrected_name;
+ GetCorrectedVariableData(kProgramOutputVariableInfo, name,
+ &corrected_name, &original_name, &size, &type);
+ GLint colorName = glGetFragDataLocation(service_id_, name.c_str());
+ program_output_infos_.push_back(
+ ProgramOutputInfo(size, type, colorName, 0, original_name));
+ }
+ }
+ }
+
#if !defined(NDEBUG)
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGPUServiceLoggingGPU)) {
@@ -714,6 +788,83 @@ bool Program::ExecuteTransformFeedbackVaryingsCall() {
return true;
}
+void Program::ExecuteProgramOutputBindCalls() {
+ Shader* fragment_shader =
+ attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+ if (!fragment_shader || !fragment_shader->valid()) {
+ return;
+ }
+
+ 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 (const auto& key_value : bind_program_output_location_index_map_) {
+ const std::string* mapped_name =
+ fragment_shader->GetVaryingMappedName(key_value.first);
+ if (mapped_name) {
+ const auto& binding = key_value.second;
Zhenyao Mo 2015/09/30 00:23:48 It's worth adding a comment here that glBindFragDa
Kimmo Kinnunen 2015/10/08 13:18:12 Done.
+ if (binding.second == 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.
+
+ // Translator is needed for the emulation. Should be handled already by the
+ // FeatureInfo.
+ DCHECK(!feature_info().disable_shader_translator());
+
+ // 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) {
@@ -792,6 +943,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");
@@ -812,6 +967,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(),
@@ -1022,6 +1180,20 @@ bool Program::SetFragmentInputLocationBinding(const std::string& name,
return true;
}
+bool Program::SetProgramOutputLocationBinding(const std::string& name,
+ GLuint colorName,
+ GLuint index) {
+ std::string short_name;
+ int element_index = 0;
+ if (!GetProgramVariableNameSansElement(name, &element_index, &short_name) ||
+ element_index != 0) {
+ return false;
+ }
+ bind_program_output_location_index_map_[short_name] =
+ std::make_pair(colorName, index);
+ return true;
+}
+
// Note: This is only valid to call right after a program has been linked
// successfully.
void Program::GetCorrectedVariableData(VariableInfoType variable_info_type,
@@ -1031,34 +1203,47 @@ void Program::GetCorrectedVariableData(VariableInfoType variable_info_type,
GLsizei* size,
GLenum* type) const {
DCHECK(corrected_name && original_name && size && type);
- for (auto shader : attached_shaders_) {
- if (!shader)
- continue;
- const sh::ShaderVariable* info = NULL;
- bool found = false;
- if (variable_info_type == kUniformVariableInfo) {
+ const sh::ShaderVariable* info = NULL;
+ bool found = false;
+
+ if (variable_info_type == kUniformVariableInfo) {
+ for (auto shader : attached_shaders_) {
+ if (!shader)
+ continue;
const sh::Uniform* uniform = shader->GetUniformInfo(name);
if (uniform)
found = uniform->findInfoByMappedName(name, &info, original_name);
- } else if (variable_info_type == kVaryingVariableInfo) {
- const sh::Varying* varying = shader->GetVaryingInfo(name);
+ }
+ } else if (variable_info_type == kFragmentInputVariableInfo) {
+ Shader* shader =
+ attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+ if (shader) {
+ const sh::Varying* varying = shader->GetInputVariableInfo(name);
if (varying)
found = varying->findInfoByMappedName(name, &info, original_name);
}
+ } else if (variable_info_type == kProgramOutputVariableInfo) {
+ Shader* shader =
+ attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+ if (shader) {
+ const sh::OutputVariable* output = shader->GetOutputVariableInfo(name);
+ if (output)
+ found = output->findInfoByMappedName(name, &info, original_name);
+ }
+ }
- if (found) {
- const std::string kArraySpec("[0]");
- if (info->arraySize > 0 &&
- !base::EndsWith(name, kArraySpec, base::CompareCase::SENSITIVE)) {
- *corrected_name = name + kArraySpec;
- *original_name += kArraySpec;
- } else {
- *corrected_name = name;
- }
- *type = info->type;
- *size = std::max(1u, info->arraySize);
- return;
+ if (found) {
+ const std::string kArraySpec("[0]");
+ if (info->arraySize > 0 &&
+ !base::EndsWith(name, kArraySpec, base::CompareCase::SENSITIVE)) {
+ *corrected_name = name + kArraySpec;
+ *original_name += kArraySpec;
+ } else {
+ *corrected_name = name;
}
+ *type = info->type;
+ *size = std::max(1u, info->arraySize);
+ return;
}
// TODO(zmo): this path should never be reached unless there is a serious
// bug in the driver or in ANGLE translator.
@@ -1483,7 +1668,8 @@ bool Program::DetectFragmentInputLocationBindingConflicts() const {
if (!mapped_name) {
continue;
}
- const sh::Varying* fragment_input = shader->GetVaryingInfo(*mapped_name);
+ const sh::Varying* fragment_input =
+ shader->GetInputVariableInfo(*mapped_name);
if (fragment_input && fragment_input->staticUse) {
auto result = location_binding_used.insert(it.second);
if (!result.second) {
@@ -1494,6 +1680,38 @@ bool Program::DetectFragmentInputLocationBindingConflicts() const {
return false;
}
+bool Program::DetectProgramOutputLocationBindingConflicts() const {
+ Shader* shader =
+ attached_shaders_[ShaderTypeToIndex(GL_FRAGMENT_SHADER)].get();
+ if (!shader || !shader->valid())
+ return false;
+
+ std::set<LocationIndexMap::mapped_type> location_binding_used;
+ for (auto it : bind_program_output_location_index_map_) {
+ // Find out if an program output is statically used in this program's
+ // shaders.
+ bool is_used = false;
+ if (feature_info().disable_shader_translator()) {
+ is_used = true;
+ } else {
+ const std::string* mapped_name = shader->GetVaryingMappedName(it.first);
+ if (mapped_name) {
+ const sh::OutputVariable* output =
+ shader->GetOutputVariableInfo(*mapped_name);
+ is_used = output && output->staticUse;
+ }
+ }
+ if (!is_used) {
+ 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 &&
@@ -1975,6 +2193,43 @@ bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const {
return true;
}
+const Program::ProgramOutputInfo* Program::GetProgramOutputInfo(
+ const std::string& original_name) const {
+ std::string short_name;
+ int element_index = 0;
+ if (!GetProgramVariableNameSansElement(original_name, &element_index,
+ &short_name) ||
+ element_index != 0) {
+ return nullptr;
+ }
+
+ auto iter =
+ std::find_if(program_output_infos_.begin(), program_output_infos_.end(),
+ [short_name](const ProgramOutputInfo& info) {
+ return info.name == short_name;
+ });
+ return iter != program_output_infos_.end() ? &(*iter) : nullptr;
+}
+
+GLint Program::GetFragDataLocation(const std::string& original_name) const {
+ DCHECK(IsValid());
+ const ProgramOutputInfo* info = GetProgramOutputInfo(original_name);
+ if (!info) {
+ return -1;
+ }
+ return info->colorName;
+}
+
+GLint Program::GetFragDataIndex(const std::string& original_name) const {
+ DCHECK(IsValid());
+ // return glGetFragDataIndex(service_id_, info->mappedName.c_str());
+ const ProgramOutputInfo* info = GetProgramOutputInfo(original_name);
+ if (!info) {
+ return -1;
+ }
+ return info->index;
+}
+
void Program::TransformFeedbackVaryings(GLsizei count,
const char* const* varyings,
GLenum buffer_mode) {
@@ -1997,11 +2252,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() {

Powered by Google App Engine
This is Rietveld 408576698