diff options
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 |