From 4c2e4c80ce519e09e5b00fd7533e64a834d70639 Mon Sep 17 00:00:00 2001 From: Jason Sams Date: Tue, 7 Feb 2012 15:32:08 -0800 Subject: Implement RS VSync on new vsync infrastructure. Change-Id: I662159a086a56e28732dd64a3a3cb30f8d4b72b1 Replace lockless fifo from server to client with sockets. Change-Id: I99a4ab4f18496c0fbac96ee7b8099797af4712ea --- graphics/jni/android_renderscript_RenderScript.cpp | 2 +- libs/rs/Android.mk | 4 +- libs/rs/driver/rsdGL.cpp | 2 + libs/rs/rs.spec | 1 + libs/rs/rsContext.cpp | 84 ++++--- libs/rs/rsContext.h | 1 - libs/rs/rsFifo.cpp | 31 --- libs/rs/rsFifo.h | 4 +- libs/rs/rsFifoSocket.cpp | 53 +++-- libs/rs/rsFifoSocket.h | 22 +- libs/rs/rsLocklessFifo.cpp | 251 -------------------- libs/rs/rsLocklessFifo.h | 84 ------- libs/rs/rsThreadIO.cpp | 264 +++++++++------------ libs/rs/rsThreadIO.h | 29 +-- libs/rs/rsg_generator.c | 49 ++-- 15 files changed, 260 insertions(+), 621 deletions(-) delete mode 100644 libs/rs/rsFifo.cpp delete mode 100644 libs/rs/rsLocklessFifo.cpp delete mode 100644 libs/rs/rsLocklessFifo.h diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index 07bf7bf..9622bd2 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -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, diff --git a/libs/rs/Android.mk b/libs/rs/Android.mk index 58d3e5c..2166ce7 100644 --- a/libs/rs/Android.mk +++ b/libs/rs/Android.mk @@ -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 \ diff --git a/libs/rs/driver/rsdGL.cpp b/libs/rs/driver/rsdGL.cpp index 7acc054..368dd71 100644 --- a/libs/rs/driver/rsdGL.cpp +++ b/libs/rs/driver/rsdGL.cpp @@ -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]; diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index 6887b22..ffb1196 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -115,6 +115,7 @@ ContextSetPriority { } ContextDestroyWorker { + sync } AssignName { diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp index ad2ff0f..04284dd 100644 --- a/libs/rs/rsContext.cpp +++ b/libs/rs/rsContext.cpp @@ -18,6 +18,7 @@ #include "rsContext.h" #include "rsThreadIO.h" #include +#include #include #include @@ -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; - - if (mDraw && rsc->mIsGraphicsContext) { - uint64_t delay = rsc->runRootScript() * 1000000; - targetTime = rsc->getTime() + delay; - doWait = (delay == 0); + bool drawOnce = false; + while (!rsc->mExit) { + rsc->timerSet(RS_TIMER_IDLE); - 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); diff --git a/libs/rs/rsContext.h b/libs/rs/rsContext.h index 61c29f9..a844a20 100644 --- a/libs/rs/rsContext.h +++ b/libs/rs/rsContext.h @@ -39,7 +39,6 @@ #include "rsFBOCache.h" #include "rsgApiStructs.h" -#include "rsLocklessFifo.h" // --------------------------------------------------------------------------- namespace android { diff --git a/libs/rs/rsFifo.cpp b/libs/rs/rsFifo.cpp deleted file mode 100644 index 3d5d8c4..0000000 --- a/libs/rs/rsFifo.cpp +++ /dev/null @@ -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() { - -} - diff --git a/libs/rs/rsFifo.h b/libs/rs/rsFifo.h index f924b95..911f446 100644 --- a/libs/rs/rsFifo.h +++ b/libs/rs/rsFifo.h @@ -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; diff --git a/libs/rs/rsFifoSocket.cpp b/libs/rs/rsFifoSocket.cpp index 163a44b..bd511cf 100644 --- a/libs/rs/rsFifoSocket.cpp +++ b/libs/rs/rsFifoSocket.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -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; } -void FifoSocket::readReturn(const void *data, size_t bytes) { - ALOGE("readReturn %p %Zu", data, bytes); - size_t ret = ::send(sv[1], data, bytes, 0); - ALOGE("readReturn %Zu", ret); - rsAssert(ret == bytes); +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::flush() { +void FifoSocket::readReturn(const void *data, size_t bytes) { + //ALOGE("readReturn %p %Zu", data, bytes); + size_t ret = ::send(sv[1], data, bytes, 0); + //ALOGE("readReturn %Zu", ret); + //rsAssert(ret == bytes); } diff --git a/libs/rs/rsFifoSocket.h b/libs/rs/rsFifoSocket.h index 7df2b67..cac0a75 100644 --- a/libs/rs/rsFifoSocket.h +++ b/libs/rs/rsFifoSocket.h @@ -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; }; } diff --git a/libs/rs/rsLocklessFifo.cpp b/libs/rs/rsLocklessFifo.cpp deleted file mode 100644 index 0466d8b..0000000 --- a/libs/rs/rsLocklessFifo.cpp +++ /dev/null @@ -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(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(mPut)[0] = command; - reinterpret_cast(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(mGet)[0]; - *bytesData = reinterpret_cast(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(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(mPut)[0] = 0; - reinterpret_cast(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(mPut)[0] = 0; - reinterpret_cast(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; - } - -} diff --git a/libs/rs/rsLocklessFifo.h b/libs/rs/rsLocklessFifo.h deleted file mode 100644 index dafc512..0000000 --- a/libs/rs/rsLocklessFifo.h +++ /dev/null @@ -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 diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp index 1917774..8e4b988 100644 --- a/libs/rs/rsThreadIO.cpp +++ b/libs/rs/rsThreadIO.cpp @@ -18,227 +18,189 @@ #include "rsThreadIO.h" +#include +#include +#include + +#include +#include + + 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); + } -void ThreadIO::setTimoutCallback(void (*cb)(void *), void *dat, uint64_t timeout) { - mToCore.setTimoutCallback(cb, dat, timeout); + mToCore.writeWaitReturn(data, dataLen); } +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; + } - uint64_t delay = 0; - if (waitForCommand) { - delay = timeToWait - (con->getTime() - startTime); - if (delay > timeToWait) { - delay = 0; - } - } + if (con->props.mLogTimes) { + con->timerSet(Context::RS_TIMER_IDLE); + } - if (delay == 0 && timeToWait != 0 && mToCore.isEmpty()) { + int waitTime = -1; + while (mRunning) { + int pr = poll(p, pollCount, waitTime); + if (pr <= 0) { 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); + 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; + } } - 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(); + 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; } - 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; } diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h index ebce0ab..d56a1c9 100644 --- a/libs/rs/rsThreadIO.h +++ b/libs/rs/rsThreadIO.h @@ -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]; + }; diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c index 6b84e56..7a90597 100644 --- a/libs/rs/rsg_generator.c +++ b/libs/rs/rsg_generator.c @@ -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(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"); -- cgit v1.1