summaryrefslogtreecommitdiffstats
path: root/gpu
diff options
context:
space:
mode:
authorgman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-11 22:27:42 +0000
committergman@chromium.org <gman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-11 22:27:42 +0000
commit2318d34df86eea7fe41468b6c724008899e1f677 (patch)
tree3f610df04596c469985db776111c83688bd2bdf9 /gpu
parent8ebf9be5e65b179f25775ecbed4e778351b62198 (diff)
downloadchromium_src-2318d34df86eea7fe41468b6c724008899e1f677.zip
chromium_src-2318d34df86eea7fe41468b6c724008899e1f677.tar.gz
chromium_src-2318d34df86eea7fe41468b6c724008899e1f677.tar.bz2
Add glGetProgramInfoCHROMIUM.
This passes all program data in one command. I'll use this in another CL to cache program data on the client side for contexts that are not sharing resources. TEST=unit tests BUG=85966 Review URL: http://codereview.chromium.org/7324035 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@92066 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'gpu')
-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