diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index cabc1773e0..563c9a90f0 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include @@ -36,8 +39,10 @@ #include #include #include +#include #endif +#include #include #include @@ -103,6 +108,37 @@ bool isInterceptorRegistrationOp(int op) { } } // namespace + // +#define GED_MAGIC 'g' +#define GED_BRIDGE_COMMAND_GPU_TIMESTAMP 103 +#define GED_IOWR(INDEX) _IOWR(GED_MAGIC, INDEX, GED_BRIDGE_PACKAGE) +#define GED_BRIDGE_IO_GPU_TIMESTAMP \ + GED_IOWR(GED_BRIDGE_COMMAND_GPU_TIMESTAMP) +typedef struct _GED_BRIDGE_PACKAGE { + unsigned int ui32FunctionID; + int i32Size; + void *pvParamIn; + int i32InBufferSize; + void *pvParamOut; + int i32OutBufferSize; +} GED_BRIDGE_PACKAGE; + +struct GED_BRIDGE_IN_GPU_TIMESTAMP { + int pid; + uint64_t ullWnd; + int32_t i32FrameID; + int fence_fd; + int QedBuffer_length; + int isSF; +}; + +struct GED_BRIDGE_OUT_GPU_TIMESTAMP { + int eError; + int is_ged_kpi_enabled; +}; + +static int doMtkGedKpi = 1; +static int ged_fd = -1; Surface::ProducerDeathListenerProxy::ProducerDeathListenerProxy(wp surfaceListener) : mSurfaceListener(surfaceListener) {} @@ -175,6 +211,43 @@ Surface::Surface(const sp& bufferProducer, bool controll mSwapIntervalZero = false; mMaxBufferCount = NUM_BUFFER_SLOTS; mSurfaceControlHandle = surfaceControlHandle; + + if (ged_fd == -1 && doMtkGedKpi == 1) { + ALOGE("Opening ged"); + ged_fd = open("/proc/ged", O_RDONLY); + ALOGE("Opening ged ret = %d", ged_fd); + { + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = 0, + //.ullWnd = (uint64_t)(intptr_t)this, + .ullWnd = 0, + .i32FrameID = 0, + .fence_fd = 0, + .isSF = 0, + .QedBuffer_length = 0, + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&in, 0, sizeof(in)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &out, + .i32OutBufferSize = sizeof(out), + }; + if (ged_fd >= 0) { + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGE("First null timestamp ioctl returned %d %d %d", ret, out.eError, out.is_ged_kpi_enabled); + if (out.is_ged_kpi_enabled != 1) { + ALOGE("is_ged_kpi_enabled reported disabled"); + doMtkGedKpi = 0; + } + } else { + ALOGE("No /proc/ged"); + } + } + } } Surface::~Surface() { @@ -754,6 +827,36 @@ int Surface::dequeueBuffer(sp* buffer, int* fenceFd) { } } + if (mGraphicBufferProducer != nullptr && ged_fd >= 0) { + uint64_t uniqueId; + mGraphicBufferProducer->getUniqueId(&uniqueId); + + const int32_t dupFenceFd = fence->isValid() ? fence->dup() : -1; + + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = mPid, + .ullWnd = uniqueId, + .i32FrameID = static_cast(reinterpret_cast(gbuf->handle)) & 0x3fffffff, + .fence_fd = dupFenceFd, + .isSF = mIsSurfaceFlinger ? 1 : 0, + .QedBuffer_length = -2, + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&out, 0, sizeof(out)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &out, + .i32OutBufferSize = sizeof(out), + }; + + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGV("GPU timestamp ioctl returned %d %d %d %d", ret, out.eError, out.is_ged_kpi_enabled, in.i32FrameID); + + close(dupFenceFd); + } if (fence->isValid()) { *fenceFd = fence->dup(); if (*fenceFd == -1) { @@ -1322,6 +1425,60 @@ void Surface::onBufferQueuedLocked(int slot, sp fence, } mQueueBufferCondition.broadcast(); + if (mGraphicBufferProducer != nullptr && ged_fd >= 0) { + sp& gbuf(mSlots[slot].buffer); + uint64_t uniqueId; + mGraphicBufferProducer->getUniqueId(&uniqueId); + + const int32_t dupFenceFd = fence->isValid() ? fence->dup() : -1; + // onQueue + { + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = mPid, + .ullWnd = uniqueId, + .i32FrameID = static_cast(reinterpret_cast(gbuf->handle)) & 0x3fffffff, + .fence_fd = dupFenceFd, + .isSF = mIsSurfaceFlinger ? 1 : 0, + .QedBuffer_length = static_cast(output.numPendingBuffers), + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&out, 0, sizeof(out)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &out, + .i32OutBufferSize = sizeof(out), + }; + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGV("GPU timestamp ioctl returned %d %d %d", ret, out.eError, in.i32FrameID); + } + // acquire + { + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = mPid, + .isSF = mIsSurfaceFlinger ? 1 : 0, + .ullWnd = uniqueId, + .i32FrameID = static_cast(reinterpret_cast(gbuf->handle)) & 0x3fffffff, + .fence_fd = dupFenceFd, + .QedBuffer_length = -1, + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&out, 0, sizeof(out)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &in, + .i32OutBufferSize = sizeof(out), + }; + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGV("GPU timestamp ioctl returned %d %d %d", ret, out.eError, in.i32FrameID); + } + close(dupFenceFd); + } if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) { static gui::FenceMonitor gpuCompletionThread("GPU completion"); @@ -2196,6 +2353,46 @@ int Surface::connect(int api, const sp& listener, bool reportBu SURF_LOGE_IF(idErr != NO_ERROR, "Unable to get ID from IGBP: %d", idErr); mIsConnected = true; } + + // For MTK GED KPI, we need to grab the Surface owner's PID + // and also know whether that owner is surfaceflinger + if (api == NATIVE_WINDOW_API_EGL && ged_fd >= 0) { + IPCThreadState *ipc = IPCThreadState::selfOrNull(); + const sp& token = IInterface::asBinder(mGraphicBufferProducer); + mPid = (token != NULL && NULL != token->localBinder()) + ? getpid() + : (ipc != nullptr)?ipc->getCallingPid():-1; + + // We've got caller PID. Now checking whether it is surfaceflinger + char cmdline[128]; + char path[128]; + snprintf(path, sizeof(path)-1, "/proc/%d/cmdline", mPid); + int fd = open(path, O_RDONLY); + read(fd, cmdline, sizeof(cmdline)-1); + // Normally cmdline is already \0-separated, but well + for(unsigned i=0; i mDequeuedSlots; + pid_t mPid; + bool mIsSurfaceFlinger; + // Indicates whether this surface holds the mouse cursor, and subsequently determines whether // the GRALLOC_USAGE_CURSOR usage flag should be set on the buffer created when this surface is // locked.