Merge 50689913a4f8deb43cc2b24d47f70a621fb1d8a1 on remote branch
Change-Id: I274bdf821cd5efae07bcae22e189f72862ac285f
diff --git a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
index 90b5653..cbc7069 100644
--- a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
+++ b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.cpp
@@ -42,6 +42,8 @@
#include "C2GoldfishAvcDec.h"
+#include <mutex>
+
#define DEBUG 0
#if DEBUG
#define DDD(...) ALOGD(__VA_ARGS__)
@@ -64,6 +66,35 @@
So total maximum output delay is 34 */
constexpr uint32_t kMaxOutputDelay = 34;
constexpr uint32_t kMinInputBytes = 4;
+
+static std::mutex s_decoder_count_mutex;
+static int s_decoder_count = 0;
+
+int allocateDecoderId() {
+ DDD("calling %s", __func__);
+ std::lock_guard<std::mutex> lock(s_decoder_count_mutex);
+ if (s_decoder_count >= 32 || s_decoder_count < 0) {
+ ALOGE("calling %s failed", __func__);
+ return -1;
+ }
+ ++ s_decoder_count;
+ DDD("calling %s success total decoder %d", __func__, s_decoder_count);
+ return s_decoder_count;;
+}
+
+bool deAllocateDecoderId() {
+ DDD("calling %s", __func__);
+ std::lock_guard<std::mutex> lock(s_decoder_count_mutex);
+ if (s_decoder_count < 1) {
+ ALOGE("calling %s failed ", __func__);
+ return false;
+ }
+ -- s_decoder_count;
+ DDD("calling %s success total decoder %d", __func__, s_decoder_count);
+ return true;
+}
+
+
} // namespace
class C2GoldfishAvcDec::IntfImpl : public SimpleInterface<void>::BaseParams {
@@ -307,6 +338,8 @@
if (me.v.matrix > C2Color::MATRIX_OTHER) {
me.set().matrix = C2Color::MATRIX_OTHER;
}
+ DDD("default primaries %d default range %d", me.set().primaries,
+ me.set().range);
return C2R::Ok();
}
@@ -326,6 +359,8 @@
if (me.v.matrix > C2Color::MATRIX_OTHER) {
me.set().matrix = C2Color::MATRIX_OTHER;
}
+ DDD("coded primaries %d coded range %d", me.set().primaries,
+ me.set().range);
return C2R::Ok();
}
@@ -336,6 +371,7 @@
(void)mayBlock;
// take default values for all unspecified fields, and coded values for
// specified ones
+ DDD("before change primaries %d range %d", me.v.primaries, me.v.range);
me.set().range =
coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
@@ -346,6 +382,8 @@
: coded.v.transfer;
me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix
: coded.v.matrix;
+
+ DDD("after change primaries %d range %d", me.v.primaries, me.v.range);
return C2R::Ok();
}
@@ -357,7 +395,13 @@
int height() const { return mSize->height; }
- private:
+ int primaries() const { return mColorAspects->primaries; }
+
+ int range() const { return mColorAspects->range; }
+
+ int transfer() const { return mColorAspects->transfer; }
+
+ private:
std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
@@ -393,6 +437,9 @@
C2GoldfishAvcDec::~C2GoldfishAvcDec() { onRelease(); }
c2_status_t C2GoldfishAvcDec::onInit() {
+ ALOGD("calling onInit");
+ mId = allocateDecoderId();
+ if (mId <= 0) return C2_NO_MEMORY;
status_t err = initDecoder();
return err == OK ? C2_OK : C2_CORRUPTED;
}
@@ -407,6 +454,11 @@
void C2GoldfishAvcDec::onReset() { (void)onStop(); }
void C2GoldfishAvcDec::onRelease() {
+ DDD("calling onRelease");
+ if (mId > 0) {
+ deAllocateDecoderId();
+ mId = -1;
+ }
deleteContext();
if (mOutBlock) {
mOutBlock.reset();
@@ -457,6 +509,30 @@
return C2_OK;
}
+void C2GoldfishAvcDec::sendMetadata() {
+ // compare and send if changed
+ MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
+ currentMetaData.primaries = mIntf->primaries();
+ currentMetaData.range = mIntf->range();
+ currentMetaData.transfer = mIntf->transfer();
+
+ DDD("metadata primaries %d range %d transfer %d",
+ (int)(currentMetaData.primaries),
+ (int)(currentMetaData.range),
+ (int)(currentMetaData.transfer)
+ );
+
+ if (mSentMetadata.primaries == currentMetaData.primaries &&
+ mSentMetadata.range == currentMetaData.range &&
+ mSentMetadata.transfer == currentMetaData.transfer) {
+ DDD("metadata is the same, no need to update");
+ return;
+ }
+ std::swap(mSentMetadata, currentMetaData);
+
+ mContext->sendMetadata(&(mSentMetadata));
+}
+
status_t C2GoldfishAvcDec::createDecoder() {
DDD("creating avc context now w %d h %d", mWidth, mHeight);
@@ -476,7 +552,6 @@
}
status_t C2GoldfishAvcDec::initDecoder() {
- // if (OK != createDecoder()) return UNKNOWN_ERROR;
mStride = ALIGN2(mWidth);
mSignalledError = false;
resetPlugin();
@@ -682,7 +757,6 @@
}
void C2GoldfishAvcDec::getVuiParams(h264_image_t &img) {
-
VuiColorAspects vuiColorAspects;
vuiColorAspects.primaries = img.color_primaries;
vuiColorAspects.transfer = img.color_trc;
@@ -931,6 +1005,8 @@
} // end of whChanged
} // end of isSpsFrame
+ sendMetadata();
+
uint32_t delay;
GETTIME(&mTimeStart, nullptr);
TIME_DIFF(mTimeEnd, mTimeStart, delay);
diff --git a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
index afa27f5..d90b11a 100644
--- a/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
+++ b/system/codecs/c2/decoders/avcdec/C2GoldfishAvcDec.h
@@ -142,6 +142,10 @@
}
} mBitstreamColorAspects;
+ MetaDataColorAspects mSentMetadata = {1, 0, 0, 0};
+
+ void sendMetadata();
+
// profile
struct timeval mTimeStart;
struct timeval mTimeEnd;
@@ -155,6 +159,7 @@
std::unique_ptr<GoldfishH264Helper> mH264Helper;
+ int mId = -1;
C2_DO_NOT_COPY(C2GoldfishAvcDec);
};
diff --git a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp
index 7909aa9..6560772 100644
--- a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp
+++ b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.cpp
@@ -49,7 +49,7 @@
}
mSlot = slot;
mAddressOffSet = static_cast<unsigned int>(mSlot) * (1 << 20);
- DDD("got memory lot %d addrr %x", mSlot, mAddressOffSet);
+ DDD("got memory lot %d addrr %lu", mSlot, mAddressOffSet);
mHasAddressSpaceMemory = true;
}
transport->writeParam(mVersion, 0, mAddressOffSet);
@@ -62,7 +62,7 @@
MediaOperation::InitContext, mAddressOffSet);
auto *retptr = transport->getReturnAddr(mAddressOffSet);
mHostHandle = *(uint64_t *)(retptr);
- DDD("initH264Context: got handle to host %lld", mHostHandle);
+ DDD("initH264Context: got handle to host %lu", mHostHandle);
}
void MediaH264Decoder::resetH264Context(unsigned int width, unsigned int height,
@@ -87,7 +87,7 @@
void MediaH264Decoder::destroyH264Context() {
- DDD("return memory lot %d addrr %x", (int)(mAddressOffSet >> 23),
+ DDD("return memory lot %d addrr %lu", (int)(mAddressOffSet >> 23),
mAddressOffSet);
auto transport = GoldfishMediaTransport::getInstance();
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
@@ -99,7 +99,7 @@
h264_result_t MediaH264Decoder::decodeFrame(uint8_t *img, size_t szBytes,
uint64_t pts) {
- DDD("decode frame: use handle to host %lld", mHostHandle);
+ DDD("decode frame: use handle to host %lu", mHostHandle);
h264_result_t res = {0, 0};
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
@@ -126,12 +126,28 @@
return res;
}
+void MediaH264Decoder::sendMetadata(MetaDataColorAspects *ptr) {
+ DDD("send metadata to host %p", ptr);
+ if (!mHasAddressSpaceMemory) {
+ ALOGE("%s no address space memory", __func__);
+ return;
+ }
+ MetaDataColorAspects& meta = *ptr;
+ auto transport = GoldfishMediaTransport::getInstance();
+ transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+ transport->writeParam(meta.type, 1, mAddressOffSet);
+ transport->writeParam(meta.primaries, 2, mAddressOffSet);
+ transport->writeParam(meta.range, 3, mAddressOffSet);
+ transport->writeParam(meta.transfer, 4, mAddressOffSet);
+ transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::SendMetadata, mAddressOffSet);
+}
+
void MediaH264Decoder::flush() {
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
return;
}
- DDD("flush: use handle to host %lld", mHostHandle);
+ DDD("flush: use handle to host %lu", mHostHandle);
auto transport = GoldfishMediaTransport::getInstance();
transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
transport->sendOperation(MediaCodecType::H264Codec, MediaOperation::Flush,
@@ -139,7 +155,7 @@
}
h264_image_t MediaH264Decoder::getImage() {
- DDD("getImage: use handle to host %lld", mHostHandle);
+ DDD("getImage: use handle to host %lu", mHostHandle);
h264_image_t res{};
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
@@ -174,7 +190,7 @@
h264_image_t
MediaH264Decoder::renderOnHostAndReturnImageMetadata(int hostColorBufferId) {
- DDD("%s: use handle to host %lld", __func__, mHostHandle);
+ DDD("%s: use handle to host %lu", __func__, mHostHandle);
h264_image_t res{};
if (hostColorBufferId < 0) {
ALOGE("%s negative color buffer id %d", __func__, hostColorBufferId);
diff --git a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h
index 1c1b262..e184cbd 100644
--- a/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h
+++ b/system/codecs/c2/decoders/avcdec/MediaH264Decoder.h
@@ -17,6 +17,8 @@
#ifndef GOLDFISH_MEDIA_H264_DEC_H_
#define GOLDFISH_MEDIA_H264_DEC_H_
+#include "goldfish_media_utils.h"
+
struct h264_init_result_t {
uint64_t host_handle;
int ret;
@@ -89,5 +91,14 @@
// ask host to render to hostColorBufferId, return only image metadata back
// to guest
h264_image_t renderOnHostAndReturnImageMetadata(int hostColorBufferId);
+
+ // send metadata about the bitstream to host, such as color aspects that
+ // are set by the framework, e.g., color primaries (601, 709 etc), range
+ // (full range or limited range), transfer etc. given metadata could be
+ // of all kinds of types, the convention is that the first field server as
+ // metadata type id. host will check the type id to decide what to do with
+ // it; unrecognized typeid will be discarded by host side.
+
+ void sendMetadata(MetaDataColorAspects *ptr);
};
#endif
diff --git a/system/codecs/c2/decoders/base/include/goldfish_media_utils.h b/system/codecs/c2/decoders/base/include/goldfish_media_utils.h
index efa8859..a45cda9 100644
--- a/system/codecs/c2/decoders/base/include/goldfish_media_utils.h
+++ b/system/codecs/c2/decoders/base/include/goldfish_media_utils.h
@@ -26,6 +26,13 @@
Max = 4,
};
+struct MetaDataColorAspects {
+ uint64_t type = 1;
+ uint64_t primaries;
+ uint64_t range;
+ uint64_t transfer;
+};
+
enum class MediaOperation : __u8 {
InitContext = 0,
DestroyContext = 1,
@@ -33,7 +40,8 @@
GetImage = 3,
Flush = 4,
Reset = 5,
- Max = 6,
+ SendMetadata = 6,
+ Max = 7,
};
// This class will abstract away the knowledge required to send media codec data
diff --git a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
index 7008bd5..13e9515 100644
--- a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
+++ b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.cpp
@@ -347,6 +347,13 @@
int height() const { return mSize->height; }
+ int primaries() const { return mColorAspects->primaries; }
+
+ int range() const { return mColorAspects->range; }
+
+ int transfer() const { return mColorAspects->transfer; }
+
+
private:
std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
@@ -404,10 +411,11 @@
}
void C2GoldfishHevcDec::decodeHeaderAfterFlush() {
- if (mContext && !mCsd0.empty() && !mCsd1.empty()) {
+ DDD("calling %s", __func__);
+ if (mContext && !mCsd0.empty()) {
mContext->decodeFrame(&(mCsd0[0]), mCsd0.size(), 0);
- mContext->decodeFrame(&(mCsd1[0]), mCsd1.size(), 0);
- DDD("resending csd0 and csd1");
+ DDD("resending csd0");
+ DDD("calling %s success", __func__);
}
}
@@ -447,6 +455,30 @@
return C2_OK;
}
+void C2GoldfishHevcDec::sendMetadata() {
+ // compare and send if changed
+ MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
+ currentMetaData.primaries = mIntf->primaries();
+ currentMetaData.range = mIntf->range();
+ currentMetaData.transfer = mIntf->transfer();
+
+ DDD("metadata primaries %d range %d transfer %d",
+ (int)(currentMetaData.primaries),
+ (int)(currentMetaData.range),
+ (int)(currentMetaData.transfer)
+ );
+
+ if (mSentMetadata.primaries == currentMetaData.primaries &&
+ mSentMetadata.range == currentMetaData.range &&
+ mSentMetadata.transfer == currentMetaData.transfer) {
+ DDD("metadata is the same, no need to update");
+ return;
+ }
+ std::swap(mSentMetadata, currentMetaData);
+
+ mContext->sendMetadata(&(mSentMetadata));
+}
+
status_t C2GoldfishHevcDec::createDecoder() {
DDD("creating hevc context now w %d h %d", mWidth, mHeight);
@@ -874,9 +906,6 @@
if (mCsd0.empty()) {
mCsd0.assign(mInPBuffer, mInPBuffer + mInPBufferSize);
DDD("assign to csd0 with %d bytpes", mInPBufferSize);
- } else if (mCsd1.empty()) {
- mCsd1.assign(mInPBuffer, mInPBuffer + mInPBufferSize);
- DDD("assign to csd1 with %d bytpes", mInPBufferSize);
}
// this is not really a valid pts from config
removePts(mPts);
@@ -885,7 +914,15 @@
bool whChanged = false;
if (GoldfishHevcHelper::isVpsFrame(mInPBuffer, mInPBufferSize)) {
mHevcHelper.reset(new GoldfishHevcHelper(mWidth, mHeight));
- whChanged = mHevcHelper->decodeHeader(mInPBuffer, mInPBufferSize);
+ bool headerStatus = true;
+ whChanged = mHevcHelper->decodeHeader(
+ mInPBuffer, mInPBufferSize, headerStatus);
+ if (!headerStatus) {
+ mSignalledError = true;
+ work->workletsProcessed = 1u;
+ work->result = C2_CORRUPTED;
+ return;
+ }
if (whChanged) {
DDD("w changed from old %d to new %d\n", mWidth, mHevcHelper->getWidth());
DDD("h changed from old %d to new %d\n", mHeight, mHevcHelper->getHeight());
@@ -922,6 +959,8 @@
} // end of whChanged
} // end of isVpsFrame
+ sendMetadata();
+
uint32_t delay;
GETTIME(&mTimeStart, nullptr);
TIME_DIFF(mTimeEnd, mTimeStart, delay);
diff --git a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
index fe080cf..bc3d65b 100644
--- a/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
+++ b/system/codecs/c2/decoders/hevcdec/C2GoldfishHevcDec.h
@@ -142,6 +142,10 @@
}
} mBitstreamColorAspects;
+ MetaDataColorAspects mSentMetadata = {1, 0, 0, 0};
+
+ void sendMetadata();
+
// profile
struct timeval mTimeStart;
struct timeval mTimeEnd;
diff --git a/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp
index 1b93a0d..d3117a7 100644
--- a/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp
+++ b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.cpp
@@ -188,7 +188,9 @@
}
}
-bool GoldfishHevcHelper::decodeHeader(const uint8_t *frame, int inSize) {
+bool GoldfishHevcHelper::decodeHeader(const uint8_t *frame, int inSize,
+ bool &helperstatus) {
+ helperstatus = true;
// should we check the header for vps/sps/pps frame ? otherwise
// there is no point calling decoder
if (!isVpsFrame(frame, inSize)) {
@@ -220,6 +222,8 @@
ALOGE("failed to call decoder function for header\n");
ALOGE("error in %s: 0x%x", __func__,
ps_decode_op->u4_error_code);
+ helperstatus = false;
+ return false;
}
if (IVD_RES_CHANGED == (ps_decode_op->u4_error_code & IVD_ERROR_MASK)) {
diff --git a/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h
index 09de830..36a496b 100644
--- a/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h
+++ b/system/codecs/c2/decoders/hevcdec/GoldfishHevcHelper.h
@@ -37,9 +37,9 @@
public:
// return true if decoding finds out w/h changed;
// otherwise false
- bool decodeHeader(const uint8_t *frame, int inSize);
- int getWidth() const { return mWidth; }
- int getHeight() const { return mHeight; }
+ bool decodeHeader(const uint8_t *frame, int inSize, bool &status);
+ int getWidth() const { return mWidth; }
+ int getHeight() const { return mHeight; }
private:
void createDecoder();
diff --git a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp
index bb2fbfa..f1bc356 100644
--- a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp
+++ b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.cpp
@@ -126,6 +126,22 @@
return res;
}
+void MediaHevcDecoder::sendMetadata(MetaDataColorAspects *ptr) {
+ DDD("send metadata to host %p", ptr);
+ if (!mHasAddressSpaceMemory) {
+ ALOGE("%s no address space memory", __func__);
+ return;
+ }
+ MetaDataColorAspects& meta = *ptr;
+ auto transport = GoldfishMediaTransport::getInstance();
+ transport->writeParam((uint64_t)mHostHandle, 0, mAddressOffSet);
+ transport->writeParam(meta.type, 1, mAddressOffSet);
+ transport->writeParam(meta.primaries, 2, mAddressOffSet);
+ transport->writeParam(meta.range, 3, mAddressOffSet);
+ transport->writeParam(meta.transfer, 4, mAddressOffSet);
+ transport->sendOperation(MediaCodecType::HevcCodec, MediaOperation::SendMetadata, mAddressOffSet);
+}
+
void MediaHevcDecoder::flush() {
if (!mHasAddressSpaceMemory) {
ALOGE("%s no address space memory", __func__);
diff --git a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h
index 8dfb0cf..878950e 100644
--- a/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h
+++ b/system/codecs/c2/decoders/hevcdec/MediaHevcDecoder.h
@@ -17,6 +17,8 @@
#ifndef GOLDFISH_MEDIA_Hevc_DEC_H_
#define GOLDFISH_MEDIA_Hevc_DEC_H_
+#include "goldfish_media_utils.h"
+
struct hevc_init_result_t {
uint64_t host_handle;
int ret;
@@ -89,5 +91,8 @@
// ask host to render to hostColorBufferId, return only image metadata back
// to guest
hevc_image_t renderOnHostAndReturnImageMetadata(int hostColorBufferId);
+
+ void sendMetadata(MetaDataColorAspects *ptr);
+
};
#endif
diff --git a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
index 99f0469..be6428e 100644
--- a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
+++ b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.cpp
@@ -324,6 +324,12 @@
int height() const { return mSize->height; }
+ int primaries() const { return mDefaultColorAspects->primaries; }
+
+ int range() const { return mDefaultColorAspects->range; }
+
+ int transfer() const { return mDefaultColorAspects->transfer; }
+
static C2R Hdr10PlusInfoInputSetter(bool mayBlock,
C2P<C2StreamHdr10PlusInfo::input> &me) {
(void)mayBlock;
@@ -416,6 +422,30 @@
void C2GoldfishVpxDec::onRelease() { destroyDecoder(); }
+void C2GoldfishVpxDec::sendMetadata() {
+ // compare and send if changed
+ MetaDataColorAspects currentMetaData = {1, 0, 0, 0};
+ currentMetaData.primaries = mIntf->primaries();
+ currentMetaData.range = mIntf->range();
+ currentMetaData.transfer = mIntf->transfer();
+
+ DDD("metadata primaries %d range %d transfer %d",
+ (int)(currentMetaData.primaries),
+ (int)(currentMetaData.range),
+ (int)(currentMetaData.transfer)
+ );
+
+ if (mSentMetadata.primaries == currentMetaData.primaries &&
+ mSentMetadata.range == currentMetaData.range &&
+ mSentMetadata.transfer == currentMetaData.transfer) {
+ DDD("metadata is the same, no need to update");
+ return;
+ }
+ std::swap(mSentMetadata, currentMetaData);
+
+ vpx_codec_send_metadata(mCtx, &(mSentMetadata));
+}
+
c2_status_t C2GoldfishVpxDec::onFlush_sm() {
if (mFrameParallelMode) {
// Flush decoder by passing nullptr data ptr and 0 size.
@@ -609,6 +639,8 @@
}
}
+ sendMetadata();
+
if (inSize) {
uint8_t *bitstream = const_cast<uint8_t *>(rView.data() + inOffset);
vpx_codec_err_t err = vpx_codec_decode(
diff --git a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h
index 4b356da..738d9fc 100644
--- a/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h
+++ b/system/codecs/c2/decoders/vpxdec/C2GoldfishVpxDec.h
@@ -16,6 +16,7 @@
#pragma once
+#include "goldfish_media_utils.h"
#include "goldfish_vpx_defs.h"
#include <SimpleC2Component.h>
@@ -95,6 +96,9 @@
const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work);
+ MetaDataColorAspects mSentMetadata = {1, 0, 0, 0};
+ void sendMetadata();
+
C2_DO_NOT_COPY(C2GoldfishVpxDec);
};
diff --git a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h
index bbcc805..1be05c9 100644
--- a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h
+++ b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_defs.h
@@ -61,4 +61,6 @@
int vpx_codec_decode(vpx_codec_ctx_t *ctx, const uint8_t *data,
unsigned int data_sz, void *user_priv, long deadline);
+void vpx_codec_send_metadata(vpx_codec_ctx_t *ctx, void*ptr);
+
#endif // MY_VPX_DEFS_H_
diff --git a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp
index d008efe..e1fa879 100644
--- a/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp
+++ b/system/codecs/c2/decoders/vpxdec/goldfish_vpx_impl.cpp
@@ -142,6 +142,17 @@
return &(ctx->myImg);
}
+void vpx_codec_send_metadata(vpx_codec_ctx_t *ctx, void *ptr) {
+ MetaDataColorAspects& meta = *(MetaDataColorAspects*)ptr;
+ auto transport = GoldfishMediaTransport::getInstance();
+ transport->writeParam(ctx->id, 0, ctx->address_offset);
+ transport->writeParam(meta.type, 1, ctx->address_offset);
+ transport->writeParam(meta.primaries, 2, ctx->address_offset);
+ transport->writeParam(meta.range, 3, ctx->address_offset);
+ transport->writeParam(meta.transfer, 4, ctx->address_offset);
+ sendVpxOperation(ctx, MediaOperation::SendMetadata);
+}
+
int vpx_codec_flush(vpx_codec_ctx_t *ctx) {
DDD("%s %d", __func__, __LINE__);
if (!ctx) {
diff --git a/system/hwc2/Android.mk b/system/hwc2/Android.mk
index b53456c..f2c4f25 100644
--- a/system/hwc2/Android.mk
+++ b/system/hwc2/Android.mk
@@ -58,6 +58,7 @@
emulator_hwcomposer_relative_path := hw
emulator_hwcomposer2_src_files := \
+ ClientComposer.cpp \
Common.cpp \
Device.cpp \
Display.cpp \
diff --git a/system/hwc2/ClientComposer.cpp b/system/hwc2/ClientComposer.cpp
new file mode 100644
index 0000000..211667b
--- /dev/null
+++ b/system/hwc2/ClientComposer.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ClientComposer.h"
+
+#include "Device.h"
+#include "Display.h"
+#include "Drm.h"
+#include "Layer.h"
+
+namespace android {
+
+ClientComposer::ClientComposer(DrmPresenter* drmPresenter)
+ : mDrmPresenter(drmPresenter) {}
+
+HWC2::Error ClientComposer::init() {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onDisplayCreate(Display* display) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ // Ensure created.
+ mDisplayInfos.emplace(displayId, DisplayInfo{});
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onDisplayDestroy(Display* display) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it == mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+ displayId);
+ return HWC2::Error::BadDisplay;
+ }
+
+ mDisplayInfos.erase(it);
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onDisplayClientTargetSet(Display* display) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto it = mDisplayInfos.find(displayId);
+ if (it == mDisplayInfos.end()) {
+ ALOGE("%s: display:%" PRIu64 " missing display buffers?", __FUNCTION__,
+ displayId);
+ return HWC2::Error::BadDisplay;
+ }
+
+ DisplayInfo& displayInfo = it->second;
+
+ auto clientTargetNativeBuffer = display->getClientTarget().getBuffer();
+ auto clientTargetDrmBuffer =
+ std::make_unique<DrmBuffer>(clientTargetNativeBuffer, mDrmPresenter);
+ if (!clientTargetDrmBuffer) {
+ ALOGE("%s: display:%" PRIu64 " failed to create client target drm buffer",
+ __FUNCTION__, displayId);
+ return HWC2::Error::NoResources;
+ }
+
+ displayInfo.clientTargetDrmBuffer = std::move(clientTargetDrmBuffer);
+
+ return HWC2::Error::None;
+}
+
+HWC2::Error ClientComposer::onActiveConfigChange(Display*) {
+ DEBUG_LOG("%s", __FUNCTION__);
+
+ return HWC2::Error::None;
+};
+
+HWC2::Error ClientComposer::validateDisplay(
+ Display* display, std::unordered_map<hwc2_layer_t, HWC2::Composition>* changes) {
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+ (void)displayId;
+
+ const std::vector<Layer*>& layers = display->getOrderedLayers();
+
+ for (Layer* layer : layers) {
+ const auto layerId = layer->getId();
+ const auto layerCompositionType = layer->getCompositionType();
+
+ if (layerCompositionType != HWC2::Composition::Client) {
+ (*changes)[layerId] = HWC2::Composition::Client;
+ }
+ }
+
+ return HWC2::Error::None;
+}
+
+std::tuple<HWC2::Error, base::unique_fd> ClientComposer::presentDisplay(
+ Display* display) {
+ ATRACE_CALL();
+
+ const auto displayId = display->getId();
+ DEBUG_LOG("%s display:%" PRIu64, __FUNCTION__, displayId);
+
+ auto displayInfoIt = mDisplayInfos.find(displayId);
+ if (displayInfoIt == mDisplayInfos.end()) {
+ ALOGE("%s: failed to find display buffers for display:%" PRIu64,
+ __FUNCTION__, displayId);
+ return std::make_tuple(HWC2::Error::BadDisplay, base::unique_fd());
+ }
+
+ DisplayInfo& displayInfo = displayInfoIt->second;
+
+ auto clientTargetFence = display->getClientTarget().getFence();
+
+ auto [error, presentFence] =
+ displayInfo.clientTargetDrmBuffer->flushToDisplay(
+ static_cast<int>(displayId), clientTargetFence);
+ if (error != HWC2::Error::None) {
+ ALOGE("%s: display:%" PRIu64 " failed to flush drm buffer" PRIu64,
+ __FUNCTION__, displayId);
+ return std::make_tuple(error, base::unique_fd());
+ }
+
+ return std::make_tuple(HWC2::Error::None, std::move(presentFence));
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/system/hwc2/ClientComposer.h b/system/hwc2/ClientComposer.h
new file mode 100644
index 0000000..58d4cce
--- /dev/null
+++ b/system/hwc2/ClientComposer.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HWC_CLIENTCOMPOSER_H
+#define ANDROID_HWC_CLIENTCOMPOSER_H
+
+#include <unordered_map>
+
+#include "Common.h"
+#include "Composer.h"
+#include "Display.h"
+#include "DrmPresenter.h"
+#include "Layer.h"
+
+namespace android {
+
+class ClientComposer : public Composer {
+ public:
+ ClientComposer(DrmPresenter* drmPresenter);
+
+ ClientComposer(const ClientComposer&) = delete;
+ ClientComposer& operator=(const ClientComposer&) = delete;
+
+ ClientComposer(ClientComposer&&) = delete;
+ ClientComposer& operator=(ClientComposer&&) = delete;
+
+ HWC2::Error init() override;
+
+ HWC2::Error onDisplayCreate(Display*) override;
+
+ HWC2::Error onDisplayDestroy(Display*) override;
+
+ HWC2::Error onDisplayClientTargetSet(Display*) override;
+
+ HWC2::Error onActiveConfigChange(Display*) override;
+
+ // Determines if this composer can compose the given layers on the given
+ // display and requests changes for layers that can't not be composed.
+ HWC2::Error validateDisplay(
+ Display* display, std::unordered_map<hwc2_layer_t, HWC2::Composition>*
+ outLayerCompositionChanges) override;
+
+ // Performs the actual composition of layers and presents the composed result
+ // to the display.
+ std::tuple<HWC2::Error, base::unique_fd> presentDisplay(
+ Display* display) override;
+
+ private:
+ struct DisplayInfo {
+ std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;
+ };
+
+ std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
+
+ DrmPresenter* mDrmPresenter = nullptr;
+};
+
+} // namespace android
+
+#endif
\ No newline at end of file
diff --git a/system/hwc2/Common.cpp b/system/hwc2/Common.cpp
index 3e465c2..021d032 100644
--- a/system/hwc2/Common.cpp
+++ b/system/hwc2/Common.cpp
@@ -31,3 +31,7 @@
bool IsNoOpMode() {
return android::base::GetProperty("ro.vendor.hwcomposer.mode", "") == "noop";
}
+
+bool IsClientCompositionMode() {
+ return android::base::GetProperty("ro.vendor.hwcomposer.mode", "") == "client";
+}
diff --git a/system/hwc2/Common.h b/system/hwc2/Common.h
index b0e0770..f13553b 100644
--- a/system/hwc2/Common.h
+++ b/system/hwc2/Common.h
@@ -45,5 +45,6 @@
bool IsCuttlefish();
bool IsCuttlefishFoldable();
bool IsNoOpMode();
+bool IsClientCompositionMode();
#endif
diff --git a/system/hwc2/Device.cpp b/system/hwc2/Device.cpp
index 1be15b3..f49905d 100644
--- a/system/hwc2/Device.cpp
+++ b/system/hwc2/Device.cpp
@@ -18,6 +18,7 @@
#include <android-base/properties.h>
+#include "ClientComposer.h"
#include "DisplayFinder.h"
#include "GuestComposer.h"
#include "HostComposer.h"
@@ -78,6 +79,9 @@
if (IsNoOpMode()) {
DEBUG_LOG("%s: using NoOpComposer", __FUNCTION__);
mComposer = std::make_unique<NoOpComposer>();
+ } else if (IsClientCompositionMode()) {
+ DEBUG_LOG("%s: using ClientComposer", __FUNCTION__);
+ mComposer = std::make_unique<ClientComposer>(mDrmPresenter.get());
} else if (ShouldUseGuestComposer()) {
DEBUG_LOG("%s: using GuestComposer", __FUNCTION__);
mComposer = std::make_unique<GuestComposer>(mDrmPresenter.get());
diff --git a/system/hwc2/DisplayFinder.cpp b/system/hwc2/DisplayFinder.cpp
index a55a49d..2016c4b 100644
--- a/system/hwc2/DisplayFinder.cpp
+++ b/system/hwc2/DisplayFinder.cpp
@@ -110,7 +110,7 @@
rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_HEIGHT), //
rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_XDPI), //
rcEnc->rcGetFBDisplayConfigsParam(rcEnc, configId, FB_YDPI), //
- getVsyncForDisplay(drmPresenter, configId) //
+ getVsyncForDisplay(drmPresenter, display.displayId) //
));
}
} else {
diff --git a/system/hwc2/HostComposer.cpp b/system/hwc2/HostComposer.cpp
index 5bf324e..472e782 100644
--- a/system/hwc2/HostComposer.cpp
+++ b/system/hwc2/HostComposer.cpp
@@ -570,7 +570,7 @@
display->clearReleaseFencesAndIdsLocked();
if (numLayer == 0) {
- ALOGW(
+ ALOGV(
"%s display has no layers to compose, flushing client target buffer.",
__FUNCTION__);
diff --git a/system/hwc3/ClientFrameComposer.cpp b/system/hwc3/ClientFrameComposer.cpp
index d7f8b55..284a46f 100644
--- a/system/hwc3/ClientFrameComposer.cpp
+++ b/system/hwc3/ClientFrameComposer.cpp
@@ -146,6 +146,11 @@
}
DisplayInfo& displayInfo = displayInfoIt->second;
+ if (!displayInfo.clientTargetDrmBuffer) {
+ ALOGW("%s: display:%" PRIu64 " no client target set, nothing to present.",
+ __FUNCTION__, displayId);
+ return HWC3::Error::None;
+ }
::android::base::unique_fd fence = display->getClientTarget().getFence();
diff --git a/system/hwc3/ClientFrameComposer.h b/system/hwc3/ClientFrameComposer.h
index 3fb0ba8..28199b3 100644
--- a/system/hwc3/ClientFrameComposer.h
+++ b/system/hwc3/ClientFrameComposer.h
@@ -64,9 +64,13 @@
std::unordered_map<int64_t, ::android::base::unique_fd>* outLayerFences)
override;
+ const DrmPresenter* getDrmPresenter() const override {
+ return &mDrmPresenter;
+ }
+
private:
struct DisplayInfo {
- std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;;
+ std::shared_ptr<DrmBuffer> clientTargetDrmBuffer;
};
std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/Common.cpp b/system/hwc3/Common.cpp
index 497f764..e9ac507 100644
--- a/system/hwc3/Common.cpp
+++ b/system/hwc3/Common.cpp
@@ -30,18 +30,34 @@
std::string::npos;
}
-bool IsNoOpMode() {
+bool IsInNoOpCompositionMode() {
const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
return mode == "noop";
}
-bool IsClientCompositionMode() {
+bool IsInClientCompositionMode() {
const std::string mode = ::android::base::GetProperty("ro.vendor.hwcomposer.mode", "");
DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.mode is %s", __FUNCTION__, mode.c_str());
return mode == "client";
}
+bool IsInNoOpDisplayFinderMode() {
+ const std::string mode =
+ ::android::base::GetProperty("ro.vendor.hwcomposer.display_finder_mode", "");
+ DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.display_finder_mode is %s",
+ __FUNCTION__, mode.c_str());
+ return mode == "noop";
+}
+
+bool IsInDrmDisplayFinderMode() {
+ const std::string mode =
+ ::android::base::GetProperty("ro.vendor.hwcomposer.display_finder_mode", "");
+ DEBUG_LOG("%s: sysprop ro.vendor.hwcomposer.display_finder_mode is %s",
+ __FUNCTION__, mode.c_str());
+ return mode == "drm";
+}
+
std::string toString(HWC3::Error error) {
switch (error) {
case HWC3::Error::None:
diff --git a/system/hwc3/Common.h b/system/hwc3/Common.h
index 5b6587e..493e5d0 100644
--- a/system/hwc3/Common.h
+++ b/system/hwc3/Common.h
@@ -44,8 +44,12 @@
bool IsCuttlefish();
bool IsCuttlefishFoldable();
-bool IsNoOpMode();
-bool IsClientCompositionMode();
+
+bool IsInNoOpCompositionMode();
+bool IsInClientCompositionMode();
+
+bool IsInNoOpDisplayFinderMode();
+bool IsInDrmDisplayFinderMode();
namespace HWC3 {
enum class Error : int32_t {
diff --git a/system/hwc3/ComposerClient.cpp b/system/hwc3/ComposerClient.cpp
index db05383..2098435 100644
--- a/system/hwc3/ComposerClient.cpp
+++ b/system/hwc3/ComposerClient.cpp
@@ -1237,7 +1237,7 @@
std::vector<DisplayMultiConfigs> displays;
- HWC3::Error error = findDisplays(displays);
+ HWC3::Error error = findDisplays(mComposer->getDrmPresenter(), &displays);
if (error != HWC3::Error::None) {
ALOGE("%s failed to find display configs", __FUNCTION__);
return error;
diff --git a/system/hwc3/Device.cpp b/system/hwc3/Device.cpp
index cf4be42..894d48b 100644
--- a/system/hwc3/Device.cpp
+++ b/system/hwc3/Device.cpp
@@ -94,10 +94,10 @@
std::unique_lock<std::mutex> lock(mMutex);
if (mComposer == nullptr) {
- if (IsNoOpMode()) {
+ if (IsInNoOpCompositionMode()) {
DEBUG_LOG("%s: using NoOpFrameComposer", __FUNCTION__);
mComposer = std::make_unique<NoOpFrameComposer>();
- } else if (IsClientCompositionMode()) {
+ } else if (IsInClientCompositionMode()) {
DEBUG_LOG("%s: using ClientFrameComposer", __FUNCTION__);
mComposer = std::make_unique<ClientFrameComposer>();
} else if (shouldUseGuestComposer()) {
diff --git a/system/hwc3/DisplayFinder.cpp b/system/hwc3/DisplayFinder.cpp
index 8e252cb..10bd5fd 100644
--- a/system/hwc3/DisplayFinder.cpp
+++ b/system/hwc3/DisplayFinder.cpp
@@ -31,7 +31,7 @@
return 1000 * 1000 * 1000 / hertz;
}
-HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC3::Error findCuttlefishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
DEBUG_LOG("%s", __FUNCTION__);
// TODO: replace with initializing directly from DRM info.
@@ -55,7 +55,7 @@
vsyncPeriodNanos),
},
};
- displays.push_back(display);
+ outDisplays->push_back(display);
++displayId;
}
@@ -79,7 +79,7 @@
}
HWC3::Error findGoldfishPrimaryDisplay(
- std::vector<DisplayMultiConfigs>& displays) {
+ std::vector<DisplayMultiConfigs>* outDisplays) {
DEBUG_LOG("%s", __FUNCTION__);
DEFINE_AND_VALIDATE_HOST_CONNECTION
@@ -118,13 +118,13 @@
}
hostCon->unlock();
- displays.push_back(display);
+ outDisplays->push_back(display);
return HWC3::Error::None;
}
HWC3::Error findGoldfishSecondaryDisplays(
- std::vector<DisplayMultiConfigs>& displays) {
+ std::vector<DisplayMultiConfigs>* outDisplays) {
DEBUG_LOG("%s", __FUNCTION__);
static constexpr const char kExternalDisplayProp[] =
@@ -170,7 +170,7 @@
/*dpiYh=*/propIntParts[3], //
/*vsyncPeriod=*/HertzToPeriodNanos(160) //
));
- displays.push_back(display);
+ outDisplays->push_back(display);
++secondaryDisplayId;
@@ -180,14 +180,14 @@
return HWC3::Error::None;
}
-HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>& displays) {
- HWC3::Error error = findGoldfishPrimaryDisplay(displays);
+HWC3::Error findGoldfishDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
+ HWC3::Error error = findGoldfishPrimaryDisplay(outDisplays);
if (error != HWC3::Error::None) {
ALOGE("%s failed to find Goldfish primary display", __FUNCTION__);
return error;
}
- error = findGoldfishSecondaryDisplays(displays);
+ error = findGoldfishSecondaryDisplays(outDisplays);
if (error != HWC3::Error::None) {
ALOGE("%s failed to find Goldfish secondary displays", __FUNCTION__);
}
@@ -197,8 +197,8 @@
// This is currently only used for Gem5 bring-up where virtio-gpu and drm
// are not currently available. For now, just return a placeholder display.
-HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>& displays) {
- displays.push_back(DisplayMultiConfigs{
+HWC3::Error findNoOpDisplays(std::vector<DisplayMultiConfigs>* outDisplays) {
+ outDisplays->push_back(DisplayMultiConfigs{
.displayId = 0,
.activeConfigId = 0,
.configs = {DisplayConfig(0,
@@ -213,16 +213,54 @@
return HWC3::Error::None;
}
+HWC3::Error findDrmDisplays(const DrmPresenter& drm,
+ std::vector<DisplayMultiConfigs>* outDisplays) {
+ outDisplays->clear();
+
+ std::vector<DrmPresenter::DisplayConfig> drmDisplayConfigs;
+
+ HWC3::Error error = drm.getDisplayConfigs(&drmDisplayConfigs);
+ if (error != HWC3::Error::None) {
+ ALOGE("%s failed to find displays from DRM.", __FUNCTION__);
+ return error;
+ }
+
+ for (const DrmPresenter::DisplayConfig drmDisplayConfig : drmDisplayConfigs) {
+ outDisplays->push_back(DisplayMultiConfigs{
+ .displayId = drmDisplayConfig.id,
+ .activeConfigId = static_cast<int32_t>(drmDisplayConfig.id),
+ .configs = {
+ DisplayConfig(static_cast<int32_t>(drmDisplayConfig.id),
+ drmDisplayConfig.width,
+ drmDisplayConfig.height,
+ drmDisplayConfig.dpiX,
+ drmDisplayConfig.dpiY,
+ HertzToPeriodNanos(drmDisplayConfig.refreshRateHz)),
+ },
+ });
+ }
+
+ return HWC3::Error::None;
+}
+
} // namespace
-HWC3::Error findDisplays(std::vector<DisplayMultiConfigs>& displays) {
+HWC3::Error findDisplays(const DrmPresenter* drm,
+ std::vector<DisplayMultiConfigs>* outDisplays) {
HWC3::Error error = HWC3::Error::None;
- if (IsNoOpMode()) {
- error = findNoOpDisplays(displays);
+ if (IsInNoOpCompositionMode()) {
+ error = findNoOpDisplays(outDisplays);
+ } else if (IsInDrmDisplayFinderMode()) {
+ if (drm == nullptr) {
+ ALOGE("%s asked to find displays from DRM, but DRM not available.",
+ __FUNCTION__);
+ return HWC3::Error::NoResources;
+ }
+ error = findDrmDisplays(*drm, outDisplays);
} else if (IsCuttlefish()) {
- error = findCuttlefishDisplays(displays);
+ error = findCuttlefishDisplays(outDisplays);
} else {
- error = findGoldfishDisplays(displays);
+ error = findGoldfishDisplays(outDisplays);
}
if (error != HWC3::Error::None) {
@@ -230,7 +268,7 @@
return error;
}
- for (auto& display : displays) {
+ for (auto& display : *outDisplays) {
DisplayConfig::addConfigGroups(&display.configs);
}
diff --git a/system/hwc3/DisplayFinder.h b/system/hwc3/DisplayFinder.h
index 8197a82..171d204 100644
--- a/system/hwc3/DisplayFinder.h
+++ b/system/hwc3/DisplayFinder.h
@@ -17,10 +17,12 @@
#ifndef ANDROID_HWC_DISPLAYFINDER_H
#define ANDROID_HWC_DISPLAYFINDER_H
+#include <optional>
#include <vector>
#include "Common.h"
#include "DisplayConfig.h"
+#include "DrmPresenter.h"
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -31,7 +33,8 @@
std::vector<DisplayConfig> configs;
};
-HWC3::Error findDisplays(std::vector<DisplayMultiConfigs>& displays);
+HWC3::Error findDisplays(const DrmPresenter* drm,
+ std::vector<DisplayMultiConfigs>* outDisplays);
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/DrmPresenter.cpp b/system/hwc3/DrmPresenter.cpp
index 6e13209..b512277 100644
--- a/system/hwc3/DrmPresenter.cpp
+++ b/system/hwc3/DrmPresenter.cpp
@@ -80,6 +80,18 @@
ALOGE("%s: Failed to initialize DRM backend", __FUNCTION__);
return HWC3::Error::NoResources;
}
+
+ constexpr const std::size_t kCachedBuffersPerDisplay = 3;
+ std::size_t numDisplays = 0;
+ for (const DrmConnector& connector : mConnectors) {
+ if (connector.connection == DRM_MODE_CONNECTED) {
+ ++numDisplays;
+ }
+ }
+ const std::size_t bufferCacheSize = kCachedBuffersPerDisplay * numDisplays;
+ DEBUG_LOG("%s: initializing DRM buffer cache to size %zu",
+ __FUNCTION__, bufferCacheSize);
+ mBufferCache = std::make_unique<DrmBufferCache>(bufferCacheSize);
}
mDrmEventListener = ::android::sp<DrmEventListener>::make(*this);
@@ -93,6 +105,31 @@
return HWC3::Error::None;
}
+HWC3::Error DrmPresenter::getDisplayConfigs(std::vector<DisplayConfig>* configs) const {
+ AutoReadLock lock(mStateMutex);
+
+ configs->clear();
+
+ for (uint32_t i = 0; i < mConnectors.size(); i++) {
+ const auto& connector = mConnectors[i];
+
+ if (connector.connection != DRM_MODE_CONNECTED) {
+ continue;
+ }
+
+ configs->emplace_back(DisplayConfig{
+ .id = i,
+ .width = connector.mMode.hdisplay,
+ .height = connector.mMode.vdisplay,
+ .dpiX = 160, //static_cast<uint32_t>(connector.dpiX),
+ .dpiY = 160, //static_cast<uint32_t>(connector.dpiY),
+ .refreshRateHz = connector.mRefreshRateAsInteger,
+ });
+ }
+
+ return HWC3::Error::None;
+}
+
HWC3::Error DrmPresenter::registerOnHotplugCallback(const HotplugCallback& cb) {
mHotplugCallback = cb;
return HWC3::Error::None;
@@ -322,54 +359,59 @@
mPlanes.clear();
}
-std::tuple<HWC3::Error, std::unique_ptr<DrmBuffer>> DrmPresenter::create(
+std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> DrmPresenter::create(
const native_handle_t* handle) {
- auto buffer = std::unique_ptr<DrmBuffer>(new DrmBuffer(*this));
-
cros_gralloc_handle* crosHandle = (cros_gralloc_handle*)handle;
if (crosHandle == nullptr) {
ALOGE("%s: invalid cros_gralloc_handle", __FUNCTION__);
- return std::make_tuple(HWC3::Error::NoResources,
- std::unique_ptr<DrmBuffer>());
+ return std::make_tuple(HWC3::Error::NoResources, nullptr);
}
+ DrmPrimeBufferHandle primeHandle = 0;
+ int ret = drmPrimeFDToHandle(mFd.get(), crosHandle->fds[0], &primeHandle);
+ if (ret) {
+ ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
+ strerror(errno), errno);
+ return std::make_tuple(HWC3::Error::NoResources, nullptr);
+ }
+
+ auto drmBufferPtr = mBufferCache->get(primeHandle);
+ if (drmBufferPtr != nullptr) {
+ return std::make_tuple(HWC3::Error::None,
+ std::shared_ptr<DrmBuffer>(*drmBufferPtr));
+ }
+
+ auto buffer = std::shared_ptr<DrmBuffer>(new DrmBuffer(*this));
buffer->mWidth = crosHandle->width;
buffer->mHeight = crosHandle->height;
buffer->mDrmFormat = crosHandle->format;
buffer->mPlaneFds[0] = crosHandle->fds[0];
+ buffer->mPlaneHandles[0] = primeHandle;
buffer->mPlanePitches[0] = crosHandle->strides[0];
buffer->mPlaneOffsets[0] = crosHandle->offsets[0];
- HWC3::Error error = createDrmFramebuffer(buffer.get());
- return std::make_tuple(error, std::move(buffer));
-}
-
-HWC3::Error DrmPresenter::createDrmFramebuffer(DrmBuffer* buffer) {
- int ret;
-
- ret = drmPrimeFDToHandle(mFd.get(), buffer->mPlaneFds[0],
- &buffer->mPlaneHandles[0]);
- if (ret) {
- ALOGE("%s: drmPrimeFDToHandle failed: %s (errno %d)", __FUNCTION__,
- strerror(errno), errno);
- return HWC3::Error::NoResources;
- }
-
uint32_t framebuffer = 0;
- ret = drmModeAddFB2(mFd.get(), buffer->mWidth, buffer->mHeight,
- buffer->mDrmFormat, buffer->mPlaneHandles,
- buffer->mPlanePitches, buffer->mPlaneOffsets,
- &framebuffer, 0);
+ ret = drmModeAddFB2(mFd.get(),
+ buffer->mWidth,
+ buffer->mHeight,
+ buffer->mDrmFormat,
+ buffer->mPlaneHandles,
+ buffer->mPlanePitches,
+ buffer->mPlaneOffsets,
+ &framebuffer,
+ 0);
if (ret) {
ALOGE("%s: drmModeAddFB2 failed: %s (errno %d)", __FUNCTION__,
strerror(errno), errno);
- return HWC3::Error::NoResources;
+ return std::make_tuple(HWC3::Error::NoResources, nullptr);
}
-
DEBUG_LOG("%s: created framebuffer:%" PRIu32, __FUNCTION__, framebuffer);
+ buffer->mDrmFramebuffer = framebuffer;
- buffer->mDrmFramebuffer.emplace(framebuffer);
- return HWC3::Error::None;
+ mBufferCache->set(primeHandle, std::shared_ptr<DrmBuffer>(buffer));
+
+ return std::make_tuple(HWC3::Error::None,
+ std::shared_ptr<DrmBuffer>(buffer));
}
HWC3::Error DrmPresenter::destroyDrmFramebuffer(DrmBuffer* buffer) {
@@ -391,6 +433,8 @@
strerror(errno), errno);
return HWC3::Error::NoResources;
}
+
+ mBufferCache->remove(buffer->mPlaneHandles[0]);
}
return HWC3::Error::None;
diff --git a/system/hwc3/DrmPresenter.h b/system/hwc3/DrmPresenter.h
index 61e546a..72e3f5a 100644
--- a/system/hwc3/DrmPresenter.h
+++ b/system/hwc3/DrmPresenter.h
@@ -29,6 +29,7 @@
#include <vector>
#include "Common.h"
+#include "LruCache.h"
#include "android/base/synchronization/AndroidLock.h"
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -60,7 +61,6 @@
uint32_t mPlaneHandles[4] = {0, 0, 0, 0};
uint32_t mPlanePitches[4] = {0, 0, 0, 0};
uint32_t mPlaneOffsets[4] = {0, 0, 0, 0};
-
std::optional<uint32_t> mDrmFramebuffer;
};
@@ -77,6 +77,17 @@
HWC3::Error init();
+ struct DisplayConfig {
+ uint32_t id;
+ uint32_t width;
+ uint32_t height;
+ uint32_t dpiX;
+ uint32_t dpiY;
+ uint32_t refreshRateHz;
+ };
+
+ HWC3::Error getDisplayConfigs(std::vector<DisplayConfig>* configs) const;
+
using HotplugCallback = std::function<void(bool /*connected*/, //
uint32_t /*id*/, //
uint32_t /*width*/, //
@@ -90,7 +101,7 @@
uint32_t refreshRate() const { return mConnectors[0].mRefreshRateAsInteger; }
- std::tuple<HWC3::Error, std::unique_ptr<DrmBuffer>> create(
+ std::tuple<HWC3::Error, std::shared_ptr<DrmBuffer>> create(
const native_handle_t* handle);
std::tuple<HWC3::Error, ::android::base::unique_fd> flushToDisplay(
@@ -100,9 +111,13 @@
std::optional<std::vector<uint8_t>> getEdid(uint32_t id);
private:
- // Grant visibility for createDrmFramebuffer and clearDrmFB to DrmBuffer.
+ // TODO: make this cache per display when enabling hotplug support.
+ using DrmPrimeBufferHandle = uint32_t;
+ using DrmBufferCache = LruCache<DrmPrimeBufferHandle, std::shared_ptr<DrmBuffer>>;
+ std::unique_ptr<DrmBufferCache> mBufferCache;
+
+ // Grant visibility to destroyDrmFramebuffer to DrmBuffer.
friend class DrmBuffer;
- HWC3::Error createDrmFramebuffer(DrmBuffer* buffer);
HWC3::Error destroyDrmFramebuffer(DrmBuffer* buffer);
// Grant visibility for handleHotplug to DrmEventListener.
@@ -117,7 +132,7 @@
std::optional<HotplugCallback> mHotplugCallback;
// Protects access to the below drm structs.
- ::android::base::guest::ReadWriteLock mStateMutex;
+ mutable ::android::base::guest::ReadWriteLock mStateMutex;
struct DrmPlane {
uint32_t mId = -1;
diff --git a/system/hwc3/FrameComposer.h b/system/hwc3/FrameComposer.h
index fdb6db3..794855b 100644
--- a/system/hwc3/FrameComposer.h
+++ b/system/hwc3/FrameComposer.h
@@ -26,6 +26,7 @@
#include "Common.h"
#include "DisplayChanges.h"
+#include "DrmPresenter.h"
namespace aidl::android::hardware::graphics::composer3::impl {
@@ -68,6 +69,10 @@
outLayerFences) = 0;
virtual HWC3::Error onActiveConfigChange(Display* display) = 0;
+
+ virtual const DrmPresenter* getDrmPresenter() const {
+ return nullptr;
+ }
};
} // namespace aidl::android::hardware::graphics::composer3::impl
diff --git a/system/hwc3/GuestFrameComposer.h b/system/hwc3/GuestFrameComposer.h
index af46b3d..e37ff87 100644
--- a/system/hwc3/GuestFrameComposer.h
+++ b/system/hwc3/GuestFrameComposer.h
@@ -62,6 +62,10 @@
HWC3::Error onActiveConfigChange(Display* /*display*/) override;
+ const DrmPresenter* getDrmPresenter() const override {
+ return &mDrmPresenter;
+ }
+
private:
struct DisplayConfig {
int width;
@@ -91,7 +95,7 @@
// Additional per display buffer for the composition result.
buffer_handle_t compositionResultBuffer = nullptr;
- std::unique_ptr<DrmBuffer> compositionResultDrmBuffer;
+ std::shared_ptr<DrmBuffer> compositionResultDrmBuffer;
};
std::unordered_map<int64_t, DisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/HostFrameComposer.cpp b/system/hwc3/HostFrameComposer.cpp
index 7b090c2..f976e05 100644
--- a/system/hwc3/HostFrameComposer.cpp
+++ b/system/hwc3/HostFrameComposer.cpp
@@ -578,7 +578,7 @@
displayId, static_cast<int>(layers.size()));
if (numLayer == 0) {
- ALOGW(
+ ALOGV(
"%s display has no layers to compose, flushing client target buffer.",
__FUNCTION__);
diff --git a/system/hwc3/HostFrameComposer.h b/system/hwc3/HostFrameComposer.h
index e99e6f2..42eb43a 100644
--- a/system/hwc3/HostFrameComposer.h
+++ b/system/hwc3/HostFrameComposer.h
@@ -65,6 +65,13 @@
HWC3::Error onActiveConfigChange(Display* display) override;
+ const DrmPresenter* getDrmPresenter() const override {
+ if (mDrmPresenter) {
+ return &*mDrmPresenter;
+ }
+ return nullptr;
+ }
+
private:
HWC3::Error createHostComposerDisplayInfo(Display* display,
uint32_t hostDisplayId);
@@ -85,10 +92,10 @@
const native_handle_t* compositionResultBuffer = nullptr;
// Drm info for the additional composition result buffer.
- std::unique_ptr<DrmBuffer> compositionResultDrmBuffer;
+ std::shared_ptr<DrmBuffer> compositionResultDrmBuffer;
// Drm info for the displays client target buffer.
- std::unique_ptr<DrmBuffer> clientTargetDrmBuffer;
+ std::shared_ptr<DrmBuffer> clientTargetDrmBuffer;
};
std::unordered_map<int64_t, HostComposerDisplayInfo> mDisplayInfos;
diff --git a/system/hwc3/LruCache.h b/system/hwc3/LruCache.h
new file mode 100644
index 0000000..9ffca46
--- /dev/null
+++ b/system/hwc3/LruCache.h
@@ -0,0 +1,83 @@
+// Copyright 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <list>
+#include <unordered_map>
+
+template <typename Key, typename Value>
+class LruCache {
+ public:
+ LruCache(std::size_t maxSize) : m_maxSize(maxSize) {
+ m_table.reserve(maxSize);
+ }
+
+ Value* get(const Key& key) {
+ auto tableIt = m_table.find(key);
+ if (tableIt == m_table.end()) {
+ return nullptr;
+ }
+
+ // Move to front.
+ auto elementsIt = tableIt->second;
+ m_elements.splice(elementsIt, m_elements, m_elements.begin());
+ return &elementsIt->value;
+ }
+
+ void set(const Key& key, Value&& value) {
+ auto tableIt = m_table.find(key);
+ if (tableIt == m_table.end()) {
+ if (m_table.size() >= m_maxSize) {
+ auto& kv = m_elements.back();
+ m_table.erase(kv.key);
+ m_elements.pop_back();
+ }
+ } else {
+ auto elementsIt = tableIt->second;
+ m_elements.erase(elementsIt);
+ }
+ m_elements.emplace_front(KeyValue{
+ key,
+ std::forward<Value>(value),
+ });
+ m_table[key] = m_elements.begin();
+ }
+
+ void remove(const Key& key) {
+ auto tableIt = m_table.find(key);
+ if (tableIt == m_table.end()) {
+ return;
+ }
+ auto elementsIt = tableIt->second;
+ m_elements.erase(elementsIt);
+ m_table.erase(tableIt);
+ }
+
+ void clear() {
+ m_elements.clear();
+ m_table.clear();
+ }
+
+ private:
+ struct KeyValue {
+ Key key;
+ Value value;
+ };
+
+ const std::size_t m_maxSize;
+ // Front is the most recently used and back is the least recently used.
+ std::list<KeyValue> m_elements;
+ std::unordered_map<Key, typename std::list<KeyValue>::iterator> m_table;
+};
diff --git a/system/vulkan_enc/ResourceTracker.cpp b/system/vulkan_enc/ResourceTracker.cpp
index 6cc7010..c9a1606 100644
--- a/system/vulkan_enc/ResourceTracker.cpp
+++ b/system/vulkan_enc/ResourceTracker.cpp
@@ -6690,7 +6690,7 @@
}
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(__linux__)
- if (semInfo.syncFd >= 0) {
+ if (semInfo.syncFd != 0) {
pre_signal_sync_fds.push_back(semInfo.syncFd);
pre_signal_semaphores.push_back(pSubmits[i].pWaitSemaphores[j]);
}
@@ -6755,13 +6755,19 @@
#endif
#if defined(VK_USE_PLATFORM_ANDROID_KHR) || defined(__linux__)
for (auto fd : pre_signal_sync_fds) {
- preSignalTasks.push_back([fd] {
- sync_wait(fd, 3000);
- });
+ // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImportSemaphoreFdInfoKHR.html
+ // fd == -1 is treated as already signaled
+ if (fd != -1) {
+ preSignalTasks.push_back([fd] {
+ sync_wait(fd, 3000);
+ });
+ }
}
#endif
- auto waitGroupHandle = mWorkPool.schedule(preSignalTasks);
- mWorkPool.waitAll(waitGroupHandle);
+ if (!preSignalTasks.empty()) {
+ auto waitGroupHandle = mWorkPool.schedule(preSignalTasks);
+ mWorkPool.waitAll(waitGroupHandle);
+ }
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,