| 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_) {
|
|
|