diff options
| -rw-r--r-- | include/gui/DisplayEventReceiver.h | 14 | ||||
| -rw-r--r-- | include/gui/IDisplayEventConnection.h | 18 | ||||
| -rw-r--r-- | libs/gui/DisplayEventReceiver.cpp | 20 | ||||
| -rw-r--r-- | libs/gui/IDisplayEventConnection.cpp | 25 | ||||
| -rw-r--r-- | opengl/libs/GLES_trace/gltrace.proto | 9 | ||||
| -rw-r--r-- | opengl/libs/GLES_trace/src/gltrace.pb.cpp | 270 | ||||
| -rw-r--r-- | opengl/libs/GLES_trace/src/gltrace.pb.h | 211 | ||||
| -rw-r--r-- | opengl/libs/GLES_trace/src/gltrace_fixup.cpp | 18 | ||||
| -rw-r--r-- | services/surfaceflinger/DisplayEventConnection.cpp | 19 | ||||
| -rw-r--r-- | services/surfaceflinger/DisplayEventConnection.h | 8 | ||||
| -rw-r--r-- | services/surfaceflinger/EventThread.cpp | 145 | ||||
| -rw-r--r-- | services/surfaceflinger/EventThread.h | 27 | ||||
| -rw-r--r-- | services/surfaceflinger/MessageQueue.cpp | 14 | ||||
| -rw-r--r-- | services/surfaceflinger/MessageQueue.h | 1 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.cpp | 18 | ||||
| -rw-r--r-- | services/surfaceflinger/SurfaceFlinger.h | 4 |
16 files changed, 757 insertions, 64 deletions
diff --git a/include/gui/DisplayEventReceiver.h b/include/gui/DisplayEventReceiver.h index 8d07c0e492..dccc1643c9 100644 --- a/include/gui/DisplayEventReceiver.h +++ b/include/gui/DisplayEventReceiver.h @@ -94,6 +94,20 @@ public: */ ssize_t getEvents(Event* events, size_t count); + /* + * setVsyncRate() sets the Event::VSync delivery rate. A value of + * 1 returns every Event::VSync. A value of 2 returns every other event, + * etc... a value of 0 returns no event unless requestNextVsync() has + * been called. + */ + status_t setVsyncRate(uint32_t count); + + /* + * requestNextVsync() schedules the next Event::VSync. It has no effect + * if the vsync rate is > 0. + */ + status_t requestNextVsync(); + private: sp<IDisplayEventConnection> mEventConnection; sp<BitTube> mDataChannel; diff --git a/include/gui/IDisplayEventConnection.h b/include/gui/IDisplayEventConnection.h index 8728bb5ed7..86247de62b 100644 --- a/include/gui/IDisplayEventConnection.h +++ b/include/gui/IDisplayEventConnection.h @@ -33,9 +33,27 @@ class BitTube; class IDisplayEventConnection : public IInterface { public: + DECLARE_META_INTERFACE(DisplayEventConnection); + /* + * getDataChannel() returns a BitTube where to receive the events from + */ virtual sp<BitTube> getDataChannel() const = 0; + + /* + * setVsyncRate() sets the vsync event delivery rate. A value of + * 1 returns every vsync events. A value of 2 returns every other events, + * etc... a value of 0 returns no event unless requestNextVsync() has + * been called. + */ + virtual void setVsyncRate(uint32_t count) = 0; + + /* + * requestNextVsync() schedules the next vsync event. It has no effect + * if the vsync rate is > 0. + */ + virtual void requestNextVsync() = 0; // asynchronous }; // ---------------------------------------------------------------------------- diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp index 3b29a113e4..fee1febb9b 100644 --- a/libs/gui/DisplayEventReceiver.cpp +++ b/libs/gui/DisplayEventReceiver.cpp @@ -58,6 +58,26 @@ int DisplayEventReceiver::getFd() const { return mDataChannel->getFd(); } +status_t DisplayEventReceiver::setVsyncRate(uint32_t count) { + if (int32_t(count) < 0) + return BAD_VALUE; + + if (mEventConnection != NULL) { + mEventConnection->setVsyncRate(count); + return NO_ERROR; + } + return NO_INIT; +} + +status_t DisplayEventReceiver::requestNextVsync() { + if (mEventConnection != NULL) { + mEventConnection->requestNextVsync(); + return NO_ERROR; + } + return NO_INIT; +} + + ssize_t DisplayEventReceiver::getEvents(DisplayEventReceiver::Event* events, size_t count) { ssize_t size = mDataChannel->read(events, sizeof(events[0])*count); diff --git a/libs/gui/IDisplayEventConnection.cpp b/libs/gui/IDisplayEventConnection.cpp index 44127fb4ac..887d176b44 100644 --- a/libs/gui/IDisplayEventConnection.cpp +++ b/libs/gui/IDisplayEventConnection.cpp @@ -32,6 +32,8 @@ namespace android { enum { GET_DATA_CHANNEL = IBinder::FIRST_CALL_TRANSACTION, + SET_VSYNC_RATE, + REQUEST_NEXT_VSYNC }; class BpDisplayEventConnection : public BpInterface<IDisplayEventConnection> @@ -49,6 +51,19 @@ public: remote()->transact(GET_DATA_CHANNEL, data, &reply); return new BitTube(reply); } + + virtual void setVsyncRate(uint32_t count) { + Parcel data, reply; + data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); + data.writeInt32(count); + remote()->transact(SET_VSYNC_RATE, data, &reply); + } + + virtual void requestNextVsync() { + Parcel data, reply; + data.writeInterfaceToken(IDisplayEventConnection::getInterfaceDescriptor()); + remote()->transact(REQUEST_NEXT_VSYNC, data, &reply, IBinder::FLAG_ONEWAY); + } }; IMPLEMENT_META_INTERFACE(DisplayEventConnection, "android.gui.DisplayEventConnection"); @@ -65,6 +80,16 @@ status_t BnDisplayEventConnection::onTransact( channel->writeToParcel(reply); return NO_ERROR; } break; + case SET_VSYNC_RATE: { + CHECK_INTERFACE(IDisplayEventConnection, data, reply); + setVsyncRate(data.readInt32()); + return NO_ERROR; + } break; + case REQUEST_NEXT_VSYNC: { + CHECK_INTERFACE(IDisplayEventConnection, data, reply); + requestNextVsync(); + return NO_ERROR; + } break; } return BBinder::onTransact(code, data, reply, flags); } diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto index 59f80e3aba..12d8e7c0e8 100644 --- a/opengl/libs/GLES_trace/gltrace.proto +++ b/opengl/libs/GLES_trace/gltrace.proto @@ -459,7 +459,7 @@ message GLMessage { BYTE = 3; // GLbyte, GLubyte INT = 4; // GLbitfield, GLshort, GLint, GLsizei, GLushort, GLuint, GLfixed FLOAT = 5; // GLfloat, GLclampf - BOOL = 6; // GLboolean + BOOL = 6; // GLboolean ENUM = 7; // GLenum }; @@ -473,9 +473,16 @@ message GLMessage { repeated bool boolValue = 7; } + message FrameBuffer { + required int32 width = 1; + required int32 height = 2; + repeated bytes contents = 3; + } + required int32 context_id = 1; // GL context ID required Function function = 2 [default = invalid]; // GL function called repeated DataType args = 3; // GL function's arguments optional DataType returnValue = 4; // GL function's return value optional float duration = 5; // duration of GL call + optional FrameBuffer fb = 6; // contents of the framebuffer }; diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp index 160afbf4ce..6c1bb918ee 100644 --- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp +++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp @@ -13,6 +13,7 @@ namespace gltrace { void protobuf_ShutdownFile_gltrace_2eproto() { delete GLMessage::default_instance_; delete GLMessage_DataType::default_instance_; + delete GLMessage_FrameBuffer::default_instance_; } void protobuf_AddDesc_gltrace_2eproto() { @@ -23,8 +24,10 @@ void protobuf_AddDesc_gltrace_2eproto() { GLMessage::default_instance_ = new GLMessage(); GLMessage_DataType::default_instance_ = new GLMessage_DataType(); + GLMessage_FrameBuffer::default_instance_ = new GLMessage_FrameBuffer(); GLMessage::default_instance_->InitAsDefaultInstance(); GLMessage_DataType::default_instance_->InitAsDefaultInstance(); + GLMessage_FrameBuffer::default_instance_->InitAsDefaultInstance(); ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_gltrace_2eproto); } @@ -1306,11 +1309,238 @@ void GLMessage_DataType::Swap(GLMessage_DataType* other) { // ------------------------------------------------------------------- #ifndef _MSC_VER +const int GLMessage_FrameBuffer::kWidthFieldNumber; +const int GLMessage_FrameBuffer::kHeightFieldNumber; +const int GLMessage_FrameBuffer::kContentsFieldNumber; +#endif // !_MSC_VER + +GLMessage_FrameBuffer::GLMessage_FrameBuffer() + : ::google::protobuf::MessageLite() { + SharedCtor(); +} + +void GLMessage_FrameBuffer::InitAsDefaultInstance() { +} + +GLMessage_FrameBuffer::GLMessage_FrameBuffer(const GLMessage_FrameBuffer& from) + : ::google::protobuf::MessageLite() { + SharedCtor(); + MergeFrom(from); +} + +void GLMessage_FrameBuffer::SharedCtor() { + _cached_size_ = 0; + width_ = 0; + height_ = 0; + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +GLMessage_FrameBuffer::~GLMessage_FrameBuffer() { + SharedDtor(); +} + +void GLMessage_FrameBuffer::SharedDtor() { + if (this != default_instance_) { + } +} + +void GLMessage_FrameBuffer::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} +const GLMessage_FrameBuffer& GLMessage_FrameBuffer::default_instance() { + if (default_instance_ == NULL) protobuf_AddDesc_gltrace_2eproto(); return *default_instance_; +} + +GLMessage_FrameBuffer* GLMessage_FrameBuffer::default_instance_ = NULL; + +GLMessage_FrameBuffer* GLMessage_FrameBuffer::New() const { + return new GLMessage_FrameBuffer; +} + +void GLMessage_FrameBuffer::Clear() { + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + width_ = 0; + height_ = 0; + } + contents_.Clear(); + ::memset(_has_bits_, 0, sizeof(_has_bits_)); +} + +bool GLMessage_FrameBuffer::MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input) { +#define DO_(EXPRESSION) if (!(EXPRESSION)) return false + ::google::protobuf::uint32 tag; + while ((tag = input->ReadTag()) != 0) { + switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { + // required int32 width = 1; + case 1: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &width_))); + _set_bit(0); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(16)) goto parse_height; + break; + } + + // required int32 height = 2; + case 2: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_height: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &height_))); + _set_bit(1); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_contents; + break; + } + + // repeated bytes contents = 3; + case 3: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_contents: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->add_contents())); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(26)) goto parse_contents; + if (input->ExpectAtEnd()) return true; + break; + } + + default: { + handle_uninterpreted: + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { + return true; + } + DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); + break; + } + } + } + return true; +#undef DO_ +} + +void GLMessage_FrameBuffer::SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const { + // required int32 width = 1; + if (_has_bit(0)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->width(), output); + } + + // required int32 height = 2; + if (_has_bit(1)) { + ::google::protobuf::internal::WireFormatLite::WriteInt32(2, this->height(), output); + } + + // repeated bytes contents = 3; + for (int i = 0; i < this->contents_size(); i++) { + ::google::protobuf::internal::WireFormatLite::WriteBytes( + 3, this->contents(i), output); + } + +} + +int GLMessage_FrameBuffer::ByteSize() const { + int total_size = 0; + + if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { + // required int32 width = 1; + if (has_width()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->width()); + } + + // required int32 height = 2; + if (has_height()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::Int32Size( + this->height()); + } + + } + // repeated bytes contents = 3; + total_size += 1 * this->contents_size(); + for (int i = 0; i < this->contents_size(); i++) { + total_size += ::google::protobuf::internal::WireFormatLite::BytesSize( + this->contents(i)); + } + + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); + return total_size; +} + +void GLMessage_FrameBuffer::CheckTypeAndMergeFrom( + const ::google::protobuf::MessageLite& from) { + MergeFrom(*::google::protobuf::down_cast<const GLMessage_FrameBuffer*>(&from)); +} + +void GLMessage_FrameBuffer::MergeFrom(const GLMessage_FrameBuffer& from) { + GOOGLE_CHECK_NE(&from, this); + contents_.MergeFrom(from.contents_); + if (from._has_bits_[0 / 32] & (0xffu << (0 % 32))) { + if (from._has_bit(0)) { + set_width(from.width()); + } + if (from._has_bit(1)) { + set_height(from.height()); + } + } +} + +void GLMessage_FrameBuffer::CopyFrom(const GLMessage_FrameBuffer& from) { + if (&from == this) return; + Clear(); + MergeFrom(from); +} + +bool GLMessage_FrameBuffer::IsInitialized() const { + if ((_has_bits_[0] & 0x00000003) != 0x00000003) return false; + + return true; +} + +void GLMessage_FrameBuffer::Swap(GLMessage_FrameBuffer* other) { + if (other != this) { + std::swap(width_, other->width_); + std::swap(height_, other->height_); + contents_.Swap(&other->contents_); + std::swap(_has_bits_[0], other->_has_bits_[0]); + std::swap(_cached_size_, other->_cached_size_); + } +} + +::std::string GLMessage_FrameBuffer::GetTypeName() const { + return "android.gltrace.GLMessage.FrameBuffer"; +} + + +// ------------------------------------------------------------------- + +#ifndef _MSC_VER const int GLMessage::kContextIdFieldNumber; const int GLMessage::kFunctionFieldNumber; const int GLMessage::kArgsFieldNumber; const int GLMessage::kReturnValueFieldNumber; const int GLMessage::kDurationFieldNumber; +const int GLMessage::kFbFieldNumber; #endif // !_MSC_VER GLMessage::GLMessage() @@ -1320,6 +1550,7 @@ GLMessage::GLMessage() void GLMessage::InitAsDefaultInstance() { returnvalue_ = const_cast< ::android::gltrace::GLMessage_DataType*>(&::android::gltrace::GLMessage_DataType::default_instance()); + fb_ = const_cast< ::android::gltrace::GLMessage_FrameBuffer*>(&::android::gltrace::GLMessage_FrameBuffer::default_instance()); } GLMessage::GLMessage(const GLMessage& from) @@ -1334,6 +1565,7 @@ void GLMessage::SharedCtor() { function_ = 3000; returnvalue_ = NULL; duration_ = 0; + fb_ = NULL; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -1344,6 +1576,7 @@ GLMessage::~GLMessage() { void GLMessage::SharedDtor() { if (this != default_instance_) { delete returnvalue_; + delete fb_; } } @@ -1370,6 +1603,9 @@ void GLMessage::Clear() { if (returnvalue_ != NULL) returnvalue_->::android::gltrace::GLMessage_DataType::Clear(); } duration_ = 0; + if (_has_bit(5)) { + if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear(); + } } args_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -1456,6 +1692,20 @@ bool GLMessage::MergePartialFromCodedStream( } else { goto handle_uninterpreted; } + if (input->ExpectTag(50)) goto parse_fb; + break; + } + + // optional .android.gltrace.GLMessage.FrameBuffer fb = 6; + case 6: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_fb: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_fb())); + } else { + goto handle_uninterpreted; + } if (input->ExpectAtEnd()) return true; break; } @@ -1505,6 +1755,12 @@ void GLMessage::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteFloat(5, this->duration(), output); } + // optional .android.gltrace.GLMessage.FrameBuffer fb = 6; + if (_has_bit(5)) { + ::google::protobuf::internal::WireFormatLite::WriteMessage( + 6, this->fb(), output); + } + } int GLMessage::ByteSize() const { @@ -1536,6 +1792,13 @@ int GLMessage::ByteSize() const { total_size += 1 + 4; } + // optional .android.gltrace.GLMessage.FrameBuffer fb = 6; + if (has_fb()) { + total_size += 1 + + ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( + this->fb()); + } + } // repeated .android.gltrace.GLMessage.DataType args = 3; total_size += 1 * this->args_size(); @@ -1572,6 +1835,9 @@ void GLMessage::MergeFrom(const GLMessage& from) { if (from._has_bit(4)) { set_duration(from.duration()); } + if (from._has_bit(5)) { + mutable_fb()->::android::gltrace::GLMessage_FrameBuffer::MergeFrom(from.fb()); + } } } @@ -1590,6 +1856,9 @@ bool GLMessage::IsInitialized() const { if (has_returnvalue()) { if (!this->returnvalue().IsInitialized()) return false; } + if (has_fb()) { + if (!this->fb().IsInitialized()) return false; + } return true; } @@ -1600,6 +1869,7 @@ void GLMessage::Swap(GLMessage* other) { args_.Swap(&other->args_); std::swap(returnvalue_, other->returnvalue_); std::swap(duration_, other->duration_); + std::swap(fb_, other->fb_); std::swap(_has_bits_[0], other->_has_bits_[0]); std::swap(_cached_size_, other->_cached_size_); } diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h index be5ca2a74f..c39e1b230c 100644 --- a/opengl/libs/GLES_trace/src/gltrace.pb.h +++ b/opengl/libs/GLES_trace/src/gltrace.pb.h @@ -34,6 +34,7 @@ void protobuf_ShutdownFile_gltrace_2eproto(); class GLMessage; class GLMessage_DataType; +class GLMessage_FrameBuffer; enum GLMessage_DataType_Type { GLMessage_DataType_Type_VOID = 1, @@ -658,6 +659,108 @@ class GLMessage_DataType : public ::google::protobuf::MessageLite { }; // ------------------------------------------------------------------- +class GLMessage_FrameBuffer : public ::google::protobuf::MessageLite { + public: + GLMessage_FrameBuffer(); + virtual ~GLMessage_FrameBuffer(); + + GLMessage_FrameBuffer(const GLMessage_FrameBuffer& from); + + inline GLMessage_FrameBuffer& operator=(const GLMessage_FrameBuffer& from) { + CopyFrom(from); + return *this; + } + + static const GLMessage_FrameBuffer& default_instance(); + + void Swap(GLMessage_FrameBuffer* other); + + // implements Message ---------------------------------------------- + + GLMessage_FrameBuffer* New() const; + void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from); + void CopyFrom(const GLMessage_FrameBuffer& from); + void MergeFrom(const GLMessage_FrameBuffer& from); + void Clear(); + bool IsInitialized() const; + + int ByteSize() const; + bool MergePartialFromCodedStream( + ::google::protobuf::io::CodedInputStream* input); + void SerializeWithCachedSizes( + ::google::protobuf::io::CodedOutputStream* output) const; + int GetCachedSize() const { return _cached_size_; } + private: + void SharedCtor(); + void SharedDtor(); + void SetCachedSize(int size) const; + public: + + ::std::string GetTypeName() const; + + // nested types ---------------------------------------------------- + + // accessors ------------------------------------------------------- + + // required int32 width = 1; + inline bool has_width() const; + inline void clear_width(); + static const int kWidthFieldNumber = 1; + inline ::google::protobuf::int32 width() const; + inline void set_width(::google::protobuf::int32 value); + + // required int32 height = 2; + inline bool has_height() const; + inline void clear_height(); + static const int kHeightFieldNumber = 2; + inline ::google::protobuf::int32 height() const; + inline void set_height(::google::protobuf::int32 value); + + // repeated bytes contents = 3; + inline int contents_size() const; + inline void clear_contents(); + static const int kContentsFieldNumber = 3; + inline const ::std::string& contents(int index) const; + inline ::std::string* mutable_contents(int index); + inline void set_contents(int index, const ::std::string& value); + inline void set_contents(int index, const char* value); + inline void set_contents(int index, const void* value, size_t size); + inline ::std::string* add_contents(); + inline void add_contents(const ::std::string& value); + inline void add_contents(const char* value); + inline void add_contents(const void* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& contents() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_contents(); + + // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage.FrameBuffer) + private: + mutable int _cached_size_; + + ::google::protobuf::int32 width_; + ::google::protobuf::int32 height_; + ::google::protobuf::RepeatedPtrField< ::std::string> contents_; + friend void protobuf_AddDesc_gltrace_2eproto(); + friend void protobuf_AssignDesc_gltrace_2eproto(); + friend void protobuf_ShutdownFile_gltrace_2eproto(); + + ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32]; + + // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? + inline bool _has_bit(int index) const { + return (_has_bits_[index / 32] & (1u << (index % 32))) != 0; + } + inline void _set_bit(int index) { + _has_bits_[index / 32] |= (1u << (index % 32)); + } + inline void _clear_bit(int index) { + _has_bits_[index / 32] &= ~(1u << (index % 32)); + } + + void InitAsDefaultInstance(); + static GLMessage_FrameBuffer* default_instance_; +}; +// ------------------------------------------------------------------- + class GLMessage : public ::google::protobuf::MessageLite { public: GLMessage(); @@ -700,6 +803,7 @@ class GLMessage : public ::google::protobuf::MessageLite { // nested types ---------------------------------------------------- typedef GLMessage_DataType DataType; + typedef GLMessage_FrameBuffer FrameBuffer; typedef GLMessage_Function Function; static const Function glActiveTexture = GLMessage_Function_glActiveTexture; @@ -1178,6 +1282,13 @@ class GLMessage : public ::google::protobuf::MessageLite { inline float duration() const; inline void set_duration(float value); + // optional .android.gltrace.GLMessage.FrameBuffer fb = 6; + inline bool has_fb() const; + inline void clear_fb(); + static const int kFbFieldNumber = 6; + inline const ::android::gltrace::GLMessage_FrameBuffer& fb() const; + inline ::android::gltrace::GLMessage_FrameBuffer* mutable_fb(); + // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage) private: mutable int _cached_size_; @@ -1187,11 +1298,12 @@ class GLMessage : public ::google::protobuf::MessageLite { ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType > args_; ::android::gltrace::GLMessage_DataType* returnvalue_; float duration_; + ::android::gltrace::GLMessage_FrameBuffer* fb_; friend void protobuf_AddDesc_gltrace_2eproto(); friend void protobuf_AssignDesc_gltrace_2eproto(); friend void protobuf_ShutdownFile_gltrace_2eproto(); - ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(6 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -1412,6 +1524,86 @@ GLMessage_DataType::mutable_boolvalue() { // ------------------------------------------------------------------- +// GLMessage_FrameBuffer + +// required int32 width = 1; +inline bool GLMessage_FrameBuffer::has_width() const { + return _has_bit(0); +} +inline void GLMessage_FrameBuffer::clear_width() { + width_ = 0; + _clear_bit(0); +} +inline ::google::protobuf::int32 GLMessage_FrameBuffer::width() const { + return width_; +} +inline void GLMessage_FrameBuffer::set_width(::google::protobuf::int32 value) { + _set_bit(0); + width_ = value; +} + +// required int32 height = 2; +inline bool GLMessage_FrameBuffer::has_height() const { + return _has_bit(1); +} +inline void GLMessage_FrameBuffer::clear_height() { + height_ = 0; + _clear_bit(1); +} +inline ::google::protobuf::int32 GLMessage_FrameBuffer::height() const { + return height_; +} +inline void GLMessage_FrameBuffer::set_height(::google::protobuf::int32 value) { + _set_bit(1); + height_ = value; +} + +// repeated bytes contents = 3; +inline int GLMessage_FrameBuffer::contents_size() const { + return contents_.size(); +} +inline void GLMessage_FrameBuffer::clear_contents() { + contents_.Clear(); +} +inline const ::std::string& GLMessage_FrameBuffer::contents(int index) const { + return contents_.Get(index); +} +inline ::std::string* GLMessage_FrameBuffer::mutable_contents(int index) { + return contents_.Mutable(index); +} +inline void GLMessage_FrameBuffer::set_contents(int index, const ::std::string& value) { + contents_.Mutable(index)->assign(value); +} +inline void GLMessage_FrameBuffer::set_contents(int index, const char* value) { + contents_.Mutable(index)->assign(value); +} +inline void GLMessage_FrameBuffer::set_contents(int index, const void* value, size_t size) { + contents_.Mutable(index)->assign( + reinterpret_cast<const char*>(value), size); +} +inline ::std::string* GLMessage_FrameBuffer::add_contents() { + return contents_.Add(); +} +inline void GLMessage_FrameBuffer::add_contents(const ::std::string& value) { + contents_.Add()->assign(value); +} +inline void GLMessage_FrameBuffer::add_contents(const char* value) { + contents_.Add()->assign(value); +} +inline void GLMessage_FrameBuffer::add_contents(const void* value, size_t size) { + contents_.Add()->assign(reinterpret_cast<const char*>(value), size); +} +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +GLMessage_FrameBuffer::contents() const { + return contents_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +GLMessage_FrameBuffer::mutable_contents() { + return &contents_; +} + +// ------------------------------------------------------------------- + // GLMessage // required int32 context_id = 1; @@ -1505,6 +1697,23 @@ inline void GLMessage::set_duration(float value) { duration_ = value; } +// optional .android.gltrace.GLMessage.FrameBuffer fb = 6; +inline bool GLMessage::has_fb() const { + return _has_bit(5); +} +inline void GLMessage::clear_fb() { + if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear(); + _clear_bit(5); +} +inline const ::android::gltrace::GLMessage_FrameBuffer& GLMessage::fb() const { + return fb_ != NULL ? *fb_ : *default_instance_->fb_; +} +inline ::android::gltrace::GLMessage_FrameBuffer* GLMessage::mutable_fb() { + _set_bit(5); + if (fb_ == NULL) fb_ = new ::android::gltrace::GLMessage_FrameBuffer; + return fb_; +} + // @@protoc_insertion_point(namespace_scope) diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp index 90021f4cb6..c5b04511a0 100644 --- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp +++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp @@ -95,20 +95,16 @@ void fixup_glGetString(GLMessage *glmsg) { } } -/* Add the contents of the framebuffer as an argument */ +/* Add the contents of the framebuffer to the protobuf message */ void fixup_addFBContents(GLMessage *glmsg) { - GLMessage_DataType *arg_fb = glmsg->add_args(); /* Add the FB as the last argument */ - GLTraceContext *glContext = getGLTraceContext(); - - void *fb; + void *fbcontents; unsigned fbsize, fbwidth, fbheight; - glContext->getCompressedFB(&fb, &fbsize, &fbwidth, &fbheight); + getGLTraceContext()->getCompressedFB(&fbcontents, &fbsize, &fbwidth, &fbheight); - arg_fb->set_isarray(true); - arg_fb->set_type(GLMessage::DataType::BYTE); - arg_fb->add_rawbytes(fb, fbsize); - arg_fb->add_intvalue(fbwidth); - arg_fb->add_intvalue(fbheight); + GLMessage_FrameBuffer *fb = glmsg->mutable_fb(); + fb->set_width(fbwidth); + fb->set_height(fbheight); + fb->add_contents(fbcontents, fbsize); } void fixup_glTexImage2D(GLMessage *glmsg) { diff --git a/services/surfaceflinger/DisplayEventConnection.cpp b/services/surfaceflinger/DisplayEventConnection.cpp index a0aa9c019e..77ecbd280e 100644 --- a/services/surfaceflinger/DisplayEventConnection.cpp +++ b/services/surfaceflinger/DisplayEventConnection.cpp @@ -25,6 +25,7 @@ #include "SurfaceFlinger.h" #include "DisplayEventConnection.h" +#include "EventThread.h" // --------------------------------------------------------------------------- @@ -33,30 +34,38 @@ namespace android { // --------------------------------------------------------------------------- DisplayEventConnection::DisplayEventConnection( - const sp<SurfaceFlinger>& flinger) - : mFlinger(flinger), mChannel(new BitTube()) + const sp<EventThread>& eventThread) + : mEventThread(eventThread), mChannel(new BitTube()) { } DisplayEventConnection::~DisplayEventConnection() { - mFlinger->cleanupDisplayEventConnection(this); + mEventThread->unregisterDisplayEventConnection(this); } void DisplayEventConnection::onFirstRef() { - // nothing to do here for now. + // NOTE: mEventThread doesn't hold a strong reference on us + mEventThread->registerDisplayEventConnection(this); } sp<BitTube> DisplayEventConnection::getDataChannel() const { return mChannel; } +void DisplayEventConnection::setVsyncRate(uint32_t count) { + mEventThread->setVsyncRate(count, this); +} + +void DisplayEventConnection::requestNextVsync() { + mEventThread->requestNextVsync(this); +} + status_t DisplayEventConnection::postEvent(const DisplayEventReceiver::Event& event) { ssize_t size = mChannel->write(&event, sizeof(DisplayEventReceiver::Event)); return size < 0 ? status_t(size) : status_t(NO_ERROR); } - // --------------------------------------------------------------------------- }; // namespace android diff --git a/services/surfaceflinger/DisplayEventConnection.h b/services/surfaceflinger/DisplayEventConnection.h index 46cf64b4a2..cc3ee3659e 100644 --- a/services/surfaceflinger/DisplayEventConnection.h +++ b/services/surfaceflinger/DisplayEventConnection.h @@ -32,13 +32,13 @@ namespace android { // --------------------------------------------------------------------------- class BitTube; -class SurfaceFlinger; +class EventThread; // --------------------------------------------------------------------------- class DisplayEventConnection : public BnDisplayEventConnection { public: - DisplayEventConnection(const sp<SurfaceFlinger>& flinger); + DisplayEventConnection(const sp<EventThread>& flinger); status_t postEvent(const DisplayEventReceiver::Event& event); @@ -46,8 +46,10 @@ private: virtual ~DisplayEventConnection(); virtual void onFirstRef(); virtual sp<BitTube> getDataChannel() const; + virtual void setVsyncRate(uint32_t count); + virtual void requestNextVsync(); // asynchronous - sp<SurfaceFlinger> const mFlinger; + sp<EventThread> const mEventThread; sp<BitTube> const mChannel; }; diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index edb06ba21a..dc39f883eb 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -47,7 +47,8 @@ void EventThread::onFirstRef() { status_t EventThread::registerDisplayEventConnection( const sp<DisplayEventConnection>& connection) { Mutex::Autolock _l(mLock); - mDisplayEventConnections.add(connection); + ConnectionInfo info; + mDisplayEventConnections.add(connection, info); mCondition.signal(); return NO_ERROR; } @@ -55,43 +56,132 @@ status_t EventThread::registerDisplayEventConnection( status_t EventThread::unregisterDisplayEventConnection( const wp<DisplayEventConnection>& connection) { Mutex::Autolock _l(mLock); - mDisplayEventConnections.remove(connection); + mDisplayEventConnections.removeItem(connection); mCondition.signal(); return NO_ERROR; } -bool EventThread::threadLoop() { - - nsecs_t timestamp; +void EventThread::removeDisplayEventConnection( + const wp<DisplayEventConnection>& connection) { Mutex::Autolock _l(mLock); - do { - // wait for listeners - while (!mDisplayEventConnections.size()) { - mCondition.wait(mLock); - } + mDisplayEventConnections.removeItem(connection); +} - // wait for vsync - mLock.unlock(); - timestamp = mHw.waitForVSync(); - mLock.lock(); +EventThread::ConnectionInfo* EventThread::getConnectionInfoLocked( + const wp<DisplayEventConnection>& connection) { + ssize_t index = mDisplayEventConnections.indexOfKey(connection); + if (index < 0) return NULL; + return &mDisplayEventConnections.editValueAt(index); +} - // make sure we still have some listeners - } while (!mDisplayEventConnections.size()); +void EventThread::setVsyncRate(uint32_t count, + const wp<DisplayEventConnection>& connection) { + if (int32_t(count) >= 0) { // server must protect against bad params + Mutex::Autolock _l(mLock); + ConnectionInfo* info = getConnectionInfoLocked(connection); + if (info) { + info->count = (count == 0) ? -1 : count; + mCondition.signal(); + } + } +} +void EventThread::requestNextVsync( + const wp<DisplayEventConnection>& connection) { + Mutex::Autolock _l(mLock); + ConnectionInfo* info = getConnectionInfoLocked(connection); + if (info) { + if (info->count < 0) { + info->count = 0; + } + mCondition.signal(); + } +} - // dispatch vsync events to listeners... - mDeliveredEvents++; - const size_t count = mDisplayEventConnections.size(); +bool EventThread::threadLoop() { + nsecs_t timestamp; DisplayEventReceiver::Event vsync; - vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; - vsync.header.timestamp = timestamp; - vsync.vsync.count = mDeliveredEvents; + KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > displayEventConnections; + + { // scope for the lock + Mutex::Autolock _l(mLock); + do { + // wait for listeners + do { + bool waitForNextVsync = false; + size_t count = mDisplayEventConnections.size(); + for (size_t i=0 ; i<count ; i++) { + const ConnectionInfo& info( + mDisplayEventConnections.valueAt(i)); + if (info.count >= 1) { + // continuous mode + waitForNextVsync = true; + } else { + // one-shot event + if (info.count >= -1) { + ConnectionInfo& info( + mDisplayEventConnections.editValueAt(i)); + info.count--; + if (info.count == -1) { + // fired this time around + waitForNextVsync = true; + } + } + } + } + + if (waitForNextVsync) + break; + + mCondition.wait(mLock); + } while(true); + + // wait for vsync + mLock.unlock(); + timestamp = mHw.waitForVSync(); + mLock.lock(); + mDeliveredEvents++; + + // make sure we still have some listeners + } while (!mDisplayEventConnections.size()); + + // dispatch vsync events to listeners... + vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC; + vsync.header.timestamp = timestamp; + vsync.vsync.count = mDeliveredEvents; + + // make a copy of our connection list, so we can + // dispatch events without holding mLock + displayEventConnections = mDisplayEventConnections; + } + const size_t count = displayEventConnections.size(); for (size_t i=0 ; i<count ; i++) { - sp<DisplayEventConnection> conn(mDisplayEventConnections.itemAt(i).promote()); + sp<DisplayEventConnection> conn(displayEventConnections.keyAt(i).promote()); // make sure the connection didn't die if (conn != NULL) { + + const ConnectionInfo& info( + displayEventConnections.valueAt(i)); + + if ((info.count > 1) && (mDeliveredEvents % info.count)) { + // continuous event, but not time to send this event yet + continue; + } else if (info.count < -1) { + // disabled event + continue; + } else if (info.count == 0) { + // impossible by construction. but we prefer to be safe. + continue; + } + + // here, either: + // count = -1 : one-shot scheduled this time around + // count = 1 : continuous not rate-limited + // count > 1 : continuous, rate-limited + // Note: count == 0 is not possible by construction + status_t err = conn->postEvent(vsync); if (err == -EAGAIN || err == -EWOULDBLOCK) { // The destination doesn't accept events anymore, it's probably @@ -103,11 +193,18 @@ bool EventThread::threadLoop() { // handle any other error on the pipe as fatal. the only // reasonable thing to do is to clean-up this connection. // The most common error we'll get here is -EPIPE. - mDisplayEventConnections.remove(conn); + removeDisplayEventConnection(displayEventConnections.keyAt(i)); } + } else { + // somehow the connection is dead, but we still have it in our list + // just clean the list. + removeDisplayEventConnection(displayEventConnections.keyAt(i)); } } + // clear all our references without holding mLock + displayEventConnections.clear(); + return true; } diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h index 0482ab7528..35bd299a86 100644 --- a/services/surfaceflinger/EventThread.h +++ b/services/surfaceflinger/EventThread.h @@ -24,7 +24,7 @@ #include <utils/Errors.h> #include <utils/threads.h> -#include <utils/SortedVector.h> +#include <utils/KeyedVector.h> #include "DisplayEventConnection.h" @@ -51,6 +51,11 @@ public: status_t unregisterDisplayEventConnection( const wp<DisplayEventConnection>& connection); + void setVsyncRate(uint32_t count, + const wp<DisplayEventConnection>& connection); + + void requestNextVsync(const wp<DisplayEventConnection>& connection); + void dump(String8& result, char* buffer, size_t SIZE) const; private: @@ -58,6 +63,22 @@ private: virtual status_t readyToRun(); virtual void onFirstRef(); + struct ConnectionInfo { + ConnectionInfo() : count(-1) { } + + // count >= 1 : continuous event. count is the vsync rate + // count == 0 : one-shot event that has not fired + // count ==-1 : one-shot event that fired this round / disabled + // count ==-2 : one-shot event that fired the round before + int32_t count; + }; + + void removeDisplayEventConnection( + const wp<DisplayEventConnection>& connection); + + ConnectionInfo* getConnectionInfoLocked( + const wp<DisplayEventConnection>& connection); + // constants sp<SurfaceFlinger> mFlinger; const DisplayHardware& mHw; @@ -66,7 +87,9 @@ private: mutable Condition mCondition; // protected by mLock - SortedVector<wp<DisplayEventConnection> > mDisplayEventConnections; + KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > mDisplayEventConnections; + + // main thread only size_t mDeliveredEvents; }; diff --git a/services/surfaceflinger/MessageQueue.cpp b/services/surfaceflinger/MessageQueue.cpp index fdde75c0a0..85845c922d 100644 --- a/services/surfaceflinger/MessageQueue.cpp +++ b/services/surfaceflinger/MessageQueue.cpp @@ -44,7 +44,7 @@ void MessageBase::handleMessage(const Message&) { // --------------------------------------------------------------------------- MessageQueue::MessageQueue() - : mLooper(new Looper(true)) + : mLooper(new Looper(true)), mWorkPending(0) { } @@ -58,11 +58,11 @@ void MessageQueue::waitMessage() { int32_t ret = mLooper->pollOnce(-1); switch (ret) { case ALOOPER_POLL_WAKE: - // we got woken-up there is work to do in the main loop - return; - case ALOOPER_POLL_CALLBACK: - // callback was handled, loop again + // callback and/or wake + if (android_atomic_and(0, &mWorkPending)) { + return; + } continue; case ALOOPER_POLL_TIMEOUT: @@ -94,7 +94,9 @@ status_t MessageQueue::postMessage( } status_t MessageQueue::invalidate() { - mLooper->wake(); + if (android_atomic_or(1, &mWorkPending) == 0) { + mLooper->wake(); + } return NO_ERROR; } diff --git a/services/surfaceflinger/MessageQueue.h b/services/surfaceflinger/MessageQueue.h index 775400f981..2317d81ab8 100644 --- a/services/surfaceflinger/MessageQueue.h +++ b/services/surfaceflinger/MessageQueue.h @@ -55,6 +55,7 @@ private: class MessageQueue { sp<Looper> mLooper; + volatile int32_t mWorkPending; public: MessageQueue(); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 51c2be84f2..014c7e24af 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -389,16 +389,10 @@ bool SurfaceFlinger::authenticateSurfaceTexture( // ---------------------------------------------------------------------------- sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() { - sp<DisplayEventConnection> result(new DisplayEventConnection(this)); - mEventThread->registerDisplayEventConnection(result); + sp<DisplayEventConnection> result(new DisplayEventConnection(mEventThread)); return result; } -void SurfaceFlinger::cleanupDisplayEventConnection( - const wp<DisplayEventConnection>& connection) { - mEventThread->unregisterDisplayEventConnection(connection); -} - // ---------------------------------------------------------------------------- #if 0 #pragma mark - @@ -720,6 +714,14 @@ void SurfaceFlinger::computeVisibleRegions( void SurfaceFlinger::commitTransaction() { + if (!mLayersPendingRemoval.isEmpty()) { + // Notify removed layers now that they can't be drawn from + for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) { + mLayersPendingRemoval[i]->onRemoved(); + } + mLayersPendingRemoval.clear(); + } + mDrawingState = mCurrentState; mTransationPending = false; mTransactionCV.broadcast(); @@ -1172,7 +1174,7 @@ status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase) mLayerPurgatory.add(layerBase); } - layerBase->onRemoved(); + mLayersPendingRemoval.push(layerBase); // it's possible that we don't find a layer, because it might // have been destroyed already -- this is not technically an error diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1039f471e5..41caee35fa 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -335,9 +335,6 @@ private: status_t electronBeamOffAnimationImplLocked(); status_t electronBeamOnAnimationImplLocked(); - void cleanupDisplayEventConnection( - const wp<DisplayEventConnection>& connection); - void debugFlashRegions(); void debugShowFPS() const; void drawWormhole() const; @@ -352,6 +349,7 @@ private: Condition mTransactionCV; SortedVector< sp<LayerBase> > mLayerPurgatory; bool mTransationPending; + Vector< sp<LayerBase> > mLayersPendingRemoval; // protected by mStateLock (but we could use another lock) GraphicPlane mGraphicPlanes[1]; |