Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
197 changes: 197 additions & 0 deletions libs/gui/Surface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#include <deque>
#include <mutex>
#include <thread>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

#include <inttypes.h>

Expand All @@ -36,8 +39,10 @@
#include <gui/LayerState.h>
#include <private/gui/ComposerService.h>
#include <private/gui/ComposerServiceAIDL.h>
#include <binder/IPCThreadState.h>
#endif

#include <android-base/properties.h>
#include <android/native_window.h>

#include <android-base/strings.h>
Expand Down Expand Up @@ -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> surfaceListener)
: mSurfaceListener(surfaceListener) {}
Expand Down Expand Up @@ -175,6 +211,43 @@ Surface::Surface(const sp<IGraphicBufferProducer>& 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() {
Expand Down Expand Up @@ -754,6 +827,36 @@ int Surface::dequeueBuffer(sp<GraphicBuffer>* 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<int32_t>(reinterpret_cast<intptr_t>(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) {
Expand Down Expand Up @@ -1322,6 +1425,60 @@ void Surface::onBufferQueuedLocked(int slot, sp<Fence> fence,
}

mQueueBufferCondition.broadcast();
if (mGraphicBufferProducer != nullptr && ged_fd >= 0) {
sp<GraphicBuffer>& 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<int32_t>(reinterpret_cast<intptr_t>(gbuf->handle)) & 0x3fffffff,
.fence_fd = dupFenceFd,
.isSF = mIsSurfaceFlinger ? 1 : 0,
.QedBuffer_length = static_cast<int>(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<int32_t>(reinterpret_cast<intptr_t>(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");
Expand Down Expand Up @@ -2196,6 +2353,46 @@ int Surface::connect(int api, const sp<SurfaceListener>& 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<IBinder>& 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<sizeof(cmdline); i++)
if(cmdline[i] == '\n')
cmdline[i] = 0;
cmdline[sizeof(cmdline)-1] = 0;

close(fd);

// Truncate to last / (also called basename)
const char *c = strrchr(cmdline, '/');
if (c != nullptr) {
c = c+1;
} else {
c = cmdline;
}
if(strcmp(c, "surfaceflinger") == 0) {
ALOGE("is surfaceflinger = 1");
mIsSurfaceFlinger = true;
} else {
ALOGE("is surfaceflinger = 0");
mIsSurfaceFlinger = false;
}
}

if (!err && api == NATIVE_WINDOW_API_CPU) {
mConnectedToCpu = true;
// Clear the dirty region in case we're switching from a non-CPU API
Expand Down
3 changes: 3 additions & 0 deletions libs/gui/include/gui/Surface.h
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,9 @@ class Surface
// Buffers that are successfully dequeued/attached and handed to clients
std::unordered_set<int> 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.
Expand Down