Merge "Implement RS VSync on new vsync infrastructure."

This commit is contained in:
Jason Sams
2012-02-07 15:39:44 -08:00
committed by Android (Google) Code Review
15 changed files with 262 additions and 623 deletions

View File

@@ -623,7 +623,7 @@ nAllocationData2D_alloc(JNIEnv *_env, jobject _this, RsContext con,
jint srcAlloc, jint srcXoff, jint srcYoff,
jint srcMip, jint srcFace)
{
LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff, dstYoff,"
LOG_API("nAllocation2DData_s, con(%p), dstAlloc(%p), dstXoff(%i), dstYoff(%i),"
" dstMip(%i), dstFace(%i), width(%i), height(%i),"
" srcAlloc(%p), srcXoff(%i), srcYoff(%i), srcMip(%i), srcFace(%i)",
con, (RsAllocation)dstAlloc, dstXoff, dstYoff, dstMip, dstFace,

View File

@@ -89,7 +89,6 @@ LOCAL_SRC_FILES:= \
rsFifoSocket.cpp \
rsFileA3D.cpp \
rsFont.cpp \
rsLocklessFifo.cpp \
rsObjectBase.cpp \
rsMatrix2x2.cpp \
rsMatrix3x3.cpp \
@@ -128,7 +127,7 @@ LOCAL_SRC_FILES:= \
driver/rsdShaderCache.cpp \
driver/rsdVertexArray.cpp
LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc libbcinfo
LOCAL_SHARED_LIBRARIES += libz libcutils libutils libEGL libGLESv1_CM libGLESv2 libui libbcc libbcinfo libgui
LOCAL_STATIC_LIBRARIES := libdex libft2
@@ -196,7 +195,6 @@ LOCAL_SRC_FILES:= \
rsFifoSocket.cpp \
rsFileA3D.cpp \
rsFont.cpp \
rsLocklessFifo.cpp \
rsObjectBase.cpp \
rsMatrix2x2.cpp \
rsMatrix3x3.cpp \

View File

@@ -215,6 +215,8 @@ bool rsdGLInit(const Context *rsc) {
ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
checkEglError("eglGetConfigs", ret);
eglSwapInterval(dc->gl.egl.display, 0);
if (numConfigs) {
EGLConfig* const configs = new EGLConfig[numConfigs];

View File

@@ -115,6 +115,7 @@ ContextSetPriority {
}
ContextDestroyWorker {
sync
}
AssignName {

View File

@@ -18,6 +18,7 @@
#include "rsContext.h"
#include "rsThreadIO.h"
#include <ui/FramebufferNativeWindow.h>
#include <gui/DisplayEventReceiver.h>
#include <sys/types.h>
#include <sys/resource.h>
@@ -245,42 +246,55 @@ void * Context::threadProc(void *vrsc) {
}
rsc->mRunning = true;
bool mDraw = true;
bool doWait = true;
uint64_t targetTime = rsc->getTime();
while (!rsc->mExit) {
uint64_t waitTime = 0;
uint64_t now = rsc->getTime();
if (!doWait) {
if (now < targetTime) {
waitTime = targetTime - now;
doWait = true;
}
if (!rsc->mIsGraphicsContext) {
while (!rsc->mExit) {
rsc->mIO.playCoreCommands(rsc, true, -1);
}
} else {
#ifndef ANDROID_RS_SERIALIZE
DisplayEventReceiver displayEvent;
DisplayEventReceiver::Event eventBuffer[1];
#endif
int vsyncRate = 0;
int targetRate = 0;
mDraw |= rsc->mIO.playCoreCommands(rsc, doWait, waitTime);
mDraw &= (rsc->mRootScript.get() != NULL);
mDraw &= rsc->mHasSurface;
bool drawOnce = false;
while (!rsc->mExit) {
rsc->timerSet(RS_TIMER_IDLE);
if (mDraw && rsc->mIsGraphicsContext) {
uint64_t delay = rsc->runRootScript() * 1000000;
targetTime = rsc->getTime() + delay;
doWait = (delay == 0);
if (rsc->props.mLogVisual) {
rsc->displayDebugStats();
#ifndef ANDROID_RS_SERIALIZE
if (vsyncRate != targetRate) {
displayEvent.setVsyncRate(targetRate);
vsyncRate = targetRate;
}
if (targetRate) {
drawOnce |= rsc->mIO.playCoreCommands(rsc, true, displayEvent.getFd());
while (displayEvent.getEvents(eventBuffer, 1) != 0) {
//ALOGE("vs2 time past %lld", (rsc->getTime() - eventBuffer[0].header.timestamp) / 1000000);
}
} else
#endif
{
drawOnce |= rsc->mIO.playCoreCommands(rsc, true, -1);
}
mDraw = !rsc->mPaused;
rsc->timerSet(RS_TIMER_CLEAR_SWAP);
rsc->mHal.funcs.swap(rsc);
rsc->timerFrame();
rsc->timerSet(RS_TIMER_INTERNAL);
rsc->timerPrint();
rsc->timerReset();
} else {
doWait = true;
if ((rsc->mRootScript.get() != NULL) && rsc->mHasSurface &&
(targetRate || drawOnce) && !rsc->mPaused) {
drawOnce = false;
targetRate = ((rsc->runRootScript() + 15) / 16);
if (rsc->props.mLogVisual) {
rsc->displayDebugStats();
}
rsc->timerSet(RS_TIMER_CLEAR_SWAP);
rsc->mHal.funcs.swap(rsc);
rsc->timerFrame();
rsc->timerSet(RS_TIMER_INTERNAL);
rsc->timerPrint();
rsc->timerReset();
}
}
}
@@ -315,8 +329,8 @@ void Context::destroyWorkerThreadResources() {
mFBOCache.deinit(this);
}
ObjectBase::freeAllChildren(this);
//ALOGV("destroyWorkerThreadResources 2");
mExit = true;
//ALOGV("destroyWorkerThreadResources 2");
}
void Context::printWatchdogInfo(void *ctx) {
@@ -382,7 +396,7 @@ bool Context::initContext(Device *dev, const RsSurfaceConfig *sc) {
pthread_mutex_lock(&gInitMutex);
mIO.init();
mIO.setTimoutCallback(printWatchdogInfo, this, 2e9);
mIO.setTimeoutCallback(printWatchdogInfo, this, 2e9);
dev->addContext(this);
mDev = dev;
@@ -434,14 +448,12 @@ Context::~Context() {
ALOGV("%p Context::~Context", this);
if (!mIsContextLite) {
mIO.coreFlush();
rsAssert(mExit);
mExit = true;
mPaused = false;
void *res;
mIO.shutdown();
int status = pthread_join(mThreadId, &res);
rsAssert(mExit);
if (mHal.funcs.shutdownDriver) {
mHal.funcs.shutdownDriver(this);

View File

@@ -39,7 +39,6 @@
#include "rsFBOCache.h"
#include "rsgApiStructs.h"
#include "rsLocklessFifo.h"
// ---------------------------------------------------------------------------
namespace android {

View File

@@ -1,31 +0,0 @@
/*
* Copyright (C) 2011 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 "rsFifoSocket.h"
#include "utils/Timers.h"
#include "utils/StopWatch.h"
using namespace android;
using namespace android::renderscript;
Fifo::Fifo() {
}
Fifo::~Fifo() {
}

View File

@@ -35,9 +35,9 @@ protected:
virtual ~Fifo();
public:
void virtual writeAsync(const void *data, size_t bytes) = 0;
bool virtual writeAsync(const void *data, size_t bytes, bool waitForSpace = true) = 0;
void virtual writeWaitReturn(void *ret, size_t retSize) = 0;
size_t virtual read(void *data, size_t bytes) = 0;
size_t virtual read(void *data, size_t bytes, bool doWait = true, uint64_t timeToWait = 0) = 0;
void virtual readReturn(const void *data, size_t bytes) = 0;
void virtual flush() = 0;

View File

@@ -22,6 +22,7 @@
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <poll.h>
#include <sys/types.h>
#include <sys/socket.h>
@@ -29,55 +30,79 @@ using namespace android;
using namespace android::renderscript;
FifoSocket::FifoSocket() {
sequence = 1;
mShutdown = false;
}
FifoSocket::~FifoSocket() {
}
bool FifoSocket::init() {
bool FifoSocket::init(bool supportNonBlocking, bool supportReturnValues, size_t maxDataSize) {
int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
return false;
}
void FifoSocket::shutdown() {
mShutdown = true;
uint64_t d = 0;
::send(sv[0], &d, sizeof(d), 0);
::send(sv[1], &d, sizeof(d), 0);
close(sv[0]);
close(sv[1]);
}
void FifoSocket::writeAsync(const void *data, size_t bytes) {
bool FifoSocket::writeAsync(const void *data, size_t bytes, bool waitForSpace) {
if (bytes == 0) {
return;
return true;
}
//ALOGE("writeAsync %p %i", data, bytes);
size_t ret = ::send(sv[0], data, bytes, 0);
//ALOGE("writeAsync ret %i", ret);
rsAssert(ret == bytes);
return true;
}
void FifoSocket::writeWaitReturn(void *retData, size_t retBytes) {
if (mShutdown) {
return;
}
//ALOGE("writeWaitReturn %p %i", retData, retBytes);
size_t ret = ::recv(sv[0], retData, retBytes, 0);
size_t ret = ::recv(sv[0], retData, retBytes, MSG_WAITALL);
//ALOGE("writeWaitReturn %i", ret);
rsAssert(ret == retBytes);
}
size_t FifoSocket::read(void *data, size_t bytes) {
if (mShutdown) {
return 0;
}
//ALOGE("read %p %i", data, bytes);
size_t ret = ::recv(sv[1], data, bytes, 0);
rsAssert(ret == bytes);
//ALOGE("read ret %i", ret);
size_t ret = ::recv(sv[1], data, bytes, MSG_WAITALL);
rsAssert(ret == bytes || mShutdown);
//ALOGE("read ret %i bytes %i", ret, bytes);
if (mShutdown) {
ret = 0;
}
return ret;
}
bool FifoSocket::isEmpty() {
struct pollfd p;
p.fd = sv[1];
p.events = POLLIN;
int r = poll(&p, 1, 0);
//ALOGE("poll r=%i", r);
return r == 0;
}
void FifoSocket::readReturn(const void *data, size_t bytes) {
ALOGE("readReturn %p %Zu", data, bytes);
//ALOGE("readReturn %p %Zu", data, bytes);
size_t ret = ::send(sv[1], data, bytes, 0);
ALOGE("readReturn %Zu", ret);
rsAssert(ret == bytes);
}
void FifoSocket::flush() {
//ALOGE("readReturn %Zu", ret);
//rsAssert(ret == bytes);
}

View File

@@ -29,23 +29,23 @@ public:
FifoSocket();
virtual ~FifoSocket();
bool init();
bool init(bool supportNonBlocking = true,
bool supportReturnValues = true,
size_t maxDataSize = 0);
void shutdown();
bool writeAsync(const void *data, size_t bytes, bool waitForSpace = true);
void writeWaitReturn(void *ret, size_t retSize);
size_t read(void *data, size_t bytes);
void readReturn(const void *data, size_t bytes);
bool isEmpty();
void virtual writeAsync(const void *data, size_t bytes);
void virtual writeWaitReturn(void *ret, size_t retSize);
size_t virtual read(void *data, size_t bytes);
void virtual readReturn(const void *data, size_t bytes);
void virtual flush();
int getWriteFd() {return sv[0];}
int getReadFd() {return sv[1];}
protected:
int sv[2];
uint32_t sequence;
bool mShutdown;
};
}

View File

@@ -1,251 +0,0 @@
/*
* Copyright (C) 2009 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 "rsLocklessFifo.h"
#include "utils/Timers.h"
#include "utils/StopWatch.h"
using namespace android;
using namespace android::renderscript;
LocklessCommandFifo::LocklessCommandFifo() : mBuffer(0), mInitialized(false) {
mTimeoutCallback = NULL;
mTimeoutCallbackData = NULL;
mTimeoutWait = 0;
}
LocklessCommandFifo::~LocklessCommandFifo() {
if (!mInShutdown && mInitialized) {
shutdown();
}
if (mBuffer) {
free(mBuffer);
}
}
void LocklessCommandFifo::shutdown() {
mInShutdown = true;
mSignalToWorker.set();
}
bool LocklessCommandFifo::init(uint32_t sizeInBytes) {
// Add room for a buffer reset command
mBuffer = static_cast<uint8_t *>(malloc(sizeInBytes + 4));
if (!mBuffer) {
ALOGE("LocklessFifo allocation failure");
return false;
}
if (!mSignalToControl.init() || !mSignalToWorker.init()) {
ALOGE("Signal setup failed");
free(mBuffer);
return false;
}
mInShutdown = false;
mSize = sizeInBytes;
mPut = mBuffer;
mGet = mBuffer;
mEnd = mBuffer + (sizeInBytes) - 1;
//dumpState("init");
mInitialized = true;
return true;
}
uint32_t LocklessCommandFifo::getFreeSpace() const {
int32_t freeSpace = 0;
//dumpState("getFreeSpace");
if (mPut >= mGet) {
freeSpace = mEnd - mPut;
} else {
freeSpace = mGet - mPut;
}
if (freeSpace < 0) {
freeSpace = 0;
}
return freeSpace;
}
bool LocklessCommandFifo::isEmpty() const {
uint32_t p = android_atomic_acquire_load((int32_t *)&mPut);
return ((uint8_t *)p) == mGet;
}
void * LocklessCommandFifo::reserve(uint32_t sizeInBytes) {
// Add space for command header and loop token;
sizeInBytes += 8;
//dumpState("reserve");
if (getFreeSpace() < sizeInBytes) {
makeSpace(sizeInBytes);
}
return mPut + 4;
}
void LocklessCommandFifo::commit(uint32_t command, uint32_t sizeInBytes) {
if (mInShutdown) {
return;
}
//dumpState("commit 1");
reinterpret_cast<uint16_t *>(mPut)[0] = command;
reinterpret_cast<uint16_t *>(mPut)[1] = sizeInBytes;
int32_t s = ((sizeInBytes + 3) & ~3) + 4;
android_atomic_add(s, (int32_t *)&mPut);
//dumpState("commit 2");
mSignalToWorker.set();
}
void LocklessCommandFifo::commitSync(uint32_t command, uint32_t sizeInBytes) {
if (mInShutdown) {
return;
}
//char buf[1024];
//sprintf(buf, "RenderScript LocklessCommandFifo::commitSync %p %i %i", this, command, sizeInBytes);
//StopWatch compileTimer(buf);
commit(command, sizeInBytes);
flush();
}
void LocklessCommandFifo::flush() {
//dumpState("flush 1");
while (mPut != mGet) {
while (!mSignalToControl.wait(mTimeoutWait)) {
if (mTimeoutCallback) {
mTimeoutCallback(mTimeoutCallbackData);
}
}
}
//dumpState("flush 2");
}
void LocklessCommandFifo::setTimoutCallback(void (*cbk)(void *), void *data, uint64_t timeout) {
mTimeoutCallback = cbk;
mTimeoutCallbackData = data;
mTimeoutWait = timeout;
}
bool LocklessCommandFifo::wait(uint64_t timeout) {
while (isEmpty() && !mInShutdown) {
mSignalToControl.set();
return mSignalToWorker.wait(timeout);
}
return true;
}
const void * LocklessCommandFifo::get(uint32_t *command, uint32_t *bytesData, uint64_t timeout) {
while (1) {
//dumpState("get");
wait(timeout);
if (isEmpty() || mInShutdown) {
*command = 0;
*bytesData = 0;
return NULL;
}
*command = reinterpret_cast<const uint16_t *>(mGet)[0];
*bytesData = reinterpret_cast<const uint16_t *>(mGet)[1];
if (*command) {
// non-zero command is valid
return mGet+4;
}
// zero command means reset to beginning.
mGet = mBuffer;
}
}
void LocklessCommandFifo::next() {
uint32_t bytes = reinterpret_cast<const uint16_t *>(mGet)[1];
android_atomic_add(((bytes + 3) & ~3) + 4, (int32_t *)&mGet);
//mGet += ((bytes + 3) & ~3) + 4;
if (isEmpty()) {
mSignalToControl.set();
}
//dumpState("next");
}
bool LocklessCommandFifo::makeSpaceNonBlocking(uint32_t bytes) {
//dumpState("make space non-blocking");
if ((mPut+bytes) > mEnd) {
// Need to loop regardless of where get is.
if ((mGet > mPut) || (mBuffer+4 >= mGet)) {
return false;
}
// Toss in a reset then the normal wait for space will do the rest.
reinterpret_cast<uint16_t *>(mPut)[0] = 0;
reinterpret_cast<uint16_t *>(mPut)[1] = 0;
mPut = mBuffer;
mSignalToWorker.set();
}
// it will fit here so we just need to wait for space.
if (getFreeSpace() < bytes) {
return false;
}
return true;
}
void LocklessCommandFifo::makeSpace(uint32_t bytes) {
//dumpState("make space");
if ((mPut+bytes) > mEnd) {
// Need to loop regardless of where get is.
while ((mGet > mPut) || (mBuffer+4 >= mGet)) {
usleep(100);
}
// Toss in a reset then the normal wait for space will do the rest.
reinterpret_cast<uint16_t *>(mPut)[0] = 0;
reinterpret_cast<uint16_t *>(mPut)[1] = 0;
mPut = mBuffer;
mSignalToWorker.set();
}
// it will fit here so we just need to wait for space.
while (getFreeSpace() < bytes) {
usleep(100);
}
}
void LocklessCommandFifo::dumpState(const char *s) const {
ALOGV("%s %p put %p, get %p, buf %p, end %p", s, this, mPut, mGet, mBuffer, mEnd);
}
void LocklessCommandFifo::printDebugData() const {
dumpState("printing fifo debug");
const uint32_t *pptr = (const uint32_t *)mGet;
pptr -= 8 * 4;
if (mGet < mBuffer) {
pptr = (const uint32_t *)mBuffer;
}
for (int ct=0; ct < 16; ct++) {
ALOGV("fifo %p = 0x%08x 0x%08x 0x%08x 0x%08x", pptr, pptr[0], pptr[1], pptr[2], pptr[3]);
pptr += 4;
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright (C) 2009 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_RS_LOCKLESS_FIFO_H
#define ANDROID_RS_LOCKLESS_FIFO_H
#include "rsUtils.h"
#include "rsSignal.h"
namespace android {
namespace renderscript {
// A simple FIFO to be used as a producer / consumer between two
// threads. One is writer and one is reader. The common cases
// will not require locking. It is not threadsafe for multiple
// readers or writers by design.
class LocklessCommandFifo {
public:
bool init(uint32_t size);
void shutdown();
void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
void printDebugData() const;
LocklessCommandFifo();
~LocklessCommandFifo();
protected:
uint8_t * volatile mPut;
uint8_t * volatile mGet;
uint8_t * mBuffer;
uint8_t * mEnd;
uint8_t mSize;
bool mInShutdown;
bool mInitialized;
Signal mSignalToWorker;
Signal mSignalToControl;
public:
void * reserve(uint32_t bytes);
void commit(uint32_t command, uint32_t bytes);
void commitSync(uint32_t command, uint32_t bytes);
void flush();
bool wait(uint64_t timeout = 0);
const void * get(uint32_t *command, uint32_t *bytesData, uint64_t timeout = 0);
void next();
void makeSpace(uint32_t bytes);
bool makeSpaceNonBlocking(uint32_t bytes);
bool isEmpty() const;
uint32_t getFreeSpace() const;
private:
void dumpState(const char *) const;
void (*mTimeoutCallback)(void *);
void * mTimeoutCallbackData;
uint64_t mTimeoutWait;
};
}
}
#endif

View File

@@ -18,227 +18,189 @@
#include "rsThreadIO.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <poll.h>
using namespace android;
using namespace android::renderscript;
ThreadIO::ThreadIO() : mUsingSocket(false) {
ThreadIO::ThreadIO() {
mRunning = true;
}
ThreadIO::~ThreadIO() {
}
void ThreadIO::init(bool useSocket) {
mUsingSocket = useSocket;
mToCore.init(16 * 1024);
if (mUsingSocket) {
mToClientSocket.init();
mToCoreSocket.init();
} else {
mToClient.init(1024);
}
void ThreadIO::init() {
mToClient.init();
mToCore.init();
}
void ThreadIO::shutdown() {
//ALOGE("shutdown 1");
mRunning = false;
mToCore.shutdown();
//ALOGE("shutdown 2");
}
void ThreadIO::coreFlush() {
//ALOGE("coreFlush 1");
if (mUsingSocket) {
} else {
mToCore.flush();
}
//ALOGE("coreFlush 2");
}
void * ThreadIO::coreHeader(uint32_t cmdID, size_t dataLen) {
//ALOGE("coreHeader %i %i", cmdID, dataLen);
if (mUsingSocket) {
CoreCmdHeader hdr;
hdr.bytes = dataLen;
hdr.cmdID = cmdID;
mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
} else {
mCoreCommandSize = dataLen;
mCoreCommandID = cmdID;
mCoreDataPtr = (uint8_t *)mToCore.reserve(dataLen);
mCoreDataBasePtr = mCoreDataPtr;
}
//ALOGE("coreHeader ret %p", mCoreDataPtr);
return mCoreDataPtr;
}
void ThreadIO::coreData(const void *data, size_t dataLen) {
//ALOGE("coreData %p %i", data, dataLen);
mToCoreSocket.writeAsync(data, dataLen);
//ALOGE("coreData ret %p", mCoreDataPtr);
CoreCmdHeader *hdr = (CoreCmdHeader *)&mSendBuffer[0];
hdr->bytes = dataLen;
hdr->cmdID = cmdID;
mSendLen = dataLen + sizeof(CoreCmdHeader);
//mToCoreSocket.writeAsync(&hdr, sizeof(hdr));
//ALOGE("coreHeader ret ");
return &mSendBuffer[sizeof(CoreCmdHeader)];
}
void ThreadIO::coreCommit() {
//ALOGE("coreCommit %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize);
if (mUsingSocket) {
} else {
rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize);
mToCore.commit(mCoreCommandID, mCoreCommandSize);
}
//ALOGE("coreCommit ret");
}
void ThreadIO::coreCommitSync() {
//ALOGE("coreCommitSync %p %p %i", mCoreDataPtr, mCoreDataBasePtr, mCoreCommandSize);
if (mUsingSocket) {
} else {
rsAssert((size_t)(mCoreDataPtr - mCoreDataBasePtr) <= mCoreCommandSize);
mToCore.commitSync(mCoreCommandID, mCoreCommandSize);
}
//ALOGE("coreCommitSync ret");
mToCore.writeAsync(&mSendBuffer, mSendLen);
}
void ThreadIO::clientShutdown() {
//ALOGE("coreShutdown 1");
mToClient.shutdown();
//ALOGE("coreShutdown 2");
}
void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
rsAssert(dataLen <= sizeof(mToCoreRet));
memcpy(&mToCoreRet, data, dataLen);
uint32_t buf;
if (data == NULL) {
data = &buf;
dataLen = sizeof(buf);
}
mToCore.readReturn(data, dataLen);
}
void ThreadIO::coreGetReturn(void *data, size_t dataLen) {
memcpy(data, &mToCoreRet, dataLen);
uint32_t buf;
if (data == NULL) {
data = &buf;
dataLen = sizeof(buf);
}
mToCore.writeWaitReturn(data, dataLen);
}
void ThreadIO::setTimoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
mToCore.setTimoutCallback(cb, dat, timeout);
void ThreadIO::setTimeoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) {
//mToCore.setTimeoutCallback(cb, dat, timeout);
}
bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait) {
bool ThreadIO::playCoreCommands(Context *con, bool waitForCommand, int waitFd) {
bool ret = false;
uint64_t startTime = con->getTime();
while (!mToCore.isEmpty() || waitForCommand) {
uint32_t cmdID = 0;
uint32_t cmdSize = 0;
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_IDLE);
uint8_t buf[2 * 1024];
const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
const void * data = (const void *)&buf[sizeof(CoreCmdHeader)];
struct pollfd p[2];
p[0].fd = mToCore.getReadFd();
p[0].events = POLLIN;
p[0].revents = 0;
p[1].fd = waitFd;
p[1].events = POLLIN;
p[1].revents = 0;
int pollCount = 1;
if (waitFd >= 0) {
pollCount = 2;
}
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_IDLE);
}
int waitTime = -1;
while (mRunning) {
int pr = poll(p, pollCount, waitTime);
if (pr <= 0) {
break;
}
uint64_t delay = 0;
if (waitForCommand) {
delay = timeToWait - (con->getTime() - startTime);
if (delay > timeToWait) {
delay = 0;
if (p[0].revents) {
size_t r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
if (r != sizeof(CoreCmdHeader)) {
// exception or timeout occurred.
break;
}
ret = true;
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_INTERNAL);
}
waitForCommand = false;
//ALOGV("playCoreCommands 3 %i %i", cmd->cmdID, cmd->bytes);
if (cmd->cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
}
gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_IDLE);
}
if (waitFd < 0) {
// If we don't have a secondary wait object we should stop blocking now
// that at least one command has been processed.
waitTime = 0;
}
}
if (delay == 0 && timeToWait != 0 && mToCore.isEmpty()) {
if (p[1].revents && !p[0].revents) {
// We want to finish processing fifo events before processing the vsync.
// Otherwise we can end up falling behind and having tremendous lag.
break;
}
const void * data = mToCore.get(&cmdID, &cmdSize, delay);
if (!cmdSize) {
// exception or timeout occurred.
break;
}
ret = true;
if (con->props.mLogTimes) {
con->timerSet(Context::RS_TIMER_INTERNAL);
}
waitForCommand = false;
//ALOGV("playCoreCommands 3 %i %i", cmdID, cmdSize);
if (cmdID >= (sizeof(gPlaybackFuncs) / sizeof(void *))) {
rsAssert(cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
ALOGE("playCoreCommands error con %p, cmd %i", con, cmdID);
mToCore.printDebugData();
}
gPlaybackFuncs[cmdID](con, data, cmdSize << 2);
mToCore.next();
}
return ret;
}
RsMessageToClientType ThreadIO::getClientHeader(size_t *receiveLen, uint32_t *usrID) {
if (mUsingSocket) {
mToClientSocket.read(&mLastClientHeader, sizeof(mLastClientHeader));
} else {
size_t bytesData = 0;
const uint32_t *d = (const uint32_t *)mToClient.get(&mLastClientHeader.cmdID, (uint32_t*)&bytesData);
if (bytesData >= sizeof(uint32_t)) {
mLastClientHeader.userID = d[0];
mLastClientHeader.bytes = bytesData - sizeof(uint32_t);
} else {
mLastClientHeader.userID = 0;
mLastClientHeader.bytes = 0;
}
}
//ALOGE("getClientHeader");
mToClient.read(&mLastClientHeader, sizeof(mLastClientHeader));
receiveLen[0] = mLastClientHeader.bytes;
usrID[0] = mLastClientHeader.userID;
//ALOGE("getClientHeader %i %i %i", mLastClientHeader.cmdID, usrID[0], receiveLen[0]);
return (RsMessageToClientType)mLastClientHeader.cmdID;
}
RsMessageToClientType ThreadIO::getClientPayload(void *data, size_t *receiveLen,
uint32_t *usrID, size_t bufferLen) {
//ALOGE("getClientPayload");
receiveLen[0] = mLastClientHeader.bytes;
usrID[0] = mLastClientHeader.userID;
if (bufferLen < mLastClientHeader.bytes) {
return RS_MESSAGE_TO_CLIENT_RESIZE;
}
if (mUsingSocket) {
if (receiveLen[0]) {
mToClientSocket.read(data, receiveLen[0]);
}
return (RsMessageToClientType)mLastClientHeader.cmdID;
} else {
uint32_t bytesData = 0;
uint32_t commandID = 0;
const uint32_t *d = (const uint32_t *)mToClient.get(&commandID, &bytesData);
//ALOGE("getMessageToClient 3 %i %i", commandID, bytesData);
//ALOGE("getMessageToClient %i %i", commandID, *subID);
if (bufferLen >= receiveLen[0]) {
memcpy(data, d+1, receiveLen[0]);
mToClient.next();
return (RsMessageToClientType)commandID;
}
if (receiveLen[0]) {
mToClient.read(data, receiveLen[0]);
}
return RS_MESSAGE_TO_CLIENT_RESIZE;
//ALOGE("getClientPayload x");
return (RsMessageToClientType)mLastClientHeader.cmdID;
}
bool ThreadIO::sendToClient(RsMessageToClientType cmdID, uint32_t usrID, const void *data,
size_t dataLen, bool waitForSpace) {
//ALOGE("sendToClient %i %i %i", cmdID, usrID, (int)dataLen);
ClientCmdHeader hdr;
hdr.bytes = dataLen;
hdr.cmdID = cmdID;
hdr.userID = usrID;
if (mUsingSocket) {
mToClientSocket.writeAsync(&hdr, sizeof(hdr));
if (dataLen) {
mToClientSocket.writeAsync(data, dataLen);
}
return true;
} else {
if (!waitForSpace) {
if (!mToClient.makeSpaceNonBlocking(dataLen + sizeof(hdr))) {
// Not enough room, and not waiting.
return false;
}
}
//ALOGE("sendMessageToClient 2");
uint32_t *p = (uint32_t *)mToClient.reserve(dataLen + sizeof(usrID));
p[0] = usrID;
if (dataLen > 0) {
memcpy(p+1, data, dataLen);
}
mToClient.commit(cmdID, dataLen + sizeof(usrID));
//ALOGE("sendMessageToClient 3");
return true;
mToClient.writeAsync(&hdr, sizeof(hdr));
if (dataLen) {
mToClient.writeAsync(data, dataLen);
}
return false;
//ALOGE("sendToClient x");
return true;
}

View File

@@ -18,7 +18,6 @@
#define ANDROID_RS_THREAD_IO_H
#include "rsUtils.h"
#include "rsLocklessFifo.h"
#include "rsFifoSocket.h"
// ---------------------------------------------------------------------------
@@ -32,23 +31,17 @@ public:
ThreadIO();
~ThreadIO();
void init(bool useSocket = false);
void init();
void shutdown();
// Plays back commands from the client.
// Returns true if any commands were processed.
bool playCoreCommands(Context *con, bool waitForCommand, uint64_t timeToWait);
bool playCoreCommands(Context *con, bool waitForCommand, int waitFd);
void setTimoutCallback(void (*)(void *), void *, uint64_t timeout);
//LocklessCommandFifo mToCore;
void setTimeoutCallback(void (*)(void *), void *, uint64_t timeout);
void coreFlush();
void * coreHeader(uint32_t, size_t dataLen);
void coreData(const void *data, size_t dataLen);
void coreCommit();
void coreCommitSync();
void coreSetReturn(const void *data, size_t dataLen);
void coreGetReturn(void *data, size_t dataLen);
@@ -71,20 +64,16 @@ protected:
} ClientCmdHeader;
ClientCmdHeader mLastClientHeader;
size_t mCoreCommandSize;
uint32_t mCoreCommandID;
uint8_t * mCoreDataPtr;
uint8_t * mCoreDataBasePtr;
bool mRunning;
bool mUsingSocket;
LocklessCommandFifo mToClient;
LocklessCommandFifo mToCore;
FifoSocket mToClientSocket;
FifoSocket mToCoreSocket;
FifoSocket mToClient;
FifoSocket mToCore;
intptr_t mToCoreRet;
size_t mSendLen;
uint8_t mSendBuffer[2 * 1024];
};

View File

@@ -256,7 +256,7 @@ void printApiCpp(FILE *f) {
fprintf(f, " memcpy(payload, %s, %s_length);\n", vt->name, vt->name);
fprintf(f, " cmd->%s = (", vt->name);
printVarType(f, vt);
fprintf(f, ")payload;\n");
fprintf(f, ")(payload - ((uint8_t *)&cmd[1]));\n");
fprintf(f, " payload += %s_length;\n", vt->name);
fprintf(f, " } else {\n");
fprintf(f, " cmd->%s = %s;\n", vt->name, vt->name);
@@ -270,26 +270,19 @@ void printApiCpp(FILE *f) {
needFlush = 1;
}
fprintf(f, " io->coreCommit();\n");
if (hasInlineDataPointers(api)) {
fprintf(f, " if (dataSize < 1024) {\n");
fprintf(f, " io->coreCommit();\n");
fprintf(f, " } else {\n");
fprintf(f, " io->coreCommitSync();\n");
fprintf(f, " if (dataSize >= 1024) {\n");
fprintf(f, " io->coreGetReturn(NULL, 0);\n");
fprintf(f, " }\n");
} else {
fprintf(f, " io->coreCommit");
if (needFlush) {
fprintf(f, "Sync");
}
fprintf(f, "();\n");
}
if (api->ret.typeName[0]) {
} else if (api->ret.typeName[0]) {
fprintf(f, "\n ");
printVarType(f, &api->ret);
fprintf(f, " ret;\n");
fprintf(f, " io->coreGetReturn(&ret, sizeof(ret));\n");
fprintf(f, " return ret;\n");
} else if (needFlush) {
fprintf(f, " io->coreGetReturn(NULL, 0);\n");
}
}
fprintf(f, "};\n\n");
@@ -434,6 +427,7 @@ void printPlaybackCpp(FILE *f) {
for (ct=0; ct < apiCount; ct++) {
const ApiEntry * api = &apis[ct];
int needFlush = 0;
if (api->direct) {
continue;
@@ -444,6 +438,13 @@ void printPlaybackCpp(FILE *f) {
//fprintf(f, " ALOGE(\"play command %s\\n\");\n", api->name);
fprintf(f, " const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
if (hasInlineDataPointers(api)) {
fprintf(f, " const uint8_t *baseData = 0;\n");
fprintf(f, " if (cmdSizeBytes != sizeof(RS_CMD_%s)) {\n", api->name);
fprintf(f, " baseData = &((const uint8_t *)vp)[sizeof(*cmd)];\n");
fprintf(f, " }\n");
}
fprintf(f, " ");
if (api->ret.typeName[0]) {
fprintf(f, "\n ");
@@ -453,12 +454,24 @@ void printPlaybackCpp(FILE *f) {
fprintf(f, "rsi_%s(con", api->name);
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
fprintf(f, ",\n cmd->%s", vt->name);
needFlush += vt->ptrLevel;
if (hasInlineDataPointers(api) && vt->ptrLevel) {
fprintf(f, ",\n (const %s *)&baseData[(intptr_t)cmd->%s]", vt->typeName, vt->name);
} else {
fprintf(f, ",\n cmd->%s", vt->name);
}
}
fprintf(f, ");\n");
if (api->ret.typeName[0]) {
if (hasInlineDataPointers(api)) {
fprintf(f, " if (cmdSizeBytes == sizeof(RS_CMD_%s)) {\n", api->name);
fprintf(f, " con->mIO.coreSetReturn(NULL, 0);\n");
fprintf(f, " }\n");
} else if (api->ret.typeName[0]) {
fprintf(f, " con->mIO.coreSetReturn(&ret, sizeof(ret));\n");
} else if (api->sync || needFlush) {
fprintf(f, " con->mIO.coreSetReturn(NULL, 0);\n");
}
fprintf(f, "};\n\n");
@@ -466,6 +479,7 @@ void printPlaybackCpp(FILE *f) {
for (ct=0; ct < apiCount; ct++) {
const ApiEntry * api = &apis[ct];
int needFlush = 0;
fprintf(f, "void rspr_%s(Context *con, Fifo *f, uint8_t *scratch, size_t scratchSize) {\n", api->name);
@@ -475,6 +489,7 @@ void printPlaybackCpp(FILE *f) {
for (ct2=0; ct2 < api->paramCount; ct2++) {
const VarType *vt = &api->params[ct2];
needFlush += vt->ptrLevel;
if (vt->ptrLevel == 1) {
fprintf(f, " cmd.%s = (", vt->name);
printVarType(f, vt);
@@ -515,6 +530,8 @@ void printPlaybackCpp(FILE *f) {
if (api->ret.typeName[0]) {
fprintf(f, " f->readReturn(&ret, sizeof(ret));\n");
} else if (needFlush) {
fprintf(f, " f->readReturn(NULL, 0);\n");
}
fprintf(f, "};\n\n");