summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gpu/GLES2/gl2ext.h3
-rwxr-xr-xgpu/command_buffer/build_gles2_cmd_buffer.py16
-rw-r--r--gpu/command_buffer/client/gles2_c_lib_autogen.h4
-rw-r--r--gpu/command_buffer/client/gles2_cmd_helper_autogen.h6
-rw-r--r--gpu/command_buffer/client/gles2_implementation.cc36
-rw-r--r--gpu/command_buffer/client/gles2_implementation.h3
-rw-r--r--gpu/command_buffer/client/gles2_implementation_autogen.h3
-rw-r--r--gpu/command_buffer/client/gles2_implementation_unittest.cc89
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format.h40
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_autogen.h50
-rw-r--r--gpu/command_buffer/common/gles2_cmd_format_test_autogen.h15
-rw-r--r--gpu/command_buffer/common/gles2_cmd_ids_autogen.h1
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder.cc23
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc28
-rw-r--r--gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h2
-rw-r--r--gpu/command_buffer/service/program_manager.cc83
-rw-r--r--gpu/command_buffer/service/program_manager.h4
-rw-r--r--gpu/command_buffer/service/program_manager_unittest.cc121
18 files changed, 516 insertions, 11 deletions
diff --git a/gpu/GLES2/gl2ext.h b/gpu/GLES2/gl2ext.h
index 2c092e6..7ad5ef1 100644
--- a/gpu/GLES2/gl2ext.h
+++ b/gpu/GLES2/gl2ext.h
@@ -999,11 +999,14 @@ typedef void (GL_APIENTRYP PFNGLRATELIMITOFFSCREENCONTEXTCHROMIUM) ();
#define GL_CHROMIUM_get_multiple 1
#ifdef GL_GLEXT_PROTOTYPES
#define glGetMultipleIntegervCHROMIUM GLES2_GET_FUN(GetMultipleIntegervCHROMIUM)
+#define glGetProgramInfoCHROMIUM GLES2_GET_FUN(GetProgramInfovCHROMIUM)
#if !defined(GLES2_USE_CPP_BINDINGS)
GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM (void);
+GL_APICALL void GL_APIENTRY glGetProgrmaInfoCHROMIUM (GLuint program, GLsizei bufsize, GLsizei* size, void* info);
#endif
#else
typedef void (GL_APIENTRYP PFNGLGETMULTIPLEINTEGERVCHROMIUM) ();
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOCHROMIUM) ();
#endif
#endif
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 479acb8..2b5876d 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -222,6 +222,7 @@ GL_APICALL void GL_APIENTRY glWaitLatchCHROMIUM (GLuint latch_id);
GL_APICALL void GL_APIENTRY glRateLimitOffscreenContextCHROMIUM (void);
GL_APICALL void GL_APIENTRY glSetSurfaceCHROMIUM (GLint surface_id);
GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
+GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
"""
# This is the list of all commmands that will be generated and their Id.
@@ -429,6 +430,7 @@ _CMD_ID_TABLE = {
'WaitLatchCHROMIUM': 452,
'SetSurfaceCHROMIUM': 453,
'GetMultipleIntegervCHROMIUM': 454,
+ 'GetProgramInfoCHROMIUM': 455,
}
# This is a list of enum names and their valid values. It is used to map
@@ -1349,6 +1351,20 @@ _FUNCTION_INFO = {
'decoder_func': 'DoGetProgramiv',
'result': ['SizedResult<GLint>'],
},
+ 'GetProgramInfoCHROMIUM': {
+ 'type': 'Custom',
+ 'immediate': False,
+ 'expectation': False,
+ 'impl_func': False,
+ 'extension': True,
+ 'chromium': True,
+ 'cmd_args': 'GLidProgram program, uint32 bucket_id',
+ 'result': [
+ 'uint32 link_status',
+ 'uint32 num_attribs',
+ 'uint32 num_uniforms',
+ ],
+ },
'GetProgramInfoLog': {
'type': 'STRn',
'expectation': False,
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 72a39db..2306501 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -585,6 +585,10 @@ void GLES2GetMultipleIntegervCHROMIUM(
gles2::GetGLContext()->GetMultipleIntegervCHROMIUM(
pnames, count, results, size);
}
+void GLES2GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+ gles2::GetGLContext()->GetProgramInfoCHROMIUM(program, bufsize, size, info);
+}
#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_C_LIB_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 2cc91eb..8078354 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -1244,5 +1244,11 @@
results_shm_offset, size);
}
+ void GetProgramInfoCHROMIUM(GLuint program, uint32 bucket_id) {
+ gles2::GetProgramInfoCHROMIUM& c =
+ GetCmdSpace<gles2::GetProgramInfoCHROMIUM>();
+ c.Init(program, bucket_id);
+ }
+
#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_CMD_HELPER_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 8ef17af..c7d550d 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -448,7 +448,8 @@ GLES2Implementation::GLES2Implementation(
client_side_array_id_(0),
client_side_element_array_id_(0),
error_bits_(0),
- debug_(false) {
+ debug_(false),
+ sharing_resources_(share_resources) {
GPU_CLIENT_LOG_CODE_BLOCK({
debug_ = CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableGPUClientLogging);
@@ -2150,5 +2151,38 @@ void GLES2Implementation::GetMultipleIntegervCHROMIUM(
});
}
+void GLES2Implementation::GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info) {
+ if (bufsize < 0) {
+ SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM: bufsize less than 0.");
+ return;
+ }
+ if (size == NULL) {
+ SetGLError(GL_INVALID_VALUE, "glProgramInfoCHROMIUM: size is null.");
+ return;
+ }
+ // Make sure they've set size to 0 else the value will be undefined on
+ // lost context.
+ GPU_DCHECK(*size == 0);
+ // Clear the bucket so if the command fails nothing will be in it.
+ helper_->SetBucketSize(kResultBucketId, 0);
+ helper_->GetProgramInfoCHROMIUM(program, kResultBucketId);
+ std::vector<int8> result;
+ GetBucketContents(kResultBucketId, &result);
+ if (result.size() == 0) {
+ return;
+ }
+ *size = result.size();
+ if (!info) {
+ return;
+ }
+ if (static_cast<size_t>(bufsize) < result.size()) {
+ SetGLError(GL_INVALID_OPERATION,
+ "glProgramInfoCHROMIUM: bufsize is too small for result.");
+ return;
+ }
+ memcpy(info, &result[0], result.size());
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index 6636030..ef7f07d 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -424,6 +424,9 @@ class GLES2Implementation {
// Whether or not to print debugging info.
bool debug_;
+ // Whether or not this context is sharing resources.
+ bool sharing_resources_;
+
// Map of GLenum to Strings for glGetString. We need to cache these because
// the pointer passed back to the client has to remain valid for eternity.
typedef std::map<uint32, std::set<std::string> > GLStringMap;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 8e048ef..902bbdf 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -1263,5 +1263,8 @@ void SetSurfaceCHROMIUM(GLint surface_id) {
void GetMultipleIntegervCHROMIUM(
const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
+void GetProgramInfoCHROMIUM(
+ GLuint program, GLsizei bufsize, GLsizei* size, void* info);
+
#endif // GPU_COMMAND_BUFFER_CLIENT_GLES2_IMPLEMENTATION_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 9b7e556..2d69fce 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -1143,6 +1143,95 @@ TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMBadArgs) {
EXPECT_EQ(kSentinel, results[num_results]);
}
+TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) {
+ const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation
+ const GLuint kProgramId = 123;
+ const char kBad = 0x12;
+ GLsizei size = 0;
+ const Str7 kString = {"foobar"};
+ char buf[20];
+
+ memset(buf, kBad, sizeof(buf));
+ uint32 offset = AllocateTransferBuffer(sizeof(kString));
+ EXPECT_CALL(*command_buffer_, OnFlush(_))
+ .WillOnce(SetMemory(uint32(sizeof(kString))))
+ .WillOnce(SetMemoryAtOffset(offset, kString))
+ .WillOnce(SetMemory(GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ GetProgramInfoCHROMIUM get_program_info;
+ cmd::GetBucketSize get_bucket_size;
+ cmd::GetBucketData get_bucket_data;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_program_info.Init(kProgramId, kBucketId);
+ expected.get_bucket_size.Init(kBucketId, kTransferBufferId, 0);
+ expected.get_bucket_data.Init(
+ kBucketId, 0, sizeof(kString), kTransferBufferId, offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), &size, &buf);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
+ EXPECT_EQ(sizeof(kString), static_cast<size_t>(size));
+ EXPECT_STREQ(kString.str, buf);
+ EXPECT_EQ(buf[sizeof(kString)], kBad);
+}
+
+TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMBadArgs) {
+ const uint32 kBucketId = 1; // This id is hardcoded into GLES2Implemenation
+ const GLuint kProgramId = 123;
+ GLsizei size = 0;
+ const Str7 kString = {"foobar"};
+ char buf[20];
+
+ uint32 offset = AllocateTransferBuffer(sizeof(kString));
+ EXPECT_CALL(*command_buffer_, OnFlush(_))
+ .WillOnce(SetMemory(uint32(sizeof(kString))))
+ .WillOnce(SetMemoryAtOffset(offset, kString))
+ .WillOnce(SetMemory(GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(GLuint(GL_NO_ERROR)))
+ .WillOnce(SetMemory(GLuint(GL_NO_ERROR)))
+ .RetiresOnSaturation();
+
+ // try bufsize not big enough.
+ struct Cmds {
+ cmd::SetBucketSize set_bucket_size1;
+ GetProgramInfoCHROMIUM get_program_info;
+ cmd::GetBucketSize get_bucket_size;
+ cmd::GetBucketData get_bucket_data;
+ cmd::SetToken set_token1;
+ cmd::SetBucketSize set_bucket_size2;
+ };
+ Cmds expected;
+ expected.set_bucket_size1.Init(kBucketId, 0);
+ expected.get_program_info.Init(kProgramId, kBucketId);
+ expected.get_bucket_size.Init(kBucketId, kTransferBufferId, 0);
+ expected.get_bucket_data.Init(
+ kBucketId, 0, sizeof(kString), kTransferBufferId, offset);
+ expected.set_token1.Init(GetNextToken());
+ expected.set_bucket_size2.Init(kBucketId, 0);
+ gl_->GetProgramInfoCHROMIUM(kProgramId, 6, &size, &buf);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), gl_->GetError());
+ ClearCommands();
+
+ // try bad bufsize
+ gl_->GetProgramInfoCHROMIUM(kProgramId, -1, &size, &buf);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+ ClearCommands();
+ // try no size ptr.
+ gl_->GetProgramInfoCHROMIUM(kProgramId, sizeof(buf), NULL, &buf);
+ EXPECT_TRUE(NoCommandsWritten());
+ EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
+}
+
} // namespace gles2
} // namespace gpu
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index e0da67d..ec9ea33 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -115,6 +115,44 @@ COMPILE_ASSERT(offsetof(SizedResult<int8>, size) == 0,
COMPILE_ASSERT(offsetof(SizedResult<int8>, data) == 4,
OffsetOf_SizedResult_data_not_4);
+// The data for one attrib or uniform from GetProgramInfoCHROMIUM.
+struct ProgramInput {
+ uint32 type; // The type (GL_VEC3, GL_MAT3, GL_SAMPLER_2D, etc.
+ int32 size; // The size (how big the array is for uniforms)
+ uint32 location_offset; // offset from ProgramInfoHeader to 'size' locations
+ // for uniforms, 1 for attribs.
+ uint32 name_offset; // offset from ProgrmaInfoHeader to start of name.
+ uint32 name_length; // length of the name.
+};
+
+// The format of the bucket filled out by GetProgramInfoCHROMIUM
+struct ProgramInfoHeader {
+ uint32 link_status;
+ uint32 num_attribs;
+ uint32 num_uniforms;
+ // ProgramInput inputs[num_attribs + num_uniforms];
+};
+
+COMPILE_ASSERT(sizeof(ProgramInput) == 20, ProgramInput_size_not_20);
+COMPILE_ASSERT(offsetof(ProgramInput, type) == 0,
+ OffsetOf_ProgramInput_type_not_0);
+COMPILE_ASSERT(offsetof(ProgramInput, size) == 4,
+ OffsetOf_ProgramInput_size_not_4);
+COMPILE_ASSERT(offsetof(ProgramInput, location_offset) == 8,
+ OffsetOf_ProgramInput_location_offset_not_8);
+COMPILE_ASSERT(offsetof(ProgramInput, name_offset) == 12,
+ OffsetOf_ProgramInput_name_offset_not_12);
+COMPILE_ASSERT(offsetof(ProgramInput, name_length) == 16,
+ OffsetOf_ProgramInput_name_length_not_16);
+
+COMPILE_ASSERT(sizeof(ProgramInfoHeader) == 12, ProgramInfoHeader_size_not_12);
+COMPILE_ASSERT(offsetof(ProgramInfoHeader, link_status) == 0,
+ OffsetOf_ProgramInfoHeader_link_status_not_0);
+COMPILE_ASSERT(offsetof(ProgramInfoHeader, num_attribs) == 4,
+ OffsetOf_ProgramInfoHeader_num_attribs_not_4);
+COMPILE_ASSERT(offsetof(ProgramInfoHeader, num_uniforms) == 8,
+ OffsetOf_ProgramInfoHeader_num_uniforms_not_8);
+
#include "../common/gles2_cmd_format_autogen.h"
// These are hand written commands.
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index 6270f9a..3b76346 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -9077,6 +9077,56 @@ COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_offset) == 20,
COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, size) == 24,
OffsetOf_GetMultipleIntegervCHROMIUM_size_not_24);
+struct GetProgramInfoCHROMIUM {
+ typedef GetProgramInfoCHROMIUM ValueType;
+ static const CommandId kCmdId = kGetProgramInfoCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+
+ struct Result {
+ uint32 link_status;
+ uint32 num_attribs;
+ uint32 num_uniforms;
+ };
+
+ static uint32 ComputeSize() {
+ return static_cast<uint32>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() {
+ header.SetCmd<ValueType>();
+ }
+
+ void Init(GLuint _program, uint32 _bucket_id) {
+ SetHeader();
+ program = _program;
+ bucket_id = _bucket_id;
+ }
+
+ void* Set(void* cmd, GLuint _program, uint32 _bucket_id) {
+ static_cast<ValueType*>(cmd)->Init(_program, _bucket_id);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32 program;
+ uint32 bucket_id;
+};
+
+COMPILE_ASSERT(sizeof(GetProgramInfoCHROMIUM) == 12,
+ Sizeof_GetProgramInfoCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM, header) == 0,
+ OffsetOf_GetProgramInfoCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM, program) == 4,
+ OffsetOf_GetProgramInfoCHROMIUM_program_not_4);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM, bucket_id) == 8,
+ OffsetOf_GetProgramInfoCHROMIUM_bucket_id_not_8);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM::Result, link_status) == 0,
+ OffsetOf_GetProgramInfoCHROMIUM_Result_link_status_not_0);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM::Result, num_attribs) == 4,
+ OffsetOf_GetProgramInfoCHROMIUM_Result_num_attribs_not_4);
+COMPILE_ASSERT(offsetof(GetProgramInfoCHROMIUM::Result, num_uniforms) == 8,
+ OffsetOf_GetProgramInfoCHROMIUM_Result_num_uniforms_not_8);
+
#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 212f8b3..40af555 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -3572,5 +3572,20 @@ TEST(GLES2FormatTest, GetMultipleIntegervCHROMIUM) {
EXPECT_EQ(static_cast<GLsizeiptr>(16), cmd.size);
}
+TEST(GLES2FormatTest, GetProgramInfoCHROMIUM) {
+ GetProgramInfoCHROMIUM cmd = { { 0 } };
+ void* next_cmd = cmd.Set(
+ &cmd,
+ static_cast<GLuint>(11),
+ static_cast<uint32>(12));
+ EXPECT_EQ(static_cast<uint32>(GetProgramInfoCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<char*>(next_cmd),
+ reinterpret_cast<char*>(&cmd) + sizeof(cmd));
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.program);
+ EXPECT_EQ(static_cast<uint32>(12), cmd.bucket_id);
+}
+
#endif // GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_TEST_AUTOGEN_H_
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 95698a6..25bf081 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -209,6 +209,7 @@
OP(WaitLatchCHROMIUM) /* 452 */ \
OP(SetSurfaceCHROMIUM) /* 453 */ \
OP(GetMultipleIntegervCHROMIUM) /* 454 */ \
+ OP(GetProgramInfoCHROMIUM) /* 455 */ \
enum CommandId {
kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 674cc63..155c908 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -6700,6 +6700,29 @@ error::Error GLES2DecoderImpl::HandleGetMultipleIntegervCHROMIUM(
return error::kNoError;
}
+error::Error GLES2DecoderImpl::HandleGetProgramInfoCHROMIUM(
+ uint32 immediate_data_size, const gles2::GetProgramInfoCHROMIUM& c) {
+ GLuint program = static_cast<GLuint>(c.program);
+ uint32 bucket_id = c.bucket_id;
+ Bucket* bucket = CreateBucket(bucket_id);
+ bucket->SetSize(sizeof(ProgramInfoHeader)); // in case we fail.
+ ProgramManager::ProgramInfo* info = NULL;
+ if (program) {
+ info = GetProgramInfoNotShader(program, "glGetProgramInfoCHROMIUM");
+ if (!info) {
+ return error::kNoError;
+ }
+ if (!info->IsValid()) {
+ // Program was not linked successfully. (ie, glLinkProgram)
+ SetGLError(GL_INVALID_OPERATION,
+ "glGetProgramInfoCHROMIUM: program not linked");
+ return error::kNoError;
+ }
+ }
+ info->GetProgramInfo(bucket);
+ return error::kNoError;
+}
+
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
// instead of having to edit some template or the code generator.
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 52b9a22..eadfbcd 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -4319,6 +4319,34 @@ TEST_F(GLES2DecoderManualInitTest, GetNoCompressedTextureFormats) {
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
+TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMValidArgs) {
+ const uint32 kBucketId = 123;
+ GetProgramInfoCHROMIUM cmd;
+ cmd.Init(client_program_id_, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ EXPECT_GT(bucket->size(), 0u);
+}
+
+TEST_F(GLES2DecoderWithShaderTest, GetProgramInfoCHROMIUMInvalidArgs) {
+ const uint32 kBucketId = 123;
+ CommonDecoder::Bucket* bucket = decoder_->GetBucket(kBucketId);
+ EXPECT_TRUE(bucket == NULL);
+ GetProgramInfoCHROMIUM cmd;
+ cmd.Init(kInvalidClientId, kBucketId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+ bucket = decoder_->GetBucket(kBucketId);
+ ASSERT_TRUE(bucket != NULL);
+ EXPECT_EQ(sizeof(ProgramInfoHeader), bucket->size());
+ ProgramInfoHeader* info = bucket->GetDataAs<ProgramInfoHeader*>(
+ 0, sizeof(ProgramInfoHeader));
+ ASSERT_TRUE(info != 0);
+ EXPECT_EQ(0u, info->link_status);
+ EXPECT_EQ(0u, info->num_attribs);
+ EXPECT_EQ(0u, info->num_uniforms);
+}
+
// TODO(gman): Complete this test.
// TEST_F(GLES2DecoderTest, CompressedTexImage2DGLError) {
// }
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 95ed93f..54bfdf6 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -15,5 +15,7 @@
// TODO(gman): SetSurfaceCHROMIUM
// TODO(gman): GetMultipleIntegervCHROMIUM
+// TODO(gman): GetProgramInfoCHROMIUM
+
#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 530fc37..faf5b3f 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_number_conversions.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
namespace gpu {
@@ -443,6 +444,88 @@ bool ProgramManager::ProgramInfo::CanLink() const {
return true;
}
+static uint32 ComputeOffset(const void* start, const void* position) {
+ return static_cast<const uint8*>(position) -
+ static_cast<const uint8*>(start);
+}
+
+void ProgramManager::ProgramInfo::GetProgramInfo(
+ CommonDecoder::Bucket* bucket) const {
+ // NOTE: It seems to me the math in here does not need check for overflow
+ // because the data being calucated from has various small limits. The max
+ // number of attribs + uniforms is somewhere well under 1024. The maximum size
+ // of an identifier is 256 characters.
+ uint32 num_locations = 0;
+ uint32 total_string_size = 0;
+
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttribInfo& info = attrib_infos_[ii];
+ num_locations += 1;
+ total_string_size += info.name.size();
+ }
+
+ for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ num_locations += info.element_locations.size();
+ total_string_size += info.name.size();
+ }
+
+ uint32 num_inputs = attrib_infos_.size() + uniform_infos_.size();
+ uint32 input_size = num_inputs * sizeof(ProgramInput);
+ uint32 location_size = num_locations * sizeof(int32);
+ uint32 size = sizeof(ProgramInfoHeader) +
+ input_size + location_size + total_string_size;
+
+ bucket->SetSize(size);
+ ProgramInfoHeader* header = bucket->GetDataAs<ProgramInfoHeader*>(0, size);
+ ProgramInput* inputs = bucket->GetDataAs<ProgramInput*>(
+ sizeof(ProgramInfoHeader), input_size);
+ int32* locations = bucket->GetDataAs<int32*>(
+ sizeof(ProgramInfoHeader) + input_size, location_size);
+ char* strings = bucket->GetDataAs<char*>(
+ sizeof(ProgramInfoHeader) + input_size + location_size,
+ total_string_size);
+ DCHECK(header);
+ DCHECK(inputs);
+ DCHECK(locations);
+ DCHECK(strings);
+
+ header->link_status = link_status_;
+ header->num_attribs = attrib_infos_.size();
+ header->num_uniforms = uniform_infos_.size();
+
+ for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
+ const VertexAttribInfo& info = attrib_infos_[ii];
+ inputs->size = info.size;
+ inputs->type = info.type;
+ inputs->location_offset = ComputeOffset(header, locations);
+ inputs->name_offset = ComputeOffset(header, strings);
+ inputs->name_length = info.name.size();
+ *locations++ = info.location;
+ memcpy(strings, info.name.c_str(), info.name.size());
+ strings += info.name.size();
+ ++inputs;
+ }
+
+ for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
+ const UniformInfo& info = uniform_infos_[ii];
+ inputs->size = info.size;
+ inputs->type = info.type;
+ inputs->location_offset = ComputeOffset(header, locations);
+ inputs->name_offset = ComputeOffset(header, strings);
+ inputs->name_length = info.name.size();
+ DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
+ for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
+ *locations++ = info.element_locations[jj];
+ }
+ memcpy(strings, info.name.c_str(), info.name.size());
+ strings += info.name.size();
+ ++inputs;
+ }
+
+ DCHECK_EQ(ComputeOffset(header, strings), size);
+}
+
ProgramManager::ProgramInfo::~ProgramInfo() {}
ProgramManager::ProgramManager() {}
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index a584177..2f59c98 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/common_decoder.h"
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/shader_manager.h"
@@ -109,6 +110,9 @@ class ProgramManager {
const UniformInfo* GetUniformInfoByLocation(
GLint location, GLint* array_index) const;
+ // Gets all the program info.
+ void GetProgramInfo(CommonDecoder::Bucket* bucket) 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.
diff --git a/gpu/command_buffer/service/program_manager_unittest.cc b/gpu/command_buffer/service/program_manager_unittest.cc
index 85d5d4a..60f652f4 100644
--- a/gpu/command_buffer/service/program_manager_unittest.cc
+++ b/gpu/command_buffer/service/program_manager_unittest.cc
@@ -10,6 +10,8 @@
#include "base/string_number_conversions.h"
#include "base/string_util.h"
#include "gpu/command_buffer/common/gl_mock.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/service/common_decoder.h"
#include "gpu/command_buffer/service/mocks.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -187,6 +189,7 @@ class ProgramManagerWithShaderTest : public testing::Test {
struct UniformInfo {
const char* name;
+ const char* good_name;
GLint size;
GLenum type;
GLint location;
@@ -381,9 +384,24 @@ const size_t ProgramManagerWithShaderTest::kNumAttribs =
ProgramManagerWithShaderTest::UniformInfo
ProgramManagerWithShaderTest::kUniforms[] = {
- { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, },
- { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, },
- { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, },
+ { kUniform1Name,
+ kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1Location,
+ },
+ { kUniform2Name,
+ kUniform2Name,
+ kUniform2Size,
+ kUniform2Type,
+ kUniform2Location,
+ },
+ { kUniform3BadName,
+ kUniform3GoodName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3Location,
+ },
};
const size_t ProgramManagerWithShaderTest::kNumUniforms =
@@ -572,9 +590,24 @@ TEST_F(ProgramManagerWithShaderTest, GetUniformInfoByLocation) {
TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsGLUnderscoreUniform) {
static const char* kUniform2Name = "gl_longNameWeCanCheckFor";
static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
- { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, },
- { kUniform2Name, kUniform2Size, kUniform2Type, kUniform2Location, },
- { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, },
+ { kUniform1Name,
+ kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1Location,
+ },
+ { kUniform2Name,
+ kUniform2Name,
+ kUniform2Size,
+ kUniform2Type,
+ kUniform2Location,
+ },
+ { kUniform3BadName,
+ kUniform3GoodName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3Location,
+ },
};
const size_t kNumUniforms = arraysize(kUniforms);
static const GLuint kClientProgramId = 1234;
@@ -656,9 +689,24 @@ TEST_F(ProgramManagerWithShaderTest, GLDriverReturnsWrongTypeInfo) {
{ kAttrib3Name, kAttrib3Size, kAttrib3Type, kAttrib3Location, },
};
static ProgramManagerWithShaderTest::UniformInfo kUniforms[] = {
- { kUniform1Name, kUniform1Size, kUniform1Type, kUniform1Location, },
- { kUniform2Name, kUniform2Size, kUniform2BadType, kUniform2Location, },
- { kUniform3BadName, kUniform3Size, kUniform3Type, kUniform3Location, },
+ { kUniform1Name,
+ kUniform1Name,
+ kUniform1Size,
+ kUniform1Type,
+ kUniform1Location,
+ },
+ { kUniform2Name,
+ kUniform2Name,
+ kUniform2Size,
+ kUniform2BadType,
+ kUniform2Location,
+ },
+ { kUniform3BadName,
+ kUniform3GoodName,
+ kUniform3Size,
+ kUniform3Type,
+ kUniform3Location,
+ },
};
const size_t kNumAttribs= arraysize(kAttribs);
const size_t kNumUniforms = arraysize(kUniforms);
@@ -795,6 +843,61 @@ TEST_F(ProgramManagerWithShaderTest, ProgramInfoUseCount2) {
EXPECT_FALSE(fshader->InUse());
}
+TEST_F(ProgramManagerWithShaderTest, ProgramInfoGetProgramInfo) {
+ CommonDecoder::Bucket bucket;
+ const ProgramManager::ProgramInfo* program_info =
+ manager_.GetProgramInfo(kClientProgramId);
+ ASSERT_TRUE(program_info != NULL);
+ program_info->GetProgramInfo(&bucket);
+ ProgramInfoHeader* header =
+ bucket.GetDataAs<ProgramInfoHeader*>(0, sizeof(ProgramInfoHeader));
+ ASSERT_TRUE(header != NULL);
+ EXPECT_EQ(1u, header->link_status);
+ EXPECT_EQ(arraysize(kAttribs), header->num_attribs);
+ EXPECT_EQ(arraysize(kUniforms), header->num_uniforms);
+ const ProgramInput* inputs = bucket.GetDataAs<const ProgramInput*>(
+ sizeof(*header),
+ sizeof(ProgramInput) * (header->num_attribs + header->num_attribs));
+ ASSERT_TRUE(inputs != NULL);
+ const ProgramInput* input = inputs;
+ // TODO(gman): Don't assume these are in order.
+ for (uint32 ii = 0; ii < header->num_attribs; ++ii) {
+ const AttribInfo& expected = kAttribs[ii];
+ EXPECT_EQ(expected.size, input->size);
+ EXPECT_EQ(expected.type, input->type);
+ const int32* location = bucket.GetDataAs<const int32*>(
+ input->location_offset, sizeof(int32));
+ ASSERT_TRUE(location != NULL);
+ EXPECT_EQ(expected.location, *location);
+ const char* name_buf = bucket.GetDataAs<const char*>(
+ input->name_offset, input->name_length);
+ ASSERT_TRUE(name_buf != NULL);
+ std::string name(name_buf, input->name_length);
+ EXPECT_STREQ(expected.name, name.c_str());
+ ++input;
+ }
+ // TODO(gman): Don't assume these are in order.
+ for (uint32 ii = 0; ii < header->num_uniforms; ++ii) {
+ const UniformInfo& expected = kUniforms[ii];
+ EXPECT_EQ(expected.size, input->size);
+ EXPECT_EQ(expected.type, input->type);
+ const int32* locations = bucket.GetDataAs<const int32*>(
+ input->location_offset, sizeof(int32) * input->size);
+ ASSERT_TRUE(locations != NULL);
+ for (int32 jj = 0; jj < input->size; ++jj) {
+ EXPECT_EQ(expected.location + jj * 2, locations[jj]);
+ }
+ const char* name_buf = bucket.GetDataAs<const char*>(
+ input->name_offset, input->name_length);
+ ASSERT_TRUE(name_buf != NULL);
+ std::string name(name_buf, input->name_length);
+ EXPECT_STREQ(expected.good_name, name.c_str());
+ ++input;
+ }
+ EXPECT_EQ(header->num_attribs + header->num_uniforms,
+ static_cast<uint32>(input - inputs));
+}
+
} // namespace gles2
} // namespace gpu