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 1f6b2d49fc95933ade0c24e9c6dc0506d1a1e177..aef7e44976e7f70709ec78c1ca5e62e28d7f3b87 100644 |
--- a/gpu/command_buffer/service/program_manager.cc |
+++ b/gpu/command_buffer/service/program_manager.cc |
@@ -24,7 +24,6 @@ |
#include "gpu/command_buffer/service/gpu_switches.h" |
#include "gpu/command_buffer/service/program_cache.h" |
#include "gpu/command_buffer/service/shader_manager.h" |
-#include "gpu/command_buffer/service/shader_translator.h" |
#include "third_party/re2/re2/re2.h" |
using base::TimeDelta; |
@@ -515,48 +514,14 @@ void Program::ExecuteBindAttribLocationCalls() { |
} |
bool Program::Link(ShaderManager* manager, |
- ShaderTranslator* vertex_translator, |
- ShaderTranslator* fragment_translator, |
Program::VaryingsPackingOption varyings_packing_option, |
const ShaderCacheCallback& shader_callback) { |
ClearLinkStatus(); |
- if (!CanLink()) { |
+ |
+ if (!AttachedShadersExist()) { |
set_log_info("missing shaders"); |
return false; |
} |
- if (DetectAttribLocationBindingConflicts()) { |
- set_log_info("glBindAttribLocation() conflicts"); |
- return false; |
- } |
- std::string conflicting_name; |
- if (DetectUniformsMismatch(&conflicting_name)) { |
- std::string info_log = "Uniforms with the same name but different " |
- "type/precision: " + conflicting_name; |
- set_log_info(ProcessLogInfo(info_log).c_str()); |
- return false; |
- } |
- if (DetectVaryingsMismatch(&conflicting_name)) { |
- std::string info_log = "Varyings with the same name but different type, " |
- "or statically used varyings in fragment shader are " |
- "not declared in vertex shader: " + conflicting_name; |
- set_log_info(ProcessLogInfo(info_log).c_str()); |
- return false; |
- } |
- if (DetectBuiltInInvariantConflicts()) { |
- set_log_info("Invariant settings for certain built-in varyings " |
- "have to match"); |
- return false; |
- } |
- if (DetectGlobalNameConflicts(&conflicting_name)) { |
- std::string info_log = "Name conflicts between an uniform and an " |
- "attribute: " + conflicting_name; |
- set_log_info(ProcessLogInfo(info_log).c_str()); |
- return false; |
- } |
- if (!CheckVaryingsPacking(varyings_packing_option)) { |
- set_log_info("Varyings over maximum register limit"); |
- return false; |
- } |
TimeTicks before_time = TimeTicks::Now(); |
bool link = true; |
@@ -565,19 +530,15 @@ bool Program::Link(ShaderManager* manager, |
DCHECK(!attached_shaders_[0]->last_compiled_source().empty() && |
!attached_shaders_[1]->last_compiled_source().empty()); |
ProgramCache::LinkedProgramStatus status = cache->GetLinkedProgramStatus( |
- attached_shaders_[0]->last_compiled_source(), |
- vertex_translator, |
- attached_shaders_[1]->last_compiled_source(), |
- fragment_translator, |
+ attached_shaders_[0]->last_compiled_signature(), |
+ attached_shaders_[1]->last_compiled_signature(), |
&bind_attrib_location_map_); |
if (status == ProgramCache::LINK_SUCCEEDED) { |
ProgramCache::ProgramLoadResult success = |
cache->LoadLinkedProgram(service_id(), |
attached_shaders_[0].get(), |
- vertex_translator, |
attached_shaders_[1].get(), |
- fragment_translator, |
&bind_attrib_location_map_, |
shader_callback); |
link = success != ProgramCache::PROGRAM_LOAD_SUCCESS; |
@@ -586,6 +547,47 @@ bool Program::Link(ShaderManager* manager, |
} |
if (link) { |
+ CompileAttachedShaders(); |
+ |
+ if (!CanLink()) { |
+ set_log_info("invalid shaders"); |
+ return false; |
+ } |
+ if (DetectAttribLocationBindingConflicts()) { |
+ set_log_info("glBindAttribLocation() conflicts"); |
+ return false; |
+ } |
+ std::string conflicting_name; |
+ if (DetectUniformsMismatch(&conflicting_name)) { |
+ std::string info_log = "Uniforms with the same name but different " |
+ "type/precision: " + conflicting_name; |
+ set_log_info(ProcessLogInfo(info_log).c_str()); |
+ return false; |
+ } |
+ if (DetectVaryingsMismatch(&conflicting_name)) { |
+ std::string info_log = "Varyings with the same name but different type, " |
+ "or statically used varyings in fragment shader " |
+ "are not declared in vertex shader: " + |
+ conflicting_name; |
+ set_log_info(ProcessLogInfo(info_log).c_str()); |
+ return false; |
+ } |
+ if (DetectBuiltInInvariantConflicts()) { |
+ set_log_info("Invariant settings for certain built-in varyings " |
+ "have to match"); |
+ return false; |
+ } |
+ if (DetectGlobalNameConflicts(&conflicting_name)) { |
+ std::string info_log = "Name conflicts between an uniform and an " |
+ "attribute: " + conflicting_name; |
+ set_log_info(ProcessLogInfo(info_log).c_str()); |
+ return false; |
+ } |
+ if (!CheckVaryingsPacking(varyings_packing_option)) { |
+ set_log_info("Varyings over maximum register limit"); |
+ return false; |
+ } |
+ |
ExecuteBindAttribLocationCalls(); |
before_time = TimeTicks::Now(); |
if (cache && gfx::g_driver_gl.ext.b_GL_ARB_get_program_binary) { |
@@ -604,9 +606,7 @@ bool Program::Link(ShaderManager* manager, |
if (cache) { |
cache->SaveLinkedProgram(service_id(), |
attached_shaders_[0].get(), |
- vertex_translator, |
attached_shaders_[1].get(), |
- fragment_translator, |
&bind_attrib_location_map_, |
shader_callback); |
} |
@@ -1001,6 +1001,23 @@ void Program::DetachShaders(ShaderManager* shader_manager) { |
} |
} |
+void Program::CompileAttachedShaders() { |
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { |
+ Shader* shader = attached_shaders_[ii].get(); |
+ if (shader) { |
+ shader->DoCompile(); |
+ } |
+ } |
+} |
+ |
+bool Program::AttachedShadersExist() const { |
+ for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { |
+ if (!attached_shaders_[ii].get()) |
+ return false; |
+ } |
+ return true; |
+} |
+ |
bool Program::CanLink() const { |
for (int ii = 0; ii < kMaxAttachedShaders; ++ii) { |
if (!attached_shaders_[ii].get() || !attached_shaders_[ii]->valid()) { |
@@ -1303,6 +1320,7 @@ bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const { |
GLuint program = service_id(); |
uint32_t header_size = sizeof(UniformBlocksHeader); |
+ bucket->SetSize(header_size); // In case we fail. |
uint32_t num_uniform_blocks = 0; |
GLint param = GL_FALSE; |
@@ -1316,10 +1334,6 @@ bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const { |
if (num_uniform_blocks == 0) { |
// Although spec allows an implementation to return uniform block info |
// even if a link fails, for consistency, we disallow that. |
- bucket->SetSize(header_size); |
- UniformBlocksHeader* header = |
- bucket->GetDataAs<UniformBlocksHeader*>(0, header_size); |
- header->num_uniform_blocks = 0; |
return true; |
} |
@@ -1390,7 +1404,7 @@ bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const { |
bucket->SetSize(total_size); |
UniformBlocksHeader* header = |
- bucket->GetDataAs<UniformBlocksHeader*>(0, total_size); |
+ bucket->GetDataAs<UniformBlocksHeader*>(0, header_size); |
UniformBlockInfo* entries = bucket->GetDataAs<UniformBlockInfo*>( |
header_size, entry_size); |
char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size); |
@@ -1405,8 +1419,8 @@ bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const { |
std::vector<GLint> params; |
for (uint32_t ii = 0; ii < num_uniform_blocks; ++ii) { |
// Get active uniform name. |
- memcpy(data, names[ii].c_str(), blocks[ii].name_length); |
- data += blocks[ii].name_length; |
+ memcpy(data, names[ii].c_str(), names[ii].length() + 1); |
+ data += names[ii].length() + 1; |
// Get active uniform indices. |
if (params.size() < blocks[ii].active_uniforms) |
@@ -1425,6 +1439,170 @@ bool Program::GetUniformBlocks(CommonDecoder::Bucket* bucket) const { |
return true; |
} |
+bool Program::GetTransformFeedbackVaryings( |
+ CommonDecoder::Bucket* bucket) const { |
+ // The data is packed into the bucket in the following order |
+ // 1) header |
+ // 2) N entries of varying data (except for name) |
+ // 3) name1, name2, ..., nameN |
+ // |
+ // We query all the data directly through GL calls, assuming they are |
+ // cheap through MANGLE. |
+ |
+ DCHECK(bucket); |
+ GLuint program = service_id(); |
+ |
+ uint32_t header_size = sizeof(TransformFeedbackVaryingsHeader); |
+ bucket->SetSize(header_size); // In case we fail. |
+ |
+ uint32_t num_transform_feedback_varyings = 0; |
+ GLint param = GL_FALSE; |
+ // We assume program is a valid program service id. |
+ glGetProgramiv(program, GL_LINK_STATUS, ¶m); |
+ if (param == GL_TRUE) { |
+ param = 0; |
+ glGetProgramiv(program, GL_TRANSFORM_FEEDBACK_VARYINGS, ¶m); |
+ num_transform_feedback_varyings = static_cast<uint32_t>(param); |
+ } |
+ if (num_transform_feedback_varyings == 0) { |
+ return true; |
+ } |
+ |
+ std::vector<TransformFeedbackVaryingInfo> varyings( |
+ num_transform_feedback_varyings); |
+ base::CheckedNumeric<uint32_t> size = sizeof(TransformFeedbackVaryingInfo); |
+ size *= num_transform_feedback_varyings; |
+ uint32_t entry_size = size.ValueOrDefault(0); |
+ size += header_size; |
+ std::vector<std::string> names(num_transform_feedback_varyings); |
+ GLint max_name_length = 0; |
+ glGetProgramiv( |
+ program, GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH, &max_name_length); |
+ if (max_name_length < 1) |
+ max_name_length = 1; |
+ std::vector<char> buffer(max_name_length); |
+ for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) { |
+ GLsizei var_size = 0; |
+ GLsizei var_name_length = 0; |
+ GLenum var_type = 0; |
+ glGetTransformFeedbackVarying( |
+ program, ii, max_name_length, |
+ &var_name_length, &var_size, &var_type, &buffer[0]); |
+ varyings[ii].size = static_cast<uint32_t>(var_size); |
+ varyings[ii].type = static_cast<uint32_t>(var_type); |
+ varyings[ii].name_offset = static_cast<uint32_t>(size.ValueOrDefault(0)); |
+ DCHECK_GT(max_name_length, var_name_length); |
+ names[ii] = std::string(&buffer[0], var_name_length); |
+ // TODO(zmo): optimize the name mapping lookup. |
+ const std::string* original_name = GetOriginalNameFromHashedName(names[ii]); |
+ if (original_name) |
+ names[ii] = *original_name; |
+ varyings[ii].name_length = names[ii].size() + 1; |
+ size += names[ii].size(); |
+ size += 1; |
+ } |
+ if (!size.IsValid()) |
+ return false; |
+ uint32_t total_size = size.ValueOrDefault(0); |
+ DCHECK_LE(header_size + entry_size, total_size); |
+ uint32_t data_size = total_size - header_size - entry_size; |
+ |
+ bucket->SetSize(total_size); |
+ TransformFeedbackVaryingsHeader* header = |
+ bucket->GetDataAs<TransformFeedbackVaryingsHeader*>(0, header_size); |
+ TransformFeedbackVaryingInfo* entries = |
+ bucket->GetDataAs<TransformFeedbackVaryingInfo*>(header_size, entry_size); |
+ char* data = bucket->GetDataAs<char*>(header_size + entry_size, data_size); |
+ DCHECK(header); |
+ DCHECK(entries); |
+ DCHECK(data); |
+ |
+ // Copy over data for the header and entries. |
+ header->num_transform_feedback_varyings = num_transform_feedback_varyings; |
+ memcpy(entries, &varyings[0], entry_size); |
+ |
+ for (uint32_t ii = 0; ii < num_transform_feedback_varyings; ++ii) { |
+ memcpy(data, names[ii].c_str(), names[ii].length() + 1); |
+ data += names[ii].length() + 1; |
+ } |
+ DCHECK_EQ(ComputeOffset(header, data), total_size); |
+ return true; |
+} |
+ |
+bool Program::GetUniformsES3(CommonDecoder::Bucket* bucket) const { |
+ // The data is packed into the bucket in the following order |
+ // 1) header |
+ // 2) N entries of UniformES3Info |
+ // |
+ // We query all the data directly through GL calls, assuming they are |
+ // cheap through MANGLE. |
+ |
+ DCHECK(bucket); |
+ GLuint program = service_id(); |
+ |
+ uint32_t header_size = sizeof(UniformsES3Header); |
+ bucket->SetSize(header_size); // In case we fail. |
+ |
+ GLsizei count = 0; |
+ GLint param = GL_FALSE; |
+ // We assume program is a valid program service id. |
+ glGetProgramiv(program, GL_LINK_STATUS, ¶m); |
+ if (param == GL_TRUE) { |
+ param = 0; |
+ glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &count); |
+ } |
+ if (count == 0) { |
+ return true; |
+ } |
+ |
+ base::CheckedNumeric<uint32_t> size = sizeof(UniformES3Info); |
+ size *= count; |
+ uint32_t entry_size = size.ValueOrDefault(0); |
+ size += header_size; |
+ if (!size.IsValid()) |
+ return false; |
+ uint32_t total_size = size.ValueOrDefault(0); |
+ bucket->SetSize(total_size); |
+ UniformsES3Header* header = |
+ bucket->GetDataAs<UniformsES3Header*>(0, header_size); |
+ DCHECK(header); |
+ header->num_uniforms = static_cast<uint32_t>(count); |
+ |
+ // Instead of GetDataAs<UniformES3Info*>, we do GetDataAs<int32_t>. This is |
+ // because struct UniformES3Info is defined as five int32_t. |
+ // By doing this, we can fill the structs through loops. |
+ int32_t* entries = |
+ bucket->GetDataAs<int32_t*>(header_size, entry_size); |
+ DCHECK(entries); |
+ const size_t kStride = sizeof(UniformES3Info) / sizeof(int32_t); |
+ |
+ const GLenum kPname[] = { |
+ GL_UNIFORM_BLOCK_INDEX, |
+ GL_UNIFORM_OFFSET, |
+ GL_UNIFORM_ARRAY_STRIDE, |
+ GL_UNIFORM_MATRIX_STRIDE, |
+ GL_UNIFORM_IS_ROW_MAJOR, |
+ }; |
+ const GLint kDefaultValue[] = { -1, -1, -1, -1, 0 }; |
+ const size_t kNumPnames = arraysize(kPname); |
+ std::vector<GLuint> indices(count); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ indices[ii] = ii; |
+ } |
+ std::vector<GLint> params(count); |
+ for (size_t pname_index = 0; pname_index < kNumPnames; ++pname_index) { |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ params[ii] = kDefaultValue[pname_index]; |
+ } |
+ glGetActiveUniformsiv( |
+ program, count, &indices[0], kPname[pname_index], ¶ms[0]); |
+ for (GLsizei ii = 0; ii < count; ++ii) { |
+ entries[kStride * ii + pname_index] = params[ii]; |
+ } |
+ } |
+ return true; |
+} |
+ |
Program::~Program() { |
if (manager_) { |
if (manager_->have_context_) { |